Merge "Update hub background animation" into main
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/api/test-current.txt b/core/api/test-current.txt
index 14ae3f5..d03dd16 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -46,6 +46,7 @@
field public static final String REMAP_MODIFIER_KEYS = "android.permission.REMAP_MODIFIER_KEYS";
field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
field public static final String REQUEST_UNIQUE_ID_ATTESTATION = "android.permission.REQUEST_UNIQUE_ID_ATTESTATION";
+ field public static final String RESERVED_FOR_TESTING_SIGNATURE = "android.permission.RESERVED_FOR_TESTING_SIGNATURE";
field public static final String RESET_APP_ERRORS = "android.permission.RESET_APP_ERRORS";
field public static final String REVOKE_POST_NOTIFICATIONS_WITHOUT_KILL = "android.permission.REVOKE_POST_NOTIFICATIONS_WITHOUT_KILL";
field public static final String SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS = "android.permission.SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS";
diff --git a/core/api/test-lint-baseline.txt b/core/api/test-lint-baseline.txt
index 6cc71e5..b4a3abc 100644
--- a/core/api/test-lint-baseline.txt
+++ b/core/api/test-lint-baseline.txt
@@ -1973,6 +1973,8 @@
UnflaggedApi: android.Manifest.permission#MANAGE_REMOTE_AUTH:
New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_REMOTE_AUTH
+UnflaggedApi: android.Manifest.permission#RESERVED_FOR_TESTING_SIGNATURE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.RESERVED_FOR_TESTING_SIGNATURE
UnflaggedApi: android.Manifest.permission#START_ACTIVITIES_FROM_SDK_SANDBOX:
New API must be flagged with @FlaggedApi: field android.Manifest.permission.START_ACTIVITIES_FROM_SDK_SANDBOX
UnflaggedApi: android.Manifest.permission#USE_REMOTE_AUTH:
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/assist/AssistContent.java b/core/java/android/app/assist/AssistContent.java
index e5316bc0..a488689 100644
--- a/core/java/android/app/assist/AssistContent.java
+++ b/core/java/android/app/assist/AssistContent.java
@@ -34,12 +34,22 @@
}
/**
+ * Create an AssistContent with extras initialized.
+ *
* @hide
+ */
+ public AssistContent(@android.annotation.NonNull Bundle extras) {
+ mExtras = extras;
+ }
+
+ /**
* Called by {@link android.app.ActivityThread} to set the default Intent based on
* {@link android.app.Activity#getIntent Activity.getIntent}.
*
* <p>Automatically populates {@link #mUri} if that Intent is an {@link Intent#ACTION_VIEW}
* of a web (http or https scheme) URI.</p>
+ *
+ * @hide
*/
public void setDefaultIntent(Intent intent) {
mIntent = intent;
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/Context.java b/core/java/android/content/Context.java
index bad73fc..4fcf6b6 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -7188,9 +7188,10 @@
* as the package remains in the foreground, or has any active manifest components (e.g. when
* another app is accessing a content provider in the package).
* <p>
- * If you want to revoke the permissions right away, you could call {@code System.exit()}, but
- * this could affect other apps that are accessing your app at the moment. For example, apps
- * accessing a content provider in your app will all crash.
+ * If you want to revoke the permissions right away, you could call {@code System.exit()} in
+ * {@code Handler.postDelayed} with a delay to allow completion of async IPC, But
+ * {@code System.exit()} could affect other apps that are accessing your app at the moment.
+ * For example, apps accessing a content provider in your app will all crash.
* <p>
* Note that the settings UI shows a permission group as granted as long as at least one
* permission in the group is granted. If you want the user to observe the revocation in the
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/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 3cc87ea..6fffb82 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -1472,9 +1472,9 @@
new Key<Integer>("android.flash.info.strengthDefaultLevel", int.class);
/**
- * <p>Maximum flash brightness level for manual flash control in SINGLE mode.</p>
+ * <p>Maximum flash brightness level for manual flash control in <code>SINGLE</code> mode.</p>
* <p>Maximum flash brightness level in camera capture mode and
- * {@link CaptureRequest#FLASH_MODE android.flash.mode} set to SINGLE.
+ * {@link CaptureRequest#FLASH_MODE android.flash.mode} set to <code>SINGLE</code>.
* Value will be > 1 if the manual flash strength control feature is supported,
* otherwise the value will be equal to 1.
* Note that this level is just a number of supported levels (the granularity of control).
@@ -1490,7 +1490,7 @@
new Key<Integer>("android.flash.singleStrengthMaxLevel", int.class);
/**
- * <p>Default flash brightness level for manual flash control in SINGLE mode.</p>
+ * <p>Default flash brightness level for manual flash control in <code>SINGLE</code> mode.</p>
* <p>If flash unit is available this will be greater than or equal to 1 and less
* or equal to {@link CameraCharacteristics#FLASH_SINGLE_STRENGTH_MAX_LEVEL android.flash.singleStrengthMaxLevel}.
* Note for devices that do not support the manual flash strength control
@@ -1506,9 +1506,9 @@
new Key<Integer>("android.flash.singleStrengthDefaultLevel", int.class);
/**
- * <p>Maximum flash brightness level for manual flash control in TORCH mode</p>
+ * <p>Maximum flash brightness level for manual flash control in <code>TORCH</code> mode</p>
* <p>Maximum flash brightness level in camera capture mode and
- * {@link CaptureRequest#FLASH_MODE android.flash.mode} set to TORCH.
+ * {@link CaptureRequest#FLASH_MODE android.flash.mode} set to <code>TORCH</code>.
* Value will be > 1 if the manual flash strength control feature is supported,
* otherwise the value will be equal to 1.</p>
* <p>Note that this level is just a number of supported levels(the granularity of control).
@@ -1530,7 +1530,7 @@
new Key<Integer>("android.flash.torchStrengthMaxLevel", int.class);
/**
- * <p>Default flash brightness level for manual flash control in TORCH mode</p>
+ * <p>Default flash brightness level for manual flash control in <code>TORCH</code> mode</p>
* <p>If flash unit is available this will be greater than or equal to 1 and less
* or equal to {@link CameraCharacteristics#FLASH_TORCH_STRENGTH_MAX_LEVEL android.flash.torchStrengthMaxLevel}.
* Note for the devices that do not support the manual flash strength control feature,
@@ -4152,10 +4152,16 @@
/**
* <p>Whether the RAW images output from this camera device are subject to
* lens shading correction.</p>
- * <p>If TRUE, all images produced by the camera device in the RAW image formats will
- * have lens shading correction already applied to it. If FALSE, the images will
- * not be adjusted for lens shading correction.
- * See {@link CameraCharacteristics#REQUEST_MAX_NUM_OUTPUT_RAW android.request.maxNumOutputRaw} for a list of RAW image formats.</p>
+ * <p>If <code>true</code>, all images produced by the camera device in the <code>RAW</code> image formats will have
+ * at least some lens shading correction already applied to it. If <code>false</code>, the images will
+ * not be adjusted for lens shading correction. See {@link CameraCharacteristics#REQUEST_MAX_NUM_OUTPUT_RAW android.request.maxNumOutputRaw} for a
+ * list of RAW image formats.</p>
+ * <p>When <code>true</code>, the <code>lensShadingCorrectionMap</code> key may still have values greater than 1.0,
+ * and those will need to be applied to any captured RAW frames for them to match the shading
+ * correction of processed buffers such as <code>YUV</code> or <code>JPEG</code> images. This may occur, for
+ * example, when some basic fixed lens shading correction is applied by hardware to RAW data,
+ * and additional correction is done dynamically in the camera processing pipeline after
+ * demosaicing.</p>
* <p>This key will be <code>null</code> for all devices do not report this information.
* Devices with RAW capability will always report this information in this key.</p>
* <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
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/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 938636f..6968f27 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -2683,27 +2683,27 @@
/**
* <p>Flash strength level to be used when manual flash control is active.</p>
* <p>Flash strength level to use in capture mode i.e. when the applications control
- * flash with either SINGLE or TORCH mode.</p>
+ * flash with either <code>SINGLE</code> or <code>TORCH</code> mode.</p>
* <p>Use {@link CameraCharacteristics#FLASH_SINGLE_STRENGTH_MAX_LEVEL android.flash.singleStrengthMaxLevel} and
* {@link CameraCharacteristics#FLASH_TORCH_STRENGTH_MAX_LEVEL android.flash.torchStrengthMaxLevel} to check whether the device supports
* flash strength control or not.
- * If the values of android.flash.info.singleStrengthMaxLevel and
+ * If the values of {@link CameraCharacteristics#FLASH_SINGLE_STRENGTH_MAX_LEVEL android.flash.singleStrengthMaxLevel} and
* {@link CameraCharacteristics#FLASH_TORCH_STRENGTH_MAX_LEVEL android.flash.torchStrengthMaxLevel} are greater than 1,
* then the device supports manual flash strength control.</p>
- * <p>If the {@link CaptureRequest#FLASH_MODE android.flash.mode} <code>==</code> TORCH the value must be >= 1
+ * <p>If the {@link CaptureRequest#FLASH_MODE android.flash.mode} <code>==</code> <code>TORCH</code> the value must be >= 1
* and <= {@link CameraCharacteristics#FLASH_TORCH_STRENGTH_MAX_LEVEL android.flash.torchStrengthMaxLevel}.
* If the application doesn't set the key and
* {@link CameraCharacteristics#FLASH_TORCH_STRENGTH_MAX_LEVEL android.flash.torchStrengthMaxLevel} > 1,
* then the flash will be fired at the default level set by HAL in
* {@link CameraCharacteristics#FLASH_TORCH_STRENGTH_DEFAULT_LEVEL android.flash.torchStrengthDefaultLevel}.
- * If the {@link CaptureRequest#FLASH_MODE android.flash.mode} <code>==</code> SINGLE, then the value must be >= 1
+ * If the {@link CaptureRequest#FLASH_MODE android.flash.mode} <code>==</code> <code>SINGLE</code>, then the value must be >= 1
* and <= {@link CameraCharacteristics#FLASH_SINGLE_STRENGTH_MAX_LEVEL android.flash.singleStrengthMaxLevel}.
* If the application does not set this key and
* {@link CameraCharacteristics#FLASH_SINGLE_STRENGTH_MAX_LEVEL android.flash.singleStrengthMaxLevel} > 1,
* then the flash will be fired at the default level set by HAL
* in {@link CameraCharacteristics#FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL android.flash.singleStrengthDefaultLevel}.
- * If {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is set to any of ON_AUTO_FLASH, ON_ALWAYS_FLASH,
- * ON_AUTO_FLASH_REDEYE, ON_EXTERNAL_FLASH values, then the strengthLevel will be ignored.</p>
+ * If {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is set to any of <code>ON_AUTO_FLASH</code>, <code>ON_ALWAYS_FLASH</code>,
+ * <code>ON_AUTO_FLASH_REDEYE</code>, <code>ON_EXTERNAL_FLASH</code> values, then the strengthLevel will be ignored.</p>
* <p><b>Range of valid values:</b><br>
* <code>[1-{@link CameraCharacteristics#FLASH_TORCH_STRENGTH_MAX_LEVEL android.flash.torchStrengthMaxLevel}]</code> when the {@link CaptureRequest#FLASH_MODE android.flash.mode} is
* set to TORCH;
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 4406a41..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>
@@ -2976,27 +2975,27 @@
/**
* <p>Flash strength level to be used when manual flash control is active.</p>
* <p>Flash strength level to use in capture mode i.e. when the applications control
- * flash with either SINGLE or TORCH mode.</p>
+ * flash with either <code>SINGLE</code> or <code>TORCH</code> mode.</p>
* <p>Use {@link CameraCharacteristics#FLASH_SINGLE_STRENGTH_MAX_LEVEL android.flash.singleStrengthMaxLevel} and
* {@link CameraCharacteristics#FLASH_TORCH_STRENGTH_MAX_LEVEL android.flash.torchStrengthMaxLevel} to check whether the device supports
* flash strength control or not.
- * If the values of android.flash.info.singleStrengthMaxLevel and
+ * If the values of {@link CameraCharacteristics#FLASH_SINGLE_STRENGTH_MAX_LEVEL android.flash.singleStrengthMaxLevel} and
* {@link CameraCharacteristics#FLASH_TORCH_STRENGTH_MAX_LEVEL android.flash.torchStrengthMaxLevel} are greater than 1,
* then the device supports manual flash strength control.</p>
- * <p>If the {@link CaptureRequest#FLASH_MODE android.flash.mode} <code>==</code> TORCH the value must be >= 1
+ * <p>If the {@link CaptureRequest#FLASH_MODE android.flash.mode} <code>==</code> <code>TORCH</code> the value must be >= 1
* and <= {@link CameraCharacteristics#FLASH_TORCH_STRENGTH_MAX_LEVEL android.flash.torchStrengthMaxLevel}.
* If the application doesn't set the key and
* {@link CameraCharacteristics#FLASH_TORCH_STRENGTH_MAX_LEVEL android.flash.torchStrengthMaxLevel} > 1,
* then the flash will be fired at the default level set by HAL in
* {@link CameraCharacteristics#FLASH_TORCH_STRENGTH_DEFAULT_LEVEL android.flash.torchStrengthDefaultLevel}.
- * If the {@link CaptureRequest#FLASH_MODE android.flash.mode} <code>==</code> SINGLE, then the value must be >= 1
+ * If the {@link CaptureRequest#FLASH_MODE android.flash.mode} <code>==</code> <code>SINGLE</code>, then the value must be >= 1
* and <= {@link CameraCharacteristics#FLASH_SINGLE_STRENGTH_MAX_LEVEL android.flash.singleStrengthMaxLevel}.
* If the application does not set this key and
* {@link CameraCharacteristics#FLASH_SINGLE_STRENGTH_MAX_LEVEL android.flash.singleStrengthMaxLevel} > 1,
* then the flash will be fired at the default level set by HAL
* in {@link CameraCharacteristics#FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL android.flash.singleStrengthDefaultLevel}.
- * If {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is set to any of ON_AUTO_FLASH, ON_ALWAYS_FLASH,
- * ON_AUTO_FLASH_REDEYE, ON_EXTERNAL_FLASH values, then the strengthLevel will be ignored.</p>
+ * If {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is set to any of <code>ON_AUTO_FLASH</code>, <code>ON_ALWAYS_FLASH</code>,
+ * <code>ON_AUTO_FLASH_REDEYE</code>, <code>ON_EXTERNAL_FLASH</code> values, then the strengthLevel will be ignored.</p>
* <p><b>Range of valid values:</b><br>
* <code>[1-{@link CameraCharacteristics#FLASH_TORCH_STRENGTH_MAX_LEVEL android.flash.torchStrengthMaxLevel}]</code> when the {@link CaptureRequest#FLASH_MODE android.flash.mode} is
* set to TORCH;
@@ -4846,6 +4845,9 @@
* correction map that needs to be applied to get shading
* corrected images that match the camera device's output for
* non-RAW formats.</p>
+ * <p>Therefore, whatever the value of lensShadingApplied is, the lens
+ * shading map should always be applied to RAW images if the goal is to
+ * match the shading appearance of processed (non-RAW) images.</p>
* <p>For a complete shading correction map, the least shaded
* section of the image will have a gain factor of 1; all
* other sections will have gains above 1.</p>
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/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 3d7b714..8519722 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -548,6 +548,20 @@
}
}
+ /**
+ * Request to power a display ON or OFF.
+ * @hide
+ */
+ @RequiresPermission("android.permission.MANAGE_DISPLAYS")
+ public boolean requestDisplayPower(int displayId, boolean on) {
+ try {
+ return mDm.requestDisplayPower(displayId, on);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Error trying to request display power " + on, ex);
+ return false;
+ }
+ }
+
public void startWifiDisplayScan() {
synchronized (mLock) {
if (mWifiDisplayScanNestCount++ == 0) {
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index 70efc6f..b7c02b0 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -236,6 +236,10 @@
@EnforcePermission("MANAGE_DISPLAYS")
void disableConnectedDisplay(int displayId);
+ // Request to power display ON or OFF.
+ @EnforcePermission("MANAGE_DISPLAYS")
+ boolean requestDisplayPower(int displayId, boolean on);
+
// Restricts display modes to specified modeIds.
@EnforcePermission("RESTRICT_DISPLAY_MODES")
void requestDisplayModes(in IBinder token, int displayId, in @nullable int[] modeIds);
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/provider/Settings.java b/core/java/android/provider/Settings.java
index 05345d8..63f0b9e 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6101,6 +6101,15 @@
public static final String POINTER_SPEED = "pointer_speed";
/**
+ * Pointer scale setting.
+ *
+ * <p>This float value represents the scale by which the size of the pointer increases.
+ * @hide
+ */
+ @Readable
+ public static final String POINTER_SCALE = "pointer_scale";
+
+ /**
* Touchpad pointer speed setting.
* This is an integer value in a range between -7 and +7, so there are 15 possible values.
* -7 = slowest
@@ -6358,6 +6367,7 @@
PRIVATE_SETTINGS.add(SIP_ASK_ME_EACH_TIME);
PRIVATE_SETTINGS.add(POINTER_SPEED);
PRIVATE_SETTINGS.add(POINTER_FILL_STYLE);
+ PRIVATE_SETTINGS.add(POINTER_SCALE);
PRIVATE_SETTINGS.add(LOCK_TO_APP_ENABLED);
PRIVATE_SETTINGS.add(EGG_MODE);
PRIVATE_SETTINGS.add(SHOW_BATTERY_PERCENT);
diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java
index e1965ef..405fe26 100644
--- a/core/java/android/service/contentcapture/ContentCaptureService.java
+++ b/core/java/android/service/contentcapture/ContentCaptureService.java
@@ -29,6 +29,7 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.app.Service;
+import android.app.assist.AssistContent;
import android.content.ComponentName;
import android.content.ContentCaptureOptions;
import android.content.Intent;
@@ -133,6 +134,16 @@
*/
public static final String SERVICE_META_DATA = "android.content_capture";
+
+ /**
+ * Extras key to flag that the passed in {@link AssistContent} is sent only during Activity
+ * start.
+ *
+ * @hide
+ */
+ public static final String ASSIST_CONTENT_ACTIVITY_START_KEY = "activity_start_assist_content";
+
+
private final LocalDataShareAdapterResourceManager mDataShareAdapterResourceManager =
new LocalDataShareAdapterResourceManager();
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/DropBoxManagerLoggerBackend.java b/core/java/android/telephony/DropBoxManagerLoggerBackend.java
new file mode 100644
index 0000000..25a3b9f
--- /dev/null
+++ b/core/java/android/telephony/DropBoxManagerLoggerBackend.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.os.DropBoxManager;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.util.Log;
+
+import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
+
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.util.Optional;
+
+/**
+ * A persistent logger backend that stores logs in Android DropBoxManager
+ *
+ * @hide
+ */
+public class DropBoxManagerLoggerBackend implements PersistentLoggerBackend {
+
+ private static final String TAG = "DropBoxManagerLoggerBackend";
+ // Separate tag reference to be explicitly used for dropboxmanager instead of logcat logging
+ private static final String DROPBOX_TAG = "DropBoxManagerLoggerBackend";
+ private static final DateTimeFormatter LOG_TIMESTAMP_FORMATTER =
+ DateTimeFormatter.ofPattern("MM-dd HH:mm:ss.SSS");
+ private static final ZoneId LOCAL_ZONE_ID = ZoneId.systemDefault();
+ private static final int BUFFER_SIZE_BYTES = 500 * 1024; // 500 KB
+ private static final int MIN_BUFFER_BYTES_FOR_FLUSH = 5 * 1024; // 5 KB
+
+ private static DropBoxManagerLoggerBackend sInstance;
+
+ private final DropBoxManager mDropBoxManager;
+ private final Object mBufferLock = new Object();
+ @GuardedBy("mBufferLock")
+ private final StringBuilder mLogBuffer = new StringBuilder();
+ private long mBufferStartTime = -1L;
+ private final HandlerThread mHandlerThread = new HandlerThread(DROPBOX_TAG);
+ private final Handler mHandler;
+ // Flag for determining if logging is enabled as a general feature
+ private final boolean mDropBoxManagerLoggingEnabled;
+ // Flag for controlling if logging is enabled at runtime
+ private boolean mIsLoggingEnabled = false;
+
+ /**
+ * Returns a singleton instance of {@code DropBoxManagerLoggerBackend} that will log to
+ * DropBoxManager if the config_dropboxmanager_persistent_logging_enabled resource config is
+ * enabled.
+ * @param context Android context
+ */
+ @Nullable
+ public static synchronized DropBoxManagerLoggerBackend getInstance(@NonNull Context context) {
+ if (sInstance == null) {
+ sInstance = new DropBoxManagerLoggerBackend(context);
+ }
+ return sInstance;
+ }
+
+ private DropBoxManagerLoggerBackend(@NonNull Context context) {
+ mDropBoxManager = context.getSystemService(DropBoxManager.class);
+ mHandlerThread.start();
+ mHandler = new Handler(mHandlerThread.getLooper());
+ mDropBoxManagerLoggingEnabled = persistentLoggingEnabled(context);
+ }
+
+ private boolean persistentLoggingEnabled(@NonNull Context context) {
+ try {
+ return context.getResources().getBoolean(
+ R.bool.config_dropboxmanager_persistent_logging_enabled);
+ } catch (RuntimeException e) {
+ Log.w(TAG, "Persistent logging config not found");
+ return false;
+ }
+ }
+
+ /**
+ * Enable or disable logging to DropBoxManager
+ * @param isLoggingEnabled Whether logging should be enabled
+ */
+ public void setLoggingEnabled(boolean isLoggingEnabled) {
+ Log.i(DROPBOX_TAG, "toggle logging: " + isLoggingEnabled);
+ mIsLoggingEnabled = isLoggingEnabled;
+ }
+
+ /**
+ * Persist a DEBUG log message.
+ * @param tag Used to identify the source of a log message.
+ * @param msg The message you would like logged.
+ */
+ public void debug(@NonNull String tag, @NonNull String msg) {
+ if (!mDropBoxManagerLoggingEnabled) {
+ return;
+ }
+ bufferLog("D", tag, msg, Optional.empty());
+ }
+
+ /**
+ * Persist a INFO log message.
+ * @param tag Used to identify the source of a log message.
+ * @param msg The message you would like logged.
+ */
+ public void info(@NonNull String tag, @NonNull String msg) {
+ if (!mDropBoxManagerLoggingEnabled) {
+ return;
+ }
+ bufferLog("I", tag, msg, Optional.empty());
+ }
+
+ /**
+ * Persist a WARN log message.
+ * @param tag Used to identify the source of a log message.
+ * @param msg The message you would like logged.
+ */
+ public void warn(@NonNull String tag, @NonNull String msg) {
+ if (!mDropBoxManagerLoggingEnabled) {
+ return;
+ }
+ bufferLog("W", tag, msg, Optional.empty());
+ }
+
+ /**
+ * Persist a WARN log message.
+ * @param tag Used to identify the source of a log message.
+ * @param msg The message you would like logged.
+ * @param t An exception to log.
+ */
+ public void warn(@NonNull String tag, @NonNull String msg, @NonNull Throwable t) {
+ if (!mDropBoxManagerLoggingEnabled) {
+ return;
+ }
+ bufferLog("W", tag, msg, Optional.of(t));
+ }
+
+ /**
+ * Persist a ERROR log message.
+ * @param tag Used to identify the source of a log message.
+ * @param msg The message you would like logged.
+ */
+ public void error(@NonNull String tag, @NonNull String msg) {
+ if (!mDropBoxManagerLoggingEnabled) {
+ return;
+ }
+ bufferLog("E", tag, msg, Optional.empty());
+ }
+
+ /**
+ * Persist a ERROR log message.
+ * @param tag Used to identify the source of a log message.
+ * @param msg The message you would like logged.
+ * @param t An exception to log.
+ */
+ public void error(@NonNull String tag, @NonNull String msg, @NonNull Throwable t) {
+ if (!mDropBoxManagerLoggingEnabled) {
+ return;
+ }
+ bufferLog("E", tag, msg, Optional.of(t));
+ }
+
+ private synchronized void bufferLog(
+ @NonNull String level,
+ @NonNull String tag,
+ @NonNull String msg,
+ Optional<Throwable> t) {
+ if (!mIsLoggingEnabled) {
+ return;
+ }
+
+ if (mBufferStartTime == -1L) {
+ mBufferStartTime = System.currentTimeMillis();
+ }
+
+ synchronized (mBufferLock) {
+ mLogBuffer
+ .append(formatLog(level, tag, msg, t))
+ .append("\n");
+
+ if (mLogBuffer.length() >= BUFFER_SIZE_BYTES) {
+ flushAsync();
+ }
+ }
+ }
+
+ private String formatLog(
+ @NonNull String level,
+ @NonNull String tag,
+ @NonNull String msg,
+ Optional<Throwable> t) {
+ // Expected format = "$Timestamp $Level $Tag: $Message"
+ return formatTimestamp(System.currentTimeMillis()) + " " + level + " " + tag + ": "
+ + t.map(throwable -> msg + ": " + Log.getStackTraceString(throwable)).orElse(msg);
+ }
+
+ private String formatTimestamp(long currentTimeMillis) {
+ return Instant.ofEpochMilli(currentTimeMillis)
+ .atZone(LOCAL_ZONE_ID)
+ .format(LOG_TIMESTAMP_FORMATTER);
+ }
+
+ /**
+ * Flushes all buffered logs into DropBoxManager as a single log record with a tag of
+ * {@link #DROPBOX_TAG} asynchronously. Should be invoked sparingly as DropBoxManager has
+ * device-level limitations on the number files that can be stored.
+ */
+ public void flushAsync() {
+ if (!mDropBoxManagerLoggingEnabled) {
+ return;
+ }
+
+ mHandler.post(this::flush);
+ };
+
+ /**
+ * Flushes all buffered logs into DropBoxManager as a single log record with a tag of
+ * {@link #DROPBOX_TAG}. Should be invoked sparingly as DropBoxManager has device-level
+ * limitations on the number files that can be stored.
+ */
+ public void flush() {
+ if (!mDropBoxManagerLoggingEnabled) {
+ return;
+ }
+
+ synchronized (mBufferLock) {
+ if (mLogBuffer.length() < MIN_BUFFER_BYTES_FOR_FLUSH) {
+ return;
+ }
+
+ Log.d(DROPBOX_TAG, "Flushing logs from "
+ + formatTimestamp(mBufferStartTime) + " to "
+ + formatTimestamp(System.currentTimeMillis()));
+
+ try {
+ mDropBoxManager.addText(DROPBOX_TAG, mLogBuffer.toString());
+ } catch (Exception e) {
+ Log.w(DROPBOX_TAG, "Failed to flush logs of length "
+ + mLogBuffer.length() + " to DropBoxManager", e);
+ }
+ mLogBuffer.setLength(0);
+ }
+ mBufferStartTime = -1L;
+ }
+}
diff --git a/core/java/android/telephony/PersistentLogger.java b/core/java/android/telephony/PersistentLogger.java
new file mode 100644
index 0000000..8b12a1c
--- /dev/null
+++ b/core/java/android/telephony/PersistentLogger.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.annotation.NonNull;
+
+/**
+ * A persistent logging client. Intended for persisting critical debug logs in situations where
+ * standard Android logcat logs may not be retained long enough.
+ *
+ * @hide
+ */
+public class PersistentLogger {
+ private final PersistentLoggerBackend mPersistentLoggerBackend;
+
+ public PersistentLogger(@NonNull PersistentLoggerBackend persistentLoggerBackend) {
+ mPersistentLoggerBackend = persistentLoggerBackend;
+ }
+
+ /**
+ * Persist a DEBUG log message.
+ * @param tag Used to identify the source of a log message.
+ * @param msg The message you would like logged.
+ */
+ public void debug(@NonNull String tag, @NonNull String msg) {
+ mPersistentLoggerBackend.debug(tag, msg);
+ }
+
+ /**
+ * Persist a INFO log message.
+ * @param tag Used to identify the source of a log message.
+ * @param msg The message you would like logged.
+ */
+ public void info(@NonNull String tag, @NonNull String msg) {
+ mPersistentLoggerBackend.info(tag, msg);
+ }
+
+ /**
+ * Persist a WARN log message.
+ * @param tag Used to identify the source of a log message.
+ * @param msg The message you would like logged.
+ */
+ public void warn(@NonNull String tag, @NonNull String msg) {
+ mPersistentLoggerBackend.warn(tag, msg);
+ }
+
+ /**
+ * Persist a WARN log message.
+ * @param tag Used to identify the source of a log message.
+ * @param msg The message you would like logged.
+ * @param t An exception to log.
+ */
+ public void warn(@NonNull String tag, @NonNull String msg, @NonNull Throwable t) {
+ mPersistentLoggerBackend.warn(tag, msg, t);
+ }
+
+ /**
+ * Persist a ERROR log message.
+ * @param tag Used to identify the source of a log message.
+ * @param msg The message you would like logged.
+ */
+ public void error(@NonNull String tag, @NonNull String msg) {
+ mPersistentLoggerBackend.error(tag, msg);
+ }
+
+ /**
+ * Persist a ERROR log message.
+ * @param tag Used to identify the source of a log message.
+ * @param msg The message you would like logged.
+ * @param t An exception to log.
+ */
+ public void error(@NonNull String tag, @NonNull String msg, @NonNull Throwable t) {
+ mPersistentLoggerBackend.error(tag, msg, t);
+ }
+}
diff --git a/core/java/android/telephony/PersistentLoggerBackend.java b/core/java/android/telephony/PersistentLoggerBackend.java
new file mode 100644
index 0000000..e3e72e1
--- /dev/null
+++ b/core/java/android/telephony/PersistentLoggerBackend.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.annotation.NonNull;
+
+/**
+ * Interface for logging backends to provide persistent log storage.
+ *
+ * @hide
+ */
+public interface PersistentLoggerBackend {
+
+ /**
+ * Persist a DEBUG log message.
+ * @param tag Used to identify the source of a log message.
+ * @param msg The message you would like logged.
+ */
+ void debug(@NonNull String tag, @NonNull String msg);
+
+ /**
+ * Persist a INFO log message.
+ * @param tag Used to identify the source of a log message.
+ * @param msg The message you would like logged.
+ */
+ void info(@NonNull String tag, @NonNull String msg);
+
+ /**
+ * Persist a WARN log message.
+ * @param tag Used to identify the source of a log message.
+ * @param msg The message you would like logged.
+ */
+ void warn(@NonNull String tag, @NonNull String msg);
+
+ /**
+ * Persist a WARN log message.
+ * @param tag Used to identify the source of a log message.
+ * @param msg The message you would like logged.
+ * @param t An exception to log.
+ */
+ void warn(@NonNull String tag, @NonNull String msg, @NonNull Throwable t);
+
+ /**
+ * Persist a ERROR log message.
+ * @param tag Used to identify the source of a log message.
+ * @param msg The message you would like logged.
+ */
+ void error(@NonNull String tag, @NonNull String msg);
+
+ /**
+ * Persist a ERROR log message.
+ * @param tag Used to identify the source of a log message.
+ * @param msg The message you would like logged.
+ * @param t An exception to log.
+ */
+ void error(@NonNull String tag, @NonNull String msg, @NonNull Throwable t);
+}
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/PointerIcon.java b/core/java/android/view/PointerIcon.java
index 7c2577f..c302126 100644
--- a/core/java/android/view/PointerIcon.java
+++ b/core/java/android/view/PointerIcon.java
@@ -193,6 +193,9 @@
/** @hide */ public static final int POINTER_ICON_VECTOR_STYLE_FILL_END =
POINTER_ICON_VECTOR_STYLE_FILL_BLUE;
+ /** @hide */ public static final float DEFAULT_POINTER_SCALE = 1f;
+ /** @hide */ public static final float LARGE_POINTER_SCALE = 2.5f;
+
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private final int mType;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@@ -253,7 +256,7 @@
* @hide
*/
public static @NonNull PointerIcon getLoadedSystemIcon(@NonNull Context context, int type,
- boolean useLargeIcons) {
+ boolean useLargeIcons, float pointerScale) {
if (type == TYPE_NOT_SPECIFIED) {
throw new IllegalStateException("Cannot load icon for type TYPE_NOT_SPECIFIED");
}
@@ -268,13 +271,18 @@
}
final int defStyle;
- // TODO(b/305193969): Use scaled vectors when large icons are requested.
- if (useLargeIcons) {
- defStyle = com.android.internal.R.style.LargePointer;
- } else if (android.view.flags.Flags.enableVectorCursors()) {
+ if (android.view.flags.Flags.enableVectorCursorA11ySettings()) {
defStyle = com.android.internal.R.style.VectorPointer;
} else {
- defStyle = com.android.internal.R.style.Pointer;
+ // TODO(b/346358375): Remove useLargeIcons and the legacy pointer styles when
+ // enableVectorCursorA11ySetting is rolled out.
+ if (useLargeIcons) {
+ defStyle = com.android.internal.R.style.LargePointer;
+ } else if (android.view.flags.Flags.enableVectorCursors()) {
+ defStyle = com.android.internal.R.style.VectorPointer;
+ } else {
+ defStyle = com.android.internal.R.style.Pointer;
+ }
}
TypedArray a = context.obtainStyledAttributes(null,
com.android.internal.R.styleable.Pointer,
@@ -286,11 +294,11 @@
Log.w(TAG, "Missing theme resources for pointer icon type " + type);
return type == TYPE_DEFAULT
? getSystemIcon(TYPE_NULL)
- : getLoadedSystemIcon(context, TYPE_DEFAULT, useLargeIcons);
+ : getLoadedSystemIcon(context, TYPE_DEFAULT, useLargeIcons, pointerScale);
}
final PointerIcon icon = new PointerIcon(type);
- icon.loadResource(context.getResources(), resourceId, context.getTheme());
+ icon.loadResource(context.getResources(), resourceId, context.getTheme(), pointerScale);
return icon;
}
@@ -353,7 +361,7 @@
}
PointerIcon icon = new PointerIcon(TYPE_CUSTOM);
- icon.loadResource(resources, resourceId, null);
+ icon.loadResource(resources, resourceId, null, DEFAULT_POINTER_SCALE);
return icon;
}
@@ -460,12 +468,13 @@
}
private BitmapDrawable getBitmapDrawableFromVectorDrawable(Resources resources,
- VectorDrawable vectorDrawable) {
+ VectorDrawable vectorDrawable, float pointerScale) {
// Ensure we pass the display metrics into the Bitmap constructor so that it is initialized
// with the correct density.
Bitmap bitmap = Bitmap.createBitmap(resources.getDisplayMetrics(),
- vectorDrawable.getIntrinsicWidth(),
- vectorDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888, true /* hasAlpha */);
+ (int) (vectorDrawable.getIntrinsicWidth() * pointerScale),
+ (int) (vectorDrawable.getIntrinsicHeight() * pointerScale),
+ Bitmap.Config.ARGB_8888, true /* hasAlpha */);
Canvas canvas = new Canvas(bitmap);
vectorDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
vectorDrawable.draw(canvas);
@@ -473,7 +482,7 @@
}
private void loadResource(@NonNull Resources resources, @XmlRes int resourceId,
- @Nullable Resources.Theme theme) {
+ @Nullable Resources.Theme theme, float pointerScale) {
final XmlResourceParser parser = resources.getXml(resourceId);
final int bitmapRes;
final float hotSpotX;
@@ -484,8 +493,10 @@
final TypedArray a = resources.obtainAttributes(
parser, com.android.internal.R.styleable.PointerIcon);
bitmapRes = a.getResourceId(com.android.internal.R.styleable.PointerIcon_bitmap, 0);
- hotSpotX = a.getDimension(com.android.internal.R.styleable.PointerIcon_hotSpotX, 0);
- hotSpotY = a.getDimension(com.android.internal.R.styleable.PointerIcon_hotSpotY, 0);
+ hotSpotX = a.getDimension(com.android.internal.R.styleable.PointerIcon_hotSpotX, 0)
+ * pointerScale;
+ hotSpotY = a.getDimension(com.android.internal.R.styleable.PointerIcon_hotSpotY, 0)
+ * pointerScale;
a.recycle();
} catch (Exception ex) {
throw new IllegalArgumentException("Exception parsing pointer icon resource.", ex);
@@ -534,7 +545,7 @@
}
if (isVectorAnimation) {
drawableFrame = getBitmapDrawableFromVectorDrawable(resources,
- (VectorDrawable) drawableFrame);
+ (VectorDrawable) drawableFrame, pointerScale);
}
mBitmapFrames[i - 1] = getBitmapFromDrawable((BitmapDrawable) drawableFrame);
}
@@ -542,7 +553,8 @@
}
if (drawable instanceof VectorDrawable) {
mDrawNativeDropShadow = true;
- drawable = getBitmapDrawableFromVectorDrawable(resources, (VectorDrawable) drawable);
+ drawable = getBitmapDrawableFromVectorDrawable(resources, (VectorDrawable) drawable,
+ pointerScale);
}
if (!(drawable instanceof BitmapDrawable)) {
throw new IllegalArgumentException("<pointer-icon> bitmap attribute must "
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/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index bcef37f..d74867c 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -366,6 +366,14 @@
"enable_content_protection_receiver";
/**
+ * Whether AssistContent snapshot should be sent on activity start.
+ *
+ * @hide
+ */
+ public static final String DEVICE_CONFIG_ENABLE_ACTIVITY_START_ASSIST_CONTENT =
+ "enable_activity_start_assist_content";
+
+ /**
* Sets the size of the in-memory ring buffer for the content protection flow.
*
* @hide
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/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 2194c89..40d760e 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -537,8 +537,13 @@
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
- if (cb != null && !isDestroyed()) {
- cb.onContentChanged();
+ if (!isDestroyed()) {
+ if (cb != null) {
+ cb.onContentChanged();
+ }
+ if (mDecorContentParent != null) {
+ mDecorContentParent.notifyContentChanged();
+ }
}
mContentParentExplicitlySet = true;
}
@@ -568,8 +573,13 @@
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
- if (cb != null && !isDestroyed()) {
- cb.onContentChanged();
+ if (!isDestroyed()) {
+ if (cb != null) {
+ cb.onContentChanged();
+ }
+ if (mDecorContentParent != null) {
+ mDecorContentParent.notifyContentChanged();
+ }
}
mContentParentExplicitlySet = true;
}
@@ -586,8 +596,13 @@
mContentParent.addView(view, params);
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
- if (cb != null && !isDestroyed()) {
- cb.onContentChanged();
+ if (!isDestroyed()) {
+ if (cb != null) {
+ cb.onContentChanged();
+ }
+ if (mDecorContentParent != null) {
+ mDecorContentParent.notifyContentChanged();
+ }
}
}
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/java/com/android/internal/widget/ActionBarOverlayLayout.java b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
index 6832825..ff57fd4 100644
--- a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
+++ b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
@@ -898,6 +898,13 @@
mDecorToolbar.dismissPopupMenus();
}
+ @Override
+ public void notifyContentChanged() {
+ mLastBaseContentInsets.setEmpty();
+ mLastBaseInnerInsets = WindowInsets.CONSUMED;
+ mLastInnerInsets = WindowInsets.CONSUMED;
+ }
+
public static class LayoutParams extends MarginLayoutParams {
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
diff --git a/core/java/com/android/internal/widget/DecorContentParent.java b/core/java/com/android/internal/widget/DecorContentParent.java
index ac524f9..8d6cfd1 100644
--- a/core/java/com/android/internal/widget/DecorContentParent.java
+++ b/core/java/com/android/internal/widget/DecorContentParent.java
@@ -22,6 +22,7 @@
import android.util.SparseArray;
import android.view.Menu;
import android.view.Window;
+
import com.android.internal.view.menu.MenuPresenter;
/**
@@ -49,4 +50,5 @@
void saveToolbarHierarchyState(SparseArray<Parcelable> toolbarStates);
void restoreToolbarHierarchyState(SparseArray<Parcelable> toolbarStates);
void dismissPopups();
+ void notifyContentChanged();
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java b/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java
index 00262be..55f2dee 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java
@@ -30,7 +30,7 @@
ArrayList<Operation> mOperations;
RemoteComposeState mRemoteComposeState = new RemoteComposeState();
- TimeVariables mTimeVariables = new TimeVariables();
+
// Semantic version of the document
Version mVersion = new Version(0, 1, 0);
@@ -70,7 +70,6 @@
public void setWidth(int width) {
this.mWidth = width;
- mRemoteComposeState.setWindowWidth(width);
}
public int getHeight() {
@@ -79,8 +78,6 @@
public void setHeight(int height) {
this.mHeight = height;
- mRemoteComposeState.setWindowHeight(height);
-
}
public RemoteComposeBuffer getBuffer() {
@@ -114,21 +111,21 @@
/**
* Sets the way the player handles the content
*
- * @param scroll set the horizontal behavior (NONE|SCROLL_HORIZONTAL|SCROLL_VERTICAL)
+ * @param scroll set the horizontal behavior (NONE|SCROLL_HORIZONTAL|SCROLL_VERTICAL)
* @param alignment set the alignment of the content (TOP|CENTER|BOTTOM|START|END)
- * @param sizing set the type of sizing for the content (NONE|SIZING_LAYOUT|SIZING_SCALE)
- * @param mode set the mode of sizing, either LAYOUT modes or SCALE modes
- * the LAYOUT modes are:
- * - LAYOUT_MATCH_PARENT
- * - LAYOUT_WRAP_CONTENT
- * or adding an horizontal mode and a vertical mode:
- * - LAYOUT_HORIZONTAL_MATCH_PARENT
- * - LAYOUT_HORIZONTAL_WRAP_CONTENT
- * - LAYOUT_HORIZONTAL_FIXED
- * - LAYOUT_VERTICAL_MATCH_PARENT
- * - LAYOUT_VERTICAL_WRAP_CONTENT
- * - LAYOUT_VERTICAL_FIXED
- * The LAYOUT_*_FIXED modes will use the intrinsic document size
+ * @param sizing set the type of sizing for the content (NONE|SIZING_LAYOUT|SIZING_SCALE)
+ * @param mode set the mode of sizing, either LAYOUT modes or SCALE modes
+ * the LAYOUT modes are:
+ * - LAYOUT_MATCH_PARENT
+ * - LAYOUT_WRAP_CONTENT
+ * or adding an horizontal mode and a vertical mode:
+ * - LAYOUT_HORIZONTAL_MATCH_PARENT
+ * - LAYOUT_HORIZONTAL_WRAP_CONTENT
+ * - LAYOUT_HORIZONTAL_FIXED
+ * - LAYOUT_VERTICAL_MATCH_PARENT
+ * - LAYOUT_VERTICAL_WRAP_CONTENT
+ * - LAYOUT_VERTICAL_FIXED
+ * The LAYOUT_*_FIXED modes will use the intrinsic document size
*/
public void setRootContentBehavior(int scroll, int alignment, int sizing, int mode) {
this.mContentScroll = scroll;
@@ -141,8 +138,8 @@
* Given dimensions w x h of where to paint the content, returns the corresponding scale factor
* according to the contentSizing information
*
- * @param w horizontal dimension of the rendering area
- * @param h vertical dimension of the rendering area
+ * @param w horizontal dimension of the rendering area
+ * @param h vertical dimension of the rendering area
* @param scaleOutput will contain the computed scale factor
*/
public void computeScale(float w, float h, float[] scaleOutput) {
@@ -157,43 +154,37 @@
float scale = Math.min(1f, Math.min(scaleX, scaleY));
contentScaleX = scale;
contentScaleY = scale;
- }
- break;
+ } break;
case RootContentBehavior.SCALE_FIT: {
float scaleX = w / mWidth;
float scaleY = h / mHeight;
float scale = Math.min(scaleX, scaleY);
contentScaleX = scale;
contentScaleY = scale;
- }
- break;
+ } break;
case RootContentBehavior.SCALE_FILL_WIDTH: {
float scale = w / mWidth;
contentScaleX = scale;
contentScaleY = scale;
- }
- break;
+ } break;
case RootContentBehavior.SCALE_FILL_HEIGHT: {
float scale = h / mHeight;
contentScaleX = scale;
contentScaleY = scale;
- }
- break;
+ } break;
case RootContentBehavior.SCALE_CROP: {
float scaleX = w / mWidth;
float scaleY = h / mHeight;
float scale = Math.max(scaleX, scaleY);
contentScaleX = scale;
contentScaleY = scale;
- }
- break;
+ } break;
case RootContentBehavior.SCALE_FILL_BOUNDS: {
float scaleX = w / mWidth;
float scaleY = h / mHeight;
contentScaleX = scaleX;
contentScaleY = scaleY;
- }
- break;
+ } break;
default:
// nothing
}
@@ -206,10 +197,10 @@
* Given dimensions w x h of where to paint the content, returns the corresponding translation
* according to the contentAlignment information
*
- * @param w horizontal dimension of the rendering area
- * @param h vertical dimension of the rendering area
- * @param contentScaleX the horizontal scale we are going to use for the content
- * @param contentScaleY the vertical scale we are going to use for the content
+ * @param w horizontal dimension of the rendering area
+ * @param h vertical dimension of the rendering area
+ * @param contentScaleX the horizontal scale we are going to use for the content
+ * @param contentScaleY the vertical scale we are going to use for the content
* @param translateOutput will contain the computed translation
*/
private void computeTranslate(float w, float h, float contentScaleX, float contentScaleY,
@@ -224,32 +215,26 @@
switch (horizontalContentAlignment) {
case RootContentBehavior.ALIGNMENT_START: {
// nothing
- }
- break;
+ } break;
case RootContentBehavior.ALIGNMENT_HORIZONTAL_CENTER: {
translateX = (w - contentWidth) / 2f;
- }
- break;
+ } break;
case RootContentBehavior.ALIGNMENT_END: {
translateX = w - contentWidth;
- }
- break;
+ } break;
default:
// nothing (same as alignment_start)
}
switch (verticalContentAlignment) {
case RootContentBehavior.ALIGNMENT_TOP: {
// nothing
- }
- break;
+ } break;
case RootContentBehavior.ALIGNMENT_VERTICAL_CENTER: {
translateY = (h - contentHeight) / 2f;
- }
- break;
+ } break;
case RootContentBehavior.ALIGNMENT_BOTTOM: {
translateY = h - contentHeight;
- }
- break;
+ } break;
default:
// nothing (same as alignment_top)
}
@@ -306,13 +291,7 @@
this.mMetadata = metadata;
}
- /**
- * Returns true if x,y coordinate is within bounds
- * @param x x-coordinate
- * @param y y-coordinate
- * @return x,y coordinate is within bounds
- */
- public boolean contains(float x, float y) {
+ public boolean contains(float x, float y) {
return x >= mLeft && x < mRight
&& y >= mTop && y < mBottom;
}
@@ -362,22 +341,16 @@
public void initializeContext(RemoteContext context) {
mRemoteComposeState.reset();
mClickAreas.clear();
- mRemoteComposeState.setNextId(RemoteComposeState.START_ID);
+
context.mDocument = this;
context.mRemoteComposeState = mRemoteComposeState;
+
// mark context to be in DATA mode, which will skip the painting ops.
context.mMode = RemoteContext.ContextMode.DATA;
- mTimeVariables.updateTime(context);
-
- for (Operation op : mOperations) {
- if (op instanceof VariableSupport) {
- ((VariableSupport) op).updateVariables(context);
- ((VariableSupport) op).registerListening(context);
- }
+ for (Operation op: mOperations) {
op.apply(context);
}
context.mMode = RemoteContext.ContextMode.UNSET;
-
}
///////////////////////////////////////////////////////////////////////////////////////////////
@@ -402,7 +375,7 @@
* @param minorVersion minor version number, increased when adding new features
* @param patch patch level, increased upon bugfixes
*/
- void setVersion(int majorVersion, int minorVersion, int patch) {
+ void setVersion(int majorVersion, int minorVersion, int patch) {
mVersion = new Version(majorVersion, minorVersion, patch);
}
@@ -416,13 +389,13 @@
* the click coordinates will be the one reported; the order of addition of those click areas
* is therefore meaningful.
*
- * @param id the id of the area, which will be reported on click
+ * @param id the id of the area, which will be reported on click
* @param contentDescription the content description (used for accessibility)
- * @param left the left coordinate of the click area (in pixels)
- * @param top the top coordinate of the click area (in pixels)
- * @param right the right coordinate of the click area (in pixels)
- * @param bottom the bottom coordinate of the click area (in pixels)
- * @param metadata arbitrary metadata associated with the are, also reported on click
+ * @param left the left coordinate of the click area (in pixels)
+ * @param top the top coordinate of the click area (in pixels)
+ * @param right the right coordinate of the click area (in pixels)
+ * @param bottom the bottom coordinate of the click area (in pixels)
+ * @param metadata arbitrary metadata associated with the are, also reported on click
*/
public void addClickArea(int id, String contentDescription,
float left, float top, float right, float bottom, String metadata) {
@@ -444,7 +417,7 @@
* listeners.
*/
public void onClick(float x, float y) {
- for (ClickAreaRepresentation clickArea : mClickAreas) {
+ for (ClickAreaRepresentation clickArea: mClickAreas) {
if (clickArea.contains(x, y)) {
warnClickListeners(clickArea);
}
@@ -457,7 +430,7 @@
* @param id the click area id
*/
public void performClick(int id) {
- for (ClickAreaRepresentation clickArea : mClickAreas) {
+ for (ClickAreaRepresentation clickArea: mClickAreas) {
if (clickArea.mId == id) {
warnClickListeners(clickArea);
}
@@ -468,36 +441,17 @@
* Warn click listeners when a click area is activated
*/
private void warnClickListeners(ClickAreaRepresentation clickArea) {
- for (ClickCallbacks listener : mClickListeners) {
+ for (ClickCallbacks listener: mClickListeners) {
listener.click(clickArea.mId, clickArea.mMetadata);
}
}
- @Override
- public String toString() {
- StringBuilder builder = new StringBuilder();
- for (Operation op : mOperations) {
- builder.append(op.toString());
- builder.append("\n");
- }
- return builder.toString();
- }
-
- //////////////////////////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////////////////////////
// Painting
- //////////////////////////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////////////////////////
private final float[] mScaleOutput = new float[2];
private final float[] mTranslateOutput = new float[2];
- private int mRepaintNext = -1; // delay to next repaint -1 = don't 1 = asap
-
- /**
- * Returns > 0 if it needs to repaint
- * @return
- */
- public int needsRepaint() {
- return mRepaintNext;
- }
/**
* Paint the document
@@ -521,11 +475,6 @@
context.mPaintContext.translate(mTranslateOutput[0], mTranslateOutput[1]);
context.mPaintContext.scale(mScaleOutput[0], mScaleOutput[1]);
}
- mTimeVariables.updateTime(context);
- context.loadFloat(RemoteContext.ID_WINDOW_WIDTH, getWidth());
- context.loadFloat(RemoteContext.ID_WINDOW_HEIGHT, getHeight());
- mRepaintNext = context.updateOps();
-
for (Operation op : mOperations) {
// operations will only be executed if no theme is set (ie UNSPECIFIED)
// or the theme is equal as the one passed in argument to paint.
diff --git a/core/java/com/android/internal/widget/remotecompose/core/Operations.java b/core/java/com/android/internal/widget/remotecompose/core/Operations.java
index 4b45ab6..54b277a 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/Operations.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/Operations.java
@@ -19,7 +19,6 @@
import com.android.internal.widget.remotecompose.core.operations.ClickArea;
import com.android.internal.widget.remotecompose.core.operations.ClipPath;
import com.android.internal.widget.remotecompose.core.operations.ClipRect;
-import com.android.internal.widget.remotecompose.core.operations.ColorExpression;
import com.android.internal.widget.remotecompose.core.operations.DrawArc;
import com.android.internal.widget.remotecompose.core.operations.DrawBitmap;
import com.android.internal.widget.remotecompose.core.operations.DrawBitmapInt;
@@ -29,12 +28,9 @@
import com.android.internal.widget.remotecompose.core.operations.DrawPath;
import com.android.internal.widget.remotecompose.core.operations.DrawRect;
import com.android.internal.widget.remotecompose.core.operations.DrawRoundRect;
-import com.android.internal.widget.remotecompose.core.operations.DrawText;
-import com.android.internal.widget.remotecompose.core.operations.DrawTextAnchored;
import com.android.internal.widget.remotecompose.core.operations.DrawTextOnPath;
+import com.android.internal.widget.remotecompose.core.operations.DrawTextRun;
import com.android.internal.widget.remotecompose.core.operations.DrawTweenPath;
-import com.android.internal.widget.remotecompose.core.operations.FloatConstant;
-import com.android.internal.widget.remotecompose.core.operations.FloatExpression;
import com.android.internal.widget.remotecompose.core.operations.Header;
import com.android.internal.widget.remotecompose.core.operations.MatrixRestore;
import com.android.internal.widget.remotecompose.core.operations.MatrixRotate;
@@ -46,10 +42,7 @@
import com.android.internal.widget.remotecompose.core.operations.PathData;
import com.android.internal.widget.remotecompose.core.operations.RootContentBehavior;
import com.android.internal.widget.remotecompose.core.operations.RootContentDescription;
-import com.android.internal.widget.remotecompose.core.operations.ShaderData;
import com.android.internal.widget.remotecompose.core.operations.TextData;
-import com.android.internal.widget.remotecompose.core.operations.TextFromFloat;
-import com.android.internal.widget.remotecompose.core.operations.TextMerge;
import com.android.internal.widget.remotecompose.core.operations.Theme;
import com.android.internal.widget.remotecompose.core.operations.utilities.IntMap;
@@ -74,10 +67,9 @@
public static final int DRAW_BITMAP = 44;
public static final int DRAW_BITMAP_INT = 66;
public static final int DATA_BITMAP = 101;
- public static final int DATA_SHADER = 45;
public static final int DATA_TEXT = 102;
- /////////////////////////////=====================
+/////////////////////////////=====================
public static final int CLIP_PATH = 38;
public static final int CLIP_RECT = 39;
public static final int PAINT_VALUES = 40;
@@ -99,12 +91,6 @@
public static final int MATRIX_SAVE = 130;
public static final int MATRIX_RESTORE = 131;
public static final int MATRIX_SET = 132;
- public static final int DATA_FLOAT = 80;
- public static final int ANIMATED_FLOAT = 81;
- public static final int DRAW_TEXT_ANCHOR = 133;
- public static final int COLOR_EXPRESSIONS = 134;
- public static final int TEXT_FROM_FLOAT = 135;
- public static final int TEXT_MERGE = 136;
/////////////////////////////////////////======================
public static IntMap<CompanionOperation> map = new IntMap<>();
@@ -128,7 +114,7 @@
map.put(DRAW_RECT, DrawRect.COMPANION);
map.put(DRAW_ROUND_RECT, DrawRoundRect.COMPANION);
map.put(DRAW_TEXT_ON_PATH, DrawTextOnPath.COMPANION);
- map.put(DRAW_TEXT_RUN, DrawText.COMPANION);
+ map.put(DRAW_TEXT_RUN, DrawTextRun.COMPANION);
map.put(DRAW_TWEEN_PATH, DrawTweenPath.COMPANION);
map.put(DATA_PATH, PathData.COMPANION);
map.put(PAINT_VALUES, PaintData.COMPANION);
@@ -140,13 +126,6 @@
map.put(MATRIX_TRANSLATE, MatrixTranslate.COMPANION);
map.put(CLIP_PATH, ClipPath.COMPANION);
map.put(CLIP_RECT, ClipRect.COMPANION);
- map.put(DATA_SHADER, ShaderData.COMPANION);
- map.put(DATA_FLOAT, FloatConstant.COMPANION);
- map.put(ANIMATED_FLOAT, FloatExpression.COMPANION);
- map.put(DRAW_TEXT_ANCHOR, DrawTextAnchored.COMPANION);
- map.put(COLOR_EXPRESSIONS, ColorExpression.COMPANION);
- map.put(TEXT_FROM_FLOAT, TextFromFloat.COMPANION);
- map.put(TEXT_MERGE, TextMerge.COMPANION);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java b/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java
index ecd0efc..eece8ad52 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java
@@ -68,35 +68,7 @@
public abstract void drawTextOnPath(int textId, int pathId, float hOffset, float vOffset);
- /**
- * Return the dimensions (left, top, right, bottom).
- * Relative to a drawTextRun x=0, y=0;
- *
- * @param textId
- * @param start
- * @param end if end is -1 it means the whole string
- * @param monospace measure with better support for monospace
- * @param bounds the bounds (left, top, right, bottom)
- */
- public abstract void getTextBounds(int textId,
- int start,
- int end,
- boolean monospace,
- float[]bounds);
-
- /**
- * Draw a text starting ast x,y
- *
- * @param textId reference to the text
- * @param start
- * @param end
- * @param contextStart
- * @param contextEnd
- * @param x
- * @param y
- * @param rtl
- */
- public abstract void drawTextRun(int textId,
+ public abstract void drawTextRun(int textID,
int start,
int end,
int contextStart,
@@ -105,14 +77,6 @@
float y,
boolean rtl);
- /**
- * Draw an interpolation between two paths
- * @param path1Id
- * @param path2Id
- * @param tween 0.0 = is path1 1.0 is path2
- * @param start
- * @param stop
- */
public abstract void drawTweenPath(int path1Id,
int path2Id,
float tween,
@@ -121,70 +85,21 @@
public abstract void applyPaint(PaintBundle mPaintData);
- /**
- * Scale the rendering by scaleX and saleY (1.0 = no scale).
- * Scaling is done about centerX,centerY.
- *
- * @param scaleX
- * @param scaleY
- * @param centerX
- * @param centerY
- */
- public abstract void matrixScale(float scaleX, float scaleY, float centerX, float centerY);
+ public abstract void mtrixScale(float scaleX, float scaleY, float centerX, float centerY);
- /**
- * Translate the rendering
- * @param translateX
- * @param translateY
- */
public abstract void matrixTranslate(float translateX, float translateY);
- /**
- * Skew the rendering
- * @param skewX
- * @param skewY
- */
public abstract void matrixSkew(float skewX, float skewY);
- /**
- * Rotate the rendering.
- * Note rotates are cumulative.
- * @param rotate angle to rotate
- * @param pivotX x-coordinate about which to rotate
- * @param pivotY y-coordinate about which to rotate
- */
public abstract void matrixRotate(float rotate, float pivotX, float pivotY);
- /**
- * Save the current state of the transform
- */
public abstract void matrixSave();
- /**
- * Restore the previously saved state of the transform
- */
public abstract void matrixRestore();
- /**
- * Set the clip to a rectangle.
- * Drawing outside the current clip region will have no effect
- * @param left
- * @param top
- * @param right
- * @param bottom
- */
public abstract void clipRect(float left, float top, float right, float bottom);
- /**
- * Clip based on a path.
- * @param pathId
- * @param regionOp
- */
public abstract void clipPath(int pathId, int regionOp);
- /**
- * Reset the paint
- */
- public abstract void reset();
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java
index 52fc314..c2e8131 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java
@@ -19,7 +19,6 @@
import com.android.internal.widget.remotecompose.core.operations.ClickArea;
import com.android.internal.widget.remotecompose.core.operations.ClipPath;
import com.android.internal.widget.remotecompose.core.operations.ClipRect;
-import com.android.internal.widget.remotecompose.core.operations.ColorExpression;
import com.android.internal.widget.remotecompose.core.operations.DrawArc;
import com.android.internal.widget.remotecompose.core.operations.DrawBitmap;
import com.android.internal.widget.remotecompose.core.operations.DrawBitmapInt;
@@ -29,12 +28,9 @@
import com.android.internal.widget.remotecompose.core.operations.DrawPath;
import com.android.internal.widget.remotecompose.core.operations.DrawRect;
import com.android.internal.widget.remotecompose.core.operations.DrawRoundRect;
-import com.android.internal.widget.remotecompose.core.operations.DrawText;
-import com.android.internal.widget.remotecompose.core.operations.DrawTextAnchored;
import com.android.internal.widget.remotecompose.core.operations.DrawTextOnPath;
+import com.android.internal.widget.remotecompose.core.operations.DrawTextRun;
import com.android.internal.widget.remotecompose.core.operations.DrawTweenPath;
-import com.android.internal.widget.remotecompose.core.operations.FloatConstant;
-import com.android.internal.widget.remotecompose.core.operations.FloatExpression;
import com.android.internal.widget.remotecompose.core.operations.Header;
import com.android.internal.widget.remotecompose.core.operations.MatrixRestore;
import com.android.internal.widget.remotecompose.core.operations.MatrixRotate;
@@ -47,12 +43,8 @@
import com.android.internal.widget.remotecompose.core.operations.RootContentBehavior;
import com.android.internal.widget.remotecompose.core.operations.RootContentDescription;
import com.android.internal.widget.remotecompose.core.operations.TextData;
-import com.android.internal.widget.remotecompose.core.operations.TextFromFloat;
-import com.android.internal.widget.remotecompose.core.operations.TextMerge;
import com.android.internal.widget.remotecompose.core.operations.Theme;
-import com.android.internal.widget.remotecompose.core.operations.Utils;
import com.android.internal.widget.remotecompose.core.operations.paint.PaintBundle;
-import com.android.internal.widget.remotecompose.core.operations.utilities.easing.FloatAnimation;
import java.io.File;
import java.io.FileInputStream;
@@ -66,20 +58,9 @@
* Provides an abstract buffer to encode/decode RemoteCompose operations
*/
public class RemoteComposeBuffer {
- public static final int EASING_CUBIC_STANDARD = FloatAnimation.CUBIC_STANDARD;
- public static final int EASING_CUBIC_ACCELERATE = FloatAnimation.CUBIC_ACCELERATE;
- public static final int EASING_CUBIC_DECELERATE = FloatAnimation.CUBIC_DECELERATE;
- public static final int EASING_CUBIC_LINEAR = FloatAnimation.CUBIC_LINEAR;
- public static final int EASING_CUBIC_ANTICIPATE = FloatAnimation.CUBIC_ANTICIPATE;
- public static final int EASING_CUBIC_OVERSHOOT = FloatAnimation.CUBIC_OVERSHOOT;
- public static final int EASING_CUBIC_CUSTOM = FloatAnimation.CUBIC_CUSTOM;
- public static final int EASING_SPLINE_CUSTOM = FloatAnimation.SPLINE_CUSTOM;
- public static final int EASING_EASE_OUT_BOUNCE = FloatAnimation.EASE_OUT_BOUNCE;
- public static final int EASING_EASE_OUT_ELASTIC = FloatAnimation.EASE_OUT_ELASTIC;
WireBuffer mBuffer = new WireBuffer();
Platform mPlatform = null;
RemoteComposeState mRemoteComposeState;
- private static final boolean DEBUG = false;
/**
* Provides an abstract buffer to encode/decode RemoteCompose operations
@@ -190,7 +171,7 @@
*
* @param text the string to inject in the buffer
*/
- public int addText(String text) {
+ int addText(String text) {
int id = mRemoteComposeState.dataGetId(text);
if (id == -1) {
id = mRemoteComposeState.cache(text);
@@ -369,6 +350,7 @@
addDrawPath(id);
}
+
/**
* Draw the specified path
*
@@ -444,160 +426,12 @@
float y,
boolean rtl) {
int textId = addText(text);
- DrawText.COMPANION.apply(
+ DrawTextRun.COMPANION.apply(
mBuffer, textId, start, end,
contextStart, contextEnd, x, y, rtl);
}
/**
- * Draw the text, with origin at (x,y). The origin is interpreted
- * based on the Align setting in the paint.
- *
- * @param textId The text to be drawn
- * @param start The index of the first character in text to draw
- * @param end (end - 1) is the index of the last character in text to draw
- * @param contextStart
- * @param contextEnd
- * @param x The x-coordinate of the origin of the text being drawn
- * @param y The y-coordinate of the baseline of the text being drawn
- * @param rtl Draw RTTL
- */
- public void addDrawTextRun(int textId,
- int start,
- int end,
- int contextStart,
- int contextEnd,
- float x,
- float y,
- boolean rtl) {
- DrawText.COMPANION.apply(
- mBuffer, textId, start, end,
- contextStart, contextEnd, x, y, rtl);
- }
-
- /**
- * Draw a text on canvas at relative to position (x, y),
- * offset panX and panY.
- * <br>
- * The panning factors (panX, panY) mapped to the
- * resulting bounding box of the text, in such a way that a
- * panning factor of (0.0, 0.0) would center the text at (x, y)
- * <ul>
- * <li> Panning of -1.0, -1.0 - the text above & right of x,y.</li>
- * <li>Panning of 1.0, 1.0 - the text is below and to the left</li>
- * <li>Panning of 1.0, 0.0 - the test is centered & to the right of x,y</li>
- * </ul>
- * Setting panY to NaN results in y being the baseline of the text.
- *
- * @param text text to draw
- * @param x Coordinate of the Anchor
- * @param y Coordinate of the Anchor
- * @param panX justifies text -1.0=right, 0.0=center, 1.0=left
- * @param panY position text -1.0=above, 0.0=center, 1.0=below, Nan=baseline
- * @param flags 1 = RTL
- */
- public void drawTextAnchored(String text,
- float x,
- float y,
- float panX,
- float panY,
- int flags) {
- int textId = addText(text);
- DrawTextAnchored.COMPANION.apply(
- mBuffer, textId,
- x, y,
- panX, panY,
- flags);
- }
-
- /**
- * Add a text and id so that it can be used
- *
- * @param text
- * @return
- */
- public int createTextId(String text) {
- return addText(text);
- }
-
- /**
- * Merge two text (from id's) output one id
- * @param id1 left id
- * @param id2 right id
- * @return new id that merges the two text
- */
- public int textMerge(int id1, int id2) {
- int textId = addText(id1 + "+" + id2);
- TextMerge.COMPANION.apply(mBuffer, textId, id1, id2);
- return textId;
- }
-
- public static final int PAD_AFTER_SPACE = TextFromFloat.PAD_AFTER_SPACE;
- public static final int PAD_AFTER_NONE = TextFromFloat.PAD_AFTER_NONE;
- public static final int PAD_AFTER_ZERO = TextFromFloat.PAD_AFTER_ZERO;
- public static final int PAD_PRE_SPACE = TextFromFloat.PAD_PRE_SPACE;
- public static final int PAD_PRE_NONE = TextFromFloat.PAD_PRE_NONE;
- public static final int PAD_PRE_ZERO = TextFromFloat.PAD_PRE_ZERO;
-
- /**
- * Create a TextFromFloat command which creates text from a Float.
- *
- * @param value The value to convert
- * @param digitsBefore the digits before the decimal point
- * @param digitsAfter the digits after the decimal point
- * @param flags configure the behaviour using PAD_PRE_* and PAD_AFTER* flags
- * @return id of the string that can be passed to drawTextAnchored
- */
- public int createTextFromFloat(float value, short digitsBefore,
- short digitsAfter, int flags) {
- String placeHolder = Utils.floatToString(value)
- + "(" + digitsBefore + "," + digitsAfter + "," + flags + ")";
- int id = mRemoteComposeState.dataGetId(placeHolder);
- if (id == -1) {
- id = mRemoteComposeState.cache(placeHolder);
- // TextData.COMPANION.apply(mBuffer, id, text);
- }
- TextFromFloat.COMPANION.apply(mBuffer, id, value, digitsBefore,
- digitsAfter, flags);
- return id;
- }
-
- /**
- * Draw a text on canvas at relative to position (x, y),
- * offset panX and panY.
- * <br>
- * The panning factors (panX, panY) mapped to the
- * resulting bounding box of the text, in such a way that a
- * panning factor of (0.0, 0.0) would center the text at (x, y)
- * <ul>
- * <li> Panning of -1.0, -1.0 - the text above & right of x,y.</li>
- * <li>Panning of 1.0, 1.0 - the text is below and to the left</li>
- * <li>Panning of 1.0, 0.0 - the test is centered & to the right of x,y</li>
- * </ul>
- * Setting panY to NaN results in y being the baseline of the text.
- *
- * @param textId text to draw
- * @param x Coordinate of the Anchor
- * @param y Coordinate of the Anchor
- * @param panX justifies text -1.0=right, 0.0=center, 1.0=left
- * @param panY position text -1.0=above, 0.0=center, 1.0=below, Nan=baseline
- * @param flags 1 = RTL
- */
- public void drawTextAnchored(int textId,
- float x,
- float y,
- float panX,
- float panY,
- int flags) {
-
- DrawTextAnchored.COMPANION.apply(
- mBuffer, textId,
- x, y,
- panX, panY,
- flags);
- }
-
- /**
* draw an interpolation between two paths that have the same pattern
* <p>
* Warning paths objects are not immutable and this is not taken into consideration
@@ -656,10 +490,6 @@
return id;
}
- /**
- * Adds a paint Bundle to the doc
- * @param paint
- */
public void addPaint(PaintBundle paint) {
PaintData.COMPANION.apply(mBuffer, paint);
}
@@ -669,9 +499,7 @@
mBuffer.setIndex(0);
while (mBuffer.available()) {
int opId = mBuffer.readByte();
- if (DEBUG) {
- Utils.log(">> " + opId);
- }
+ System.out.println(">>> " + opId);
CompanionOperation operation = Operations.map.get(opId);
if (operation == null) {
throw new RuntimeException("Unknown operation encountered " + opId);
@@ -691,6 +519,7 @@
Theme.COMPANION.apply(mBuffer, theme);
}
+
static String version() {
return "v1.0";
}
@@ -825,8 +654,8 @@
/**
* Add a pre-concat of the current matrix with the specified scale.
*
- * @param scaleX The amount to scale in X
- * @param scaleY The amount to scale in Y
+ * @param scaleX The amount to scale in X
+ * @param scaleY The amount to scale in Y
*/
public void addMatrixScale(float scaleX, float scaleY) {
MatrixScale.COMPANION.apply(mBuffer, scaleX, scaleY, Float.NaN, Float.NaN);
@@ -844,174 +673,12 @@
MatrixScale.COMPANION.apply(mBuffer, scaleX, scaleY, centerX, centerY);
}
- /**
- * sets the clip based on clip id
- * @param pathId 0 clears the clip
- */
public void addClipPath(int pathId) {
ClipPath.COMPANION.apply(mBuffer, pathId);
}
- /**
- * Sets the clip based on clip rec
- * @param left
- * @param top
- * @param right
- * @param bottom
- */
public void addClipRect(float left, float top, float right, float bottom) {
ClipRect.COMPANION.apply(mBuffer, left, top, right, bottom);
}
-
- /**
- * Add a float return a NaN number pointing to that float
- * @param value
- * @return
- */
- public float addFloat(float value) {
- int id = mRemoteComposeState.cacheFloat(value);
- FloatConstant.COMPANION.apply(mBuffer, id, value);
- return Utils.asNan(id);
- }
-
- /**
- * Add a float that is a computation based on variables
- * @param value A RPN style float operation i.e. "4, 3, ADD" outputs 7
- * @return NaN id of the result of the calculation
- */
- public float addAnimatedFloat(float... value) {
- int id = mRemoteComposeState.cache(value);
- FloatExpression.COMPANION.apply(mBuffer, id, value, null);
- return Utils.asNan(id);
- }
-
- /**
- * Add a float that is a computation based on variables.
- * see packAnimation
- * @param value A RPN style float operation i.e. "4, 3, ADD" outputs 7
- * @param animation Array of floats that represents animation
- * @return NaN id of the result of the calculation
- */
- public float addAnimatedFloat(float[] value, float[] animation) {
- int id = mRemoteComposeState.cache(value);
- FloatExpression.COMPANION.apply(mBuffer, id, value, animation);
- return Utils.asNan(id);
- }
-
- /**
- * Add a color that represents the tween between two colors
- * @param color1
- * @param color2
- * @param tween
- * @return id of the color (color ids are short)
- */
- public short addColorExpression(int color1, int color2, float tween) {
- ColorExpression c = new ColorExpression(0, 0, color1, color2, tween);
- short id = (short) mRemoteComposeState.cache(c);
- c.mId = id;
- c.write(mBuffer);
- return id;
- }
-
- /**
- * Add a color that represents the tween between two colors where color1
- * is the id of a color
- * @param color1
- * @param color2
- * @param tween
- * @return id of the color (color ids are short)
- */
- public short addColorExpression(short color1, int color2, float tween) {
- ColorExpression c = new ColorExpression(0, 1, color1, color2, tween);
- short id = (short) mRemoteComposeState.cache(c);
- c.mId = id;
- c.write(mBuffer);
- return id;
- }
-
- /**
- * Add a color that represents the tween between two colors where color2
- * is the id of a color
- * @param color1
- * @param color2
- * @param tween
- * @return id of the color (color ids are short)
- */
- public short addColorExpression(int color1, short color2, float tween) {
- ColorExpression c = new ColorExpression(0, 2, color1, color2, tween);
- short id = (short) mRemoteComposeState.cache(c);
- c.mId = id;
- c.write(mBuffer);
- return id;
- }
-
- /**
- * Add a color that represents the tween between two colors where color1 &
- * color2 are the ids of colors
- * @param color1
- * @param color2
- * @param tween
- * @return id of the color (color ids are short)
- */
- public short addColorExpression(short color1, short color2, float tween) {
- ColorExpression c = new ColorExpression(0, 3, color1, color2, tween);
- short id = (short) mRemoteComposeState.cache(c);
- c.mId = id;
- c.write(mBuffer);
- return id;
- }
-
- /**
- * Color calculated by Hue saturation and value.
- * (as floats they can be variables used to create color transitions)
- * @param hue
- * @param sat
- * @param value
- * @return id of the color (color ids are short)
- */
- public short addColorExpression(float hue, float sat, float value) {
- ColorExpression c = new ColorExpression(0, hue, sat, value);
- short id = (short) mRemoteComposeState.cache(c);
- c.mId = id;
- c.write(mBuffer);
- return id;
- }
-
- /**
- * Color calculated by Alpha, Hue saturation and value.
- * (as floats they can be variables used to create color transitions)
- * @param alpha
- * @param hue
- * @param sat
- * @param value
- * @return id of the color (color ids are short)
- */
- public short addColorExpression(int alpha, float hue, float sat, float value) {
- ColorExpression c = new ColorExpression(0, alpha, hue, sat, value);
- short id = (short) mRemoteComposeState.cache(c);
- c.mId = id;
- c.write(mBuffer);
- return id;
- }
-
- /**
- * create and animation based on description and return as an array of
- * floats. see addAnimatedFloat
- * @param duration
- * @param type
- * @param spec
- * @param initialValue
- * @param wrap
- * @return
- */
- public static float[] packAnimation(float duration,
- int type,
- float[] spec,
- float initialValue,
- float wrap) {
-
- return FloatAnimation.packToFloatArray(duration, type, spec, initialValue, wrap);
- }
-
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java
index 66a37e67..17e8c83 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java
@@ -15,53 +15,26 @@
*/
package com.android.internal.widget.remotecompose.core;
-import static com.android.internal.widget.remotecompose.core.RemoteContext.ID_CONTINUOUS_SEC;
-import static com.android.internal.widget.remotecompose.core.RemoteContext.ID_TIME_IN_MIN;
-import static com.android.internal.widget.remotecompose.core.RemoteContext.ID_TIME_IN_SEC;
-import static com.android.internal.widget.remotecompose.core.RemoteContext.ID_WINDOW_HEIGHT;
-import static com.android.internal.widget.remotecompose.core.RemoteContext.ID_WINDOW_WIDTH;
-
import com.android.internal.widget.remotecompose.core.operations.utilities.IntMap;
-import java.util.ArrayList;
import java.util.HashMap;
/**
* Represents runtime state for a RemoteCompose document
- * State includes things like the value of variables
*/
public class RemoteComposeState {
- public static final int START_ID = 42;
- private static final int MAX_FLOATS = 500;
+
private final IntMap<Object> mIntDataMap = new IntMap<>();
private final IntMap<Boolean> mIntWrittenMap = new IntMap<>();
private final HashMap<Object, Integer> mDataIntMap = new HashMap();
- private final float[] mFloatMap = new float[MAX_FLOATS]; // efficient cache
- private final int[] mColorMap = new int[MAX_FLOATS]; // efficient cache
- private int mNextId = START_ID;
- {
- for (int i = 0; i < mFloatMap.length; i++) {
- mFloatMap[i] = Float.NaN;
- }
- }
+ private static int sNextId = 42;
- /**
- * Get Object based on id. The system will cache things like bitmaps
- * Paths etc. They can be accessed with this command
- * @param id
- * @return
- */
- public Object getFromId(int id) {
+ public Object getFromId(int id) {
return mIntDataMap.get(id);
}
- /**
- * true if the cache contain this id
- * @param id
- * @return
- */
- public boolean containsId(int id) {
+ public boolean containsId(int id) {
return mIntDataMap.get(id) != null;
}
@@ -96,65 +69,6 @@
}
/**
- * Insert an item in the cache
- */
- public void update(int id, Object item) {
- mDataIntMap.remove(mIntDataMap.get(id));
- mDataIntMap.put(item, id);
- mIntDataMap.put(id, item);
- }
-
- /**
- * Insert an item in the cache
- */
- public int cacheFloat(float item) {
- int id = nextId();
- mFloatMap[id] = item;
- return id;
- }
-
- /**
- * Insert an item in the cache
- */
- public void cacheFloat(int id, float item) {
- mFloatMap[id] = item;
- }
-
- /**
- * Insert an item in the cache
- */
- public void updateFloat(int id, float item) {
- mFloatMap[id] = item;
- }
-
- /**
- * get float
- */
- public float getFloat(int id) {
- return mFloatMap[id];
- }
-
- /**
- * Get the float value
- *
- * @param id
- * @return
- */
- public int getColor(int id) {
- return mColorMap[id];
- }
-
- /**
- * Modify the color at id.
- * @param id
- * @param color
- */
- public void updateColor(int id, int color) {
- mColorMap[id] = color;
- }
-
-
- /**
* Method to determine if a cached value has been written to the documents WireBuffer based on
* its id.
*/
@@ -165,90 +79,22 @@
/**
* Method to mark that a value, represented by its id, has been written to the WireBuffer
*/
- public void markWritten(int id) {
+ public void markWritten(int id) {
mIntWrittenMap.put(id, true);
}
/**
- * Clear the record of the values that have been written to the WireBuffer.
+ * Clear the record of the values that have been written to the WireBuffer.
*/
void reset() {
mIntWrittenMap.clear();
}
- /**
- * Get the next available id
- * @return
- */
- public int nextId() {
- return mNextId++;
+ public static int nextId() {
+ return sNextId++;
}
-
- /**
- * Set the next id
- * @param id
- */
- public void setNextId(int id) {
- mNextId = id;
- }
-
- IntMap<ArrayList<VariableSupport>> mVarListeners = new IntMap<>();
- ArrayList<VariableSupport> mAllVarListeners = new ArrayList<>();
-
- private void add(int id, VariableSupport variableSupport) {
- ArrayList<VariableSupport> v = mVarListeners.get(id);
- if (v == null) {
- v = new ArrayList<VariableSupport>();
- mVarListeners.put(id, v);
- }
- v.add(variableSupport);
- mAllVarListeners.add(variableSupport);
- }
-
- /**
- * Commands that listen to variables add themselves.
- * @param id
- * @param variableSupport
- */
- public void listenToVar(int id, VariableSupport variableSupport) {
- add(id, variableSupport);
- }
-
- /**
- * List of Commands that need to be updated
- * @param context
- * @return
- */
- public int getOpsToUpdate(RemoteContext context) {
- for (VariableSupport vs : mAllVarListeners) {
- vs.updateVariables(context);
- }
- if (mVarListeners.get(ID_CONTINUOUS_SEC) != null) {
- return 1;
- }
- if (mVarListeners.get(ID_TIME_IN_SEC) != null) {
- return 1000;
- }
- if (mVarListeners.get(ID_TIME_IN_MIN) != null) {
- return 1000 * 60;
- }
- return -1;
- }
-
- /**
- * Set the width of the overall document on screen.
- * @param width
- */
- public void setWindowWidth(float width) {
- updateFloat(ID_WINDOW_WIDTH, width);
- }
-
- /**
- * Set the width of the overall document on screen.
- * @param height
- */
- public void setWindowHeight(float height) {
- updateFloat(ID_WINDOW_HEIGHT, height);
+ public static void setNextId(int id) {
+ sNextId = id;
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java
index 7e72168..d16cbc5 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2024 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,10 +15,7 @@
*/
package com.android.internal.widget.remotecompose.core;
-import com.android.internal.widget.remotecompose.core.operations.FloatExpression;
-import com.android.internal.widget.remotecompose.core.operations.ShaderData;
import com.android.internal.widget.remotecompose.core.operations.Theme;
-import com.android.internal.widget.remotecompose.core.operations.Utils;
/**
* Specify an abstract context used to playback RemoteCompose documents
@@ -30,7 +27,7 @@
public abstract class RemoteContext {
protected CoreDocument mDocument;
public RemoteComposeState mRemoteComposeState;
- long mStart = System.nanoTime(); // todo This should be set at a hi level
+
protected PaintContext mPaintContext = null;
ContextMode mMode = ContextMode.UNSET;
@@ -40,40 +37,9 @@
public float mWidth = 0f;
public float mHeight = 0f;
- /**
- * Load a path under an id.
- * Paths can be use in clip drawPath and drawTweenPath
- * @param instanceId
- * @param floatPath
- */
public abstract void loadPathData(int instanceId, float[] floatPath);
/**
- * Associate a name with a give id.
- *
- * @param varName
- * @param varId
- * @param varType
- */
- public abstract void loadVariableName(String varName, int varId, int varType);
-
- /**
- * Save a color under a given id
- * @param id
- * @param color
- */
- public abstract void loadColor(int id, int color);
-
- /**
- * gets the time animation clock as float in seconds
- * @return a monotonic time in seconds (arbitrary zero point)
- */
- public float getAnimationTime() {
- return (System.nanoTime() - mStart) * 1E-9f;
- }
-
-
- /**
* The context can be used in a few different mode, allowing operations to skip being executed:
* - UNSET : all operations will get executed
* - DATA : only operations dealing with DATA (eg loading a bitmap) should execute
@@ -130,8 +96,6 @@
public void header(int majorVersion, int minorVersion, int patchVersion,
int width, int height, long capabilities
) {
- mRemoteComposeState.setWindowWidth(width);
- mRemoteComposeState.setWindowHeight(height);
mDocument.setVersion(majorVersion, minorVersion, patchVersion);
mDocument.setWidth(width);
mDocument.setHeight(height);
@@ -173,105 +137,9 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// Data handling
///////////////////////////////////////////////////////////////////////////////////////////////
-
- /**
- * Save a bitmap under an imageId
- * @param imageId
- * @param width
- * @param height
- * @param bitmap
- */
public abstract void loadBitmap(int imageId, int width, int height, byte[] bitmap);
-
- /**
- * Save a string under a given id
- * @param id
- * @param text
- */
public abstract void loadText(int id, String text);
- /**
- * Get a string given an id
- * @param id
- * @return
- */
- public abstract String getText(int id);
-
- /**
- * Load a float
- * @param id
- * @param value
- */
- public abstract void loadFloat(int id, float value);
-
- /**
- * Load an animated float associated with an id
- * Todo: Remove?
- * @param id
- * @param animatedFloat
- */
- public abstract void loadAnimatedFloat(int id, FloatExpression animatedFloat);
-
- /**
- * Save a shader under and ID
- * @param id
- * @param value
- */
- public abstract void loadShader(int id, ShaderData value);
-
- /**
- * Get a float given an id
- * @param id
- * @return
- */
- public abstract float getFloat(int id);
-
- /**
- * Get the color given and ID
- * @param id
- * @return
- */
- public abstract int getColor(int id);
-
- /**
- * called to notify system that a command is interested in a variable
- * @param id
- * @param variableSupport
- */
- public abstract void listensTo(int id, VariableSupport variableSupport);
-
- /**
- * Notify commands with variables have changed
- * @return
- */
- public abstract int updateOps();
-
- /**
- * Get a shader given the id
- * @param id
- * @return
- */
- public abstract ShaderData getShader(int id);
-
- public static final int ID_CONTINUOUS_SEC = 1;
- public static final int ID_TIME_IN_SEC = 2;
- public static final int ID_TIME_IN_MIN = 3;
- public static final int ID_TIME_IN_HR = 4;
- public static final int ID_WINDOW_WIDTH = 5;
- public static final int ID_WINDOW_HEIGHT = 6;
- public static final int ID_COMPONENT_WIDTH = 7;
- public static final int ID_COMPONENT_HEIGHT = 8;
- public static final int ID_CALENDAR_MONTH = 9;
-
- public static final float FLOAT_CONTINUOUS_SEC = Utils.asNan(ID_CONTINUOUS_SEC);
- public static final float FLOAT_TIME_IN_SEC = Utils.asNan(ID_TIME_IN_SEC);
- public static final float FLOAT_TIME_IN_MIN = Utils.asNan(ID_TIME_IN_MIN);
- public static final float FLOAT_TIME_IN_HR = Utils.asNan(ID_TIME_IN_HR);
- public static final float FLOAT_CALENDAR_MONTH = Utils.asNan(ID_CALENDAR_MONTH);
- public static final float FLOAT_WINDOW_WIDTH = Utils.asNan(ID_WINDOW_WIDTH);
- public static final float FLOAT_WINDOW_HEIGHT = Utils.asNan(ID_WINDOW_HEIGHT);
- public static final float FLOAT_COMPONENT_WIDTH = Utils.asNan(ID_COMPONENT_WIDTH);
- public static final float FLOAT_COMPONENT_HEIGHT = Utils.asNan(ID_COMPONENT_HEIGHT);
///////////////////////////////////////////////////////////////////////////////////////////////
// Click handling
///////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/core/java/com/android/internal/widget/remotecompose/core/TimeVariables.java b/core/java/com/android/internal/widget/remotecompose/core/TimeVariables.java
deleted file mode 100644
index e9708b7..0000000
--- a/core/java/com/android/internal/widget/remotecompose/core/TimeVariables.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.widget.remotecompose.core;
-
-import java.time.LocalDateTime;
-
-/**
- * This generates the standard system variables for time.
- */
-public class TimeVariables {
- /**
- * This class populates all time variables in the system
- * @param context
- */
- public void updateTime(RemoteContext context) {
- LocalDateTime dateTime = LocalDateTime.now();
- // This define the time in the format
- // seconds run from Midnight=0 quantized to seconds hour 0..3599
- // minutes run from Midnight=0 quantized to minutes 0..1439
- // hours run from Midnight=0 quantized to Hours 0-23
- // CONTINUOUS_SEC is seconds from midnight looping every hour 0-3600
- // CONTINUOUS_SEC is accurate to milliseconds due to float precession
- int month = dateTime.getDayOfMonth();
- int hour = dateTime.getHour();
- int minute = dateTime.getMinute();
- int seconds = dateTime.getSecond();
- int currentMinute = hour * 60 + minute;
- int currentSeconds = minute * 60 + seconds;
- float sec = currentSeconds + dateTime.getNano() * 1E-9f;
-
- context.loadFloat(RemoteContext.ID_CONTINUOUS_SEC, sec);
- context.loadFloat(RemoteContext.ID_TIME_IN_SEC, currentSeconds);
- context.loadFloat(RemoteContext.ID_TIME_IN_MIN, currentMinute);
- context.loadFloat(RemoteContext.ID_TIME_IN_HR, hour);
- context.loadFloat(RemoteContext.ID_CALENDAR_MONTH, month);
-
- }
-}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/VariableSupport.java b/core/java/com/android/internal/widget/remotecompose/core/VariableSupport.java
deleted file mode 100644
index d59b1bc..0000000
--- a/core/java/com/android/internal/widget/remotecompose/core/VariableSupport.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.widget.remotecompose.core;
-
-/**
- * Interface for operators that interact with variables
- * Threw this they register to listen to particular variables
- * and are notified when they change
- */
-public interface VariableSupport {
- /**
- * Call to allow an operator to register interest in variables.
- * Typically they call context.listensTo(id, this)
- * @param context
- */
- void registerListening(RemoteContext context);
-
- /**
- * Called to be notified that the variables you are interested have changed.
- * @param context
- */
- void updateVariables(RemoteContext context);
-}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/BitmapData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/BitmapData.java
index f186322..76b7144 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/BitmapData.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/BitmapData.java
@@ -51,12 +51,11 @@
@Override
public String toString() {
- return "BITMAP DATA " + mImageId;
+ return "BITMAP DATA $imageId";
}
public static class Companion implements CompanionOperation {
- private Companion() {
- }
+ private Companion() {}
@Override
public String name() {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ClipPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ClipPath.java
index e6d5fe7..8d4a787 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ClipPath.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ClipPath.java
@@ -24,11 +24,6 @@
import java.util.List;
-/**
- * Defines a path that clips a the subsequent drawing commands
- * Use MatrixSave and MatrixRestore commands to remove clip
- * TODO allow id 0 to mean null?
- */
public class ClipPath extends PaintOperation {
public static final Companion COMPANION = new Companion();
int mId;
@@ -98,4 +93,5 @@
public void paint(PaintContext context) {
context.clipPath(mId, mRegionOp);
}
-}
\ No newline at end of file
+}
+
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ClipRect.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ClipRect.java
index 613eceb..803618a 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ClipRect.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ClipRect.java
@@ -15,36 +15,88 @@
*/
package com.android.internal.widget.remotecompose.core.operations;
+import com.android.internal.widget.remotecompose.core.CompanionOperation;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
+import com.android.internal.widget.remotecompose.core.PaintOperation;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
-/**
- * Support clip with a rectangle
- */
-public class ClipRect extends DrawBase4 {
- public static final Companion COMPANION =
- new Companion(Operations.CLIP_RECT) {
- @Override
- public Operation construct(float x1,
- float y1,
- float x2,
- float y2) {
- return new ClipRect(x1, y1, x2, y2);
- }
- };
+import java.util.List;
+
+public class ClipRect extends PaintOperation {
+ public static final Companion COMPANION = new Companion();
+ float mLeft;
+ float mTop;
+ float mRight;
+ float mBottom;
public ClipRect(
float left,
float top,
float right,
float bottom) {
- super(left, top, right, bottom);
- mName = "ClipRect";
+ mLeft = left;
+ mTop = top;
+ mRight = right;
+ mBottom = bottom;
+
+ }
+
+ @Override
+ public void write(WireBuffer buffer) {
+ COMPANION.apply(buffer, mLeft, mTop, mRight, mBottom);
+ }
+
+ @Override
+ public String toString() {
+ return "ClipRect " + mLeft + " " + mTop
+ + " " + mRight + " " + mBottom + ";";
+ }
+
+ public static class Companion implements CompanionOperation {
+ private Companion() {
+ }
+
+ @Override
+ public void read(WireBuffer buffer, List<Operation> operations) {
+ float sLeft = buffer.readFloat();
+ float srcTop = buffer.readFloat();
+ float srcRight = buffer.readFloat();
+ float srcBottom = buffer.readFloat();
+
+ ClipRect op = new ClipRect(sLeft, srcTop, srcRight, srcBottom);
+ operations.add(op);
+ }
+
+ @Override
+ public String name() {
+ return "ClipRect";
+ }
+
+ @Override
+ public int id() {
+ return Operations.CLIP_RECT;
+ }
+
+ public void apply(WireBuffer buffer,
+ float left,
+ float top,
+ float right,
+ float bottom) {
+ buffer.start(Operations.CLIP_RECT);
+ buffer.writeFloat(left);
+ buffer.writeFloat(top);
+ buffer.writeFloat(right);
+ buffer.writeFloat(bottom);
+ }
}
@Override
public void paint(PaintContext context) {
- context.clipRect(mX1, mY1, mX2, mY2);
+ context.clipRect(mLeft,
+ mTop,
+ mRight,
+ mBottom);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ColorExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ColorExpression.java
deleted file mode 100644
index 7d28cea..0000000
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ColorExpression.java
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.widget.remotecompose.core.operations;
-
-import com.android.internal.widget.remotecompose.core.CompanionOperation;
-import com.android.internal.widget.remotecompose.core.Operation;
-import com.android.internal.widget.remotecompose.core.Operations;
-import com.android.internal.widget.remotecompose.core.RemoteContext;
-import com.android.internal.widget.remotecompose.core.VariableSupport;
-import com.android.internal.widget.remotecompose.core.WireBuffer;
-
-import java.util.List;
-
-/**
- * Operation to Colors
- * Color modes
- * mMode = 0 two colors and a tween
- * mMode = 1 color1 is a colorID.
- * mMode = 2 color2 is a colorID.
- * mMode = 3 color1 & color2 are ids
- * mMode = 4 H S V mode
- */
-public class ColorExpression implements Operation, VariableSupport {
- public int mId;
- int mMode;
- public int mColor1;
- public int mColor2;
- public float mTween = 0.0f;
-
-
- public float mHue = 0; // only in Mode 4
- public float mSat = 0;
- public float mValue = 0;
- public float mOutHue = 0; // only in Mode 4
- public float mOutSat = 0;
- public float mOutValue = 0;
- public int mAlpha = 0xFF; // only used in hsv mode
-
- public float mOutTween = 0.0f;
- public int mOutColor1;
- public int mOutColor2;
- public static final Companion COMPANION = new Companion();
- public static final int HSV_MODE = 4;
- public ColorExpression(int id, float hue, float sat, float value) {
- mMode = HSV_MODE;
- mAlpha = 0xFF;
- mOutHue = mHue = hue;
- mOutSat = mSat = sat;
- mOutValue = mValue = value;
- mColor1 = Float.floatToRawIntBits(hue);
- mColor2 = Float.floatToRawIntBits(sat);
- mTween = value;
- }
- public ColorExpression(int id, int alpha, float hue, float sat, float value) {
- mMode = HSV_MODE;
- mAlpha = alpha;
- mOutHue = mHue = hue;
- mOutSat = mSat = sat;
- mOutValue = mValue = value;
- mColor1 = Float.floatToRawIntBits(hue);
- mColor2 = Float.floatToRawIntBits(sat);
- mTween = value;
- }
-
- public ColorExpression(int id, int mode, int color1, int color2, float tween) {
- this.mId = id;
- this.mMode = mode & 0xFF;
- this.mAlpha = (mode >> 16) & 0xFF;
- if (mMode == HSV_MODE) {
- mOutHue = mHue = Float.intBitsToFloat(color1);
- mOutSat = mSat = Float.intBitsToFloat(color2);
- mOutValue = mValue = tween;
- }
- this.mColor1 = color1;
- this.mColor2 = color2;
- this.mTween = tween;
- this.mOutTween = tween;
- this.mOutColor1 = color1;
- this.mOutColor2 = color2;
-
- }
-
- @Override
- public void updateVariables(RemoteContext context) {
- if (mMode == 4) {
- if (Float.isNaN(mHue)) {
- mOutHue = context.getFloat(Utils.idFromNan(mHue));
- }
- if (Float.isNaN(mSat)) {
- mOutSat = context.getFloat(Utils.idFromNan(mSat));
- }
- if (Float.isNaN(mValue)) {
- mOutValue = context.getFloat(Utils.idFromNan(mValue));
- }
- }
- if (Float.isNaN(mTween)) {
- mOutTween = context.getFloat(Utils.idFromNan(mTween));
- }
- if ((mMode & 1) == 1) {
- mOutColor1 = context.getColor(mColor1);
- }
- if ((mMode & 2) == 2) {
- mOutColor2 = context.getColor(mColor2);
- }
- }
-
-
- @Override
- public void registerListening(RemoteContext context) {
- if (mMode == 4) {
- if (Float.isNaN(mHue)) {
- context.listensTo(Utils.idFromNan(mHue), this);
- }
- if (Float.isNaN(mSat)) {
- context.listensTo(Utils.idFromNan(mSat), this);
- }
- if (Float.isNaN(mValue)) {
- context.listensTo(Utils.idFromNan(mValue), this);
- }
- return;
- }
- if (Float.isNaN(mTween)) {
- context.listensTo(Utils.idFromNan(mTween), this);
- }
- if ((mMode & 1) == 1) {
- context.listensTo(mColor1, this);
- }
- if ((mMode & 2) == 2) {
- context.listensTo(mColor2, this);
- }
- }
-
- @Override
- public void apply(RemoteContext context) {
- if (mMode == 4) {
- context.loadColor(mId, (mAlpha << 24)
- | (0xFFFFFF & Utils.hsvToRgb(mOutHue, mOutSat, mOutValue)));
- return;
- }
- if (mOutTween == 0.0) {
- context.loadColor(mId, mColor1);
- } else {
- if ((mMode & 1) == 1) {
- mOutColor1 = context.getColor(mColor1);
- }
- if ((mMode & 2) == 2) {
- mOutColor2 = context.getColor(mColor2);
- }
-
- context.loadColor(mId,
- Utils.interpolateColor(mOutColor1, mOutColor2, mOutTween));
- }
-
- }
-
- @Override
- public void write(WireBuffer buffer) {
- int mode = mMode | (mAlpha << 16);
- COMPANION.apply(buffer, mId, mode, mColor1, mColor2, mTween);
- }
-
- @Override
- public String toString() {
- if (mMode == 4) {
- return "ColorExpression[" + mId + "] = hsv (" + Utils.floatToString(mHue)
- + ", " + Utils.floatToString(mSat)
- + ", " + Utils.floatToString(mValue) + ")";
- }
-
- String c1 = (mMode & 1) == 1 ? "[" + mColor1 + "]" : Utils.colorInt(mColor1);
- String c2 = (mMode & 2) == 2 ? "[" + mColor2 + "]" : Utils.colorInt(mColor2);
- return "ColorExpression[" + mId + "] = tween(" + c1
- + ", " + c2 + ", "
- + Utils.floatToString(mTween) + ")";
- }
-
- public static class Companion implements CompanionOperation {
- private Companion() {
- }
-
- @Override
- public String name() {
- return "ColorExpression";
- }
-
- @Override
- public int id() {
- return Operations.COLOR_EXPRESSIONS;
- }
-
- /**
- * Call to write a ColorExpression object on the buffer
- * @param buffer
- * @param id of the ColorExpression object
- * @param mode if colors are id or actual values
- * @param color1
- * @param color2
- * @param tween
- */
- public void apply(WireBuffer buffer,
- int id, int mode,
- int color1, int color2, float tween) {
- buffer.start(Operations.COLOR_EXPRESSIONS);
- buffer.writeInt(id);
- buffer.writeInt(mode);
- buffer.writeInt(color1);
- buffer.writeInt(color2);
- buffer.writeFloat(tween);
-
- }
-
- @Override
- public void read(WireBuffer buffer, List<Operation> operations) {
- int id = buffer.readInt();
- int mode = buffer.readInt();
- int color1 = buffer.readInt();
- int color2 = buffer.readInt();
- float tween = buffer.readFloat();
-
- operations.add(new ColorExpression(id, mode, color1, color2, tween));
- }
- }
-
- @Override
- public String deepToString(String indent) {
- return indent + toString();
- }
-
-}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawArc.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawArc.java
index c176864..e829975 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawArc.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawArc.java
@@ -15,36 +15,107 @@
*/
package com.android.internal.widget.remotecompose.core.operations;
+import com.android.internal.widget.remotecompose.core.CompanionOperation;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
+import com.android.internal.widget.remotecompose.core.PaintOperation;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
-public class DrawArc extends DrawBase6 {
- public static final Companion COMPANION =
- new Companion(Operations.DRAW_ARC) {
- @Override
- public Operation construct(float v1,
- float v2,
- float v3,
- float v4,
- float v5,
- float v6) {
- return new DrawArc(v1, v2, v3, v4, v5, v6);
- }
- };
+import java.util.List;
- public DrawArc(float v1,
- float v2,
- float v3,
- float v4,
- float v5,
- float v6) {
- super(v1, v2, v3, v4, v5, v6);
- mName = "DrawArc";
+public class DrawArc extends PaintOperation {
+ public static final Companion COMPANION = new Companion();
+ float mLeft;
+ float mTop;
+ float mRight;
+ float mBottom;
+ float mStartAngle;
+ float mSweepAngle;
+
+ public DrawArc(
+ float left,
+ float top,
+ float right,
+ float bottom,
+ float startAngle,
+ float sweepAngle) {
+ mLeft = left;
+ mTop = top;
+ mRight = right;
+ mBottom = bottom;
+ mStartAngle = startAngle;
+ mSweepAngle = sweepAngle;
+ }
+
+ @Override
+ public void write(WireBuffer buffer) {
+ COMPANION.apply(buffer, mLeft,
+ mTop,
+ mRight,
+ mBottom,
+ mStartAngle,
+ mSweepAngle);
+ }
+
+ @Override
+ public String toString() {
+ return "DrawArc " + mLeft + " " + mTop
+ + " " + mRight + " " + mBottom + " "
+ + "- " + mStartAngle + " " + mSweepAngle + ";";
+ }
+
+ public static class Companion implements CompanionOperation {
+ private Companion() {
+ }
+
+ @Override
+ public void read(WireBuffer buffer, List<Operation> operations) {
+ float sLeft = buffer.readFloat();
+ float srcTop = buffer.readFloat();
+ float srcRight = buffer.readFloat();
+ float srcBottom = buffer.readFloat();
+ float mStartAngle = buffer.readFloat();
+ float mSweepAngle = buffer.readFloat();
+ DrawArc op = new DrawArc(sLeft, srcTop, srcRight, srcBottom,
+ mStartAngle, mSweepAngle);
+ operations.add(op);
+ }
+
+ @Override
+ public String name() {
+ return "DrawArc";
+ }
+
+ @Override
+ public int id() {
+ return Operations.DRAW_ARC;
+ }
+
+ public void apply(WireBuffer buffer,
+ float left,
+ float top,
+ float right,
+ float bottom,
+ float startAngle,
+ float sweepAngle) {
+ buffer.start(Operations.DRAW_ARC);
+ buffer.writeFloat(left);
+ buffer.writeFloat(top);
+ buffer.writeFloat(right);
+ buffer.writeFloat(bottom);
+ buffer.writeFloat(startAngle);
+ buffer.writeFloat(sweepAngle);
+ }
}
@Override
public void paint(PaintContext context) {
- context.drawArc(mV1, mV2, mV3, mV4, mV5, mV6);
+ context.drawArc(mLeft,
+ mTop,
+ mRight,
+ mBottom,
+ mStartAngle,
+ mSweepAngle);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase2.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase2.java
deleted file mode 100644
index 0963c13..0000000
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase2.java
+++ /dev/null
@@ -1,134 +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.internal.widget.remotecompose.core.operations;
-
-import static com.android.internal.widget.remotecompose.core.operations.Utils.floatToString;
-
-import com.android.internal.widget.remotecompose.core.CompanionOperation;
-import com.android.internal.widget.remotecompose.core.Operation;
-import com.android.internal.widget.remotecompose.core.Operations;
-import com.android.internal.widget.remotecompose.core.PaintOperation;
-import com.android.internal.widget.remotecompose.core.RemoteContext;
-import com.android.internal.widget.remotecompose.core.VariableSupport;
-import com.android.internal.widget.remotecompose.core.WireBuffer;
-
-import java.util.List;
-
-/**
- * Base class for commands that take 3 float
- */
-public abstract class DrawBase2 extends PaintOperation
- implements VariableSupport {
- public static final Companion COMPANION =
- new Companion(Operations.DRAW_CIRCLE) {
- @Override
- public Operation construct(float x1, float y1) {
- // subclass should return new DrawX(x1, y1);
- return null;
- }
- };
- protected String mName = "DrawRectBase";
- float mV1;
- float mV2;
- float mValue1;
- float mValue2;
-
- public DrawBase2(float v1, float v2) {
- mValue1 = v1;
- mValue2 = v2;
- mV1 = v1;
- mV2 = v2;
- }
-
- @Override
- public void updateVariables(RemoteContext context) {
- mV1 = (Float.isNaN(mValue1))
- ? context.getFloat(Utils.idFromNan(mValue1)) : mValue1;
- mV2 = (Float.isNaN(mValue2))
- ? context.getFloat(Utils.idFromNan(mValue2)) : mValue2;
- }
-
- @Override
- public void registerListening(RemoteContext context) {
- if (Float.isNaN(mValue1)) {
- context.listensTo(Utils.idFromNan(mValue1), this);
- }
- if (Float.isNaN(mValue2)) {
- context.listensTo(Utils.idFromNan(mValue2), this);
- }
- }
-
- @Override
- public void write(WireBuffer buffer) {
- COMPANION.apply(buffer, mV1, mV2);
- }
-
- @Override
- public String toString() {
- return mName + " " + floatToString(mV1) + " " + floatToString(mV2);
- }
-
- public static class Companion implements CompanionOperation {
- public final int OP_CODE;
-
- protected Companion(int code) {
- OP_CODE = code;
- }
-
- @Override
- public void read(WireBuffer buffer, List<Operation> operations) {
- float v1 = buffer.readFloat();
- float v2 = buffer.readFloat();
-
- Operation op = construct(v1, v2);
- operations.add(op);
- }
-
- /**
- * Override to construct a 2 float value operation
- * @param x1
- * @param y1
- * @return
- */
- public Operation construct(float x1, float y1) {
- return null;
- }
-
- @Override
- public String name() {
- return "DrawRect";
- }
-
- @Override
- public int id() {
- return OP_CODE;
- }
-
- /**
- * Writes out the operation to the buffer
- * @param buffer
- * @param x1
- * @param y1
- */
- public void apply(WireBuffer buffer,
- float x1,
- float y1) {
- buffer.start(OP_CODE);
- buffer.writeFloat(x1);
- buffer.writeFloat(y1);
- }
- }
-}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase3.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase3.java
deleted file mode 100644
index 56b2f1f..0000000
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase3.java
+++ /dev/null
@@ -1,157 +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.internal.widget.remotecompose.core.operations;
-
-import static com.android.internal.widget.remotecompose.core.operations.Utils.floatToString;
-
-import com.android.internal.widget.remotecompose.core.CompanionOperation;
-import com.android.internal.widget.remotecompose.core.Operation;
-import com.android.internal.widget.remotecompose.core.Operations;
-import com.android.internal.widget.remotecompose.core.PaintOperation;
-import com.android.internal.widget.remotecompose.core.RemoteContext;
-import com.android.internal.widget.remotecompose.core.VariableSupport;
-import com.android.internal.widget.remotecompose.core.WireBuffer;
-
-import java.util.List;
-
-/**
- * Base class for commands that take 3 float
- */
-public abstract class DrawBase3 extends PaintOperation
- implements VariableSupport {
- public static final Companion COMPANION =
- new Companion(Operations.DRAW_CIRCLE) {
- @Override
- public Operation construct(float x1, float y1, float x2) {
- // subclass should return new DrawX(x1, y1, x2, y2);
- return null;
- }
- };
- protected String mName = "DrawRectBase";
- float mV1;
- float mV2;
- float mV3;
- float mValue1;
- float mValue2;
- float mValue3;
-
- public DrawBase3(
- float v1,
- float v2,
- float v3) {
- mValue1 = v1;
- mValue2 = v2;
- mValue3 = v3;
-
- mV1 = v1;
- mV2 = v2;
- mV3 = v3;
- }
-
- @Override
- public void updateVariables(RemoteContext context) {
- mV1 = (Float.isNaN(mValue1))
- ? context.getFloat(Utils.idFromNan(mValue1)) : mValue1;
- mV2 = (Float.isNaN(mValue2))
- ? context.getFloat(Utils.idFromNan(mValue2)) : mValue2;
- mV3 = (Float.isNaN(mValue3))
- ? context.getFloat(Utils.idFromNan(mValue3)) : mValue3;
- }
-
- @Override
- public void registerListening(RemoteContext context) {
- if (Float.isNaN(mValue1)) {
- context.listensTo(Utils.idFromNan(mValue1), this);
- }
- if (Float.isNaN(mValue2)) {
- context.listensTo(Utils.idFromNan(mValue2), this);
- }
- if (Float.isNaN(mValue3)) {
- context.listensTo(Utils.idFromNan(mValue3), this);
- }
- }
-
- @Override
- public void write(WireBuffer buffer) {
- COMPANION.apply(buffer, mV1, mV2, mV3);
- }
-
- @Override
- public String toString() {
- return mName + " " + floatToString(mV1) + " " + floatToString(mV2)
- + " " + floatToString(mV3);
- }
-
- public static class Companion implements CompanionOperation {
- public final int OP_CODE;
-
- protected Companion(int code) {
- OP_CODE = code;
- }
-
- @Override
- public void read(WireBuffer buffer, List<Operation> operations) {
- float v1 = buffer.readFloat();
- float v2 = buffer.readFloat();
- float v3 = buffer.readFloat();
-
- Operation op = construct(v1, v2, v3);
- operations.add(op);
- }
-
- /**
- * Construct and Operation from the 3 variables.
- * This must be overridden by subclasses
- * @param x1
- * @param y1
- * @param x2
- * @return
- */
- public Operation construct(float x1,
- float y1,
- float x2) {
- return null;
- }
-
- @Override
- public String name() {
- return "DrawRect";
- }
-
- @Override
- public int id() {
- return OP_CODE;
- }
-
- /**
- * Writes out the operation to the buffer
- * @param buffer
- * @param x1
- * @param y1
- * @param x2
- */
- public void apply(WireBuffer buffer,
- float x1,
- float y1,
- float x2) {
- buffer.start(OP_CODE);
- buffer.writeFloat(x1);
- buffer.writeFloat(y1);
- buffer.writeFloat(x2);
-
- }
- }
-}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase4.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase4.java
deleted file mode 100644
index ec35a16..0000000
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase4.java
+++ /dev/null
@@ -1,171 +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.internal.widget.remotecompose.core.operations;
-
-import static com.android.internal.widget.remotecompose.core.operations.Utils.floatToString;
-
-import com.android.internal.widget.remotecompose.core.CompanionOperation;
-import com.android.internal.widget.remotecompose.core.Operation;
-import com.android.internal.widget.remotecompose.core.Operations;
-import com.android.internal.widget.remotecompose.core.PaintOperation;
-import com.android.internal.widget.remotecompose.core.RemoteContext;
-import com.android.internal.widget.remotecompose.core.VariableSupport;
-import com.android.internal.widget.remotecompose.core.WireBuffer;
-
-import java.util.List;
-
-/**
- * Base class for draw commands that take 4 floats
- */
-public abstract class DrawBase4 extends PaintOperation
- implements VariableSupport {
- public static final Companion COMPANION =
- new Companion(Operations.DRAW_RECT) {
- @Override
- public Operation construct(float x1, float y1, float x2, float y2) {
- // return new DrawRectBase(x1, y1, x2, y2);
- return null;
- }
- };
- protected String mName = "DrawRectBase";
- float mX1;
- float mY1;
- float mX2;
- float mY2;
- float mX1Value;
- float mY1Value;
- float mX2Value;
- float mY2Value;
-
- public DrawBase4(
- float x1,
- float y1,
- float x2,
- float y2) {
- mX1Value = x1;
- mY1Value = y1;
- mX2Value = x2;
- mY2Value = y2;
-
- mX1 = x1;
- mY1 = y1;
- mX2 = x2;
- mY2 = y2;
- }
-
- @Override
- public void updateVariables(RemoteContext context) {
- mX1 = (Float.isNaN(mX1Value))
- ? context.getFloat(Utils.idFromNan(mX1Value)) : mX1Value;
- mY1 = (Float.isNaN(mY1Value))
- ? context.getFloat(Utils.idFromNan(mY1Value)) : mY1Value;
- mX2 = (Float.isNaN(mX2Value))
- ? context.getFloat(Utils.idFromNan(mX2Value)) : mX2Value;
- mY2 = (Float.isNaN(mY2Value))
- ? context.getFloat(Utils.idFromNan(mY2Value)) : mY2Value;
- }
-
- @Override
- public void registerListening(RemoteContext context) {
- if (Float.isNaN(mX1Value)) {
- context.listensTo(Utils.idFromNan(mX1Value), this);
- }
- if (Float.isNaN(mY1Value)) {
- context.listensTo(Utils.idFromNan(mY1Value), this);
- }
- if (Float.isNaN(mX2Value)) {
- context.listensTo(Utils.idFromNan(mX2Value), this);
- }
- if (Float.isNaN(mY2Value)) {
- context.listensTo(Utils.idFromNan(mY2Value), this);
- }
- }
-
- @Override
- public void write(WireBuffer buffer) {
- COMPANION.apply(buffer, mX1, mY1, mX2, mY2);
- }
-
- @Override
- public String toString() {
- return mName + " " + floatToString(mX1Value, mX1) + " " + floatToString(mY1Value, mY1)
- + " " + floatToString(mX2Value, mX2) + " " + floatToString(mY2Value, mY2);
- }
-
- public static class Companion implements CompanionOperation {
- public final int OP_CODE;
-
- protected Companion(int code) {
- OP_CODE = code;
- }
-
- @Override
- public void read(WireBuffer buffer, List<Operation> operations) {
- float sLeft = buffer.readFloat();
- float srcTop = buffer.readFloat();
- float srcRight = buffer.readFloat();
- float srcBottom = buffer.readFloat();
-
- Operation op = construct(sLeft, srcTop, srcRight, srcBottom);
- operations.add(op);
- }
-
- /**
- * Construct and Operation from the 3 variables.
- * @param x1
- * @param y1
- * @param x2
- * @param y2
- * @return
- */
- public Operation construct(float x1,
- float y1,
- float x2,
- float y2) {
- return null;
- }
-
- @Override
- public String name() {
- return "DrawRect";
- }
-
- @Override
- public int id() {
- return OP_CODE;
- }
-
- /**
- * Writes out the operation to the buffer
- * @param buffer
- * @param x1
- * @param y1
- * @param x2
- * @param y2
- */
- public void apply(WireBuffer buffer,
- float x1,
- float y1,
- float x2,
- float y2) {
- buffer.start(OP_CODE);
- buffer.writeFloat(x1);
- buffer.writeFloat(y1);
- buffer.writeFloat(x2);
- buffer.writeFloat(y2);
- }
- }
-}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase6.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase6.java
deleted file mode 100644
index 2f4335e..0000000
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase6.java
+++ /dev/null
@@ -1,202 +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.internal.widget.remotecompose.core.operations;
-
-import static com.android.internal.widget.remotecompose.core.operations.Utils.floatToString;
-
-import com.android.internal.widget.remotecompose.core.CompanionOperation;
-import com.android.internal.widget.remotecompose.core.Operation;
-import com.android.internal.widget.remotecompose.core.Operations;
-import com.android.internal.widget.remotecompose.core.PaintOperation;
-import com.android.internal.widget.remotecompose.core.RemoteContext;
-import com.android.internal.widget.remotecompose.core.VariableSupport;
-import com.android.internal.widget.remotecompose.core.WireBuffer;
-
-import java.util.List;
-
-/**
- * Base class for draw commands the take 6 floats
- */
-public abstract class DrawBase6 extends PaintOperation
- implements VariableSupport {
- public static final Companion COMPANION =
- new Companion(Operations.DRAW_RECT) {
- public Operation construct(float x1, float y1, float x2, float y2) {
- // return new DrawRectBase(x1, y1, x2, y2);
- return null;
- }
- };
- protected String mName = "DrawRectBase";
- float mV1;
- float mV2;
- float mV3;
- float mV4;
- float mV5;
- float mV6;
- float mValue1;
- float mValue2;
- float mValue3;
- float mValue4;
- float mValue5;
- float mValue6;
-
- public DrawBase6(
- float v1,
- float v2,
- float v3,
- float v4,
- float v5,
- float v6) {
- mValue1 = v1;
- mValue2 = v2;
- mValue3 = v3;
- mValue4 = v4;
- mValue5 = v5;
- mValue6 = v6;
-
- mV1 = v1;
- mV2 = v2;
- mV3 = v3;
- mV4 = v4;
- mV5 = v5;
- mV6 = v6;
- }
-
- @Override
- public void updateVariables(RemoteContext context) {
- mV1 = (Float.isNaN(mValue1))
- ? context.getFloat(Utils.idFromNan(mValue1)) : mValue1;
- mV2 = (Float.isNaN(mValue2))
- ? context.getFloat(Utils.idFromNan(mValue2)) : mValue2;
- mV3 = (Float.isNaN(mValue3))
- ? context.getFloat(Utils.idFromNan(mValue3)) : mValue3;
- mV4 = (Float.isNaN(mValue4))
- ? context.getFloat(Utils.idFromNan(mValue4)) : mValue4;
- mV5 = (Float.isNaN(mValue5))
- ? context.getFloat(Utils.idFromNan(mValue5)) : mValue5;
- mV6 = (Float.isNaN(mValue6))
- ? context.getFloat(Utils.idFromNan(mValue6)) : mValue6;
- }
-
- @Override
- public void registerListening(RemoteContext context) {
- if (Float.isNaN(mValue1)) {
- context.listensTo(Utils.idFromNan(mValue1), this);
- }
- if (Float.isNaN(mValue2)) {
- context.listensTo(Utils.idFromNan(mValue2), this);
- }
- if (Float.isNaN(mValue3)) {
- context.listensTo(Utils.idFromNan(mValue3), this);
- }
- if (Float.isNaN(mValue4)) {
- context.listensTo(Utils.idFromNan(mValue4), this);
- }
- if (Float.isNaN(mValue5)) {
- context.listensTo(Utils.idFromNan(mValue5), this);
- }
- if (Float.isNaN(mValue6)) {
- context.listensTo(Utils.idFromNan(mValue6), this);
- }
- }
-
- @Override
- public void write(WireBuffer buffer) {
- COMPANION.apply(buffer, mV1, mV2, mV3, mV4, mV5, mV6);
- }
-
- @Override
- public String toString() {
- return mName + " " + floatToString(mV1) + " " + floatToString(mV2)
- + " " + floatToString(mV3) + " " + floatToString(mV4);
- }
-
- public static class Companion implements CompanionOperation {
- public final int OP_CODE;
-
- protected Companion(int code) {
- OP_CODE = code;
- }
-
- @Override
- public void read(WireBuffer buffer, List<Operation> operations) {
- float sv1 = buffer.readFloat();
- float sv2 = buffer.readFloat();
- float sv3 = buffer.readFloat();
- float sv4 = buffer.readFloat();
- float sv5 = buffer.readFloat();
- float sv6 = buffer.readFloat();
-
- Operation op = construct(sv1, sv2, sv3, sv4, sv5, sv6);
- operations.add(op);
- }
-
- /**
- * writes out a the operation to the buffer.
- * @param v1
- * @param v2
- * @param v3
- * @param v4
- * @param v5
- * @param v6
- * @return
- */
- public Operation construct(float v1,
- float v2,
- float v3,
- float v4,
- float v5,
- float v6) {
- return null;
- }
-
- @Override
- public String name() {
- return "DrawRect";
- }
-
- @Override
- public int id() {
- return OP_CODE;
- }
-
- /**
- * Writes out the operation to the buffer
- * @param buffer
- * @param v1
- * @param v2
- * @param v3
- * @param v4
- * @param v5
- * @param v6
- */
- public void apply(WireBuffer buffer,
- float v1,
- float v2,
- float v3,
- float v4,
- float v5,
- float v6) {
- buffer.start(OP_CODE);
- buffer.writeFloat(v1);
- buffer.writeFloat(v2);
- buffer.writeFloat(v3);
- buffer.writeFloat(v4);
- buffer.writeFloat(v5);
- buffer.writeFloat(v6);
- }
- }
-}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmap.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmap.java
index ca40d12..2e971f5 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmap.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmap.java
@@ -20,22 +20,16 @@
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
import com.android.internal.widget.remotecompose.core.PaintOperation;
-import com.android.internal.widget.remotecompose.core.RemoteContext;
-import com.android.internal.widget.remotecompose.core.VariableSupport;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import java.util.List;
-public class DrawBitmap extends PaintOperation implements VariableSupport {
+public class DrawBitmap extends PaintOperation {
public static final Companion COMPANION = new Companion();
float mLeft;
float mTop;
float mRight;
float mBottom;
- float mOutputLeft;
- float mOutputTop;
- float mOutputRight;
- float mOutputBottom;
int mId;
int mDescriptionId = 0;
@@ -55,34 +49,6 @@
}
@Override
- public void updateVariables(RemoteContext context) {
- mOutputLeft = (Float.isNaN(mLeft))
- ? context.getFloat(Utils.idFromNan(mLeft)) : mLeft;
- mOutputTop = (Float.isNaN(mTop))
- ? context.getFloat(Utils.idFromNan(mTop)) : mTop;
- mOutputRight = (Float.isNaN(mRight))
- ? context.getFloat(Utils.idFromNan(mRight)) : mRight;
- mOutputBottom = (Float.isNaN(mBottom))
- ? context.getFloat(Utils.idFromNan(mBottom)) : mBottom;
- }
-
- @Override
- public void registerListening(RemoteContext context) {
- if (Float.isNaN(mLeft)) {
- context.listensTo(Utils.idFromNan(mLeft), this);
- }
- if (Float.isNaN(mTop)) {
- context.listensTo(Utils.idFromNan(mTop), this);
- }
- if (Float.isNaN(mRight)) {
- context.listensTo(Utils.idFromNan(mRight), this);
- }
- if (Float.isNaN(mBottom)) {
- context.listensTo(Utils.idFromNan(mBottom), this);
- }
- }
-
- @Override
public void write(WireBuffer buffer) {
COMPANION.apply(buffer, mId, mLeft, mTop, mRight, mBottom, mDescriptionId);
}
@@ -139,9 +105,9 @@
@Override
public void paint(PaintContext context) {
- context.drawBitmap(mId, mOutputLeft,
- mOutputTop,
- mOutputRight,
- mOutputBottom);
+ context.drawBitmap(mId, mLeft,
+ mTop,
+ mRight,
+ mBottom);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawCircle.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawCircle.java
index 3a22e4f..9ce754d 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawCircle.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawCircle.java
@@ -1,31 +1,89 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package com.android.internal.widget.remotecompose.core.operations;
+import com.android.internal.widget.remotecompose.core.CompanionOperation;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
+import com.android.internal.widget.remotecompose.core.PaintOperation;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
-public class DrawCircle extends DrawBase3 {
- public static final Companion COMPANION =
- new Companion(Operations.DRAW_CIRCLE) {
- @Override
- public Operation construct(float x1,
- float y1,
- float x2
- ) {
- return new DrawCircle(x1, y1, x2);
- }
- };
+import java.util.List;
- public DrawCircle(
- float left,
- float top,
- float right) {
- super(left, top, right);
- mName = "DrawCircle";
+public class DrawCircle extends PaintOperation {
+ public static final Companion COMPANION = new Companion();
+ float mCenterX;
+ float mCenterY;
+ float mRadius;
+
+ public DrawCircle(float centerX, float centerY, float radius) {
+ mCenterX = centerX;
+ mCenterY = centerY;
+ mRadius = radius;
+ }
+
+ @Override
+ public void write(WireBuffer buffer) {
+ COMPANION.apply(buffer, mCenterX,
+ mCenterY,
+ mRadius);
+ }
+
+ @Override
+ public String toString() {
+ return "";
+ }
+
+ public static class Companion implements CompanionOperation {
+ private Companion() {
+ }
+
+ @Override
+ public void read(WireBuffer buffer, List<Operation> operations) {
+ float centerX = buffer.readFloat();
+ float centerY = buffer.readFloat();
+ float radius = buffer.readFloat();
+
+ DrawCircle op = new DrawCircle(centerX, centerY, radius);
+ operations.add(op);
+ }
+
+ @Override
+ public String name() {
+ return "";
+ }
+
+ @Override
+ public int id() {
+ return 0;
+ }
+
+ public void apply(WireBuffer buffer, float centerX, float centerY, float radius) {
+ buffer.start(Operations.DRAW_CIRCLE);
+ buffer.writeFloat(centerX);
+ buffer.writeFloat(centerY);
+ buffer.writeFloat(radius);
+ }
}
@Override
public void paint(PaintContext context) {
- context.drawCircle(mV1, mV2, mV3);
+ context.drawCircle(mCenterX,
+ mCenterY,
+ mRadius);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawLine.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawLine.java
index c70c6ea..c7a8315 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawLine.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawLine.java
@@ -15,28 +15,83 @@
*/
package com.android.internal.widget.remotecompose.core.operations;
+import com.android.internal.widget.remotecompose.core.CompanionOperation;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
+import com.android.internal.widget.remotecompose.core.PaintOperation;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
-public class DrawLine extends DrawBase4 {
- public static final Companion COMPANION = new Companion(Operations.DRAW_LINE) {
- @Override
- public Operation construct(float x1,
- float y1,
- float x2,
- float y2) {
- return new DrawLine(x1, y1, x2, y2);
- }
- };
+import java.util.List;
+
+public class DrawLine extends PaintOperation {
+ public static final Companion COMPANION = new Companion();
+ float mX1;
+ float mY1;
+ float mX2;
+ float mY2;
public DrawLine(
- float left,
- float top,
- float right,
- float bottom) {
- super(left, top, right, bottom);
- mName = "DrawLine";
+ float x1,
+ float y1,
+ float x2,
+ float y2) {
+ mX1 = x1;
+ mY1 = y1;
+ mX2 = x2;
+ mY2 = y2;
+ }
+
+ @Override
+ public void write(WireBuffer buffer) {
+ COMPANION.apply(buffer, mX1,
+ mY1,
+ mX2,
+ mY2);
+ }
+
+ @Override
+ public String toString() {
+ return "DrawArc " + mX1 + " " + mY1
+ + " " + mX2 + " " + mY2 + ";";
+ }
+
+ public static class Companion implements CompanionOperation {
+ private Companion() {
+ }
+
+ @Override
+ public void read(WireBuffer buffer, List<Operation> operations) {
+ float x1 = buffer.readFloat();
+ float y1 = buffer.readFloat();
+ float x2 = buffer.readFloat();
+ float y2 = buffer.readFloat();
+
+ DrawLine op = new DrawLine(x1, y1, x2, y2);
+ operations.add(op);
+ }
+
+ @Override
+ public String name() {
+ return "DrawLine";
+ }
+
+ @Override
+ public int id() {
+ return Operations.DRAW_LINE;
+ }
+
+ public void apply(WireBuffer buffer,
+ float x1,
+ float y1,
+ float x2,
+ float y2) {
+ buffer.start(Operations.DRAW_LINE);
+ buffer.writeFloat(x1);
+ buffer.writeFloat(y1);
+ buffer.writeFloat(x2);
+ buffer.writeFloat(y2);
+ }
}
@Override
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawOval.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawOval.java
index ba17994..7143753 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawOval.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawOval.java
@@ -15,33 +15,88 @@
*/
package com.android.internal.widget.remotecompose.core.operations;
+import com.android.internal.widget.remotecompose.core.CompanionOperation;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
+import com.android.internal.widget.remotecompose.core.PaintOperation;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
-public class DrawOval extends DrawBase4 {
- public static final Companion COMPANION =
- new Companion(Operations.DRAW_OVAL) {
- @Override
- public Operation construct(float x1,
- float y1,
- float x2,
- float y2) {
- return new DrawOval(x1, y1, x2, y2);
- }
- };
+import java.util.List;
+
+public class DrawOval extends PaintOperation {
+ public static final Companion COMPANION = new Companion();
+ float mLeft;
+ float mTop;
+ float mRight;
+ float mBottom;
+
public DrawOval(
float left,
float top,
float right,
float bottom) {
- super(left, top, right, bottom);
- mName = "DrawOval";
+ mLeft = left;
+ mTop = top;
+ mRight = right;
+ mBottom = bottom;
+ }
+
+ @Override
+ public void write(WireBuffer buffer) {
+ COMPANION.apply(buffer, mLeft, mTop, mRight, mBottom);
+ }
+
+ @Override
+ public String toString() {
+ return "DrawOval " + mLeft + " " + mTop
+ + " " + mRight + " " + mBottom + ";";
+ }
+
+ public static class Companion implements CompanionOperation {
+ private Companion() {
+ }
+
+ @Override
+ public void read(WireBuffer buffer, List<Operation> operations) {
+ float sLeft = buffer.readFloat();
+ float srcTop = buffer.readFloat();
+ float srcRight = buffer.readFloat();
+ float srcBottom = buffer.readFloat();
+
+ DrawOval op = new DrawOval(sLeft, srcTop, srcRight, srcBottom);
+ operations.add(op);
+ }
+
+ @Override
+ public String name() {
+ return "DrawOval";
+ }
+
+ @Override
+ public int id() {
+ return Operations.DRAW_OVAL;
+ }
+
+ public void apply(WireBuffer buffer,
+ float left,
+ float top,
+ float right,
+ float bottom) {
+ buffer.start(Operations.DRAW_OVAL);
+ buffer.writeFloat(left);
+ buffer.writeFloat(top);
+ buffer.writeFloat(right);
+ buffer.writeFloat(bottom);
+ }
}
@Override
public void paint(PaintContext context) {
- context.drawOval(mX1, mY1, mX2, mY2);
+ context.drawOval(mLeft,
+ mTop,
+ mRight,
+ mBottom);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawPath.java
index 6dbc5a6..7b8a9e9 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawPath.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawPath.java
@@ -41,7 +41,7 @@
@Override
public String toString() {
- return "DrawPath " + "[" + mId + "]" + ", " + mStart + ", " + mEnd;
+ return "DrawPath " + ";";
}
public static class Companion implements CompanionOperation {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRect.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRect.java
index 633aed4..4775241 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRect.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRect.java
@@ -15,37 +15,88 @@
*/
package com.android.internal.widget.remotecompose.core.operations;
+import com.android.internal.widget.remotecompose.core.CompanionOperation;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
+import com.android.internal.widget.remotecompose.core.PaintOperation;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
-/**
- * Draw a Rectangle
- */
-public class DrawRect extends DrawBase4 {
- public static final Companion COMPANION =
- new Companion(Operations.DRAW_RECT) {
- @Override
- public Operation construct(float x1,
- float y1,
- float x2,
- float y2) {
- return new DrawRect(x1, y1, x2, y2);
- }
- };
+import java.util.List;
+
+public class DrawRect extends PaintOperation {
+ public static final Companion COMPANION = new Companion();
+ float mLeft;
+ float mTop;
+ float mRight;
+ float mBottom;
public DrawRect(
float left,
float top,
float right,
float bottom) {
- super(left, top, right, bottom);
- mName = "DrawRect";
+ mLeft = left;
+ mTop = top;
+ mRight = right;
+ mBottom = bottom;
+ }
+
+ @Override
+ public void write(WireBuffer buffer) {
+ COMPANION.apply(buffer, mLeft, mTop, mRight, mBottom);
+ }
+
+ @Override
+ public String toString() {
+ return "DrawRect " + mLeft + " " + mTop
+ + " " + mRight + " " + mBottom + ";";
+ }
+
+ public static class Companion implements CompanionOperation {
+ private Companion() {
+ }
+
+ @Override
+ public void read(WireBuffer buffer, List<Operation> operations) {
+ float sLeft = buffer.readFloat();
+ float srcTop = buffer.readFloat();
+ float srcRight = buffer.readFloat();
+ float srcBottom = buffer.readFloat();
+
+ DrawRect op = new DrawRect(sLeft, srcTop, srcRight, srcBottom);
+ operations.add(op);
+ }
+
+ @Override
+ public String name() {
+ return "DrawRect";
+ }
+
+ @Override
+ public int id() {
+ return Operations.DRAW_RECT;
+ }
+
+ public void apply(WireBuffer buffer,
+ float left,
+ float top,
+ float right,
+ float bottom) {
+ buffer.start(Operations.DRAW_RECT);
+ buffer.writeFloat(left);
+ buffer.writeFloat(top);
+ buffer.writeFloat(right);
+ buffer.writeFloat(bottom);
+ }
}
@Override
public void paint(PaintContext context) {
- context.drawRect(mX1, mY1, mX2, mY2);
+ context.drawRect(mLeft,
+ mTop,
+ mRight,
+ mBottom);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRoundRect.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRoundRect.java
index b9d0a67..8da16e7 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRoundRect.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRoundRect.java
@@ -15,40 +15,104 @@
*/
package com.android.internal.widget.remotecompose.core.operations;
+import com.android.internal.widget.remotecompose.core.CompanionOperation;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
+import com.android.internal.widget.remotecompose.core.PaintOperation;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
-/**
- * Draw a rounded rectangle
- */
-public class DrawRoundRect extends DrawBase6 {
- public static final Companion COMPANION =
- new Companion(Operations.DRAW_ROUND_RECT) {
- @Override
- public Operation construct(float v1,
- float v2,
- float v3,
- float v4,
- float v5,
- float v6) {
- return new DrawRoundRect(v1, v2, v3, v4, v5, v6);
- }
- };
+import java.util.List;
- public DrawRoundRect(float v1,
- float v2,
- float v3,
- float v4,
- float v5,
- float v6) {
- super(v1, v2, v3, v4, v5, v6);
- mName = "ClipRect";
+public class DrawRoundRect extends PaintOperation {
+ public static final Companion COMPANION = new Companion();
+ float mLeft;
+ float mTop;
+ float mRight;
+ float mBottom;
+ float mRadiusX;
+ float mRadiusY;
+
+ public DrawRoundRect(
+ float left,
+ float top,
+ float right,
+ float bottom,
+ float radiusX,
+ float radiusY) {
+ mLeft = left;
+ mTop = top;
+ mRight = right;
+ mBottom = bottom;
+ mRadiusX = radiusX;
+ mRadiusY = radiusY;
+ }
+
+ @Override
+ public void write(WireBuffer buffer) {
+ COMPANION.apply(buffer, mLeft, mTop, mRight, mBottom, mRadiusX, mRadiusY);
+ }
+
+ @Override
+ public String toString() {
+ return "DrawRoundRect " + mLeft + " " + mTop
+ + " " + mRight + " " + mBottom
+ + " (" + mRadiusX + " " + mRadiusY + ");";
+ }
+
+ public static class Companion implements CompanionOperation {
+ private Companion() {
+ }
+
+ @Override
+ public void read(WireBuffer buffer, List<Operation> operations) {
+ float sLeft = buffer.readFloat();
+ float srcTop = buffer.readFloat();
+ float srcRight = buffer.readFloat();
+ float srcBottom = buffer.readFloat();
+ float srcRadiusX = buffer.readFloat();
+ float srcRadiusY = buffer.readFloat();
+
+ DrawRoundRect op = new DrawRoundRect(sLeft, srcTop, srcRight,
+ srcBottom, srcRadiusX, srcRadiusY);
+ operations.add(op);
+ }
+
+ @Override
+ public String name() {
+ return "DrawOval";
+ }
+
+ @Override
+ public int id() {
+ return Operations.DRAW_ROUND_RECT;
+ }
+
+ public void apply(WireBuffer buffer,
+ float left,
+ float top,
+ float right,
+ float bottom,
+ float radiusX,
+ float radiusY) {
+ buffer.start(Operations.DRAW_ROUND_RECT);
+ buffer.writeFloat(left);
+ buffer.writeFloat(top);
+ buffer.writeFloat(right);
+ buffer.writeFloat(bottom);
+ buffer.writeFloat(radiusX);
+ buffer.writeFloat(radiusY);
+ }
}
@Override
public void paint(PaintContext context) {
- context.drawRoundRect(mV1, mV2, mV3, mV4, mV5, mV6
+ context.drawRoundRect(mLeft,
+ mTop,
+ mRight,
+ mBottom,
+ mRadiusX,
+ mRadiusY
);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawText.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawText.java
deleted file mode 100644
index f8f8afd..0000000
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawText.java
+++ /dev/null
@@ -1,136 +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.internal.widget.remotecompose.core.operations;
-
-import com.android.internal.widget.remotecompose.core.CompanionOperation;
-import com.android.internal.widget.remotecompose.core.Operation;
-import com.android.internal.widget.remotecompose.core.Operations;
-import com.android.internal.widget.remotecompose.core.PaintContext;
-import com.android.internal.widget.remotecompose.core.PaintOperation;
-import com.android.internal.widget.remotecompose.core.WireBuffer;
-
-import java.util.List;
-
-/**
- * Draw Text
- */
-public class DrawText extends PaintOperation {
- public static final Companion COMPANION = new Companion();
- int mTextID;
- int mStart = 0;
- int mEnd = 0;
- int mContextStart = 0;
- int mContextEnd = 0;
- float mX = 0f;
- float mY = 0f;
- boolean mRtl = false;
-
- public DrawText(int textID,
- int start,
- int end,
- int contextStart,
- int contextEnd,
- float x,
- float y,
- boolean rtl) {
- mTextID = textID;
- mStart = start;
- mEnd = end;
- mContextStart = contextStart;
- mContextEnd = contextEnd;
- mX = x;
- mY = y;
- mRtl = rtl;
- }
-
- @Override
- public void write(WireBuffer buffer) {
- COMPANION.apply(buffer, mTextID, mStart, mEnd, mContextStart, mContextEnd, mX, mY, mRtl);
-
- }
-
- @Override
- public String toString() {
- return "DrawTextRun [" + mTextID + "] " + mStart + ", " + mEnd + ", " + mX + ", " + mY;
- }
-
- public static class Companion implements CompanionOperation {
- private Companion() {
- }
-
- @Override
- public void read(WireBuffer buffer, List<Operation> operations) {
- int text = buffer.readInt();
- int start = buffer.readInt();
- int end = buffer.readInt();
- int contextStart = buffer.readInt();
- int contextEnd = buffer.readInt();
- float x = buffer.readFloat();
- float y = buffer.readFloat();
- boolean rtl = buffer.readBoolean();
- DrawText op = new DrawText(text, start, end, contextStart, contextEnd, x, y, rtl);
-
- operations.add(op);
- }
-
- @Override
- public String name() {
- return "";
- }
-
- @Override
- public int id() {
- return 0;
- }
-
- /**
- * Writes out the operation to the buffer
- * @param buffer
- * @param textID
- * @param start
- * @param end
- * @param contextStart
- * @param contextEnd
- * @param x
- * @param y
- * @param rtl
- */
- public void apply(WireBuffer buffer,
- int textID,
- int start,
- int end,
- int contextStart,
- int contextEnd,
- float x,
- float y,
- boolean rtl) {
- buffer.start(Operations.DRAW_TEXT_RUN);
- buffer.writeInt(textID);
- buffer.writeInt(start);
- buffer.writeInt(end);
- buffer.writeInt(contextStart);
- buffer.writeInt(contextEnd);
- buffer.writeFloat(x);
- buffer.writeFloat(y);
- buffer.writeBoolean(rtl);
- }
- }
-
- @Override
- public void paint(PaintContext context) {
- context.drawTextRun(mTextID, mStart, mEnd, mContextStart, mContextEnd, mX, mY, mRtl);
- }
-}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextAnchored.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextAnchored.java
deleted file mode 100644
index 4f0641f..0000000
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextAnchored.java
+++ /dev/null
@@ -1,204 +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.internal.widget.remotecompose.core.operations;
-
-import com.android.internal.widget.remotecompose.core.CompanionOperation;
-import com.android.internal.widget.remotecompose.core.Operation;
-import com.android.internal.widget.remotecompose.core.Operations;
-import com.android.internal.widget.remotecompose.core.PaintContext;
-import com.android.internal.widget.remotecompose.core.PaintOperation;
-import com.android.internal.widget.remotecompose.core.RemoteContext;
-import com.android.internal.widget.remotecompose.core.VariableSupport;
-import com.android.internal.widget.remotecompose.core.WireBuffer;
-
-import java.util.List;
-
-/**
- * Draw Text in Anchored to a point
- */
-public class DrawTextAnchored extends PaintOperation implements VariableSupport {
- public static final Companion COMPANION = new Companion();
- int mTextID;
- float mX;
- float mY;
- float mPanX;
- float mPanY;
- int mFlags;
- float mOutX;
- float mOutY;
- float mOutPanX;
- float mOutPanY;
-
- public static final int ANCHOR_TEXT_RTL = 1;
- public static final int ANCHOR_MONOSPACE_MEASURE = 2;
-
- public DrawTextAnchored(int textID,
- float x,
- float y,
- float panX,
- float panY,
- int flags) {
- mTextID = textID;
- mX = x;
- mY = y;
- mOutX = mX;
- mOutY = mY;
- mFlags = flags;
- mOutPanX = mPanX = panX;
- mOutPanY = mPanY = panY;
- }
-
- @Override
- public void updateVariables(RemoteContext context) {
- mOutX = (Float.isNaN(mX))
- ? context.getFloat(Utils.idFromNan(mX)) : mX;
- mOutY = (Float.isNaN(mY))
- ? context.getFloat(Utils.idFromNan(mY)) : mY;
- mOutPanX = (Float.isNaN(mPanX))
- ? context.getFloat(Utils.idFromNan(mPanX)) : mPanX;
- mOutPanY = (Float.isNaN(mPanY))
- ? context.getFloat(Utils.idFromNan(mPanY)) : mPanY;
- }
-
- @Override
- public void registerListening(RemoteContext context) {
- if (Float.isNaN(mX)) {
- context.listensTo(Utils.idFromNan(mX), this);
- }
- if (Float.isNaN(mY)) {
- context.listensTo(Utils.idFromNan(mY), this);
- }
- if (Float.isNaN(mPanX)) {
- context.listensTo(Utils.idFromNan(mPanX), this);
- }
- if (Float.isNaN(mPanY) && Utils.idFromNan(mPanY) > 0) {
- context.listensTo(Utils.idFromNan(mPanY), this);
- }
- }
-
- @Override
- public void write(WireBuffer buffer) {
- COMPANION.apply(buffer, mTextID, mX,
- mY,
- mPanX,
- mPanY,
- mFlags);
- }
-
- @Override
- public String toString() {
- return "DrawTextAnchored [" + mTextID + "] " + floatToStr(mX) + ", "
- + floatToStr(mY) + ", "
- + floatToStr(mPanX) + ", " + floatToStr(mPanY) + ", "
- + Integer.toBinaryString(mFlags);
- }
-
- private static String floatToStr(float v) {
- if (Float.isNaN(v)) {
- return "[" + Utils.idFromNan(v) + "]";
- }
- return Float.toString(v);
- }
-
- public static class Companion implements CompanionOperation {
- private Companion() {
- }
-
- @Override
- public void read(WireBuffer buffer, List<Operation> operations) {
- int textID = buffer.readInt();
- float x = buffer.readFloat();
- float y = buffer.readFloat();
- float panX = buffer.readFloat();
- float panY = buffer.readFloat();
- int flags = buffer.readInt();
-
- DrawTextAnchored op = new DrawTextAnchored(textID,
- x, y,
- panX, panY,
- flags);
-
- operations.add(op);
- }
-
- @Override
- public String name() {
- return "";
- }
-
- @Override
- public int id() {
- return 0;
- }
-
- /**
- * Writes out the operation to the buffer
- * @param buffer
- * @param textID
- * @param x
- * @param y
- * @param panX
- * @param panY
- * @param flags
- */
- public void apply(WireBuffer buffer,
- int textID,
- float x,
- float y,
- float panX,
- float panY,
- int flags) {
- buffer.start(Operations.DRAW_TEXT_ANCHOR);
- buffer.writeInt(textID);
- buffer.writeFloat(x);
- buffer.writeFloat(y);
- buffer.writeFloat(panX);
- buffer.writeFloat(panY);
- buffer.writeInt(flags);
- }
- }
-
- float[] mBounds = new float[4];
-
- private float getHorizontalOffset() {
- // TODO scale TextSize / BaseTextSize;
- float scale = 1.0f;
-
- float textWidth = scale * (mBounds[2] - mBounds[0]);
- float boxWidth = 0;
- return (boxWidth - textWidth) * (1 + mOutPanX) / 2.f
- - (scale * mBounds[0]);
- }
-
- private float getVerticalOffset() {
- // TODO scale TextSize / BaseTextSize;
- float scale = 1.0f;
- float boxHeight = 0;
- float textHeight = scale * (mBounds[3] - mBounds[1]);
- return (boxHeight - textHeight) * (1 - mOutPanY) / 2
- - (scale * mBounds[1]);
- }
-
- @Override
- public void paint(PaintContext context) {
- context.getTextBounds(mTextID, 0, -1,
- (mFlags & ANCHOR_MONOSPACE_MEASURE) != 0, mBounds);
- float x = mOutX + getHorizontalOffset();
- float y = (Float.isNaN(mOutPanY)) ? mOutY : mOutY + getVerticalOffset();
- context.drawTextRun(mTextID, 0, -1, 0, 1, x, y,
- (mFlags & ANCHOR_TEXT_RTL) == 1);
- }
-}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java
index b1a0172..1856e30 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java
@@ -24,9 +24,6 @@
import java.util.List;
-/**
- * Draw text along a path.
- */
public class DrawTextOnPath extends PaintOperation {
public static final Companion COMPANION = new Companion();
int mPathId;
@@ -48,8 +45,7 @@
@Override
public String toString() {
- return "DrawTextOnPath [" + mTextId + "] [" + mPathId + "] "
- + mHOffset + ", " + mVOffset;
+ return "DrawTextOnPath " + " " + mPathId + ";";
}
public static class Companion implements CompanionOperation {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTweenPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTweenPath.java
index 48fc94e..ef0a4ad 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTweenPath.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTweenPath.java
@@ -58,7 +58,7 @@
public String toString() {
return "DrawTweenPath " + mPath1Id + " " + mPath2Id
+ " " + mTween + " " + mStart + " "
- + "- " + mStop;
+ + "- " + mStop + ";";
}
public static class Companion implements CompanionOperation {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/FloatConstant.java b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatConstant.java
deleted file mode 100644
index 576b53f..0000000
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/FloatConstant.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.widget.remotecompose.core.operations;
-
-import com.android.internal.widget.remotecompose.core.CompanionOperation;
-import com.android.internal.widget.remotecompose.core.Operation;
-import com.android.internal.widget.remotecompose.core.Operations;
-import com.android.internal.widget.remotecompose.core.RemoteContext;
-import com.android.internal.widget.remotecompose.core.WireBuffer;
-
-import java.util.List;
-
-/**
- * Operation to deal with Text data
- */
-public class FloatConstant implements Operation {
- public int mTextId;
- public float mValue;
- public static final Companion COMPANION = new Companion();
- public static final int MAX_STRING_SIZE = 4000;
-
- public FloatConstant(int textId, float value) {
- this.mTextId = textId;
- this.mValue = value;
- }
-
- @Override
- public void write(WireBuffer buffer) {
- COMPANION.apply(buffer, mTextId, mValue);
- }
-
- @Override
- public String toString() {
- return "FloatConstant[" + mTextId + "] = " + mValue + "";
- }
-
- public static class Companion implements CompanionOperation {
- private Companion() {}
-
- @Override
- public String name() {
- return "FloatExpression";
- }
-
- @Override
- public int id() {
- return Operations.DATA_FLOAT;
- }
-
- /**
- * Writes out the operation to the buffer
- * @param buffer
- * @param textId
- * @param value
- */
- public void apply(WireBuffer buffer, int textId, float value) {
- buffer.start(Operations.DATA_FLOAT);
- buffer.writeInt(textId);
- buffer.writeFloat(value);
- }
-
- @Override
- public void read(WireBuffer buffer, List<Operation> operations) {
- int textId = buffer.readInt();
-
- float value = buffer.readFloat();
- operations.add(new FloatConstant(textId, value));
- }
- }
-
- @Override
- public void apply(RemoteContext context) {
- context.loadFloat(mTextId, mValue);
- }
-
- @Override
- public String deepToString(String indent) {
- return indent + toString();
- }
-}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java
deleted file mode 100644
index 354f41b..0000000
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.widget.remotecompose.core.operations;
-
-import com.android.internal.widget.remotecompose.core.CompanionOperation;
-import com.android.internal.widget.remotecompose.core.Operation;
-import com.android.internal.widget.remotecompose.core.Operations;
-import com.android.internal.widget.remotecompose.core.RemoteContext;
-import com.android.internal.widget.remotecompose.core.VariableSupport;
-import com.android.internal.widget.remotecompose.core.WireBuffer;
-import com.android.internal.widget.remotecompose.core.operations.utilities.AnimatedFloatExpression;
-import com.android.internal.widget.remotecompose.core.operations.utilities.easing.FloatAnimation;
-
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * Operation to deal with AnimatedFloats
- * This is designed to be an optimized calculation for things like
- * injecting the width of the component int draw rect
- * As well as supporting generalized animation floats.
- * The floats represent a RPN style calculator
- */
-public class FloatExpression implements Operation, VariableSupport {
- public int mId;
- public float[] mSrcValue;
- public float[] mSrcAnimation;
- public FloatAnimation mFloatAnimation;
- public float[] mPreCalcValue;
- private float mLastChange = Float.NaN;
- AnimatedFloatExpression mExp = new AnimatedFloatExpression();
- public static final Companion COMPANION = new Companion();
- public static final int MAX_STRING_SIZE = 4000;
-
- public FloatExpression(int id, float[] value, float[] animation) {
- this.mId = id;
- this.mSrcValue = value;
- this.mSrcAnimation = animation;
- if (mSrcAnimation != null) {
- mFloatAnimation = new FloatAnimation(mSrcAnimation);
- }
- }
-
- @Override
- public void updateVariables(RemoteContext context) {
- if (mPreCalcValue == null || mPreCalcValue.length != mSrcValue.length) {
- mPreCalcValue = new float[mSrcValue.length];
- }
- //Utils.log("updateVariables ");
- boolean value_changed = false;
- for (int i = 0; i < mSrcValue.length; i++) {
- float v = mSrcValue[i];
- if (Float.isNaN(v) && !AnimatedFloatExpression.isMathOperator(v)) {
- float newValue = context.getFloat(Utils.idFromNan(v));
- if (mFloatAnimation != null) {
- if (mPreCalcValue[i] != newValue) {
- mLastChange = context.getAnimationTime();
- value_changed = true;
- mPreCalcValue[i] = newValue;
- }
- } else {
- mPreCalcValue[i] = newValue;
- }
- } else {
- mPreCalcValue[i] = mSrcValue[i];
- }
- }
- if (value_changed && mFloatAnimation != null) {
- float v = mExp.eval(Arrays.copyOf(mPreCalcValue, mPreCalcValue.length));
- if (Float.isNaN(mFloatAnimation.getTargetValue())) {
- mFloatAnimation.setInitialValue(v);
- } else {
- mFloatAnimation.setInitialValue(mFloatAnimation.getTargetValue());
- }
- mFloatAnimation.setTargetValue(v);
- }
- }
-
- @Override
- public void registerListening(RemoteContext context) {
- for (int i = 0; i < mSrcValue.length; i++) {
- float v = mSrcValue[i];
- if (Float.isNaN(v) && !AnimatedFloatExpression.isMathOperator(v)) {
- context.listensTo(Utils.idFromNan(v), this);
- }
- }
- }
-
- @Override
- public void apply(RemoteContext context) {
- updateVariables(context);
- float t = context.getAnimationTime();
- if (Float.isNaN(mLastChange)) {
- mLastChange = t;
- }
- if (mFloatAnimation != null) {
- float f = mFloatAnimation.get(t - mLastChange);
- context.loadFloat(mId, f);
- } else {
- context.loadFloat(mId, mExp.eval(Arrays.copyOf(mPreCalcValue, mPreCalcValue.length)));
- }
- }
-
- @Override
- public void write(WireBuffer buffer) {
- COMPANION.apply(buffer, mId, mSrcValue, mSrcAnimation);
- }
-
- @Override
- public String toString() {
- String[] labels = new String[mSrcValue.length];
- for (int i = 0; i < mSrcValue.length; i++) {
- if (Float.isNaN(mSrcValue[i])) {
- labels[i] = "[" + Utils.idFromNan(mSrcValue[i]) + "]";
- }
-
- }
- return "FloatExpression[" + mId + "] = ("
- + AnimatedFloatExpression.toString(mPreCalcValue, labels) + ")";
- }
-
- public static class Companion implements CompanionOperation {
- private Companion() {
- }
-
- @Override
- public String name() {
- return "FloatExpression";
- }
-
- @Override
- public int id() {
- return Operations.ANIMATED_FLOAT;
- }
-
- /**
- * Writes out the operation to the buffer
- * @param buffer
- * @param id
- * @param value
- * @param animation
- */
- public void apply(WireBuffer buffer, int id, float[] value, float[] animation) {
- buffer.start(Operations.ANIMATED_FLOAT);
- buffer.writeInt(id);
-
- int len = value.length;
- if (animation != null) {
- len |= (animation.length << 16);
- }
- buffer.writeInt(len);
-
- for (int i = 0; i < value.length; i++) {
- buffer.writeFloat(value[i]);
- }
- if (animation != null) {
- for (int i = 0; i < animation.length; i++) {
- buffer.writeFloat(animation[i]);
- }
- }
-
- }
-
- @Override
- public void read(WireBuffer buffer, List<Operation> operations) {
- int id = buffer.readInt();
- int len = buffer.readInt();
- int valueLen = len & 0xFFFF;
- int animLen = (len >> 16) & 0xFFFF;
- float[] values = new float[valueLen];
- for (int i = 0; i < values.length; i++) {
- values[i] = buffer.readFloat();
- }
-
- float[] animation;
- if (animLen != 0) {
- animation = new float[animLen];
- for (int i = 0; i < animation.length; i++) {
- animation[i] = buffer.readFloat();
- }
- } else {
- animation = null;
- }
- operations.add(new FloatExpression(id, values, animation));
- }
- }
-
- @Override
- public String deepToString(String indent) {
- return indent + toString();
- }
-
-}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java
index 0dad45c..482e0e2 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java
@@ -37,7 +37,7 @@
@Override
public String toString() {
- return "MatrixRestore";
+ return "MatrixRestore;";
}
public static class Companion implements CompanionOperation {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRotate.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRotate.java
index bbf4135..d6c89e0 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRotate.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRotate.java
@@ -15,29 +15,68 @@
*/
package com.android.internal.widget.remotecompose.core.operations;
+import com.android.internal.widget.remotecompose.core.CompanionOperation;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
+import com.android.internal.widget.remotecompose.core.PaintOperation;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
-public class MatrixRotate extends DrawBase3 {
- public static final Companion COMPANION =
- new Companion(Operations.MATRIX_ROTATE) {
- @Override
- public Operation construct(float rotate,
- float pivotX,
- float pivotY
- ) {
- return new MatrixRotate(rotate, pivotX, pivotY);
- }
- };
+import java.util.List;
+
+public class MatrixRotate extends PaintOperation {
+ public static final Companion COMPANION = new Companion();
+ float mRotate, mPivotX, mPivotY;
public MatrixRotate(float rotate, float pivotX, float pivotY) {
- super(rotate, pivotX, pivotY);
- mName = "MatrixRotate";
+ mRotate = rotate;
+ mPivotX = pivotX;
+ mPivotY = pivotY;
+ }
+
+ @Override
+ public void write(WireBuffer buffer) {
+ COMPANION.apply(buffer, mRotate, mPivotX, mPivotY);
+ }
+
+ @Override
+ public String toString() {
+ return "DrawArc " + mRotate + ", " + mPivotX + ", " + mPivotY + ";";
+ }
+
+ public static class Companion implements CompanionOperation {
+ private Companion() {
+ }
+
+ @Override
+ public void read(WireBuffer buffer, List<Operation> operations) {
+ float rotate = buffer.readFloat();
+ float pivotX = buffer.readFloat();
+ float pivotY = buffer.readFloat();
+ MatrixRotate op = new MatrixRotate(rotate, pivotX, pivotY);
+ operations.add(op);
+ }
+
+ @Override
+ public String name() {
+ return "Matrix";
+ }
+
+ @Override
+ public int id() {
+ return Operations.MATRIX_ROTATE;
+ }
+
+ public void apply(WireBuffer buffer, float rotate, float pivotX, float pivotY) {
+ buffer.start(Operations.MATRIX_ROTATE);
+ buffer.writeFloat(rotate);
+ buffer.writeFloat(pivotX);
+ buffer.writeFloat(pivotY);
+ }
}
@Override
public void paint(PaintContext context) {
- context.matrixRotate(mV1, mV2, mV3);
+ context.matrixRotate(mRotate, mPivotX, mPivotY);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixScale.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixScale.java
index 04b940b..28aa68dd 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixScale.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixScale.java
@@ -15,30 +15,74 @@
*/
package com.android.internal.widget.remotecompose.core.operations;
+import com.android.internal.widget.remotecompose.core.CompanionOperation;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
+import com.android.internal.widget.remotecompose.core.PaintOperation;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
-public class MatrixScale extends DrawBase4 {
- public static final Companion COMPANION =
- new Companion(Operations.MATRIX_SCALE) {
- @Override
- public Operation construct(float scaleX,
- float scaleY,
- float centerX,
- float centerY
- ) {
- return new MatrixScale(scaleX, scaleY, centerX, centerY);
- }
- };
+import java.util.List;
+
+public class MatrixScale extends PaintOperation {
+ public static final Companion COMPANION = new Companion();
+ float mScaleX, mScaleY;
+ float mCenterX, mCenterY;
public MatrixScale(float scaleX, float scaleY, float centerX, float centerY) {
- super(scaleX, scaleY, centerX, centerY);
- mName = "MatrixScale";
+ mScaleX = scaleX;
+ mScaleY = scaleY;
+ mCenterX = centerX;
+ mCenterY = centerY;
+ }
+
+ @Override
+ public void write(WireBuffer buffer) {
+ COMPANION.apply(buffer, mScaleX, mScaleY, mCenterX, mCenterY);
+ }
+
+ @Override
+ public String toString() {
+ return "MatrixScale " + mScaleY + ", " + mScaleY + ";";
+ }
+
+ public static class Companion implements CompanionOperation {
+ private Companion() {
+ }
+
+ @Override
+ public void read(WireBuffer buffer, List<Operation> operations) {
+ float scaleX = buffer.readFloat();
+ float scaleY = buffer.readFloat();
+ float centerX = buffer.readFloat();
+ float centerY = buffer.readFloat();
+ MatrixScale op = new MatrixScale(scaleX, scaleY, centerX, centerY);
+ operations.add(op);
+ }
+
+ @Override
+ public String name() {
+ return "Matrix";
+ }
+
+ @Override
+ public int id() {
+ return Operations.MATRIX_SCALE;
+ }
+
+ public void apply(WireBuffer buffer, float scaleX, float scaleY,
+ float centerX, float centerY) {
+ buffer.start(Operations.MATRIX_SCALE);
+ buffer.writeFloat(scaleX);
+ buffer.writeFloat(scaleY);
+ buffer.writeFloat(centerX);
+ buffer.writeFloat(centerY);
+
+ }
}
@Override
public void paint(PaintContext context) {
- context.matrixScale(mX1, mY1, mX2, mY2);
+ context.mtrixScale(mScaleX, mScaleY, mCenterX, mCenterY);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixTranslate.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixTranslate.java
index 4f34e98..3298752 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixTranslate.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixTranslate.java
@@ -15,28 +15,65 @@
*/
package com.android.internal.widget.remotecompose.core.operations;
+import com.android.internal.widget.remotecompose.core.CompanionOperation;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
+import com.android.internal.widget.remotecompose.core.PaintOperation;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
-public class MatrixTranslate extends DrawBase2 {
- public static final Companion COMPANION =
- new Companion(Operations.MATRIX_TRANSLATE) {
- @Override
- public Operation construct(float x1,
- float y1
- ) {
- return new MatrixTranslate(x1, y1);
- }
- };
+import java.util.List;
+
+public class MatrixTranslate extends PaintOperation {
+ public static final Companion COMPANION = new Companion();
+ float mTranslateX, mTranslateY;
public MatrixTranslate(float translateX, float translateY) {
- super(translateX, translateY);
- mName = "MatrixTranslate";
+ mTranslateX = translateX;
+ mTranslateY = translateY;
+ }
+
+ @Override
+ public void write(WireBuffer buffer) {
+ COMPANION.apply(buffer, mTranslateX, mTranslateY);
+ }
+
+ @Override
+ public String toString() {
+ return "DrawArc " + mTranslateY + ", " + mTranslateY + ";";
+ }
+
+ public static class Companion implements CompanionOperation {
+ private Companion() {
+ }
+
+ @Override
+ public void read(WireBuffer buffer, List<Operation> operations) {
+ float translateX = buffer.readFloat();
+ float translateY = buffer.readFloat();
+ MatrixTranslate op = new MatrixTranslate(translateX, translateY);
+ operations.add(op);
+ }
+
+ @Override
+ public String name() {
+ return "Matrix";
+ }
+
+ @Override
+ public int id() {
+ return Operations.MATRIX_TRANSLATE;
+ }
+
+ public void apply(WireBuffer buffer, float translateX, float translateY) {
+ buffer.start(Operations.MATRIX_TRANSLATE);
+ buffer.writeFloat(translateX);
+ buffer.writeFloat(translateY);
+ }
}
@Override
public void paint(PaintContext context) {
- context.matrixTranslate(mV1, mV2);
+ context.matrixTranslate(mTranslateX, mTranslateY);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/NamedVariable.java b/core/java/com/android/internal/widget/remotecompose/core/operations/NamedVariable.java
deleted file mode 100644
index 0c5b286..0000000
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/NamedVariable.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.widget.remotecompose.core.operations;
-
-import com.android.internal.widget.remotecompose.core.CompanionOperation;
-import com.android.internal.widget.remotecompose.core.Operation;
-import com.android.internal.widget.remotecompose.core.Operations;
-import com.android.internal.widget.remotecompose.core.RemoteContext;
-import com.android.internal.widget.remotecompose.core.WireBuffer;
-
-import java.util.List;
-
-/**
- * Operation to deal with Text data
- */
-public class NamedVariable implements Operation {
- public int mVarId;
- public String mVarName;
- public int mVarType;
- public static final Companion COMPANION = new Companion();
- public static final int MAX_STRING_SIZE = 4000;
-
- public NamedVariable(int varId, int varType, String name) {
- this.mVarId = varId;
- this.mVarType = varType;
- this.mVarName = name;
- }
-
- @Override
- public void write(WireBuffer buffer) {
- COMPANION.apply(buffer, mVarId, mVarType, mVarName);
- }
-
- @Override
- public String toString() {
- return "VariableName[" + mVarId + "] = \""
- + Utils.trimString(mVarName, 10) + "\" type=" + mVarType;
- }
-
- public static class Companion implements CompanionOperation {
- private Companion() {
- }
-
- @Override
- public String name() {
- return "TextData";
- }
-
- @Override
- public int id() {
- return Operations.DATA_TEXT;
- }
-
- /**
- * Writes out the operation to the buffer
- * @param buffer
- * @param varId
- * @param varType
- * @param text
- */
- public void apply(WireBuffer buffer, int varId, int varType, String text) {
- buffer.start(Operations.DATA_TEXT);
- buffer.writeInt(varId);
- buffer.writeInt(varType);
- buffer.writeUTF8(text);
- }
-
- @Override
- public void read(WireBuffer buffer, List<Operation> operations) {
- int varId = buffer.readInt();
- int varType = buffer.readInt();
- String text = buffer.readUTF8(MAX_STRING_SIZE);
- operations.add(new NamedVariable(varId, varType, text));
- }
- }
-
- @Override
- public void apply(RemoteContext context) {
- context.loadVariableName(mVarName, mVarId, mVarType);
- }
-
- @Override
- public String deepToString(String indent) {
- return indent + toString();
- }
-}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java
index 0807bcd..e5683ec 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java
@@ -20,14 +20,12 @@
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
import com.android.internal.widget.remotecompose.core.PaintOperation;
-import com.android.internal.widget.remotecompose.core.RemoteContext;
-import com.android.internal.widget.remotecompose.core.VariableSupport;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.operations.paint.PaintBundle;
import java.util.List;
-public class PaintData extends PaintOperation implements VariableSupport {
+public class PaintData extends PaintOperation {
public PaintBundle mPaintData = new PaintBundle();
public static final Companion COMPANION = new Companion();
public static final int MAX_STRING_SIZE = 4000;
@@ -36,16 +34,6 @@
}
@Override
- public void updateVariables(RemoteContext context) {
- mPaintData.updateVariables(context);
- }
-
- @Override
- public void registerListening(RemoteContext context) {
- mPaintData.registerVars(context, this);
- }
-
- @Override
public void write(WireBuffer buffer) {
COMPANION.apply(buffer, mPaintData);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java
index e467e7b..2646b27 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java
@@ -18,50 +18,27 @@
import com.android.internal.widget.remotecompose.core.CompanionOperation;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
+import com.android.internal.widget.remotecompose.core.PaintContext;
import com.android.internal.widget.remotecompose.core.RemoteContext;
-import com.android.internal.widget.remotecompose.core.VariableSupport;
import com.android.internal.widget.remotecompose.core.WireBuffer;
-import java.util.Arrays;
import java.util.List;
-public class PathData implements Operation, VariableSupport {
+public class PathData implements Operation {
public static final Companion COMPANION = new Companion();
int mInstanceId;
+ float[] mRef;
float[] mFloatPath;
- float[] mOutputPath;
+ float[] mRetFloats;
PathData(int instanceId, float[] floatPath) {
mInstanceId = instanceId;
mFloatPath = floatPath;
- mOutputPath = Arrays.copyOf(mFloatPath, mFloatPath.length);
- }
-
- @Override
- public void updateVariables(RemoteContext context) {
- for (int i = 0; i < mFloatPath.length; i++) {
- float v = mFloatPath[i];
- if (Utils.isVariable(v)) {
- mOutputPath[i] = (Float.isNaN(v))
- ? context.getFloat(Utils.idFromNan(v)) : v;
- } else {
- mOutputPath[i] = v;
- }
- }
- }
-
- @Override
- public void registerListening(RemoteContext context) {
- for (int i = 0; i < mFloatPath.length; i++) {
- if (Float.isNaN(mFloatPath[i])) {
- context.listensTo(Utils.idFromNan(mFloatPath[i]), this);
- }
- }
}
@Override
public void write(WireBuffer buffer) {
- COMPANION.apply(buffer, mInstanceId, mOutputPath);
+ COMPANION.apply(buffer, mInstanceId, mFloatPath);
}
@Override
@@ -69,35 +46,29 @@
return pathString(mFloatPath);
}
- @Override
- public String toString() {
- return "PathData[" + mInstanceId + "] = " + "\"" + deepToString(" ") + "\"";
+ public float[] getFloatPath(PaintContext context) {
+ float[] ret = mRetFloats; // Assume retFloats is declared elsewhere
+ if (ret == null) {
+ return mFloatPath; // Assume floatPath is declared elsewhere
+ }
+ float[] localRef = mRef; // Assume ref is of type Float[]
+ if (localRef == null) {
+ for (int i = 0; i < mFloatPath.length; i++) {
+ ret[i] = mFloatPath[i];
+ }
+ } else {
+ for (int i = 0; i < mFloatPath.length; i++) {
+ float lr = localRef[i];
+ if (Float.isNaN(lr)) {
+ ret[i] = Utils.getActualValue(lr);
+ } else {
+ ret[i] = mFloatPath[i];
+ }
+ }
+ }
+ return ret;
}
- /**
- * public float[] getFloatPath(PaintContext context) {
- * float[] ret = mRetFloats; // Assume retFloats is declared elsewhere
- * if (ret == null) {
- * return mFloatPath; // Assume floatPath is declared elsewhere
- * }
- * float[] localRef = mRef; // Assume ref is of type Float[]
- * if (localRef == null) {
- * for (int i = 0; i < mFloatPath.length; i++) {
- * ret[i] = mFloatPath[i];
- * }
- * } else {
- * for (int i = 0; i < mFloatPath.length; i++) {
- * float lr = localRef[i];
- * if (Float.isNaN(lr)) {
- * ret[i] = Utils.getActualValue(lr);
- * } else {
- * ret[i] = mFloatPath[i];
- * }
- * }
- * }
- * return ret;
- * }
- */
public static final int MOVE = 10;
public static final int LINE = 11;
public static final int QUADRATIC = 12;
@@ -184,7 +155,7 @@
str.append(".");
break;
default:
- str.append("[" + id + "]");
+ str.append("X");
break;
}
} else {
@@ -199,7 +170,7 @@
@Override
public void apply(RemoteContext context) {
- context.loadPathData(mInstanceId, mOutputPath);
+ context.loadPathData(mInstanceId, mFloatPath);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java
index 997e8dc..6d924eb 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java
@@ -94,6 +94,7 @@
public static final int SCALE_CROP = 5;
public static final int SCALE_FILL_BOUNDS = 6;
+
public static final Companion COMPANION = new Companion();
/**
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java
index 076b28e..64c7f3e 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java
@@ -48,7 +48,7 @@
@Override
public String toString() {
- return "RootContentDescription " + mContentDescription;
+ return "ROOT_CONTENT_DESCRIPTION " + mContentDescription;
}
@Override
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java
deleted file mode 100644
index 8463ac5..0000000
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.widget.remotecompose.core.operations;
-
-import com.android.internal.widget.remotecompose.core.CompanionOperation;
-import com.android.internal.widget.remotecompose.core.Operation;
-import com.android.internal.widget.remotecompose.core.Operations;
-import com.android.internal.widget.remotecompose.core.RemoteContext;
-import com.android.internal.widget.remotecompose.core.VariableSupport;
-import com.android.internal.widget.remotecompose.core.WireBuffer;
-
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-
-/**
- * Operation to deal with bitmap data
- * On getting an Image during a draw call the bitmap is compressed and saved
- * in playback the image is decompressed
- */
-public class ShaderData implements Operation, VariableSupport {
- int mShaderTextId; // the actual text of a shader
- int mShaderID; // allows shaders to be referenced by number
- HashMap<String, float[]> mUniformRawFloatMap = null;
- HashMap<String, float[]> mUniformFloatMap = null;
- HashMap<String, int[]> mUniformIntMap = null;
- HashMap<String, Integer> mUniformBitmapMap = null;
-
- public static final int MAX_IMAGE_DIMENSION = 8000;
-
- public static final Companion COMPANION = new Companion();
-
- public ShaderData(int shaderID,
- int shaderTextId,
- HashMap<String, float[]> floatMap,
- HashMap<String, int[]> intMap,
- HashMap<String, Integer> bitmapMap) {
- mShaderID = shaderID;
- mShaderTextId = shaderTextId;
- if (floatMap != null) {
- mUniformFloatMap = new HashMap<>();
- mUniformRawFloatMap = new HashMap<>();
-
- for (String name : floatMap.keySet()) {
- mUniformRawFloatMap.put(name, floatMap.get(name));
- mUniformFloatMap.put(name, floatMap.get(name));
- }
- }
-
- if (intMap != null) {
- mUniformIntMap = new HashMap<>();
- for (String name : intMap.keySet()) {
- mUniformIntMap.put(name, intMap.get(name));
- }
- }
- if (bitmapMap != null) {
- mUniformBitmapMap = new HashMap<>();
- for (String name : bitmapMap.keySet()) {
- mUniformBitmapMap.put(name, bitmapMap.get(name));
- }
- }
-
- }
-
- public int getShaderTextId() {
- return mShaderTextId;
- }
-
- /**
- * get names of all known floats
- * @return
- */
- public String[] getUniformFloatNames() {
- if (mUniformFloatMap == null) return new String[0];
- return mUniformFloatMap.keySet().toArray(new String[0]);
- }
-
- /**
- * Get float values associated with the name
- * @param name
- * @return
- */
- public float[] getUniformFloats(String name) {
- return mUniformFloatMap.get(name);
- }
-
- /**
- * get the name of all know uniform integers
- * @return
- */
- public String[] getUniformIntegerNames() {
- if (mUniformIntMap == null) return new String[0];
- return mUniformIntMap.keySet().toArray(new String[0]);
- }
-
- /**
- * Get Int value associated with the name
- * @param name
- * @return
- */
- public int[] getUniformInts(String name) {
- return mUniformIntMap.get(name);
- }
-
- /**
- * get list of uniform Bitmaps
- * @return
- */
- public String[] getUniformBitmapNames() {
- if (mUniformBitmapMap == null) return new String[0];
- return mUniformBitmapMap.keySet().toArray(new String[0]);
- }
-
- /**
- * Get a bitmap stored under that name
- * @param name
- * @return
- */
- public int getUniformBitmapId(String name) {
- return mUniformBitmapMap.get(name);
- }
-
- @Override
- public void write(WireBuffer buffer) {
- COMPANION.apply(buffer, mShaderID, mShaderTextId,
- mUniformFloatMap, mUniformIntMap, mUniformBitmapMap);
- }
-
- @Override
- public String toString() {
- return "SHADER DATA " + mShaderID;
- }
-
- @Override
- public void updateVariables(RemoteContext context) {
- for (String name : mUniformRawFloatMap.keySet()) {
- float[] value = mUniformRawFloatMap.get(name);
- float[] out = null;
- for (int i = 0; i < value.length; i++) {
- if (Float.isNaN(value[i])) {
- if (out == null) { // need to copy
- out = Arrays.copyOf(value, value.length);
- }
- out[i] = context.getFloat(Utils.idFromNan(value[i]));
- }
- }
- mUniformFloatMap.put(name, out == null ? value : out);
- }
- }
-
- @Override
- public void registerListening(RemoteContext context) {
- for (String name : mUniformRawFloatMap.keySet()) {
- float[] value = mUniformRawFloatMap.get(name);
- for (int i = 0; i < value.length; i++) {
- if (Float.isNaN(value[i])) {
- context.listensTo(Utils.idFromNan(value[i]), this);
- }
- }
- }
- }
-
- public static class Companion implements CompanionOperation {
- private Companion() {
- }
-
- @Override
- public String name() {
- return "BitmapData";
- }
-
- @Override
- public int id() {
- return Operations.DATA_SHADER;
- }
-
- /**
- * Writes out the operation to the buffer
- * @param buffer
- * @param shaderID
- * @param shaderTextId
- * @param floatMap
- * @param intMap
- * @param bitmapMap
- */
- public void apply(WireBuffer buffer, int shaderID, int shaderTextId,
- HashMap<String, float[]> floatMap,
- HashMap<String, int[]> intMap,
- HashMap<String, Integer> bitmapMap) {
- buffer.start(Operations.DATA_SHADER);
- buffer.writeInt(shaderID);
-
- buffer.writeInt(shaderTextId);
- int floatSize = (floatMap == null) ? 0 : floatMap.size();
- int intSize = (intMap == null) ? 0 : intMap.size();
- int bitmapSize = (bitmapMap == null) ? 0 : bitmapMap.size();
- int sizes = floatSize | (intSize << 8) | (bitmapSize << 16);
- buffer.writeInt(sizes);
-
- if (floatSize > 0) {
-
- for (String name : floatMap.keySet()) {
- buffer.writeUTF8(name);
- float[] values = floatMap.get(name);
- buffer.writeInt(values.length);
-
- for (int i = 0; i < values.length; i++) {
- buffer.writeFloat(values[i]);
- }
- }
- }
-
- if (intSize > 0) {
- for (String name : intMap.keySet()) {
- buffer.writeUTF8(name);
- int[] values = intMap.get(name);
- buffer.writeInt(values.length);
- for (int i = 0; i < values.length; i++) {
- buffer.writeInt(values[i]);
- }
- }
- }
- if (bitmapSize > 0) {
- for (String name : bitmapMap.keySet()) {
- buffer.writeUTF8(name);
- int value = bitmapMap.get(name);
- buffer.writeInt(value);
- }
- }
- }
-
- @Override
- public void read(WireBuffer buffer, List<Operation> operations) {
- int shaderID = buffer.readInt();
- int shaderTextId = buffer.readInt();
- HashMap<String, float[]> floatMap = null;
- HashMap<String, int[]> intMap = null;
- HashMap<String, Integer> bitmapMap = null;
-
- int sizes = buffer.readInt();
-
- int floatMapSize = sizes & 0xFF;
- if (floatMapSize > 0) {
- floatMap = new HashMap<>();
- for (int i = 0; i < floatMapSize; i++) {
- String name = buffer.readUTF8();
- int len = buffer.readInt();
- float[] val = new float[len];
-
- for (int j = 0; j < len; j++) {
- val[j] = buffer.readFloat();
- }
-
- floatMap.put(name, val);
- }
- }
- int intMapSize = (sizes >> 8) & 0xFF;
-
- if (intMapSize > 0) {
-
- intMap = new HashMap<>();
- for (int i = 0; i < intMapSize; i++) {
- String name = buffer.readUTF8();
- int len = buffer.readInt();
- int[] val = new int[len];
- for (int j = 0; j < len; j++) {
- val[j] = buffer.readInt();
- }
- intMap.put(name, val);
- }
- }
- int bitmapMapSize = (sizes >> 16) & 0xFF;
-
- if (bitmapMapSize > 0) {
- bitmapMap = new HashMap<>();
- for (int i = 0; i < bitmapMapSize; i++) {
- String name = buffer.readUTF8();
- int val = buffer.readInt();
- bitmapMap.put(name, val);
- }
- }
- operations.add(new ShaderData(shaderID, shaderTextId,
- floatMap, intMap, bitmapMap));
- }
- }
-
- @Override
- public void apply(RemoteContext context) {
- context.loadShader(mShaderID, this);
- }
-
- @Override
- public String deepToString(String indent) {
- return indent + toString();
- }
-}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java
index ed13449..5b622ae 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java
@@ -44,13 +44,11 @@
@Override
public String toString() {
- return "TextData[" + mTextId + "] = \""
- + Utils.trimString(mText, 10) + "\"";
+ return "TEXT DATA " + mTextId + "\"" + mText + "\"";
}
public static class Companion implements CompanionOperation {
- private Companion() {
- }
+ private Companion() {}
@Override
public String name() {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextFromFloat.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextFromFloat.java
deleted file mode 100644
index 65a39a1e..0000000
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextFromFloat.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.widget.remotecompose.core.operations;
-
-import com.android.internal.widget.remotecompose.core.CompanionOperation;
-import com.android.internal.widget.remotecompose.core.Operation;
-import com.android.internal.widget.remotecompose.core.Operations;
-import com.android.internal.widget.remotecompose.core.RemoteContext;
-import com.android.internal.widget.remotecompose.core.VariableSupport;
-import com.android.internal.widget.remotecompose.core.WireBuffer;
-import com.android.internal.widget.remotecompose.core.operations.utilities.StringUtils;
-
-import java.util.List;
-
-/**
- * Operation convert floats to text
- * This command is structured [command][textID][before,after][flags]
- * before and after define number of digits before and after the decimal point
- */
-public class TextFromFloat implements Operation, VariableSupport {
- public int mTextId;
- public float mValue;
- public float mOutValue;
- public short mDigitsBefore;
- public short mDigitsAfter;
- public int mFlags;
- public static final Companion COMPANION = new Companion();
- public static final int MAX_STRING_SIZE = 4000;
- char mPre = ' ';
- char mAfter = ' ';
- // Theses flags define what how to/if fill the space
- public static final int PAD_AFTER_SPACE = 0; // pad past point with space
- public static final int PAD_AFTER_NONE = 1; // do not pad past last digit
- public static final int PAD_AFTER_ZERO = 3; // pad with 0 past last digit
- public static final int PAD_PRE_SPACE = 0; // pad before number with spaces
- public static final int PAD_PRE_NONE = 4; // pad before number with 0s
- public static final int PAD_PRE_ZERO = 12; // do not pad before number
-
- public TextFromFloat(int textId, float value, short digitsBefore,
- short digitsAfter, int flags) {
- this.mTextId = textId;
- this.mValue = value;
- this.mDigitsAfter = digitsAfter;
- this.mDigitsBefore = digitsBefore;
- this.mFlags = flags;
- mOutValue = mValue;
- switch (mFlags & 3) {
- case PAD_AFTER_SPACE:
- mAfter = ' ';
- break;
- case PAD_AFTER_NONE:
- mAfter = 0;
- break;
- case PAD_AFTER_ZERO:
- mAfter = '0';
- break;
- }
- switch (mFlags & 12) {
- case PAD_PRE_SPACE:
- mPre = ' ';
- break;
- case PAD_PRE_NONE:
- mPre = 0;
- break;
- case PAD_PRE_ZERO:
- mPre = '0';
- break;
- }
- }
-
- @Override
- public void write(WireBuffer buffer) {
- COMPANION.apply(buffer, mTextId, mValue, mDigitsAfter, mDigitsBefore, mFlags);
- }
-
- @Override
- public String toString() {
- return "TextFromFloat[" + mTextId + "] = "
- + Utils.floatToString(mValue) + " " + mDigitsBefore
- + "." + mDigitsAfter + " " + mFlags;
- }
-
-
- @Override
- public void updateVariables(RemoteContext context) {
- if (Float.isNaN(mValue)) {
- mOutValue = context.getFloat(Utils.idFromNan(mValue));
- }
-
- }
-
-
- @Override
- public void registerListening(RemoteContext context) {
- if (Float.isNaN(mValue)) {
- context.listensTo(Utils.idFromNan(mValue), this);
- }
- }
-
- public static class Companion implements CompanionOperation {
- private Companion() {
- }
-
- @Override
- public String name() {
- return "TextData";
- }
-
- @Override
- public int id() {
- return Operations.TEXT_FROM_FLOAT;
- }
-
- /**
- * Writes out the operation to the buffer
- * @param buffer
- * @param textId
- * @param value
- * @param digitsBefore
- * @param digitsAfter
- * @param flags
- */
- public void apply(WireBuffer buffer, int textId,
- float value, short digitsBefore,
- short digitsAfter, int flags) {
- buffer.start(Operations.TEXT_FROM_FLOAT);
- buffer.writeInt(textId);
- buffer.writeFloat(value);
- buffer.writeInt((digitsBefore << 16) | digitsAfter);
- buffer.writeInt(flags);
-
- }
-
- @Override
- public void read(WireBuffer buffer, List<Operation> operations) {
- int textId = buffer.readInt();
- float value = buffer.readFloat();
- int tmp = buffer.readInt();
- short post = (short) (tmp & 0xFFFF);
- short pre = (short) ((tmp >> 16) & 0xFFFF);
-
- int flags = buffer.readInt();
- operations.add(new TextFromFloat(textId, value, pre, post, flags));
- }
- }
-
- @Override
- public void apply(RemoteContext context) {
- float v = mOutValue;
- String s = StringUtils.floatToString(v, mDigitsBefore,
- mDigitsAfter, mPre, mAfter);
- context.loadText(mTextId, s);
- }
-
- @Override
- public String deepToString(String indent) {
- return indent + toString();
- }
-}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java
deleted file mode 100644
index a0fc854..0000000
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.widget.remotecompose.core.operations;
-
-import com.android.internal.widget.remotecompose.core.CompanionOperation;
-import com.android.internal.widget.remotecompose.core.Operation;
-import com.android.internal.widget.remotecompose.core.Operations;
-import com.android.internal.widget.remotecompose.core.RemoteContext;
-import com.android.internal.widget.remotecompose.core.WireBuffer;
-
-import java.util.List;
-
-/**
- * Operation to deal with Text data
- */
-public class TextMerge implements Operation {
- public int mTextId;
- public int mSrcId1;
- public int mSrcId2;
- public static final Companion COMPANION = new Companion();
- public static final int MAX_STRING_SIZE = 4000;
-
- public TextMerge(int textId, int srcId1, int srcId2) {
- this.mTextId = textId;
- this.mSrcId1 = srcId1;
- this.mSrcId2 = srcId2;
- }
-
- @Override
- public void write(WireBuffer buffer) {
- COMPANION.apply(buffer, mTextId, mSrcId1, mSrcId2);
- }
-
- @Override
- public String toString() {
- return "TextMerge[" + mTextId + "] = [" + mSrcId1 + " ] + [ " + mSrcId2 + "]";
- }
-
- public static class Companion implements CompanionOperation {
- private Companion() {
- }
-
- @Override
- public String name() {
- return "TextData";
- }
-
- @Override
- public int id() {
- return Operations.TEXT_MERGE;
- }
-
- /**
- * Writes out the operation to the buffer
- * @param buffer
- * @param textId
- * @param srcId1
- * @param srcId2
- */
- public void apply(WireBuffer buffer, int textId, int srcId1, int srcId2) {
- buffer.start(Operations.TEXT_MERGE);
- buffer.writeInt(textId);
- buffer.writeInt(srcId1);
- buffer.writeInt(srcId2);
- }
-
- @Override
- public void read(WireBuffer buffer, List<Operation> operations) {
- int textId = buffer.readInt();
- int srcId1 = buffer.readInt();
- int srcId2 = buffer.readInt();
-
- operations.add(new TextMerge(textId, srcId1, srcId2));
- }
- }
-
- @Override
- public void apply(RemoteContext context) {
- String str1 = context.getText(mSrcId1);
- String str2 = context.getText(mSrcId2);
- context.loadText(mTextId, str1 + str2);
- }
-
- @Override
- public String deepToString(String indent) {
- return indent + toString();
- }
-}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/Utils.java b/core/java/com/android/internal/widget/remotecompose/core/operations/Utils.java
index fdc6860..00e2f20 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/Utils.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/Utils.java
@@ -15,16 +15,13 @@
*/
package com.android.internal.widget.remotecompose.core.operations;
-/**
- * Utilities to be used across all core operations
- */
public class Utils {
public static float asNan(int v) {
return Float.intBitsToFloat(v | -0x800000);
}
public static int idFromNan(float value) {
- int b = Float.floatToRawIntBits(value);
+ int b = Float.floatToRawIntBits(value);
return b & 0xFFFFF;
}
@@ -32,194 +29,13 @@
return 0;
}
- /**
- * trim a string to n characters if needing to trim
- * end in "..."
- *
- * @param str
- * @param n
- * @return
- */
- static String trimString(String str, int n) {
- if (str.length() > n) {
- str = str.substring(0, n - 3) + "...";
- }
- return str;
- }
-
- /**
- * print the id and the value of a float
- * @param idvalue
- * @param value
- * @return
- */
- public static String floatToString(float idvalue, float value) {
- if (Float.isNaN(idvalue)) {
- return "[" + idFromNan(idvalue) + "]" + floatToString(value);
- }
- return floatToString(value);
- }
-
- /**
- * Convert float to string but render nan id in brackets [n]
- * @param value
- * @return
- */
- public static String floatToString(float value) {
+ String getFloatString(float value) {
if (Float.isNaN(value)) {
- return "[" + idFromNan(value) + "]";
+ int id = idFromNan(value);
+ if (id > 0) {
+ return "NaN(" + id + ")";
+ }
}
- return Float.toString(value);
+ return "" + value;
}
-
- /**
- * Debugging util to print a message and include the file/line it came from
- * @param str
- */
- public static void log(String str) {
- StackTraceElement s = new Throwable().getStackTrace()[1];
- System.out.println("(" + s.getFileName() + ":" + s.getLineNumber() + ")." + str);
- }
-
- /**
- * Debugging util to print the stack
- * @param str
- * @param n
- */
- public static void logStack(String str, int n) {
- StackTraceElement[] st = new Throwable().getStackTrace();
- for (int i = 1; i < n + 1; i++) {
- StackTraceElement s = st[i];
- String space = new String(new char[i]).replace('\0', ' ');
- System.out.println(space + "(" + s.getFileName()
- + ":" + s.getLineNumber() + ")." + str);
- }
- }
-
- /**
- * Is a variable Allowed int calculation and references.
- *
- * @param v
- * @return
- */
- public static boolean isVariable(float v) {
- if (Float.isNaN(v)) {
- int id = idFromNan(v);
- return id > 40 || id < 10;
- }
- return false;
- }
-
- /**
- * print a color in the familiar 0xAARRGGBB pattern
- *
- * @param color
- * @return
- */
- public static String colorInt(int color) {
- String str = "000000000000" + Integer.toHexString(color);
- return "0x" + str.substring(str.length() - 8);
- }
-
- /**
- * Interpolate two colors.
- * gamma corrected colors are interpolated in the form c1 * (1-t) + c2 * t
- *
- * @param c1
- * @param c2
- * @param t
- * @return
- */
- public static int interpolateColor(int c1, int c2, float t) {
- if (Float.isNaN(t) || t == 0.0f) {
- return c1;
- } else if (t == 1.0f) {
- return c2;
- }
- int a = 0xFF & (c1 >> 24);
- int r = 0xFF & (c1 >> 16);
- int g = 0xFF & (c1 >> 8);
- int b = 0xFF & c1;
- float f_r = (float) Math.pow(r / 255.0f, 2.2);
- float f_g = (float) Math.pow(g / 255.0f, 2.2);
- float f_b = (float) Math.pow(b / 255.0f, 2.2);
- float c1fr = f_r;
- float c1fg = f_g;
- float c1fb = f_b;
- float c1fa = a / 255f;
-
- a = 0xFF & (c2 >> 24);
- r = 0xFF & (c2 >> 16);
- g = 0xFF & (c2 >> 8);
- b = 0xFF & c2;
- f_r = (float) Math.pow(r / 255.0f, 2.2);
- f_g = (float) Math.pow(g / 255.0f, 2.2);
- f_b = (float) Math.pow(b / 255.0f, 2.2);
- float c2fr = f_r;
- float c2fg = f_g;
- float c2fb = f_b;
- float c2fa = a / 255f;
- f_r = c1fr + t * (c2fr - c1fr);
- f_g = c1fg + t * (c2fg - c1fg);
- f_b = c1fb + t * (c2fb - c1fb);
- float f_a = c1fa + t * (c2fa - c1fa);
-
- int outr = clamp((int) ((float) Math.pow(f_r, 1.0 / 2.2) * 255.0f));
- int outg = clamp((int) ((float) Math.pow(f_g, 1.0 / 2.2) * 255.0f));
- int outb = clamp((int) ((float) Math.pow(f_b, 1.0 / 2.2) * 255.0f));
- int outa = clamp((int) (f_a * 255.0f));
-
-
- return (outa << 24 | outr << 16 | outg << 8 | outb);
- }
-
- /**
- * Efficient clamping function
- *
- * @param c
- * @return number between 0 and 255
- */
- public static int clamp(int c) {
- int n = 255;
- c &= ~(c >> 31);
- c -= n;
- c &= (c >> 31);
- c += n;
- return c;
- }
-
- /**
- * convert hue saturation and value to RGB
- *
- * @param hue 0..1
- * @param saturation 0..1 0=on the gray scale
- * @param value 0..1 0=black
- * @return
- */
- public static int hsvToRgb(float hue, float saturation, float value) {
- int h = (int) (hue * 6);
- float f = hue * 6 - h;
- int p = (int) (0.5f + 255 * value * (1 - saturation));
- int q = (int) (0.5f + 255 * value * (1 - f * saturation));
- int t = (int) (0.5f + 255 * value * (1 - (1 - f) * saturation));
- int v = (int) (0.5f + 255 * value);
- switch (h) {
- case 0:
- return 0XFF000000 | (v << 16) + (t << 8) + p;
- case 1:
- return 0XFF000000 | (q << 16) + (v << 8) + p;
- case 2:
- return 0XFF000000 | (p << 16) + (v << 8) + t;
- case 3:
- return 0XFF000000 | (p << 16) + (q << 8) + v;
- case 4:
- return 0XFF000000 | (t << 16) + (p << 8) + v;
- case 5:
- return 0XFF000000 | (v << 16) + (p << 8) + q;
-
- }
- return 0;
- }
-
-
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java
index a7d0ac6..8abb0bf 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java
@@ -15,60 +15,43 @@
*/
package com.android.internal.widget.remotecompose.core.operations.paint;
-import com.android.internal.widget.remotecompose.core.PaintContext;
-import com.android.internal.widget.remotecompose.core.RemoteContext;
-import com.android.internal.widget.remotecompose.core.VariableSupport;
import com.android.internal.widget.remotecompose.core.WireBuffer;
-import com.android.internal.widget.remotecompose.core.operations.Utils;
import java.util.Arrays;
-/**
- * Paint Bundle represents a delta of changes to a paint object
- */
public class PaintBundle {
int[] mArray = new int[200];
- int[] mOutArray = null;
int mPos = 0;
- /**
- * Apply changes to a PaintChanges interface
- * @param paintContext
- * @param p
- */
- public void applyPaintChange(PaintContext paintContext, PaintChanges p) {
+ public void applyPaintChange(PaintChanges p) {
int i = 0;
int mask = 0;
- if (mOutArray == null) {
- mOutArray = mArray;
- }
while (i < mPos) {
- int cmd = mOutArray[i++];
+ int cmd = mArray[i++];
mask = mask | (1 << (cmd - 1));
switch (cmd & 0xFFFF) {
case TEXT_SIZE: {
- p.setTextSize(Float.intBitsToFloat(mOutArray[i++]));
+ p.setTextSize(Float.intBitsToFloat(mArray[i++]));
break;
}
case TYPEFACE:
int style = (cmd >> 16);
int weight = style & 0x3ff;
boolean italic = (style >> 10) > 0;
- int font_type = mOutArray[i++];
+ int font_type = mArray[i++];
p.setTypeFace(font_type, weight, italic);
break;
- case COLOR_ID: // mOutArray should have already decoded it
case COLOR: {
- p.setColor(mOutArray[i++]);
+ p.setColor(mArray[i++]);
break;
}
case STROKE_WIDTH: {
- p.setStrokeWidth(Float.intBitsToFloat(mOutArray[i++]));
+ p.setStrokeWidth(Float.intBitsToFloat(mArray[i++]));
break;
}
case STROKE_MITER: {
- p.setStrokeMiter(Float.intBitsToFloat(mOutArray[i++]));
+ p.setStrokeMiter(Float.intBitsToFloat(mArray[i++]));
break;
}
case STROKE_CAP: {
@@ -80,7 +63,6 @@
break;
}
case SHADER: {
- p.setShader(mOutArray[i++]);
break;
}
case STROKE_JOIN: {
@@ -99,16 +81,17 @@
p.setFilterBitmap(!((cmd >> 16) == 0));
break;
}
+
case GRADIENT: {
- i = callSetGradient(cmd, mOutArray, i, p);
+ i = callSetGradient(cmd, mArray, i, p);
break;
}
case COLOR_FILTER: {
- p.setColorFilter(mOutArray[i++], cmd >> 16);
+ p.setColorFilter(mArray[i++], cmd >> 16);
break;
}
case ALPHA: {
- p.setAlpha(Float.intBitsToFloat(mOutArray[i++]));
+ p.setAlpha(Float.intBitsToFloat(mArray[i++]));
break;
}
}
@@ -123,6 +106,7 @@
switch (id) {
case TEXT_SIZE:
return "TEXT_SIZE";
+
case COLOR:
return "COLOR";
case STROKE_WIDTH:
@@ -149,6 +133,7 @@
return "ALPHA";
case COLOR_FILTER:
return "COLOR_FILTER";
+
}
return "????" + id + "????";
}
@@ -169,14 +154,6 @@
return str + "]";
}
- private static String asFloatStr(int value) {
- float fValue = Float.intBitsToFloat(value);
- if (Float.isNaN(fValue)) {
- return "[" + Utils.idFromNan(fValue) + "]";
- }
- return Float.toString(fValue);
- }
-
@Override
public String toString() {
StringBuilder ret = new StringBuilder("\n");
@@ -187,8 +164,7 @@
switch (type) {
case TEXT_SIZE: {
- ret.append(" TextSize("
- + asFloatStr(mArray[i++]));
+ ret.append(" TextSize(" + Float.intBitsToFloat(mArray[i++]));
}
break;
@@ -205,18 +181,14 @@
ret.append(" Color(" + colorInt(mArray[i++]));
}
break;
- case COLOR_ID: {
- ret.append(" ColorId([" + mArray[i++] + "]");
- }
- break;
case STROKE_WIDTH: {
ret.append(" StrokeWidth("
- + (asFloatStr(mArray[i++])));
+ + (Float.intBitsToFloat(mArray[i++])));
}
break;
case STROKE_MITER: {
ret.append(" StrokeMiter("
- + (asFloatStr(mArray[i++])));
+ + (Float.intBitsToFloat(mArray[i++])));
}
break;
case STROKE_CAP: {
@@ -235,12 +207,11 @@
}
break;
case SHADER: {
- ret.append(" Shader(" + mArray[i++]);
}
break;
case ALPHA: {
ret.append(" Alpha("
- + (asFloatStr(mArray[i++])));
+ + (Float.intBitsToFloat(mArray[i++])));
}
break;
case IMAGE_FILTER_QUALITY: {
@@ -273,6 +244,7 @@
return ret.toString();
}
+
int callPrintGradient(int cmd, int[] array, int i, StringBuilder p) {
int ret = i;
int type = (cmd >> 16);
@@ -286,25 +258,26 @@
colors = new int[len];
for (int j = 0; j < colors.length; j++) {
colors[j] = array[ret++];
+
}
}
len = array[ret++];
- String[] stops = null;
+ float[] stops = null;
if (len > 0) {
- stops = new String[len];
+ stops = new float[len];
for (int j = 0; j < stops.length; j++) {
- stops[j] = asFloatStr(array[ret++]);
+ stops[j] = Float.intBitsToFloat(array[ret++]);
}
}
p.append(" colors = " + colorInt(colors) + ",\n");
p.append(" stops = " + Arrays.toString(stops) + ",\n");
p.append(" start = ");
- p.append("[" + asFloatStr(array[ret++]));
- p.append(", " + asFloatStr(array[ret++]) + "],\n");
+ p.append("[" + Float.intBitsToFloat(array[ret++]));
+ p.append(", " + Float.intBitsToFloat(array[ret++]) + "],\n");
p.append(" end = ");
- p.append("[" + asFloatStr(array[ret++]));
- p.append(", " + asFloatStr(array[ret++]) + "],\n");
+ p.append("[" + Float.intBitsToFloat(array[ret++]));
+ p.append(", " + Float.intBitsToFloat(array[ret++]) + "],\n");
int tileMode = array[ret++];
p.append(" tileMode = " + tileMode + "\n ");
}
@@ -322,21 +295,21 @@
}
}
len = array[ret++];
- String[] stops = null;
+ float[] stops = null;
if (len > 0) {
- stops = new String[len];
+ stops = new float[len];
for (int j = 0; j < stops.length; j++) {
- stops[j] = asFloatStr(array[ret++]);
+ stops[j] = Float.intBitsToFloat(array[ret++]);
}
}
p.append(" colors = " + colorInt(colors) + ",\n");
p.append(" stops = " + Arrays.toString(stops) + ",\n");
p.append(" center = ");
- p.append("[" + asFloatStr(array[ret++]));
- p.append(", " + asFloatStr(array[ret++]) + "],\n");
+ p.append("[" + Float.intBitsToFloat(array[ret++]));
+ p.append(", " + Float.intBitsToFloat(array[ret++]) + "],\n");
p.append(" radius =");
- p.append(" " + asFloatStr(array[ret++]) + ",\n");
+ p.append(" " + Float.intBitsToFloat(array[ret++]) + ",\n");
int tileMode = array[ret++];
p.append(" tileMode = " + tileMode + "\n ");
}
@@ -354,19 +327,20 @@
}
}
len = array[ret++];
- String[] stops = null;
+ float[] stops = null;
if (len > 0) {
- stops = new String[len];
+ stops = new float[len];
for (int j = 0; j < stops.length; j++) {
- stops[j] = asFloatStr(array[ret++]);
+ stops[j] = Float.intBitsToFloat(array[ret++]);
}
}
+
p.append(" colors = " + colorInt(colors) + ",\n");
p.append(" stops = " + Arrays.toString(stops) + ",\n");
p.append(" center = ");
- p.append("[" + asFloatStr(array[ret++]));
- p.append(", "
- + asFloatStr(array[ret++]) + "],\n ");
+ p.append("[" + Float.intBitsToFloat(array[ret++]));
+ p.append(", " + Float.intBitsToFloat(array[ret++]) + "],\n ");
+
}
break;
default: {
@@ -402,6 +376,7 @@
return ret;
}
+
switch (gradientType) {
case LINEAR_GRADIENT: {
@@ -458,7 +433,7 @@
public static final int COLOR = 4; // int
public static final int STROKE_WIDTH = 5; // float
public static final int STROKE_MITER = 6;
- public static final int STROKE_CAP = 7; // int
+ public static final int STROKE_CAP = 7; // int
public static final int STYLE = 8; // int
public static final int SHADER = 9; // int
public static final int IMAGE_FILTER_QUALITY = 10; // int
@@ -470,7 +445,7 @@
public static final int TYPEFACE = 16;
public static final int FILTER_BITMAP = 17;
public static final int BLEND_MODE = 18;
- public static final int COLOR_ID = 19; // int
+
public static final int BLEND_MODE_CLEAR = 0;
public static final int BLEND_MODE_SRC = 1;
@@ -659,8 +634,8 @@
/**
* @param fontType 0 = default 1 = sans serif 2 = serif 3 = monospace
- * @param weight 100-1000
- * @param italic tur
+ * @param weight 100-1000
+ * @param italic tur
*/
public void setTextStyle(int fontType, int weight, boolean italic) {
int style = (weight & 0x3FF) | (italic ? 2048 : 0); // pack the weight and italic
@@ -683,10 +658,6 @@
mPos++;
}
- /**
- * Set the Color based on Color
- * @param color
- */
public void setColor(int color) {
mArray[mPos] = COLOR;
mPos++;
@@ -695,18 +666,6 @@
}
/**
- * Set the Color based on ID
- * @param color
- */
- public void setColorId(int color) {
- mArray[mPos] = COLOR_ID;
- mPos++;
- mArray[mPos] = color;
- mPos++;
- }
-
-
- /**
* Set the paint's Cap.
*
* @param cap set the paint's line cap style, used whenever the paint's
@@ -717,29 +676,16 @@
mPos++;
}
- /**
- * Set the style STROKE and/or FILL
- * @param style
- */
public void setStyle(int style) {
mArray[mPos] = STYLE | (style << 16);
mPos++;
}
- /**
- * Set the shader id to use
- * @param shaderId
- */
- public void setShader(int shaderId) {
- mArray[mPos] = SHADER;
- mPos++;
- mArray[mPos] = shaderId;
+ public void setShader(int shader, String shaderString) {
+ mArray[mPos] = SHADER | (shader << 16);
mPos++;
}
- /**
- * Set the Alpha value
- */
public void setAlpha(float alpha) {
mArray[mPos] = ALPHA;
mPos++;
@@ -783,6 +729,7 @@
* destination pixels
* (content of the render target).
*
+ *
* @param blendmode The blend mode to be installed in the paint
*/
public void setBlendMode(int blendmode) {
@@ -878,216 +825,5 @@
return "null";
}
- /**
- * Check all the floats for Nan(id) floats and call listenTo
- * @param context
- * @param support
- */
- public void registerVars(RemoteContext context, VariableSupport support) {
- int i = 0;
- while (i < mPos) {
- int cmd = mArray[i++];
- int type = cmd & 0xFFFF;
- switch (type) {
- case STROKE_MITER:
- case STROKE_WIDTH:
- case ALPHA:
- case TEXT_SIZE:
- float v = Float.intBitsToFloat(mArray[i++]);
- if (Float.isNaN(v)) {
- context.listensTo(Utils.idFromNan(v), support);
- }
- break;
- case COLOR_ID:
- context.listensTo(mArray[i++], support);
- break;
- case COLOR:
+}
- case TYPEFACE:
- case SHADER:
- case COLOR_FILTER:
- i++;
- break;
- case STROKE_JOIN:
- case FILTER_BITMAP:
- case STROKE_CAP:
- case STYLE:
- case IMAGE_FILTER_QUALITY:
- case BLEND_MODE:
- case ANTI_ALIAS:
- break;
-
- case GRADIENT: {
- // TODO gradients should be handled correctly
- i = callPrintGradient(cmd, mArray, i, new StringBuilder());
- }
- }
- }
- }
-
- /**
- * Update variables if any are float ids
- * @param context
- */
- public void updateVariables(RemoteContext context) {
- if (mOutArray == null) {
- mOutArray = Arrays.copyOf(mArray, mArray.length);
- } else {
- System.arraycopy(mArray, 0, mOutArray, 0, mArray.length);
- }
- int i = 0;
- while (i < mPos) {
- int cmd = mArray[i++];
- int type = cmd & 0xFFFF;
- switch (type) {
- case STROKE_MITER:
- case STROKE_WIDTH:
- case ALPHA:
- case TEXT_SIZE:
- mOutArray[i] = fixFloatVar(mArray[i], context);
- i++;
- break;
- case COLOR_ID:
- mOutArray[i] = fixColor(mArray[i], context);
- i++;
- break;
- case COLOR:
- case TYPEFACE:
- case SHADER:
- case COLOR_FILTER:
- i++;
- break;
- case STROKE_JOIN:
- case FILTER_BITMAP:
- case STROKE_CAP:
- case STYLE:
- case IMAGE_FILTER_QUALITY:
- case BLEND_MODE:
- case ANTI_ALIAS:
- break;
-
- case GRADIENT: {
- // TODO gradients should be handled correctly
- i = updateFloatsInGradient(cmd, mOutArray, mArray, i, context);
- }
- }
- }
- }
-
- private int fixFloatVar(int val, RemoteContext context) {
- float v = Float.intBitsToFloat(val);
- if (Float.isNaN(v)) {
- int id = Utils.idFromNan(v);
- return Float.floatToRawIntBits(context.getFloat(id));
- }
- return val;
- }
-
- private int fixColor(int colorId, RemoteContext context) {
- int n = context.getColor(colorId);
- return n;
- }
-
- int updateFloatsInGradient(int cmd, int[] out, int[] array,
- int i,
- RemoteContext context) {
- int ret = i;
- int type = (cmd >> 16);
- switch (type) {
- case 0: {
- int len = array[ret++];
- if (len > 0) {
- for (int j = 0; j < len; j++) {
- ret++;
- }
- }
- len = array[ret++];
-
- if (len > 0) {
- for (int j = 0; j < len; j++) {
- out[ret] = fixFloatVar(array[ret], context);
- ret++;
- }
- }
-
- out[ret] = fixFloatVar(array[ret], context);
- ret++;
- out[ret] = fixFloatVar(array[ret], context);
- ret++;
-
- // end
- out[ret] = fixFloatVar(array[ret], context);
- ret++;
- out[ret] = fixFloatVar(array[ret], context);
- ret++;
- ret++; // tileMode
- }
-
- break;
- case 1: {
- // RadialGradient
- int len = array[ret++];
- if (len > 0) {
- for (int j = 0; j < len; j++) {
- ret++;
- }
- }
- len = array[ret++];
- if (len > 0) {
- for (int j = 0; j < len; j++) {
- out[ret] = fixFloatVar(array[ret], context);
- ret++;
- }
- }
-
-
- // center
- out[ret] = fixFloatVar(array[ret], context);
- ret++;
- out[ret] = fixFloatVar(array[ret], context);
- ret++;
- // radius
- out[ret] = fixFloatVar(array[ret], context);
- ret++;
- ret++; // tileMode
-
- }
-
- break;
- case 2: {
- // SweepGradient
- int len = array[ret++];
- int[] colors = null;
- if (len > 0) {
- colors = new int[len];
- for (int j = 0; j < colors.length; j++) {
- colors[j] = array[ret++];
-
- }
- }
- len = array[ret++];
- float[] stops = null;
- if (len > 0) {
- stops = new float[len];
- for (int j = 0; j < stops.length; j++) {
- out[ret] = fixFloatVar(array[ret], context);
- ret++;
- }
- }
-
- // center
- out[ret] = fixFloatVar(array[ret], context);
- ret++;
- out[ret] = fixFloatVar(array[ret], context);
- ret++;
- }
- break;
- default: {
- System.err.println("gradient type unknown");
- }
- }
-
- return ret;
- }
-
-}
\ No newline at end of file
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChangeAdapter.java b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChangeAdapter.java
index 28fe63a..994bf6d 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChangeAdapter.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChangeAdapter.java
@@ -27,6 +27,7 @@
}
+
@Override
public void setStrokeWidth(float width) {
@@ -48,7 +49,7 @@
}
@Override
- public void setShader(int shader) {
+ public void setShader(int shader, String shaderString) {
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChanges.java b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChanges.java
index d5dc388..87e58ac 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChanges.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChanges.java
@@ -15,14 +15,9 @@
*/
package com.android.internal.widget.remotecompose.core.operations.paint;
-/**
- * Interface to a paint object
- * For more details see Android Paint
- */
public interface PaintChanges {
- // MASK to be set/cleared
- int CLEAR_TEXT_SIZE = 1 << (PaintBundle.TEXT_SIZE - 1);
+
int CLEAR_TEXT_STYLE = 1 << (PaintBundle.TYPEFACE - 1);
int CLEAR_COLOR = 1 << (PaintBundle.COLOR - 1);
int CLEAR_STROKE_WIDTH = 1 << (PaintBundle.STROKE_WIDTH - 1);
@@ -37,101 +32,21 @@
int CLEAR_COLOR_FILTER = 1 << (PaintBundle.COLOR_FILTER - 1);
int VALID_BITS = 0x1FFF; // only the first 13 bit are valid now
- /**
- * Set the size of text
- * @param size
- */
+
void setTextSize(float size);
-
- /**
- * Set the width of lines
- * @param width
- */
void setStrokeWidth(float width);
-
- /**
- * Set the color to use
- * @param color
- */
void setColor(int color);
-
- /**
- * Set the Stroke Cap
- * @param cap
- */
void setStrokeCap(int cap);
-
- /**
- * Set the Stroke style FILL and/or STROKE
- * @param style
- */
void setStyle(int style);
-
- /**
- * Set the id of the shader to use
- * @param shader
- */
- void setShader(int shader);
-
- /**
- * Set the way image is interpolated
- * @param quality
- */
+ void setShader(int shader, String shaderString);
void setImageFilterQuality(int quality);
-
- /**
- * Set the alpha to draw under
- * @param a
- */
void setAlpha(float a);
-
- /**
- * Set the Stroke Miter
- * @param miter
- */
void setStrokeMiter(float miter);
-
- /**
- * Set the Stroke Join
- * @param join
- */
void setStrokeJoin(int join);
-
- /**
- * Should bitmaps be interpolated
- * @param filter
- */
void setFilterBitmap(boolean filter);
-
- /**
- * Set the blend mode can be porterduff + others
- * @param mode
- */
void setBlendMode(int mode);
-
- /**
- * Set the AntiAlias. Typically true
- * Set to off when you need pixilated look (e.g. QR codes)
- * @param aa
- */
void setAntiAlias(boolean aa);
-
- /**
- * Clear some sub set of the settings
- * @param mask
- */
void clear(long mask);
-
- /**
- * Set a linear gradient fill
- * @param colorsArray
- * @param stopsArray
- * @param startX
- * @param startY
- * @param endX
- * @param endY
- * @param tileMode
- */
void setLinearGradient(
int[] colorsArray,
float[] stopsArray,
@@ -142,15 +57,6 @@
int tileMode
);
- /**
- * Set a radial gradient fill
- * @param colorsArray
- * @param stopsArray
- * @param centerX
- * @param centerY
- * @param radius
- * @param tileMode
- */
void setRadialGradient(
int[] colorsArray,
float[] stopsArray,
@@ -160,13 +66,6 @@
int tileMode
);
- /**
- * Set a sweep gradient fill
- * @param colorsArray
- * @param stopsArray
- * @param centerX
- * @param centerY
- */
void setSweepGradient(
int[] colorsArray,
float[] stopsArray,
@@ -174,19 +73,9 @@
float centerY
);
- /**
- * Set Color filter mod
- * @param color
- * @param mode
- */
+
void setColorFilter(int color, int mode);
- /**
- * Set TypeFace 0,1,2
- * TODO above should point to a string to be decoded
- * @param fontType
- * @param weight
- * @param italic
- */
void setTypeFace(int fontType, int weight, boolean italic);
-}
\ No newline at end of file
+}
+
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/AnimatedFloatExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/AnimatedFloatExpression.java
deleted file mode 100644
index 616048d..0000000
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/AnimatedFloatExpression.java
+++ /dev/null
@@ -1,452 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.widget.remotecompose.core.operations.utilities;
-
-/**
- * high performance floating point expression evaluator used in animation
- */
-public class AnimatedFloatExpression {
- static IntMap<String> sNames = new IntMap<>();
- public static final int OFFSET = 0x100;
- public static final float ADD = asNan(OFFSET + 1);
- public static final float SUB = asNan(OFFSET + 2);
- public static final float MUL = asNan(OFFSET + 3);
- public static final float DIV = asNan(OFFSET + 4);
- public static final float MOD = asNan(OFFSET + 5);
- public static final float MIN = asNan(OFFSET + 6);
- public static final float MAX = asNan(OFFSET + 7);
- public static final float POW = asNan(OFFSET + 8);
- public static final float SQRT = asNan(OFFSET + 9);
- public static final float ABS = asNan(OFFSET + 10);
- public static final float SIGN = asNan(OFFSET + 11);
- public static final float COPY_SIGN = asNan(OFFSET + 12);
- public static final float EXP = asNan(OFFSET + 13);
- public static final float FLOOR = asNan(OFFSET + 14);
- public static final float LOG = asNan(OFFSET + 15);
- public static final float LN = asNan(OFFSET + 16);
- public static final float ROUND = asNan(OFFSET + 17);
- public static final float SIN = asNan(OFFSET + 18);
- public static final float COS = asNan(OFFSET + 19);
- public static final float TAN = asNan(OFFSET + 20);
- public static final float ASIN = asNan(OFFSET + 21);
- public static final float ACOS = asNan(OFFSET + 22);
-
- public static final float ATAN = asNan(OFFSET + 23);
-
- public static final float ATAN2 = asNan(OFFSET + 24);
- public static final float MAD = asNan(OFFSET + 25);
- public static final float IFELSE = asNan(OFFSET + 26);
-
- public static final float CLAMP = asNan(OFFSET + 27);
- public static final float CBRT = asNan(OFFSET + 28);
- public static final float DEG = asNan(OFFSET + 29);
- public static final float RAD = asNan(OFFSET + 30);
- public static final float CEIL = asNan(OFFSET + 31);
-
-
- public static final float LAST_OP = 31;
-
-
- public static final float VAR1 = asNan(OFFSET + 27);
- public static final float VAR2 = asNan(OFFSET + 28);
-
- // TODO CLAMP, CBRT, DEG, RAD, EXPM1, CEIL, FLOOR
- private static final float FP_PI = (float) Math.PI;
- private static final float FP_TO_RAD = 57.29577951f; // 180/PI
- private static final float FP_TO_DEG = 0.01745329252f; // 180/PI
-
- float[] mStack;
- float[] mLocalStack = new float[128];
- float[] mVar;
-
- /**
- * is float a math operator
- * @param v
- * @return
- */
- public static boolean isMathOperator(float v) {
- if (Float.isNaN(v)) {
- int pos = fromNaN(v);
- return pos > OFFSET && pos <= OFFSET + LAST_OP;
- }
- return false;
- }
-
- interface Op {
- int eval(int sp);
- }
-
- /**
- * Evaluate a float expression
- * @param exp
- * @param var
- * @return
- */
- public float eval(float[] exp, float... var) {
- mStack = exp;
- mVar = var;
- int sp = -1;
- for (int i = 0; i < mStack.length; i++) {
- float v = mStack[i];
- if (Float.isNaN(v)) {
- sp = mOps[fromNaN(v) - OFFSET].eval(sp);
- } else {
- mStack[++sp] = v;
- }
- }
- return mStack[sp];
- }
-
- /**
- * Evaluate a float expression
- * @param exp
- * @param len
- * @param var
- * @return
- */
- public float eval(float[] exp, int len, float... var) {
- System.arraycopy(exp, 0, mLocalStack, 0, len);
- mStack = mLocalStack;
- mVar = var;
- int sp = -1;
- for (int i = 0; i < len; i++) {
- float v = mStack[i];
- if (Float.isNaN(v)) {
- sp = mOps[fromNaN(v) - OFFSET].eval(sp);
- } else {
- mStack[++sp] = v;
- }
- }
- return mStack[sp];
- }
-
- /**
- * Evaluate a float expression
- * @param exp
- * @param var
- * @return
- */
- public float evalDB(float[] exp, float... var) {
- mStack = exp;
- mVar = var;
- int sp = -1;
- for (float v : exp) {
- if (Float.isNaN(v)) {
- System.out.print(" " + sNames.get((fromNaN(v) - OFFSET)));
- sp = mOps[fromNaN(v) - OFFSET].eval(sp);
- } else {
- System.out.print(" " + v);
- mStack[++sp] = v;
- }
- }
- return mStack[sp];
- }
-
- Op[] mOps = {
- null,
- (sp) -> { // ADD
- mStack[sp - 1] = mStack[sp - 1] + mStack[sp];
- return sp - 1;
- },
- (sp) -> { // SUB
- mStack[sp - 1] = mStack[sp - 1] - mStack[sp];
- return sp - 1;
- },
- (sp) -> { // MUL
- mStack[sp - 1] = mStack[sp - 1] * mStack[sp];
- return sp - 1;
- },
- (sp) -> { // DIV
- mStack[sp - 1] = mStack[sp - 1] / mStack[sp];
- return sp - 1;
- },
- (sp) -> { // MOD
- mStack[sp - 1] = mStack[sp - 1] % mStack[sp];
- return sp - 1;
- },
- (sp) -> { // MIN
- mStack[sp - 1] = (float) Math.min(mStack[sp - 1], mStack[sp]);
- return sp - 1;
- },
- (sp) -> { // MAX
- mStack[sp - 1] = (float) Math.max(mStack[sp - 1], mStack[sp]);
- return sp - 1;
- },
- (sp) -> { // POW
- mStack[sp - 1] = (float) Math.pow(mStack[sp - 1], mStack[sp]);
- return sp - 1;
- },
- (sp) -> { // SQRT
- mStack[sp] = (float) Math.sqrt(mStack[sp]);
- return sp;
- },
- (sp) -> { // ABS
- mStack[sp] = (float) Math.abs(mStack[sp]);
- return sp;
- },
- (sp) -> { // SIGN
- mStack[sp] = (float) Math.signum(mStack[sp]);
- return sp;
- },
- (sp) -> { // copySign
- mStack[sp - 1] = (float) Math.copySign(mStack[sp - 1], mStack[sp]);
- return sp - 1;
- },
- (sp) -> { // EXP
- mStack[sp] = (float) Math.exp(mStack[sp]);
- return sp;
- },
- (sp) -> { // FLOOR
- mStack[sp] = (float) Math.floor(mStack[sp]);
- return sp;
- },
- (sp) -> { // LOG
- mStack[sp] = (float) Math.log10(mStack[sp]);
- return sp;
- },
- (sp) -> { // LN
- mStack[sp] = (float) Math.log(mStack[sp]);
- return sp;
- },
- (sp) -> { // ROUND
- mStack[sp] = (float) Math.round(mStack[sp]);
- return sp;
- },
- (sp) -> { // SIN
- mStack[sp] = (float) Math.sin(mStack[sp]);
- return sp;
- },
- (sp) -> { // COS
- mStack[sp] = (float) Math.cos(mStack[sp]);
- return sp;
- },
- (sp) -> { // TAN
- mStack[sp] = (float) Math.tan(mStack[sp]);
- return sp;
- },
- (sp) -> { // ASIN
- mStack[sp] = (float) Math.asin(mStack[sp]);
- return sp;
- },
- (sp) -> { // ACOS
- mStack[sp] = (float) Math.acos(mStack[sp]);
- return sp;
- },
- (sp) -> { // ATAN
- mStack[sp] = (float) Math.atan(mStack[sp]);
- return sp;
- },
- (sp) -> { // ATAN2
- mStack[sp - 1] = (float) Math.atan2(mStack[sp - 1], mStack[sp]);
- return sp - 1;
- },
- (sp) -> { // MAD
- mStack[sp - 2] = mStack[sp] + mStack[sp - 1] * mStack[sp - 2];
- return sp - 2;
- },
- (sp) -> { // Ternary conditional
- mStack[sp - 2] = (mStack[sp] > 0)
- ? mStack[sp - 1] : mStack[sp - 2];
- return sp - 2;
- },
- (sp) -> { // CLAMP(min,max, val)
- mStack[sp - 2] = Math.min(Math.max(mStack[sp - 2], mStack[sp]),
- mStack[sp - 1]);
- return sp - 2;
- },
- (sp) -> { // CBRT cuberoot
- mStack[sp] = (float) Math.pow(mStack[sp], 1 / 3.);
- return sp;
- },
- (sp) -> { // DEG
- mStack[sp] = mStack[sp] * FP_TO_RAD;
- return sp;
- },
- (sp) -> { // RAD
- mStack[sp] = mStack[sp] * FP_TO_DEG;
- return sp;
- },
- (sp) -> { // CEIL
- mStack[sp] = (float) Math.ceil(mStack[sp]);
- return sp;
- },
- (sp) -> { // first var =
- mStack[sp] = mVar[0];
- return sp;
- },
- (sp) -> { // second var y?
- mStack[sp] = mVar[1];
- return sp;
- },
- (sp) -> { // 3rd var z?
- mStack[sp] = mVar[2];
- return sp;
- },
- };
-
- static {
- int k = 0;
- sNames.put(k++, "NOP");
- sNames.put(k++, "+");
- sNames.put(k++, "-");
- sNames.put(k++, "*");
- sNames.put(k++, "/");
- sNames.put(k++, "%");
- sNames.put(k++, "min");
- sNames.put(k++, "max");
- sNames.put(k++, "pow");
- sNames.put(k++, "sqrt");
- sNames.put(k++, "abs");
- sNames.put(k++, "sign");
- sNames.put(k++, "copySign");
- sNames.put(k++, "exp");
- sNames.put(k++, "floor");
- sNames.put(k++, "log");
- sNames.put(k++, "ln");
- sNames.put(k++, "round");
- sNames.put(k++, "sin");
- sNames.put(k++, "cos");
- sNames.put(k++, "tan");
- sNames.put(k++, "asin");
- sNames.put(k++, "acos");
- sNames.put(k++, "atan");
- sNames.put(k++, "atan2");
- sNames.put(k++, "mad");
- sNames.put(k++, "ifElse");
- sNames.put(k++, "clamp");
- sNames.put(k++, "cbrt");
- sNames.put(k++, "deg");
- sNames.put(k++, "rad");
- sNames.put(k++, "ceil");
- sNames.put(k++, "a[0]");
- sNames.put(k++, "a[1]");
- sNames.put(k++, "a[2]");
- }
-
- /**
- * given a float command return its math name (e.g sin, cos etc.)
- * @param f
- * @return
- */
- public static String toMathName(float f) {
- int id = fromNaN(f) - OFFSET;
- return sNames.get(id);
- }
-
- /**
- * Convert an expression encoded as an array of floats int ot a string
- * @param exp
- * @param labels
- * @return
- */
- public static String toString(float[] exp, String[] labels) {
- StringBuilder s = new StringBuilder();
- for (int i = 0; i < exp.length; i++) {
- float v = exp[i];
- if (Float.isNaN(v)) {
- if (isMathOperator(v)) {
- s.append(toMathName(v));
- } else {
- s.append("[");
- s.append(fromNaN(v));
- s.append("]");
- }
- } else {
- if (labels[i] != null) {
- s.append(labels[i]);
- }
- s.append(v);
- }
- s.append(" ");
- }
- return s.toString();
- }
-
- static String toString(float[] exp, int sp) {
- String[] str = new String[exp.length];
- if (Float.isNaN(exp[sp])) {
- int id = fromNaN(exp[sp]) - OFFSET;
- switch (NO_OF_OPS[id]) {
- case -1:
- return "nop";
- case 1:
- return sNames.get(id) + "(" + toString(exp, sp + 1) + ") ";
- case 2:
- if (infix(id)) {
- return "(" + toString(exp, sp + 1)
- + sNames.get(id) + " "
- + toString(exp, sp + 2) + ") ";
- } else {
- return sNames.get(id) + "("
- + toString(exp, sp + 1) + ", "
- + toString(exp, sp + 2) + ")";
- }
- case 3:
- if (infix(id)) {
- return "((" + toString(exp, sp + 1) + ") ? "
- + toString(exp, sp + 2) + ":"
- + toString(exp, sp + 3) + ")";
- } else {
- return sNames.get(id)
- + "(" + toString(exp, sp + 1)
- + ", " + toString(exp, sp + 2)
- + ", " + toString(exp, sp + 3) + ")";
- }
- }
- }
- return Float.toString(exp[sp]);
- }
-
- static final int[] NO_OF_OPS = {
- -1, // no op
- 2, 2, 2, 2, 2, // + - * / %
- 2, 2, 2, // min max, power
- 1, 1, 1, 1, 1, 1, 1, 1, //sqrt,abs,CopySign,exp,floor,log,ln
- 1, 1, 1, 1, 1, 1, 1, 2, // round,sin,cos,tan,asin,acos,atan,atan2
- 3, 3, 3, 1, 1, 1, 1,
- 0, 0, 0 // mad, ?:,
- // a[0],a[1],a[2]
- };
-
- /**
- * to be used by parser to determine if command is infix
- * @param n
- * @return
- */
- static boolean infix(int n) {
- return ((n < 6) || (n == 25) || (n == 26));
- }
-
- /**
- * Convert an id into a NaN object
- * @param v
- * @return
- */
- public static float asNan(int v) {
- return Float.intBitsToFloat(v | -0x800000);
- }
-
- /**
- * Get ID from a NaN float
- * @param v
- * @return
- */
- public static int fromNaN(float v) {
- int b = Float.floatToRawIntBits(v);
- return b & 0xFFFFF;
- }
-
-}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/ColorUtils.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/ColorUtils.java
deleted file mode 100644
index 0ea28a8..0000000
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/ColorUtils.java
+++ /dev/null
@@ -1,68 +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.internal.widget.remotecompose.core.operations.utilities;
-
-/**
- * These are tools to use long Color as variables
- * long colors are stored a 0xXXXXXXXX XXXXXX??
- * in SRGB the colors are stored 0xAARRGGBB,00000000
- * SRGB color sapce is color space 0
- * Our Color will use color float with a
- * Current android supports
- * SRGB, LINEAR_SRGB, EXTENDED_SRGB, LINEAR_EXTENDED_SRGB, BT709, BT2020,
- * DCI_P3, DISPLAY_P3, NTSC_1953, SMPTE_C, ADOBE_RGB, PRO_PHOTO_RGB, ACES,
- * ACESCG, CIE_XYZ, CIE_LAB, BT2020_HLG, BT2020_PQ 0..17 respectively
- *
- * Our color space will be 62 (MAX_ID-1). (0x3E)
- * Storing the default value in SRGB format and having the
- * id of the color between the ARGB values and the 62 i.e.
- * 0xAARRGGBB 00 00 00 3E
- *
- */
-public class ColorUtils {
- public static int RC_COLOR = 62;
-
- long packRCColor(int defaultARGB, int id) {
- long l = defaultARGB;
- return (l << 32) | id << 8 | RC_COLOR;
- }
-
- boolean isRCColor(long color) {
- return ((color & 0x3F) == 62);
- }
-
- int getID(long color) {
- if (isRCColor(color)) {
- return (int) ((color & 0xFFFFFF00) >> 8);
- }
- return -1;
- }
-
- /**
- * get default color from long color
- * @param color
- * @return
- */
- public int getDefaultColor(long color) {
- if (isRCColor(color)) {
- return (int) (color >> 32);
- }
- if (((color & 0xFF) == 0)) {
- return (int) (color >> 32);
- }
- return 0;
- }
-}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntMap.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntMap.java
index 0512fa6..8051ef1 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntMap.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntMap.java
@@ -50,6 +50,7 @@
return insert(key, value);
}
+
public T get(int key) {
int index = findKey(key);
if (index == -1) {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/NanMap.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/NanMap.java
deleted file mode 100644
index f4cd504..0000000
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/NanMap.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.widget.remotecompose.core.operations.utilities;
-
-import com.android.internal.widget.remotecompose.core.operations.Utils;
-
-/**
- * This defines the major id maps and ranges used by remote compose
- * Generally ids ranging from 0 ... FFF (4095) are for ids
- * 0x1000-0x1100 are used for path operations in PathData
- * 0x1100-0x1200 are used for math operations in Animated float
- * 0x
- */
-public class NanMap {
-
- public static final int MOVE = 0x1000;
- public static final int LINE = 0x1001;
- public static final int QUADRATIC = 0x1002;
- public static final int CONIC = 0x1003;
- public static final int CUBIC = 0x1004;
- public static final int CLOSE = 0x1005;
- public static final int DONE = 0x1006;
- public static final float MOVE_NAN = Utils.asNan(MOVE);
- public static final float LINE_NAN = Utils.asNan(LINE);
- public static final float QUADRATIC_NAN = Utils.asNan(QUADRATIC);
- public static final float CONIC_NAN = Utils.asNan(CONIC);
- public static final float CUBIC_NAN = Utils.asNan(CUBIC);
- public static final float CLOSE_NAN = Utils.asNan(CLOSE);
- public static final float DONE_NAN = Utils.asNan(DONE);
-
- /**
- *
- */
- public static final float ADD = asNan(0x1100);
- public static final float SUB = asNan(0x1101);
- public static final float MUL = asNan(0x1102);
- public static final float DIV = asNan(0x1103);
- public static final float MOD = asNan(0x1104);
- public static final float MIN = asNan(0x1105);
- public static final float MAX = asNan(0x1106);
- public static final float POW = asNan(0x1107);
-
-
- /**
- * Get ID from Nan float
- * @param v
- * @return
- */
- public static int fromNaN(float v) {
- int b = Float.floatToRawIntBits(v);
- return b & 0xFFFFF;
- }
-
- /**
- * Given id return as a Nan float
- * @param v
- * @return
- */
- public static float asNan(int v) {
- return Float.intBitsToFloat(v | 0xFF800000);
- }
-}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/StringUtils.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/StringUtils.java
deleted file mode 100644
index 8dd5405..0000000
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/StringUtils.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.widget.remotecompose.core.operations.utilities;
-
-import java.util.Arrays;
-
-/**
- * Utilities for string manipulation
- */
-public class StringUtils {
- /**
- * Converts a float into a string.
- * Providing a defined number of characters before and after the
- * decimal point.
- *
- * @param value The value to convert to string
- * @param beforeDecimalPoint digits before the decimal point
- * @param afterDecimalPoint digits after the decimal point
- * @param pre character to pad width 0 = no pad typically ' ' or '0'
- * @param post character to pad width 0 = no pad typically ' ' or '0'
- * @return
- */
- public static String floatToString(float value,
- int beforeDecimalPoint,
- int afterDecimalPoint,
- char pre, char post) {
-
- int integerPart = (int) value;
- float fractionalPart = value % 1;
-
- // Convert integer part to string and pad with spaces
- String integerPartString = String.valueOf(integerPart);
- int iLen = integerPartString.length();
- if (iLen < beforeDecimalPoint) {
- int spacesToPad = beforeDecimalPoint - iLen;
- if (pre != 0) {
- char[] pad = new char[spacesToPad];
- Arrays.fill(pad, pre);
- integerPartString = new String(pad) + integerPartString;
- }
-
-
- } else if (iLen > beforeDecimalPoint) {
- integerPartString = integerPartString.substring(iLen - beforeDecimalPoint);
- }
- if (afterDecimalPoint == 0) {
- return integerPartString;
- }
- // Convert fractional part to string and pad with zeros
-
- for (int i = 0; i < afterDecimalPoint; i++) {
- fractionalPart *= 10;
- }
-
- fractionalPart = Math.round(fractionalPart);
-
- for (int i = 0; i < afterDecimalPoint; i++) {
- fractionalPart *= .1;
- }
-
- String fact = Float.toString(fractionalPart);
- fact = fact.substring(2, Math.min(fact.length(), afterDecimalPoint + 2));
- int trim = fact.length();
- for (int i = fact.length() - 1; i >= 0; i--) {
- if (fact.charAt(i) != '0') {
- break;
- }
- trim--;
- }
- if (trim != fact.length()) {
- fact = fact.substring(0, trim);
- }
- int len = fact.length();
- if (post != 0 && len < afterDecimalPoint) {
- char[] c = new char[afterDecimalPoint - len];
- Arrays.fill(c, post);
- fact = fact + new String(c);
- }
-
- return integerPartString + "." + fact;
- }
-
-}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/BounceCurve.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/BounceCurve.java
deleted file mode 100644
index c3cd5ae9..0000000
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/BounceCurve.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.widget.remotecompose.core.operations.utilities.easing;
-
-/**
- * Provide a specific bouncing easing function
- */
-public class BounceCurve extends Easing {
- private static final float N1 = 7.5625f;
- private static final float D1 = 2.75f;
-
- BounceCurve(int type) {
- mType = type;
- }
-
- @Override
- public float get(float x) {
- float t = x;
- if (t < 0) {
- return 0f;
- }
- if (t < 1 / D1) {
- return 1 / (1 + 1 / D1) * (N1 * t * t + t);
- } else if (t < 2 / D1) {
- t -= 1.5f / D1;
- return N1 * t * t + 0.75f;
- } else if (t < 2.5 / D1) {
- t -= 2.25f / D1;
- return N1 * t * t + 0.9375f;
- } else if (t <= 1) {
- t -= 2.625f / D1;
- return N1 * t * t + 0.984375f;
- }
- return 1f;
- }
-
- @Override
- public float getDiff(float x) {
- if (x < 0) {
- return 0f;
- }
- if (x < 1 / D1) {
- return 2 * N1 * x / (1 + 1 / D1) + 1 / (1 + 1 / D1);
- } else if (x < 2 / D1) {
- return 2 * N1 * (x - 1.5f / D1);
- } else if (x < 2.5 / D1) {
- return 2 * N1 * (x - 2.25f / D1);
- } else if (x <= 1) {
- return 2 * N1 * (x - 2.625f / D1);
- }
- return 0f;
- }
-
-}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/CubicEasing.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/CubicEasing.java
deleted file mode 100644
index fd1ee03..0000000
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/CubicEasing.java
+++ /dev/null
@@ -1,157 +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.internal.widget.remotecompose.core.operations.utilities.easing;
-
-class CubicEasing extends Easing {
- float mType = 0;
- float mX1 = 0f;
- float mY1 = 0f;
- float mX2 = 0f;
- float mY2 = 0f;
-
- private static final float[] STANDARD = {0.4f, 0.0f, 0.2f, 1f};
- private static final float[] ACCELERATE = {0.4f, 0.05f, 0.8f, 0.7f};
- private static final float[] DECELERATE = {0.0f, 0.0f, 0.2f, 0.95f};
- private static final float[] LINEAR = {1f, 1f, 0f, 0f};
- private static final float[] ANTICIPATE = {0.36f, 0f, 0.66f, -0.56f};
- private static final float[] OVERSHOOT = {0.34f, 1.56f, 0.64f, 1f};
-
- CubicEasing(int type) {
- mType = type;
- config(type);
- }
-
- CubicEasing(float x1, float y1, float x2, float y2) {
- setup(x1, y1, x2, y2);
- }
-
- public void config(int type) {
-
- switch (type) {
- case CUBIC_STANDARD:
- setup(STANDARD);
- break;
- case CUBIC_ACCELERATE:
- setup(ACCELERATE);
- break;
- case CUBIC_DECELERATE:
- setup(DECELERATE);
- break;
- case CUBIC_LINEAR:
- setup(LINEAR);
- break;
- case CUBIC_ANTICIPATE:
- setup(ANTICIPATE);
- break;
- case CUBIC_OVERSHOOT:
- setup(OVERSHOOT);
- break;
- }
- mType = type;
- }
-
- void setup(float[] values) {
- setup(values[0], values[1], values[2], values[3]);
- }
-
- void setup(float x1, float y1, float x2, float y2) {
- mX1 = x1;
- mY1 = y1;
- mX2 = x2;
- mY2 = y2;
- }
-
- private float getX(float t) {
- float t1 = 1 - t;
- // no need for because start at 0,0 float f0 = (1 - t) * (1 - t) * (1 - t)
- float f1 = 3 * t1 * t1 * t;
- float f2 = 3 * t1 * t * t;
- float f3 = t * t * t;
- return mX1 * f1 + mX2 * f2 + f3;
- }
-
- private float getY(float t) {
- float t1 = 1 - t;
- // no need for testing because start at 0,0 float f0 = (1 - t) * (1 - t) * (1 - t)
- float f1 = 3 * t1 * t1 * t;
- float f2 = 3 * t1 * t * t;
- float f3 = t * t * t;
- return mY1 * f1 + mY2 * f2 + f3;
- }
-
- private float getDiffX(float t) {
- float t1 = 1 - t;
- return 3 * t1 * t1 * mX1 + 6 * t1 * t * (mX2 - mX1) + 3 * t * t * (1 - mX2);
- }
-
- private float getDiffY(float t) {
- float t1 = 1 - t;
- return 3 * t1 * t1 * mY1 + 6 * t1 * t * (mY2 - mY1) + 3 * t * t * (1 - mY2);
- }
-
- /**
- * binary search for the region and linear interpolate the answer
- */
- public float getDiff(float x) {
- float t = 0.5f;
- float range = 0.5f;
- while (range > D_ERROR) {
- float tx = getX(t);
- range *= 0.5;
- if (tx < x) {
- t += range;
- } else {
- t -= range;
- }
- }
- float x1 = getX(t - range);
- float x2 = getX(t + range);
- float y1 = getY(t - range);
- float y2 = getY(t + range);
- return (y2 - y1) / (x2 - x1);
- }
-
- /**
- * binary search for the region and linear interpolate the answer
- */
- public float get(float x) {
- if (x <= 0.0f) {
- return 0f;
- }
- if (x >= 1.0f) {
- return 1.0f;
- }
- float t = 0.5f;
- float range = 0.5f;
- while (range > ERROR) {
- float tx = getX(t);
- range *= 0.5f;
- if (tx < x) {
- t += range;
- } else {
- t -= range;
- }
- }
- float x1 = getX(t - range);
- float x2 = getX(t + range);
- float y1 = getY(t - range);
- float y2 = getY(t + range);
- return (y2 - y1) * (x - x1) / (x2 - x1) + y1;
- }
-
- private static final float ERROR = 0.01f;
- private static final float D_ERROR = 0.0001f;
-}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/Easing.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/Easing.java
deleted file mode 100644
index 4ed9550..0000000
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/Easing.java
+++ /dev/null
@@ -1,48 +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.internal.widget.remotecompose.core.operations.utilities.easing;
-
-/**
- * The standard interface to Easing functions
- */
-public abstract class Easing {
- int mType;
- /**
- * get the value at point x
- */
- public abstract float get(float x);
-
- /**
- * get the slope of the easing function at at x
- */
- public abstract float getDiff(float x);
-
- public int getType() {
- return mType;
- }
-
- public static final int CUBIC_STANDARD = 1;
- public static final int CUBIC_ACCELERATE = 2;
- public static final int CUBIC_DECELERATE = 3;
- public static final int CUBIC_LINEAR = 4;
- public static final int CUBIC_ANTICIPATE = 5;
- public static final int CUBIC_OVERSHOOT = 6;
- public static final int CUBIC_CUSTOM = 11;
- public static final int SPLINE_CUSTOM = 12;
- public static final int EASE_OUT_BOUNCE = 13;
- public static final int EASE_OUT_ELASTIC = 14;
-
-}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/ElasticOutCurve.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/ElasticOutCurve.java
deleted file mode 100644
index e269583..0000000
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/ElasticOutCurve.java
+++ /dev/null
@@ -1,49 +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.internal.widget.remotecompose.core.operations.utilities.easing;
-
-/**
- * Provide a bouncing Easing function
- */
-public class ElasticOutCurve extends Easing {
- private static final float F_PI = (float) Math.PI;
- private static final float C4 = 2 * F_PI / 3;
- private static final float TWENTY_PI = 20 * F_PI;
- private static final float LOG_8 = (float) Math.log(8.0f);
-
- @Override
- public float get(float x) {
- if (x <= 0) {
- return 0.0f;
- }
- if (x >= 1) {
- return 1.0f;
- } else
- return (float) (Math.pow(2.0f, -10 * x)
- * Math.sin((x * 10 - 0.75f) * C4) + 1);
- }
-
- @Override
- public float getDiff(float x) {
- if (x < 0 || x > 1) {
- return 0.0f;
- } else
- return (float) ((5 * Math.pow(2.0f, (1 - 10 * x))
- * (LOG_8 * Math.cos(TWENTY_PI * x / 3) + 2
- * F_PI * Math.sin(TWENTY_PI * x / 3))
- / 3));
- }
-}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/FloatAnimation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/FloatAnimation.java
deleted file mode 100644
index 4f484de..0000000
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/FloatAnimation.java
+++ /dev/null
@@ -1,259 +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.internal.widget.remotecompose.core.operations.utilities.easing;
-
-/**
- * Support Animation of the FloatExpression
- */
-public class FloatAnimation extends Easing {
- float[] mSpec;
- // mSpec[0] = duration
- // int(mSpec[1]) = num_of_param << 16 | type
- // mSpec[2..1+num_of_param] params
- // mSpec[2+num_of_param] starting Value
- Easing mEasingCurve;
- private int mType = CUBIC_STANDARD;
- private float mDuration = 1;
- private float mWrap = Float.NaN;
- private float mInitialValue = Float.NaN;
- private float mTargetValue = Float.NaN;
- private float mScale = 1;
- float mOffset = 0;
-
- @Override
- public String toString() {
-
- String str = "type " + mType;
- if (!Float.isNaN(mInitialValue)) {
- str += " " + mInitialValue;
- }
- if (!Float.isNaN(mTargetValue)) {
- str += " -> " + mTargetValue;
- }
- if (!Float.isNaN(mWrap)) {
- str += " % " + mWrap;
- }
-
- return str;
- }
-
- public FloatAnimation() {
- }
-
- public FloatAnimation(float... description) {
- setAnimationDescription(description);
- }
-
- public FloatAnimation(int type,
- float duration,
- float[] description,
- float initialValue,
- float wrap) {
- setAnimationDescription(packToFloatArray(duration,
- type, description, initialValue, wrap));
- }
-
- /**
- * packs spec into a float array
- *
- * @param duration
- * @param type
- * @param spec
- * @param initialValue
- * @return
- */
- public static float[] packToFloatArray(float duration,
- int type,
- float[] spec,
- float initialValue,
- float wrap) {
- int count = 0;
-
- if (!Float.isNaN(initialValue)) {
- count++;
- }
- if (spec != null) {
- count++;
- }
- if (spec != null || type != CUBIC_STANDARD) {
- count++;
- count += (spec == null) ? 0 : spec.length;
- }
- if (duration != 1 || count > 0) {
- count++;
- }
- if (!Float.isNaN(initialValue)) {
- count++;
- }
- if (!Float.isNaN(wrap)) {
- count++;
- }
- float[] ret = new float[count];
- int pos = 0;
- int specLen = (spec == null) ? 0 : spec.length;
-
- if (ret.length > 0) {
- ret[pos++] = duration;
-
- }
- if (ret.length > 1) {
- int wrapBit = (Float.isNaN(wrap)) ? 0 : 1;
- int initBit = (Float.isNaN(initialValue)) ? 0 : 2;
- int bits = type | ((wrapBit | initBit) << 8);
- ret[pos++] = Float.intBitsToFloat(specLen << 16 | bits);
- }
-
- if (specLen > 0) {
- System.arraycopy(spec, 0, ret, pos, spec.length);
- pos += spec.length;
- }
- if (!Float.isNaN(initialValue)) {
- ret[pos++] = initialValue;
- }
- if (!Float.isNaN(wrap)) {
- ret[pos] = wrap;
- }
- return ret;
- }
-
- /**
- * Create an animation based on a float encoding of the animation
- * @param description
- */
- public void setAnimationDescription(float[] description) {
- mSpec = description;
- mDuration = (mSpec.length == 0) ? 1 : mSpec[0];
- int len = 0;
- if (mSpec.length > 1) {
- int num_type = Float.floatToRawIntBits(mSpec[1]);
- mType = num_type & 0xFF;
- boolean wrap = ((num_type >> 8) & 0x1) > 0;
- boolean init = ((num_type >> 8) & 0x2) > 0;
- len = (num_type >> 16) & 0xFFFF;
- int off = 2 + len;
- if (init) {
- mInitialValue = mSpec[off++];
- }
- if (wrap) {
- mWrap = mSpec[off];
- }
- }
- create(mType, description, 2, len);
- }
-
- private void create(int type, float[] params, int offset, int len) {
- switch (type) {
- case CUBIC_STANDARD:
- case CUBIC_ACCELERATE:
- case CUBIC_DECELERATE:
- case CUBIC_LINEAR:
- case CUBIC_ANTICIPATE:
- case CUBIC_OVERSHOOT:
- mEasingCurve = new CubicEasing(type);
- break;
- case CUBIC_CUSTOM:
- mEasingCurve = new CubicEasing(params[offset + 0],
- params[offset + 1],
- params[offset + 2],
- params[offset + 3]
- );
- break;
- case EASE_OUT_BOUNCE:
- mEasingCurve = new BounceCurve(type);
- break;
- case EASE_OUT_ELASTIC:
- mEasingCurve = new ElasticOutCurve();
- break;
- case SPLINE_CUSTOM:
- mEasingCurve = new StepCurve(params, offset, len);
- break;
- }
- }
-
- /**
- * Get the duration the interpolate is to take
- * @return duration in seconds
- */
- public float getDuration() {
- return mDuration;
- }
-
- /**
- * Set the initial Value
- * @param value
- */
- public void setInitialValue(float value) {
-
- if (Float.isNaN(mWrap)) {
- mInitialValue = value;
- } else {
- mInitialValue = value % mWrap;
- }
- setScaleOffset();
- }
-
- /**
- * Set the target value to interpolate to
- * @param value
- */
- public void setTargetValue(float value) {
- if (Float.isNaN(mWrap)) {
- mTargetValue = value;
- } else {
- if (Math.abs((value % mWrap) + mWrap - mInitialValue)
- < Math.abs((value % mWrap) - mInitialValue)) {
- mTargetValue = (value % mWrap) + mWrap;
-
- } else {
- mTargetValue = value % mWrap;
- }
- }
- setScaleOffset();
- }
-
- public float getTargetValue() {
- return mTargetValue;
- }
-
- private void setScaleOffset() {
- if (!Float.isNaN(mInitialValue) && !Float.isNaN(mTargetValue)) {
- mScale = (mTargetValue - mInitialValue);
- mOffset = mInitialValue;
- } else {
- mScale = 1;
- mOffset = 0;
- }
- }
-
- /**
- * get the value at time t in seconds since start
- */
- public float get(float t) {
- return mEasingCurve.get(t / mDuration)
- * (mTargetValue - mInitialValue) + mInitialValue;
- }
-
- /**
- * get the slope of the easing function at at x
- */
- public float getDiff(float t) {
- return mEasingCurve.getDiff(t / mDuration) * (mTargetValue - mInitialValue);
- }
-
- public float getInitialValue() {
- return mInitialValue;
- }
-}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/GeneralEasing.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/GeneralEasing.java
deleted file mode 100644
index 693deaf..0000000
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/GeneralEasing.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.widget.remotecompose.core.operations.utilities.easing;
-
-/**
- * Provides and interface to create easing functions
- */
-public class GeneralEasing extends Easing{
- float[] mEasingData = new float[0];
- Easing mEasingCurve = new CubicEasing(CUBIC_STANDARD);
-
- /**
- * Set the curve based on the float encoding of it
- * @param data
- */
- public void setCurveSpecification(float[] data) {
- mEasingData = data;
- createEngine();
- }
-
- public float[] getCurveSpecification() {
- return mEasingData;
- }
-
- void createEngine() {
- int type = Float.floatToRawIntBits(mEasingData[0]);
- switch (type) {
- case CUBIC_STANDARD:
- case CUBIC_ACCELERATE:
- case CUBIC_DECELERATE:
- case CUBIC_LINEAR:
- case CUBIC_ANTICIPATE:
- case CUBIC_OVERSHOOT:
- mEasingCurve = new CubicEasing(type);
- break;
- case CUBIC_CUSTOM:
- mEasingCurve = new CubicEasing(mEasingData[1],
- mEasingData[2],
- mEasingData[3],
- mEasingData[5]
- );
- break;
- case EASE_OUT_BOUNCE:
- mEasingCurve = new BounceCurve(type);
- break;
- }
- }
-
- /**
- * get the value at point x
- */
- public float get(float x) {
- return mEasingCurve.get(x);
- }
-
- /**
- * get the slope of the easing function at at x
- */
- public float getDiff(float x) {
- return mEasingCurve.getDiff(x);
- }
-
- public int getType() {
- return mEasingCurve.getType();
- }
-
-
-}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/MonotonicCurveFit.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/MonotonicCurveFit.java
deleted file mode 100644
index 23930b9..0000000
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/MonotonicCurveFit.java
+++ /dev/null
@@ -1,370 +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.internal.widget.remotecompose.core.operations.utilities.easing;
-
-import java.util.Arrays;
-
-/**
- * This performs a spline interpolation in multiple dimensions
- *
- *
- */
-public class MonotonicCurveFit {
- private static final String TAG = "MonotonicCurveFit";
- private double[] mT;
- private double[][] mY;
- private double[][] mTangent;
- private boolean mExtrapolate = true;
- double[] mSlopeTemp;
-
- /**
- * create a collection of curves
- * @param time the point along the curve
- * @param y the parameter at those points
- */
- public MonotonicCurveFit(double[] time, double[][] y) {
- final int n = time.length;
- final int dim = y[0].length;
- mSlopeTemp = new double[dim];
- double[][] slope = new double[n - 1][dim]; // could optimize this out
- double[][] tangent = new double[n][dim];
- for (int j = 0; j < dim; j++) {
- for (int i = 0; i < n - 1; i++) {
- double dt = time[i + 1] - time[i];
- slope[i][j] = (y[i + 1][j] - y[i][j]) / dt;
- if (i == 0) {
- tangent[i][j] = slope[i][j];
- } else {
- tangent[i][j] = (slope[i - 1][j] + slope[i][j]) * 0.5f;
- }
- }
- tangent[n - 1][j] = slope[n - 2][j];
- }
-
- for (int i = 0; i < n - 1; i++) {
- for (int j = 0; j < dim; j++) {
- if (slope[i][j] == 0.) {
- tangent[i][j] = 0.;
- tangent[i + 1][j] = 0.;
- } else {
- double a = tangent[i][j] / slope[i][j];
- double b = tangent[i + 1][j] / slope[i][j];
- double h = Math.hypot(a, b);
- if (h > 9.0) {
- double t = 3. / h;
- tangent[i][j] = t * a * slope[i][j];
- tangent[i + 1][j] = t * b * slope[i][j];
- }
- }
- }
- }
- mT = time;
- mY = y;
- mTangent = tangent;
- }
-
- /**
- * Get the position of all curves at time t
- * @param t
- * @param v
- */
- public void getPos(double t, double[] v) {
- final int n = mT.length;
- final int dim = mY[0].length;
- if (mExtrapolate) {
- if (t <= mT[0]) {
- getSlope(mT[0], mSlopeTemp);
- for (int j = 0; j < dim; j++) {
- v[j] = mY[0][j] + (t - mT[0]) * mSlopeTemp[j];
- }
- return;
- }
- if (t >= mT[n - 1]) {
- getSlope(mT[n - 1], mSlopeTemp);
- for (int j = 0; j < dim; j++) {
- v[j] = mY[n - 1][j] + (t - mT[n - 1]) * mSlopeTemp[j];
- }
- return;
- }
- } else {
- if (t <= mT[0]) {
- for (int j = 0; j < dim; j++) {
- v[j] = mY[0][j];
- }
- return;
- }
- if (t >= mT[n - 1]) {
- for (int j = 0; j < dim; j++) {
- v[j] = mY[n - 1][j];
- }
- return;
- }
- }
-
- for (int i = 0; i < n - 1; i++) {
- if (t == mT[i]) {
- for (int j = 0; j < dim; j++) {
- v[j] = mY[i][j];
- }
- }
- if (t < mT[i + 1]) {
- double h = mT[i + 1] - mT[i];
- double x = (t - mT[i]) / h;
- for (int j = 0; j < dim; j++) {
- double y1 = mY[i][j];
- double y2 = mY[i + 1][j];
- double t1 = mTangent[i][j];
- double t2 = mTangent[i + 1][j];
- v[j] = interpolate(h, x, y1, y2, t1, t2);
- }
- return;
- }
- }
- }
-
- /**
- * Get the position of all curves at time t
- * @param t
- * @param v
- */
- public void getPos(double t, float[] v) {
- final int n = mT.length;
- final int dim = mY[0].length;
- if (mExtrapolate) {
- if (t <= mT[0]) {
- getSlope(mT[0], mSlopeTemp);
- for (int j = 0; j < dim; j++) {
- v[j] = (float) (mY[0][j] + (t - mT[0]) * mSlopeTemp[j]);
- }
- return;
- }
- if (t >= mT[n - 1]) {
- getSlope(mT[n - 1], mSlopeTemp);
- for (int j = 0; j < dim; j++) {
- v[j] = (float) (mY[n - 1][j] + (t - mT[n - 1]) * mSlopeTemp[j]);
- }
- return;
- }
- } else {
- if (t <= mT[0]) {
- for (int j = 0; j < dim; j++) {
- v[j] = (float) mY[0][j];
- }
- return;
- }
- if (t >= mT[n - 1]) {
- for (int j = 0; j < dim; j++) {
- v[j] = (float) mY[n - 1][j];
- }
- return;
- }
- }
-
- for (int i = 0; i < n - 1; i++) {
- if (t == mT[i]) {
- for (int j = 0; j < dim; j++) {
- v[j] = (float) mY[i][j];
- }
- }
- if (t < mT[i + 1]) {
- double h = mT[i + 1] - mT[i];
- double x = (t - mT[i]) / h;
- for (int j = 0; j < dim; j++) {
- double y1 = mY[i][j];
- double y2 = mY[i + 1][j];
- double t1 = mTangent[i][j];
- double t2 = mTangent[i + 1][j];
- v[j] = (float) interpolate(h, x, y1, y2, t1, t2);
- }
- return;
- }
- }
- }
-
- /**
- * Get the position of the jth curve at time t
- * @param t
- * @param j
- * @return
- */
- public double getPos(double t, int j) {
- final int n = mT.length;
- if (mExtrapolate) {
- if (t <= mT[0]) {
- return mY[0][j] + (t - mT[0]) * getSlope(mT[0], j);
- }
- if (t >= mT[n - 1]) {
- return mY[n - 1][j] + (t - mT[n - 1]) * getSlope(mT[n - 1], j);
- }
- } else {
- if (t <= mT[0]) {
- return mY[0][j];
- }
- if (t >= mT[n - 1]) {
- return mY[n - 1][j];
- }
- }
-
- for (int i = 0; i < n - 1; i++) {
- if (t == mT[i]) {
- return mY[i][j];
- }
- if (t < mT[i + 1]) {
- double h = mT[i + 1] - mT[i];
- double x = (t - mT[i]) / h;
- double y1 = mY[i][j];
- double y2 = mY[i + 1][j];
- double t1 = mTangent[i][j];
- double t2 = mTangent[i + 1][j];
- return interpolate(h, x, y1, y2, t1, t2);
-
- }
- }
- return 0; // should never reach here
- }
-
- /**
- * Get the slope of all the curves at position t
- * @param t
- * @param v
- */
- public void getSlope(double t, double[] v) {
- final int n = mT.length;
- int dim = mY[0].length;
- if (t <= mT[0]) {
- t = mT[0];
- } else if (t >= mT[n - 1]) {
- t = mT[n - 1];
- }
-
- for (int i = 0; i < n - 1; i++) {
- if (t <= mT[i + 1]) {
- double h = mT[i + 1] - mT[i];
- double x = (t - mT[i]) / h;
- for (int j = 0; j < dim; j++) {
- double y1 = mY[i][j];
- double y2 = mY[i + 1][j];
- double t1 = mTangent[i][j];
- double t2 = mTangent[i + 1][j];
- v[j] = diff(h, x, y1, y2, t1, t2) / h;
- }
- break;
- }
- }
- return;
- }
-
- /**
- * Get the slope of the j curve at position t
- * @param t
- * @param j
- * @return
- */
- public double getSlope(double t, int j) {
- final int n = mT.length;
-
- if (t < mT[0]) {
- t = mT[0];
- } else if (t >= mT[n - 1]) {
- t = mT[n - 1];
- }
- for (int i = 0; i < n - 1; i++) {
- if (t <= mT[i + 1]) {
- double h = mT[i + 1] - mT[i];
- double x = (t - mT[i]) / h;
- double y1 = mY[i][j];
- double y2 = mY[i + 1][j];
- double t1 = mTangent[i][j];
- double t2 = mTangent[i + 1][j];
- return diff(h, x, y1, y2, t1, t2) / h;
- }
- }
- return 0; // should never reach here
- }
-
- public double[] getTimePoints() {
- return mT;
- }
-
- /**
- * Cubic Hermite spline
- */
- private static double interpolate(double h,
- double x,
- double y1,
- double y2,
- double t1,
- double t2) {
- double x2 = x * x;
- double x3 = x2 * x;
- return -2 * x3 * y2 + 3 * x2 * y2 + 2 * x3 * y1 - 3 * x2 * y1 + y1
- + h * t2 * x3 + h * t1 * x3 - h * t2 * x2 - 2 * h * t1 * x2
- + h * t1 * x;
- }
-
- /**
- * Cubic Hermite spline slope differentiated
- */
- private static double diff(double h, double x, double y1, double y2, double t1, double t2) {
- double x2 = x * x;
- return -6 * x2 * y2 + 6 * x * y2 + 6 * x2 * y1 - 6 * x * y1 + 3 * h * t2 * x2
- + 3 * h * t1 * x2 - 2 * h * t2 * x - 4 * h * t1 * x + h * t1;
- }
-
- /**
- * This builds a monotonic spline to be used as a wave function
- */
- public static MonotonicCurveFit buildWave(String configString) {
- // done this way for efficiency
- String str = configString;
- double[] values = new double[str.length() / 2];
- int start = configString.indexOf('(') + 1;
- int off1 = configString.indexOf(',', start);
- int count = 0;
- while (off1 != -1) {
- String tmp = configString.substring(start, off1).trim();
- values[count++] = Double.parseDouble(tmp);
- off1 = configString.indexOf(',', start = off1 + 1);
- }
- off1 = configString.indexOf(')', start);
- String tmp = configString.substring(start, off1).trim();
- values[count++] = Double.parseDouble(tmp);
-
- return buildWave(Arrays.copyOf(values, count));
- }
-
- private static MonotonicCurveFit buildWave(double[] values) {
- int length = values.length * 3 - 2;
- int len = values.length - 1;
- double gap = 1.0 / len;
- double[][] points = new double[length][1];
- double[] time = new double[length];
- for (int i = 0; i < values.length; i++) {
- double v = values[i];
- points[i + len][0] = v;
- time[i + len] = i * gap;
- if (i > 0) {
- points[i + len * 2][0] = v + 1;
- time[i + len * 2] = i * gap + 1;
-
- points[i - 1][0] = v - 1 - gap;
- time[i - 1] = i * gap + -1 - gap;
- }
- }
-
- return new MonotonicCurveFit(time, points);
- }
-}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/StepCurve.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/StepCurve.java
deleted file mode 100644
index 6ed6548..0000000
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/StepCurve.java
+++ /dev/null
@@ -1,66 +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.internal.widget.remotecompose.core.operations.utilities.easing;
-
-
-/**
- * This class translates a series of floating point values into a continuous
- * curve for use in an easing function including quantize functions
- * it is used with the "spline(0,0.3,0.3,0.5,...0.9,1)" it should start at 0 and end at one 1
- */
-public class StepCurve extends Easing {
- private static final boolean DEBUG = false;
- MonotonicCurveFit mCurveFit;
-
- public StepCurve(float[] params, int offset, int len) {
- mCurveFit = genSpline(params, offset, len);
- }
-
- private static MonotonicCurveFit genSpline(float[] values, int off, int arrayLen) {
- int length = arrayLen * 3 - 2;
- int len = arrayLen - 1;
- double gap = 1.0 / len;
- double[][] points = new double[length][1];
- double[] time = new double[length];
- for (int i = 0; i < arrayLen; i++) {
- double v = values[i + off];
- points[i + len][0] = v;
- time[i + len] = i * gap;
- if (i > 0) {
- points[i + len * 2][0] = v + 1;
- time[i + len * 2] = i * gap + 1;
-
- points[i - 1][0] = v - 1 - gap;
- time[i - 1] = i * gap + -1 - gap;
- }
- }
-
- MonotonicCurveFit ms = new MonotonicCurveFit(time, points);
-
- return ms;
- }
-
- @Override
- public float getDiff(float x) {
- return (float) mCurveFit.getSlope(x, 0);
- }
-
-
- @Override
- public float get(float x) {
- return (float) mCurveFit.getPos(x, 0);
- }
-}
diff --git a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposeDocument.java b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposeDocument.java
index cb0d62e..bcda27a 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposeDocument.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposeDocument.java
@@ -79,13 +79,6 @@
}
/**
- * The delay in milliseconds to next repaint -1 = not needed 0 = asap
- * @return delay in milliseconds to next repaint or -1
- */
- public int needsRepaint() {
- return mDocument.needsRepaint();
- }
- /**
* Returns true if the document can be displayed given this version of the player
*
* @param majorVersion the max major version supported by the player
@@ -96,11 +89,5 @@
return mDocument.canBeDisplayed(majorVersion, minorVersion, capabilities);
}
- @Override
- public String toString() {
- return "Document{\n"
- + mDocument
- + '}';
- }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java
index cc1f3dd..7423a16 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java
@@ -16,6 +16,7 @@
package com.android.internal.widget.remotecompose.player;
import android.content.Context;
+import android.graphics.Color;
import android.util.AttributeSet;
import android.util.Log;
import android.view.ViewGroup;
@@ -97,6 +98,7 @@
LayoutParams.MATCH_PARENT);
HorizontalScrollView horizontalScrollView =
new HorizontalScrollView(getContext());
+ horizontalScrollView.setBackgroundColor(Color.TRANSPARENT);
horizontalScrollView.setFillViewport(true);
horizontalScrollView.addView(mInner, layoutParamsInner);
LayoutParams layoutParams = new LayoutParams(
@@ -113,6 +115,7 @@
LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT);
ScrollView scrollView = new ScrollView(getContext());
+ scrollView.setBackgroundColor(Color.TRANSPARENT);
scrollView.setFillViewport(true);
scrollView.addView(mInner, layoutParamsInner);
LayoutParams layoutParams = new LayoutParams(
@@ -136,7 +139,9 @@
private void init(Context context, AttributeSet attrs, int defStyleAttr) {
LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT);
+ setBackgroundColor(Color.TRANSPARENT);
mInner = new RemoteComposeCanvas(context, attrs, defStyleAttr);
+ mInner.setBackgroundColor(Color.TRANSPARENT);
addView(mInner, layoutParams);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java
index ecb68bb..d0d6e69 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java
@@ -26,7 +26,6 @@
import android.graphics.RadialGradient;
import android.graphics.Rect;
import android.graphics.RectF;
-import android.graphics.RuntimeShader;
import android.graphics.Shader;
import android.graphics.SweepGradient;
import android.graphics.Typeface;
@@ -34,8 +33,6 @@
import com.android.internal.widget.remotecompose.core.PaintContext;
import com.android.internal.widget.remotecompose.core.RemoteContext;
import com.android.internal.widget.remotecompose.core.operations.ClipPath;
-import com.android.internal.widget.remotecompose.core.operations.ShaderData;
-import com.android.internal.widget.remotecompose.core.operations.Utils;
import com.android.internal.widget.remotecompose.core.operations.paint.PaintBundle;
import com.android.internal.widget.remotecompose.core.operations.paint.PaintChanges;
@@ -46,7 +43,6 @@
public class AndroidPaintContext extends PaintContext {
Paint mPaint = new Paint();
Canvas mCanvas;
- Rect mTmpRect = new Rect(); // use in calculation of bounds
public AndroidPaintContext(RemoteContext context, Canvas canvas) {
super(context);
@@ -181,22 +177,6 @@
}
@Override
- public void getTextBounds(int textId, int start, int end, boolean monospace, float[] bounds) {
- String str = getText(textId);
- if (end == -1) {
- end = str.length();
- }
-
- mPaint.getTextBounds(str, start, end, mTmpRect);
-
- bounds[0] = mTmpRect.left;
- bounds[1] = mTmpRect.top;
- bounds[2] = monospace ? (mPaint.measureText(str, start, end) - mTmpRect.left)
- : mTmpRect.right;
- bounds[3] = mTmpRect.bottom;
- }
-
- @Override
public void drawTextRun(int textID,
int start,
int end,
@@ -205,16 +185,7 @@
float x,
float y,
boolean rtl) {
-
- String textToPaint = getText(textID);
- if (end == -1) {
- if (start != 0) {
- textToPaint = textToPaint.substring(start);
- }
- } else {
- textToPaint = textToPaint.substring(start, end);
- }
-
+ String textToPaint = getText(textID).substring(start, end);
mCanvas.drawText(textToPaint, x, y, mPaint);
}
@@ -337,7 +308,7 @@
@Override
public void applyPaint(PaintBundle mPaintData) {
- mPaintData.applyPaintChange((PaintContext) this, new PaintChanges() {
+ mPaintData.applyPaintChange(new PaintChanges() {
@Override
public void setTextSize(float size) {
mPaint.setTextSize(size);
@@ -390,8 +361,10 @@
}
}
+
}
+
@Override
public void setStrokeWidth(float width) {
mPaint.setStrokeWidth(width);
@@ -413,37 +386,13 @@
}
@Override
- public void setShader(int shaderId) {
- // TODO this stuff should check the shader creation
- if (shaderId == 0) {
- mPaint.setShader(null);
- return;
- }
- ShaderData data = getShaderData(shaderId);
- RuntimeShader shader = new RuntimeShader(getText(data.getShaderTextId()));
- String[] names = data.getUniformFloatNames();
- for (int i = 0; i < names.length; i++) {
- String name = names[i];
- float[] val = data.getUniformFloats(name);
- shader.setFloatUniform(name, val);
- }
- names = data.getUniformIntegerNames();
- for (int i = 0; i < names.length; i++) {
- String name = names[i];
- int[] val = data.getUniformInts(name);
- shader.setIntUniform(name, val);
- }
- names = data.getUniformBitmapNames();
- for (int i = 0; i < names.length; i++) {
- String name = names[i];
- int val = data.getUniformBitmapId(name);
- }
- mPaint.setShader(shader);
+ public void setShader(int shader, String shaderString) {
+
}
@Override
public void setImageFilterQuality(int quality) {
- Utils.log(" quality =" + quality);
+ System.out.println(">>>>>>>>>>>> ");
}
@Override
@@ -471,6 +420,7 @@
mPaint.setFilterBitmap(filter);
}
+
@Override
public void setAntiAlias(boolean aa) {
mPaint.setAntiAlias(aa);
@@ -487,6 +437,7 @@
case PaintBundle.COLOR_FILTER:
mPaint.setColorFilter(null);
+ System.out.println(">>>>>>>>>>>>> CLEAR!!!!");
break;
}
}
@@ -495,11 +446,12 @@
}
}
- Shader.TileMode[] mTileModes = new Shader.TileMode[]{
+ Shader.TileMode[] mTilesModes = new Shader.TileMode[]{
Shader.TileMode.CLAMP,
Shader.TileMode.REPEAT,
Shader.TileMode.MIRROR};
+
@Override
public void setLinearGradient(int[] colors,
float[] stops,
@@ -511,7 +463,7 @@
mPaint.setShader(new LinearGradient(startX,
startY,
endX,
- endY, colors, stops, mTileModes[tileMode]));
+ endY, colors, stops, mTilesModes[tileMode]));
}
@@ -523,7 +475,7 @@
float radius,
int tileMode) {
mPaint.setShader(new RadialGradient(centerX, centerY, radius,
- colors, stops, mTileModes[tileMode]));
+ colors, stops, mTilesModes[tileMode]));
}
@Override
@@ -538,6 +490,7 @@
@Override
public void setColorFilter(int color, int mode) {
PorterDuff.Mode pmode = origamiToPorterDuffMode(mode);
+ System.out.println("setting color filter to " + pmode.name());
if (pmode != null) {
mPaint.setColorFilter(
new PorterDuffColorFilter(color, pmode));
@@ -547,10 +500,10 @@
}
@Override
- public void matrixScale(float scaleX,
- float scaleY,
- float centerX,
- float centerY) {
+ public void mtrixScale(float scaleX,
+ float scaleY,
+ float centerX,
+ float centerY) {
if (Float.isNaN(centerX)) {
mCanvas.scale(scaleX, scaleY);
} else {
@@ -603,11 +556,6 @@
}
}
- @Override
- public void reset() {
- mPaint.reset();
- }
-
private Path getPath(int path1Id,
int path2Id,
float tween,
@@ -651,9 +599,5 @@
private String getText(int id) {
return (String) mContext.mRemoteComposeState.getFromId(id);
}
-
- private ShaderData getShaderData(int id) {
- return (ShaderData) mContext.mRemoteComposeState.getFromId(id);
- }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java
index 6e4893b..270e96f 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java
@@ -20,15 +20,10 @@
import android.graphics.Canvas;
import com.android.internal.widget.remotecompose.core.RemoteContext;
-import com.android.internal.widget.remotecompose.core.VariableSupport;
-import com.android.internal.widget.remotecompose.core.operations.FloatExpression;
-import com.android.internal.widget.remotecompose.core.operations.ShaderData;
-
-import java.util.HashMap;
/**
* An implementation of Context for Android.
- * <p>
+ *
* This is used to play the RemoteCompose operations on Android.
*/
class AndroidRemoteContext extends RemoteContext {
@@ -38,7 +33,6 @@
mPaintContext = new AndroidPaintContext(this, canvas);
} else {
// need to make sure to update the canvas for the current one
- mPaintContext.reset();
((AndroidPaintContext) mPaintContext).setCanvas(canvas);
}
mWidth = canvas.getWidth();
@@ -56,32 +50,13 @@
}
}
- static class VarName {
- String mName;
- int mId;
- int mType;
-
- VarName(String name, int id, int type) {
- mName = name;
- mId = id;
- mType = type;
- }
- }
-
- HashMap<String, VarName> mVarNameHashMap = new HashMap<>();
-
- @Override
- public void loadVariableName(String varName, int varId, int varType) {
- mVarNameHashMap.put(varName, new VarName(varName, varId, varType));
- }
-
/**
* Decode a byte array into an image and cache it using the given imageId
*
- * @param width with of image to be loaded
+ * @oaram imageId the id of the image
+ * @param width with of image to be loaded
* @param height height of image to be loaded
* @param bitmap a byte array containing the image information
- * @oaram imageId the id of the image
*/
@Override
public void loadBitmap(int imageId, int width, int height, byte[] bitmap) {
@@ -95,66 +70,14 @@
public void loadText(int id, String text) {
if (!mRemoteComposeState.containsId(id)) {
mRemoteComposeState.cache(id, text);
- } else {
- mRemoteComposeState.update(id, text);
}
}
- @Override
- public String getText(int id) {
- return (String) mRemoteComposeState.getFromId(id);
- }
-
- @Override
- public void loadFloat(int id, float value) {
- mRemoteComposeState.updateFloat(id, value);
- }
-
-
- @Override
- public void loadColor(int id, int color) {
- mRemoteComposeState.updateColor(id, color);
- }
-
- @Override
- public void loadAnimatedFloat(int id, FloatExpression animatedFloat) {
- mRemoteComposeState.cache(id, animatedFloat);
- }
-
- @Override
- public void loadShader(int id, ShaderData value) {
- mRemoteComposeState.cache(id, value);
- }
-
- @Override
- public float getFloat(int id) {
- return (float) mRemoteComposeState.getFloat(id);
- }
-
- @Override
- public int getColor(int id) {
- return mRemoteComposeState.getColor(id);
- }
-
- @Override
- public void listensTo(int id, VariableSupport variableSupport) {
- mRemoteComposeState.listenToVar(id, variableSupport);
- }
-
- @Override
- public int updateOps() {
- return mRemoteComposeState.getOpsToUpdate(this);
- }
-
- @Override
- public ShaderData getShader(int id) {
- return (ShaderData) mRemoteComposeState.getFromId(id);
- }
-
///////////////////////////////////////////////////////////////////////////////////////////////
// Click handling
///////////////////////////////////////////////////////////////////////////////////////////////
+
@Override
public void addClickArea(int id,
int contentDescriptionId,
@@ -164,7 +87,7 @@
float bottom,
int metadataId) {
String contentDescription = (String) mRemoteComposeState.getFromId(contentDescriptionId);
- String metadata = (String) mRemoteComposeState.getFromId(metadataId);
+ String metadata = (String) mRemoteComposeState.getFromId(metadataId);
mDocument.addClickArea(id, contentDescription, left, top, right, bottom, metadata);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/ClickAreaView.java b/core/java/com/android/internal/widget/remotecompose/player/platform/ClickAreaView.java
index 329178a..672dae3 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/platform/ClickAreaView.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/platform/ClickAreaView.java
@@ -20,6 +20,7 @@
import android.graphics.Paint;
import android.view.View;
+
/**
* Implementation for the click handling
*/
@@ -39,6 +40,7 @@
setContentDescription(contentDescription);
}
+
public void setDebug(boolean value) {
if (mDebug != value) {
mDebug = value;
diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java b/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java
index 97d23c8..a3bb73e 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java
@@ -85,7 +85,6 @@
mDocument.initializeContext(mARContext);
setContentDescription(mDocument.getDocument().getContentDescription());
requestLayout();
- invalidate();
}
AndroidRemoteContext mARContext = new AndroidRemoteContext();
@@ -120,7 +119,8 @@
removeAllViews();
}
- public interface ClickCallbacks {
+
+ public interface ClickCallbacks {
void click(int id, String metadata);
}
@@ -213,9 +213,6 @@
setMeasuredDimension(w, h);
}
- private int mCount;
- private long mTime = System.nanoTime();
-
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
@@ -227,17 +224,6 @@
mARContext.mWidth = getWidth();
mARContext.mHeight = getHeight();
mDocument.paint(mARContext, mTheme);
- if (mDebug) {
- mCount++;
- if (System.nanoTime() - mTime > 1000000000L) {
- System.out.println(" count " + mCount + " fps");
- mCount = 0;
- mTime = System.nanoTime();
- }
- }
- if (mDocument.needsRepaint() > 0) {
- invalidate();
- }
}
}
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/proto/android/providers/settings/system.proto b/core/proto/android/providers/settings/system.proto
index 1233069..6a0ec1d 100644
--- a/core/proto/android/providers/settings/system.proto
+++ b/core/proto/android/providers/settings/system.proto
@@ -126,6 +126,7 @@
option (android.msg_privacy).dest = DEST_EXPLICIT;
optional SettingProto pointer_fill_style = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto pointer_scale = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
}
optional Pointer pointer = 37;
optional SettingProto pointer_speed = 18 [ (android.privacy).dest = DEST_AUTOMATIC ];
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 09ffdf3..c6db371 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3249,16 +3249,20 @@
<permission android:name="android.permission.INTERACT_ACROSS_PROFILES"
android:protectionLevel="signature|appop" />
- <!-- Allows applications to access profiles with ACCESS_HIDDEN_PROFILES user property
- <p>Protection level: normal
- @FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles") -->
+ <!-- Allows applications to access profiles with
+ {@code android.content.pm.UserProperties#PROFILE_API_VISIBILITY_HIDDEN} user property, e.g.
+ {@link android.os.UserManager#USER_TYPE_PROFILE_PRIVATE}.
+ <p>Protection level: normal
+ @FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles") -->
<permission android:name="android.permission.ACCESS_HIDDEN_PROFILES"
android:label="@string/permlab_accessHiddenProfile"
android:description="@string/permdesc_accessHiddenProfile"
android:protectionLevel="normal" />
- <!-- @SystemApi @hide Allows privileged applications to get details about hidden profile
- users.
+ <!-- @SystemApi @hide Allows privileged applications to get details about profiles with
+ {@code android.content.pm.UserProperties#PROFILE_API_VISIBILITY_HIDDEN} user property, e.g.
+ {@link android.os.UserManager#USER_TYPE_PROFILE_PRIVATE}. Removes extra requirements such
+ as having {@link android.app.role.RoleManager#ROLE_HOME} role for LauncherApps APIs.
@FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles") -->
<permission
android:name="android.permission.ACCESS_HIDDEN_PROFILES_FULL"
@@ -8194,6 +8198,17 @@
<permission android:name="android.permission.SETUP_FSVERITY"
android:protectionLevel="signature|privileged"/>
+ <!--
+ @TestApi
+ Signature permission reserved for testing. This should never be used to
+ gate any actual functionality.
+ <p>
+ Protection level: signature
+ @hide
+ -->
+ <permission android:name="android.permission.RESERVED_FOR_TESTING_SIGNATURE"
+ android:protectionLevel="signature"/>
+
<!-- Attribution for Geofencing service. -->
<attribution android:tag="GeofencingService" android:label="@string/geofencing_service"/>
<!-- Attribution for Country Detector. -->
diff --git a/core/res/res/drawable/floating_popup_background_light.xml b/core/res/res/drawable/floating_popup_background.xml
similarity index 84%
rename from core/res/res/drawable/floating_popup_background_light.xml
rename to core/res/res/drawable/floating_popup_background.xml
index 767140d..99acedf 100644
--- a/core/res/res/drawable/floating_popup_background_light.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_light" />
+ <solid android:color="?androidprv:attr/materialColorSurfaceContainerHighest"/>
<corners android:radius="?android:attr/dialogCornerRadius" />
</shape>
diff --git a/core/res/res/drawable/floating_popup_background_dark.xml b/core/res/res/drawable/floating_popup_background_dark.xml
deleted file mode 100644
index c4b4448..0000000
--- a/core/res/res/drawable/floating_popup_background_dark.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_dark" />
- <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/config_telephony.xml b/core/res/res/values/config_telephony.xml
index dcda5d8..fba95a5 100644
--- a/core/res/res/values/config_telephony.xml
+++ b/core/res/res/values/config_telephony.xml
@@ -409,4 +409,10 @@
<bool name="config_force_phone_globals_creation">false</bool>
<java-symbol type="bool" name="config_force_phone_globals_creation" />
+ <!-- Boolean indicating whether to enable persistent logging via DropBoxManager.
+ Used in persisting SOS/emergency related log messages.
+ -->
+ <bool name="config_dropboxmanager_persistent_logging_enabled">false</bool>
+ <java-symbol type="bool" name="config_dropboxmanager_persistent_logging_enabled" />
+
</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/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
index 16c77d0..ecf4720 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
@@ -24,6 +24,7 @@
import android.app.compat.CompatChanges;
import android.content.Context;
import android.hardware.devicestate.DeviceStateManager;
+import android.os.SystemProperties;
import android.util.Log;
import androidx.annotation.NonNull;
@@ -50,6 +51,11 @@
private static final String TAG = "WindowExtensionsImpl";
/**
+ * The value of the system property that indicates no override is set.
+ */
+ private static final int NO_LEVEL_OVERRIDE = -1;
+
+ /**
* The min version of the WM Extensions that must be supported in the current platform version.
*/
@VisibleForTesting
@@ -66,14 +72,30 @@
WindowExtensionsImpl() {
mIsActivityEmbeddingEnabled = isActivityEmbeddingEnabled();
- Log.i(TAG, "Initializing Window Extensions, vendor API level=" + mVersion
- + ", activity embedding enabled=" + mIsActivityEmbeddingEnabled);
+
+ Log.i(TAG, generateLogMessage());
+ }
+
+ private String generateLogMessage() {
+ final StringBuilder logBuilder = new StringBuilder("Initializing Window Extensions, "
+ + "vendor API level=" + mVersion);
+ final int levelOverride = getLevelOverride();
+ if (levelOverride != NO_LEVEL_OVERRIDE) {
+ logBuilder.append(", override to ").append(levelOverride);
+ }
+ logBuilder.append(", activity embedding enabled=").append(mIsActivityEmbeddingEnabled);
+ return logBuilder.toString();
}
// TODO(b/241126279) Introduce constants to better version functionality
@Override
public int getVendorApiLevel() {
- return mVersion;
+ final int levelOverride = getLevelOverride();
+ return (levelOverride != NO_LEVEL_OVERRIDE) ? levelOverride : mVersion;
+ }
+
+ private int getLevelOverride() {
+ return SystemProperties.getInt("persist.wm.debug.ext_version_override", NO_LEVEL_OVERRIDE);
}
@NonNull
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/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
index 57e95d6..f4ac5f2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
@@ -538,8 +538,10 @@
@Override
public void onAnimationStart(Animator animation) {
+ ValueAnimator valueAnimator = (ValueAnimator) animation;
+ float value = (float) valueAnimator.getAnimatedValue();
SurfaceControl.Transaction t = mTransactionPool.acquire();
- t.setPosition(mImeSourceControl.getLeash(), x, startY);
+ t.setPosition(mImeSourceControl.getLeash(), x, value);
if (DEBUG) {
Slog.d(TAG, "onAnimationStart d:" + mDisplayId + " top:"
+ imeTop(hiddenY) + "->" + imeTop(shownY)
@@ -549,7 +551,7 @@
imeTop(shownY), mAnimationDirection == DIRECTION_SHOW, isFloating, t);
mAnimateAlpha = (flags & ImePositionProcessor.IME_ANIMATION_NO_ALPHA) == 0;
final float alpha = (mAnimateAlpha || isFloating)
- ? (startY - hiddenY) / (shownY - hiddenY)
+ ? (value - hiddenY) / (shownY - hiddenY)
: 1.f;
t.setAlpha(mImeSourceControl.getLeash(), alpha);
if (mAnimationDirection == DIRECTION_SHOW) {
@@ -560,7 +562,7 @@
if (DEBUG_IME_VISIBILITY) {
EventLog.writeEvent(IMF_IME_REMOTE_ANIM_START,
mStatsToken != null ? mStatsToken.getTag() : ImeTracker.TOKEN_NONE,
- mDisplayId, mAnimationDirection, alpha, startY , endY,
+ mDisplayId, mAnimationDirection, alpha, value, endY,
Objects.toString(mImeSourceControl.getLeash()),
Objects.toString(mImeSourceControl.getInsetsHint()),
Objects.toString(mImeSourceControl.getSurfacePosition()),
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/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index 991fbaf..609e5af 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -87,6 +87,7 @@
import com.android.wm.shell.recents.RecentTasks;
import com.android.wm.shell.recents.RecentTasksController;
import com.android.wm.shell.recents.RecentsTransitionHandler;
+import com.android.wm.shell.recents.TaskStackTransitionObserver;
import com.android.wm.shell.shared.DesktopModeStatus;
import com.android.wm.shell.shared.ShellTransitions;
import com.android.wm.shell.shared.annotations.ShellAnimationThread;
@@ -619,12 +620,13 @@
TaskStackListenerImpl taskStackListener,
ActivityTaskManager activityTaskManager,
Optional<DesktopModeTaskRepository> desktopModeTaskRepository,
+ TaskStackTransitionObserver taskStackTransitionObserver,
@ShellMainThread ShellExecutor mainExecutor
) {
return Optional.ofNullable(
RecentTasksController.create(context, shellInit, shellController,
shellCommandHandler, taskStackListener, activityTaskManager,
- desktopModeTaskRepository, mainExecutor));
+ desktopModeTaskRepository, taskStackTransitionObserver, mainExecutor));
}
@BindsOptionalOf
@@ -924,6 +926,19 @@
}
//
+ // Task Stack
+ //
+
+ @WMSingleton
+ @Provides
+ static TaskStackTransitionObserver provideTaskStackTransitionObserver(
+ Lazy<Transitions> transitions,
+ ShellInit shellInit
+ ) {
+ return new TaskStackTransitionObserver(transitions, shellInit);
+ }
+
+ //
// Misc
//
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index 12bbd51..87bd840 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -121,9 +121,9 @@
*/
@Module(
includes = {
- WMShellBaseModule.class,
- PipModule.class,
- ShellBackAnimationModule.class,
+ WMShellBaseModule.class,
+ PipModule.class,
+ ShellBackAnimationModule.class,
})
public abstract class WMShellModule {
@@ -664,7 +664,8 @@
@Provides
static Object provideIndependentShellComponentsToCreate(
DragAndDropController dragAndDropController,
- Optional<DesktopTasksTransitionObserver> desktopTasksTransitionObserverOptional) {
+ Optional<DesktopTasksTransitionObserver> desktopTasksTransitionObserverOptional
+ ) {
return new Object();
}
}
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/recents/IRecentTasksListener.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasksListener.aidl
index 62d195e..245829e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasksListener.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasksListener.aidl
@@ -42,4 +42,7 @@
* Called when a running task changes.
*/
void onRunningTaskChanged(in RunningTaskInfo taskInfo);
-}
+
+ /** A task has moved to front. */
+ oneway void onTaskMovedToFront(in RunningTaskInfo taskInfo);
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/OWNERS
new file mode 100644
index 0000000..452644b
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/OWNERS
@@ -0,0 +1,6 @@
+# WM shell sub-module task stack owners
+uysalorhan@google.com
+samcackett@google.com
+alexchau@google.com
+silvajordan@google.com
+uwaisashraf@google.com
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
index 9d16246..03c8cf8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
@@ -20,6 +20,7 @@
import static android.content.pm.PackageManager.FEATURE_PC;
import static com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps;
+import static com.android.window.flags.Flags.enableTaskStackObserverInShell;
import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_RECENT_TASKS;
import android.app.ActivityManager;
@@ -57,6 +58,7 @@
import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
+import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.util.GroupedRecentTaskInfo;
import com.android.wm.shell.util.SplitBounds;
@@ -73,7 +75,8 @@
* Manages the recent task list from the system, caching it as necessary.
*/
public class RecentTasksController implements TaskStackListenerCallback,
- RemoteCallable<RecentTasksController>, DesktopModeTaskRepository.ActiveTasksListener {
+ RemoteCallable<RecentTasksController>, DesktopModeTaskRepository.ActiveTasksListener,
+ TaskStackTransitionObserver.TaskStackTransitionObserverListener {
private static final String TAG = RecentTasksController.class.getSimpleName();
private final Context mContext;
@@ -84,6 +87,7 @@
private final TaskStackListenerImpl mTaskStackListener;
private final RecentTasksImpl mImpl = new RecentTasksImpl();
private final ActivityTaskManager mActivityTaskManager;
+ private final TaskStackTransitionObserver mTaskStackTransitionObserver;
private RecentsTransitionHandler mTransitionHandler = null;
private IRecentTasksListener mListener;
private final boolean mPcFeatureEnabled;
@@ -112,13 +116,15 @@
TaskStackListenerImpl taskStackListener,
ActivityTaskManager activityTaskManager,
Optional<DesktopModeTaskRepository> desktopModeTaskRepository,
+ TaskStackTransitionObserver taskStackTransitionObserver,
@ShellMainThread ShellExecutor mainExecutor
) {
if (!context.getResources().getBoolean(com.android.internal.R.bool.config_hasRecents)) {
return null;
}
return new RecentTasksController(context, shellInit, shellController, shellCommandHandler,
- taskStackListener, activityTaskManager, desktopModeTaskRepository, mainExecutor);
+ taskStackListener, activityTaskManager, desktopModeTaskRepository,
+ taskStackTransitionObserver, mainExecutor);
}
RecentTasksController(Context context,
@@ -128,6 +134,7 @@
TaskStackListenerImpl taskStackListener,
ActivityTaskManager activityTaskManager,
Optional<DesktopModeTaskRepository> desktopModeTaskRepository,
+ TaskStackTransitionObserver taskStackTransitionObserver,
ShellExecutor mainExecutor) {
mContext = context;
mShellController = shellController;
@@ -136,6 +143,7 @@
mPcFeatureEnabled = mContext.getPackageManager().hasSystemFeature(FEATURE_PC);
mTaskStackListener = taskStackListener;
mDesktopModeTaskRepository = desktopModeTaskRepository;
+ mTaskStackTransitionObserver = taskStackTransitionObserver;
mMainExecutor = mainExecutor;
shellInit.addInitCallback(this::onInit, this);
}
@@ -154,6 +162,10 @@
mShellCommandHandler.addDumpCallback(this::dump, this);
mTaskStackListener.addListener(this);
mDesktopModeTaskRepository.ifPresent(it -> it.addActiveTaskListener(this));
+ if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+ mTaskStackTransitionObserver.addTaskStackTransitionObserverListener(this,
+ mMainExecutor);
+ }
}
void setTransitionHandler(RecentsTransitionHandler handler) {
@@ -267,6 +279,12 @@
notifyRecentTasksChanged();
}
+ @Override
+ public void onTaskMovedToFrontThroughTransition(
+ ActivityManager.RunningTaskInfo runningTaskInfo) {
+ notifyTaskMovedToFront(runningTaskInfo);
+ }
+
@VisibleForTesting
void notifyRecentTasksChanged() {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENT_TASKS, "Notify recent tasks changed");
@@ -328,6 +346,19 @@
}
}
+ private void notifyTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) {
+ if (mListener == null
+ || !enableTaskStackObserverInShell()
+ || taskInfo.realActivity == null) {
+ return;
+ }
+ try {
+ mListener.onTaskMovedToFront(taskInfo);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed call onTaskMovedToFront", e);
+ }
+ }
+
private boolean shouldEnableRunningTasksForDesktopMode() {
return mPcFeatureEnabled
|| (DesktopModeStatus.canEnterDesktopMode(mContext)
@@ -464,6 +495,7 @@
}
return null;
}
+
public void dump(@NonNull PrintWriter pw, String prefix) {
final String innerPrefix = prefix + " ";
pw.println(prefix + TAG);
@@ -547,6 +579,11 @@
public void onRunningTaskChanged(ActivityManager.RunningTaskInfo taskInfo) {
mListener.call(l -> l.onRunningTaskChanged(taskInfo));
}
+
+ @Override
+ public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) {
+ mListener.call(l -> l.onTaskMovedToFront(taskInfo));
+ }
};
public IRecentTasksImpl(RecentTasksController controller) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/TaskStackTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/TaskStackTransitionObserver.kt
new file mode 100644
index 0000000..7c5f10a
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/TaskStackTransitionObserver.kt
@@ -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.wm.shell.recents
+
+import android.app.ActivityManager.RunningTaskInfo
+import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
+import android.os.IBinder
+import android.util.ArrayMap
+import android.view.SurfaceControl
+import android.view.WindowManager
+import android.window.TransitionInfo
+import com.android.window.flags.Flags.enableTaskStackObserverInShell
+import com.android.wm.shell.shared.TransitionUtil
+import com.android.wm.shell.sysui.ShellInit
+import com.android.wm.shell.transition.Transitions
+import dagger.Lazy
+import java.util.concurrent.Executor
+
+/**
+ * A [Transitions.TransitionObserver] that observes shell transitions and sends updates to listeners
+ * about task stack changes.
+ *
+ * TODO(346588978) Move split/pip signals here as well so that launcher don't need to handle it
+ */
+class TaskStackTransitionObserver(
+ private val transitions: Lazy<Transitions>,
+ shellInit: ShellInit
+) : Transitions.TransitionObserver {
+
+ private val transitionToTransitionChanges: MutableMap<IBinder, TransitionChanges> =
+ mutableMapOf()
+ private val taskStackTransitionObserverListeners =
+ ArrayMap<TaskStackTransitionObserverListener, Executor>()
+
+ init {
+ if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+ shellInit.addInitCallback(::onInit, this)
+ }
+ }
+
+ fun onInit() {
+ transitions.get().registerObserver(this)
+ }
+
+ override fun onTransitionReady(
+ transition: IBinder,
+ info: TransitionInfo,
+ startTransaction: SurfaceControl.Transaction,
+ finishTransaction: SurfaceControl.Transaction
+ ) {
+ if (enableTaskStackObserverInShell()) {
+ val taskInfoList = mutableListOf<RunningTaskInfo>()
+ val transitionTypeList = mutableListOf<Int>()
+
+ for (change in info.changes) {
+ if (change.flags and TransitionInfo.FLAG_IS_WALLPAPER != 0) {
+ continue
+ }
+
+ val taskInfo = change.taskInfo
+ if (taskInfo == null || taskInfo.taskId == -1) {
+ continue
+ }
+
+ if (change.mode == WindowManager.TRANSIT_OPEN) {
+ change.taskInfo?.let { taskInfoList.add(it) }
+ transitionTypeList.add(change.mode)
+ }
+ }
+ transitionToTransitionChanges.put(
+ transition,
+ TransitionChanges(taskInfoList, transitionTypeList)
+ )
+ }
+ }
+
+ override fun onTransitionStarting(transition: IBinder) {}
+
+ override fun onTransitionMerged(merged: IBinder, playing: IBinder) {}
+
+ override fun onTransitionFinished(transition: IBinder, aborted: Boolean) {
+ val taskInfoList =
+ transitionToTransitionChanges.getOrDefault(transition, TransitionChanges()).taskInfoList
+ val typeList =
+ transitionToTransitionChanges
+ .getOrDefault(transition, TransitionChanges())
+ .transitionTypeList
+ transitionToTransitionChanges.remove(transition)
+
+ for ((index, taskInfo) in taskInfoList.withIndex()) {
+ if (
+ TransitionUtil.isOpeningType(typeList[index]) &&
+ taskInfo.windowingMode == WINDOWING_MODE_FREEFORM
+ ) {
+ notifyTaskStackTransitionObserverListeners(taskInfo)
+ }
+ }
+ }
+
+ fun addTaskStackTransitionObserverListener(
+ taskStackTransitionObserverListener: TaskStackTransitionObserverListener,
+ executor: Executor
+ ) {
+ taskStackTransitionObserverListeners[taskStackTransitionObserverListener] = executor
+ }
+
+ fun removeTaskStackTransitionObserverListener(
+ taskStackTransitionObserverListener: TaskStackTransitionObserverListener
+ ) {
+ taskStackTransitionObserverListeners.remove(taskStackTransitionObserverListener)
+ }
+
+ private fun notifyTaskStackTransitionObserverListeners(taskInfo: RunningTaskInfo) {
+ taskStackTransitionObserverListeners.forEach { (listener, executor) ->
+ executor.execute { listener.onTaskMovedToFrontThroughTransition(taskInfo) }
+ }
+ }
+
+ /** Listener to use to get updates regarding task stack from this observer */
+ interface TaskStackTransitionObserverListener {
+ /** Called when a task is moved to front. */
+ fun onTaskMovedToFrontThroughTransition(taskInfo: RunningTaskInfo) {}
+ }
+
+ private data class TransitionChanges(
+ val taskInfoList: MutableList<RunningTaskInfo> = ArrayList(),
+ val transitionTypeList: MutableList<Int> = ArrayList()
+ )
+}
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/flicker/splitscreen/Android.bp b/libs/WindowManager/Shell/tests/flicker/splitscreen/Android.bp
index f813b0d..0fe7a16b 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/Android.bp
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/Android.bp
@@ -65,9 +65,11 @@
android_test {
name: "WMShellFlickerTestsSplitScreenGroup2",
+ defaults: ["WMShellFlickerTestsDefault"],
manifest: "AndroidManifest.xml",
package_name: "com.android.wm.shell.flicker.splitscreen",
instrumentation_target_package: "com.android.wm.shell.flicker.splitscreen",
+ test_config_template: "AndroidTestTemplate.xml",
srcs: [
":WMShellFlickerTestsSplitScreenBase-src",
":WMShellFlickerTestsSplitScreenGroup2-src",
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/MultipleShowImeRequestsInSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/MultipleShowImeRequestsInSplitScreen.kt
new file mode 100644
index 0000000..dad5db9
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/MultipleShowImeRequestsInSplitScreen.kt
@@ -0,0 +1,67 @@
+/*
+ * 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.wm.shell.flicker.splitscreen
+
+import android.platform.test.annotations.Presubmit
+import android.tools.Rotation
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.splitscreen.benchmark.MultipleShowImeRequestsInSplitScreenBenchmark
+import com.android.wm.shell.flicker.utils.ICommonAssertions
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test quick switch between two split pairs.
+ *
+ * To run this test: `atest WMShellFlickerTestsSplitScreenGroup2:MultipleShowImeRequestsInSplitScreen`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class MultipleShowImeRequestsInSplitScreen(override val flicker: LegacyFlickerTest) :
+ MultipleShowImeRequestsInSplitScreenBenchmark(flicker), ICommonAssertions {
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
+ }
+
+ @Presubmit
+ @Test
+ fun imeLayerAlwaysVisible() =
+ flicker.assertLayers {
+ this.isVisible(ComponentNameMatcher.IME)
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests(
+ supportedRotations = listOf(Rotation.ROTATION_0)
+ )
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt
index 9045364..d349988 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt
@@ -47,7 +47,7 @@
* To run this test: `atest WMShellFlickerTestsSplitScreen:UnlockKeyguardToSplitScreen`
*/
@RequiresDevice
-@Postsubmit
+@FlakyTest(bugId = 293578017)
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@@ -61,7 +61,6 @@
}
@Test
- @FlakyTest(bugId = 293578017)
override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
super.visibleLayersShownMoreThanOneConsecutiveEntry()
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/MultipleShowImeRequestsInSplitScreenBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/MultipleShowImeRequestsInSplitScreenBenchmark.kt
new file mode 100644
index 0000000..2492531
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/MultipleShowImeRequestsInSplitScreenBenchmark.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.wm.shell.flicker.splitscreen.benchmark
+
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.helpers.ImeAppHelper
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+abstract class MultipleShowImeRequestsInSplitScreenBenchmark(
+ override val flicker: LegacyFlickerTest
+) : SplitScreenBase(flicker) {
+ override val primaryApp = ImeAppHelper(instrumentation)
+ override val defaultTeardown: FlickerBuilder.() -> Unit
+ get() = {
+ teardown {
+ primaryApp.closeIME(wmHelper)
+ super.defaultTeardown
+ }
+ }
+
+ protected val thisTransition: FlickerBuilder.() -> Unit
+ get() = {
+ setup {
+ SplitScreenUtils.enterSplit(
+ wmHelper,
+ tapl,
+ device,
+ primaryApp,
+ secondaryApp,
+ flicker.scenario.startRotation
+ )
+ // initially open the IME
+ primaryApp.openIME(wmHelper)
+ }
+ transitions {
+ for (i in 1..OPEN_IME_COUNT) {
+ primaryApp.openIME(wmHelper)
+ }
+ }
+ }
+
+ companion object {
+ const val OPEN_IME_COUNT = 30
+
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SplitScreenBase.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SplitScreenBase.kt
index 4b10603..51074f6 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SplitScreenBase.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SplitScreenBase.kt
@@ -25,7 +25,7 @@
abstract class SplitScreenBase(flicker: LegacyFlickerTest) : BaseBenchmarkTest(flicker) {
protected val context: Context = instrumentation.context
- protected val primaryApp = SplitScreenUtils.getPrimary(instrumentation)
+ protected open val primaryApp = SplitScreenUtils.getPrimary(instrumentation)
protected val secondaryApp = SplitScreenUtils.getSecondary(instrumentation)
protected open val defaultSetup: FlickerBuilder.() -> Unit = {
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..0d3cd10 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
@@ -40,14 +40,14 @@
import com.android.wm.shell.common.ShellExecutor
import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.EnterReason
import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ExitReason
-import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_EXIT_DESKTOP_MODE_HANDLE_MENU_BUTTON
-import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_EXIT_DESKTOP_MODE_KEYBOARD_SHORTCUT
-import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_EXIT_DESKTOP_MODE_TASK_DRAG
-import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_EXIT_DESKTOP_MODE_UNKNOWN
import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_ENTER_DESKTOP_FROM_APP_FROM_OVERVIEW
import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_ENTER_DESKTOP_FROM_APP_HANDLE_MENU_BUTTON
import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_ENTER_DESKTOP_FROM_KEYBOARD_SHORTCUT
import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_ENTER_DESKTOP_FROM_UNKNOWN
+import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_EXIT_DESKTOP_MODE_HANDLE_MENU_BUTTON
+import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_EXIT_DESKTOP_MODE_KEYBOARD_SHORTCUT
+import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_EXIT_DESKTOP_MODE_TASK_DRAG
+import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_EXIT_DESKTOP_MODE_UNKNOWN
import com.android.wm.shell.shared.DesktopModeStatus
import com.android.wm.shell.sysui.ShellInit
import com.android.wm.shell.transition.TransitionInfoBuilder
@@ -78,410 +78,397 @@
@RunWith(AndroidTestingRunner::class)
class DesktopModeLoggerTransitionObserverTest {
- @JvmField
- @Rule
- val extendedMockitoRule =
- ExtendedMockitoRule.Builder(this)
- .mockStatic(DesktopModeEventLogger::class.java)
- .mockStatic(DesktopModeStatus::class.java)
- .build()!!
+ @JvmField
+ @Rule
+ val extendedMockitoRule =
+ ExtendedMockitoRule.Builder(this)
+ .mockStatic(DesktopModeEventLogger::class.java)
+ .mockStatic(DesktopModeStatus::class.java)
+ .build()!!
- @Mock lateinit var testExecutor: ShellExecutor
- @Mock private lateinit var mockShellInit: ShellInit
- @Mock private lateinit var transitions: Transitions
- @Mock private lateinit var context: Context
+ @Mock lateinit var testExecutor: ShellExecutor
+ @Mock private lateinit var mockShellInit: ShellInit
+ @Mock private lateinit var transitions: Transitions
+ @Mock private lateinit var context: Context
- private lateinit var transitionObserver: DesktopModeLoggerTransitionObserver
- private lateinit var shellInit: ShellInit
- private lateinit var desktopModeEventLogger: DesktopModeEventLogger
+ private lateinit var transitionObserver: DesktopModeLoggerTransitionObserver
+ private lateinit var shellInit: ShellInit
+ private lateinit var desktopModeEventLogger: DesktopModeEventLogger
- @Before
- fun setup() {
- doReturn(true).`when` { DesktopModeStatus.canEnterDesktopMode(any()) }
- shellInit = Mockito.spy(ShellInit(testExecutor))
- desktopModeEventLogger = mock(DesktopModeEventLogger::class.java)
+ @Before
+ fun setup() {
+ doReturn(true).`when` { DesktopModeStatus.canEnterDesktopMode(any()) }
+ shellInit = Mockito.spy(ShellInit(testExecutor))
+ desktopModeEventLogger = mock(DesktopModeEventLogger::class.java)
- transitionObserver =
- DesktopModeLoggerTransitionObserver(
- context,
- mockShellInit,
- transitions,
- desktopModeEventLogger
- )
- if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- val initRunnableCaptor = ArgumentCaptor.forClass(Runnable::class.java)
- verify(mockShellInit)
- .addInitCallback(initRunnableCaptor.capture(), same(transitionObserver))
- initRunnableCaptor.value.run()
- } else {
- transitionObserver.onInit()
- }
+ transitionObserver =
+ DesktopModeLoggerTransitionObserver(
+ context, mockShellInit, transitions, desktopModeEventLogger)
+ if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+ val initRunnableCaptor = ArgumentCaptor.forClass(Runnable::class.java)
+ verify(mockShellInit).addInitCallback(initRunnableCaptor.capture(), same(transitionObserver))
+ initRunnableCaptor.value.run()
+ } else {
+ transitionObserver.onInit()
+ }
+ }
+
+ @Test
+ fun testRegistersObserverAtInit() {
+ verify(transitions).registerObserver(same(transitionObserver))
+ }
+
+ @Test
+ fun transitOpen_notFreeformWindow_doesNotLogTaskAddedOrSessionEnter() {
+ val change = createChange(TRANSIT_OPEN, createTaskInfo(1, WINDOWING_MODE_FULLSCREEN))
+ val transitionInfo = TransitionInfoBuilder(TRANSIT_OPEN, 0).addChange(change).build()
+
+ callOnTransitionReady(transitionInfo)
+
+ verify(desktopModeEventLogger, never()).logSessionEnter(any(), any())
+ verify(desktopModeEventLogger, never()).logTaskAdded(any(), any())
+ }
+
+ @Test
+ fun transitOpen_logTaskAddedAndEnterReasonAppFreeformIntent() {
+ val change = createChange(TRANSIT_OPEN, createTaskInfo(1, WINDOWING_MODE_FREEFORM))
+ val transitionInfo = TransitionInfoBuilder(TRANSIT_OPEN, 0).addChange(change).build()
+
+ callOnTransitionReady(transitionInfo)
+ val sessionId = transitionObserver.getLoggerSessionId()
+
+ assertThat(sessionId).isNotNull()
+ verify(desktopModeEventLogger, times(1))
+ .logSessionEnter(eq(sessionId!!), eq(EnterReason.APP_FREEFORM_INTENT))
+ verify(desktopModeEventLogger, times(1)).logTaskAdded(eq(sessionId), any())
+ verifyZeroInteractions(desktopModeEventLogger)
+ }
+
+ @Test
+ fun transitEndDragToDesktop_logTaskAddedAndEnterReasonAppHandleDrag() {
+ val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(1, WINDOWING_MODE_FREEFORM))
+ // task change is finalised when drag ends
+ val transitionInfo =
+ TransitionInfoBuilder(Transitions.TRANSIT_DESKTOP_MODE_END_DRAG_TO_DESKTOP, 0)
+ .addChange(change)
+ .build()
+
+ callOnTransitionReady(transitionInfo)
+ val sessionId = transitionObserver.getLoggerSessionId()
+
+ assertThat(sessionId).isNotNull()
+ verify(desktopModeEventLogger, times(1))
+ .logSessionEnter(eq(sessionId!!), eq(EnterReason.APP_HANDLE_DRAG))
+ verify(desktopModeEventLogger, times(1)).logTaskAdded(eq(sessionId), any())
+ verifyZeroInteractions(desktopModeEventLogger)
+ }
+
+ @Test
+ fun transitEnterDesktopByButtonTap_logTaskAddedAndEnterReasonButtonTap() {
+ val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(1, WINDOWING_MODE_FREEFORM))
+ val transitionInfo =
+ TransitionInfoBuilder(TRANSIT_ENTER_DESKTOP_FROM_APP_HANDLE_MENU_BUTTON, 0)
+ .addChange(change)
+ .build()
+
+ callOnTransitionReady(transitionInfo)
+ val sessionId = transitionObserver.getLoggerSessionId()
+
+ assertThat(sessionId).isNotNull()
+ verify(desktopModeEventLogger, times(1))
+ .logSessionEnter(eq(sessionId!!), eq(EnterReason.APP_HANDLE_MENU_BUTTON))
+ verify(desktopModeEventLogger, times(1)).logTaskAdded(eq(sessionId), any())
+ verifyZeroInteractions(desktopModeEventLogger)
+ }
+
+ @Test
+ fun transitEnterDesktopFromAppFromOverview_logTaskAddedAndEnterReasonUnknown() {
+ val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(1, WINDOWING_MODE_FREEFORM))
+ val transitionInfo =
+ TransitionInfoBuilder(TRANSIT_ENTER_DESKTOP_FROM_APP_FROM_OVERVIEW, 0)
+ .addChange(change)
+ .build()
+
+ callOnTransitionReady(transitionInfo)
+ val sessionId = transitionObserver.getLoggerSessionId()
+
+ assertThat(sessionId).isNotNull()
+ verify(desktopModeEventLogger, times(1))
+ .logSessionEnter(eq(sessionId!!), eq(EnterReason.APP_FROM_OVERVIEW))
+ verify(desktopModeEventLogger, times(1)).logTaskAdded(eq(sessionId), any())
+ verifyZeroInteractions(desktopModeEventLogger)
+ }
+
+ @Test
+ fun transitEnterDesktopFromKeyboardShortcut_logTaskAddedAndEnterReasonKeyboardShortcut() {
+ val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(1, WINDOWING_MODE_FREEFORM))
+ val transitionInfo =
+ TransitionInfoBuilder(TRANSIT_ENTER_DESKTOP_FROM_KEYBOARD_SHORTCUT, 0)
+ .addChange(change)
+ .build()
+
+ callOnTransitionReady(transitionInfo)
+ val sessionId = transitionObserver.getLoggerSessionId()
+
+ assertThat(sessionId).isNotNull()
+ verify(desktopModeEventLogger, times(1))
+ .logSessionEnter(eq(sessionId!!), eq(EnterReason.KEYBOARD_SHORTCUT_ENTER))
+ verify(desktopModeEventLogger, times(1)).logTaskAdded(eq(sessionId), any())
+ verifyZeroInteractions(desktopModeEventLogger)
+ }
+
+ @Test
+ fun transitEnterDesktopFromUnknown_logTaskAddedAndEnterReasonUnknown() {
+ val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(1, WINDOWING_MODE_FREEFORM))
+ val transitionInfo =
+ TransitionInfoBuilder(TRANSIT_ENTER_DESKTOP_FROM_UNKNOWN, 0).addChange(change).build()
+
+ callOnTransitionReady(transitionInfo)
+ val sessionId = transitionObserver.getLoggerSessionId()
+
+ assertThat(sessionId).isNotNull()
+ verify(desktopModeEventLogger, times(1))
+ .logSessionEnter(eq(sessionId!!), eq(EnterReason.UNKNOWN_ENTER))
+ verify(desktopModeEventLogger, times(1)).logTaskAdded(eq(sessionId), any())
+ verifyZeroInteractions(desktopModeEventLogger)
+ }
+
+ @Test
+ fun transitWake_logTaskAddedAndEnterReasonScreenOn() {
+ val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(1, WINDOWING_MODE_FREEFORM))
+ val transitionInfo = TransitionInfoBuilder(TRANSIT_WAKE, 0).addChange(change).build()
+
+ callOnTransitionReady(transitionInfo)
+ val sessionId = transitionObserver.getLoggerSessionId()
+
+ assertThat(sessionId).isNotNull()
+ verify(desktopModeEventLogger, times(1))
+ .logSessionEnter(eq(sessionId!!), eq(EnterReason.SCREEN_ON))
+ verify(desktopModeEventLogger, times(1)).logTaskAdded(eq(sessionId), any())
+ verifyZeroInteractions(desktopModeEventLogger)
+ }
+
+ @Test
+ fun transitSleep_logTaskAddedAndExitReasonScreenOff_sessionIdNull() {
+ val sessionId = 1
+ // add a freeform task
+ transitionObserver.addTaskInfosToCachedMap(createTaskInfo(1, WINDOWING_MODE_FREEFORM))
+ transitionObserver.setLoggerSessionId(sessionId)
+
+ val transitionInfo = TransitionInfoBuilder(TRANSIT_SLEEP).build()
+ callOnTransitionReady(transitionInfo)
+
+ verify(desktopModeEventLogger, times(1)).logTaskRemoved(eq(sessionId), any())
+ verify(desktopModeEventLogger, times(1))
+ .logSessionExit(eq(sessionId), eq(ExitReason.SCREEN_OFF))
+ verifyZeroInteractions(desktopModeEventLogger)
+ assertThat(transitionObserver.getLoggerSessionId()).isNull()
+ }
+
+ @Test
+ fun transitExitDesktopTaskDrag_logTaskRemovedAndExitReasonDragToExit_sessionIdNull() {
+ val sessionId = 1
+ // add a freeform task
+ transitionObserver.addTaskInfosToCachedMap(createTaskInfo(1, WINDOWING_MODE_FREEFORM))
+ transitionObserver.setLoggerSessionId(sessionId)
+
+ // window mode changing from FREEFORM to FULLSCREEN
+ val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(1, WINDOWING_MODE_FULLSCREEN))
+ val transitionInfo =
+ TransitionInfoBuilder(TRANSIT_EXIT_DESKTOP_MODE_TASK_DRAG).addChange(change).build()
+ callOnTransitionReady(transitionInfo)
+
+ verify(desktopModeEventLogger, times(1)).logTaskRemoved(eq(sessionId), any())
+ verify(desktopModeEventLogger, times(1))
+ .logSessionExit(eq(sessionId), eq(ExitReason.DRAG_TO_EXIT))
+ verifyZeroInteractions(desktopModeEventLogger)
+ assertThat(transitionObserver.getLoggerSessionId()).isNull()
+ }
+
+ @Test
+ fun transitExitDesktopAppHandleButton_logTaskRemovedAndExitReasonButton_sessionIdNull() {
+ val sessionId = 1
+ // add a freeform task
+ transitionObserver.addTaskInfosToCachedMap(createTaskInfo(1, WINDOWING_MODE_FREEFORM))
+ transitionObserver.setLoggerSessionId(sessionId)
+
+ // window mode changing from FREEFORM to FULLSCREEN
+ val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(1, WINDOWING_MODE_FULLSCREEN))
+ val transitionInfo =
+ TransitionInfoBuilder(TRANSIT_EXIT_DESKTOP_MODE_HANDLE_MENU_BUTTON)
+ .addChange(change)
+ .build()
+ callOnTransitionReady(transitionInfo)
+
+ verify(desktopModeEventLogger, times(1)).logTaskRemoved(eq(sessionId), any())
+ verify(desktopModeEventLogger, times(1))
+ .logSessionExit(eq(sessionId), eq(ExitReason.APP_HANDLE_MENU_BUTTON_EXIT))
+ verifyZeroInteractions(desktopModeEventLogger)
+ assertThat(transitionObserver.getLoggerSessionId()).isNull()
+ }
+
+ @Test
+ fun transitExitDesktopUsingKeyboard_logTaskRemovedAndExitReasonKeyboard_sessionIdNull() {
+ val sessionId = 1
+ // add a freeform task
+ transitionObserver.addTaskInfosToCachedMap(createTaskInfo(1, WINDOWING_MODE_FREEFORM))
+ transitionObserver.setLoggerSessionId(sessionId)
+
+ // window mode changing from FREEFORM to FULLSCREEN
+ val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(1, WINDOWING_MODE_FULLSCREEN))
+ val transitionInfo =
+ TransitionInfoBuilder(TRANSIT_EXIT_DESKTOP_MODE_KEYBOARD_SHORTCUT).addChange(change).build()
+ callOnTransitionReady(transitionInfo)
+
+ verify(desktopModeEventLogger, times(1)).logTaskRemoved(eq(sessionId), any())
+ verify(desktopModeEventLogger, times(1))
+ .logSessionExit(eq(sessionId), eq(ExitReason.KEYBOARD_SHORTCUT_EXIT))
+ verifyZeroInteractions(desktopModeEventLogger)
+ assertThat(transitionObserver.getLoggerSessionId()).isNull()
+ }
+
+ @Test
+ fun transitExitDesktopUnknown_logTaskRemovedAndExitReasonUnknown_sessionIdNull() {
+ val sessionId = 1
+ // add a freeform task
+ transitionObserver.addTaskInfosToCachedMap(createTaskInfo(1, WINDOWING_MODE_FREEFORM))
+ transitionObserver.setLoggerSessionId(sessionId)
+
+ // window mode changing from FREEFORM to FULLSCREEN
+ val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(1, WINDOWING_MODE_FULLSCREEN))
+ val transitionInfo =
+ TransitionInfoBuilder(TRANSIT_EXIT_DESKTOP_MODE_UNKNOWN).addChange(change).build()
+ callOnTransitionReady(transitionInfo)
+
+ verify(desktopModeEventLogger, times(1)).logTaskRemoved(eq(sessionId), any())
+ verify(desktopModeEventLogger, times(1))
+ .logSessionExit(eq(sessionId), eq(ExitReason.UNKNOWN_EXIT))
+ verifyZeroInteractions(desktopModeEventLogger)
+ assertThat(transitionObserver.getLoggerSessionId()).isNull()
+ }
+
+ @Test
+ fun transitToFrontWithFlagRecents_logTaskRemovedAndExitReasonOverview_sessionIdNull() {
+ val sessionId = 1
+ // add a freeform task
+ transitionObserver.addTaskInfosToCachedMap(createTaskInfo(1, WINDOWING_MODE_FREEFORM))
+ transitionObserver.setLoggerSessionId(sessionId)
+
+ // recents transition
+ val change = createChange(TRANSIT_TO_BACK, createTaskInfo(1, WINDOWING_MODE_FREEFORM))
+ val transitionInfo =
+ TransitionInfoBuilder(TRANSIT_TO_FRONT, TRANSIT_FLAG_IS_RECENTS).addChange(change).build()
+ callOnTransitionReady(transitionInfo)
+
+ verify(desktopModeEventLogger, times(1)).logTaskRemoved(eq(sessionId), any())
+ verify(desktopModeEventLogger, times(1))
+ .logSessionExit(eq(sessionId), eq(ExitReason.RETURN_HOME_OR_OVERVIEW))
+ verifyZeroInteractions(desktopModeEventLogger)
+ assertThat(transitionObserver.getLoggerSessionId()).isNull()
+ }
+
+ @Test
+ fun transitClose_logTaskRemovedAndExitReasonTaskFinished_sessionIdNull() {
+ val sessionId = 1
+ // add a freeform task
+ transitionObserver.addTaskInfosToCachedMap(createTaskInfo(1, WINDOWING_MODE_FREEFORM))
+ transitionObserver.setLoggerSessionId(sessionId)
+
+ // task closing
+ val change = createChange(TRANSIT_CLOSE, createTaskInfo(1, WINDOWING_MODE_FULLSCREEN))
+ val transitionInfo = TransitionInfoBuilder(TRANSIT_CLOSE).addChange(change).build()
+ callOnTransitionReady(transitionInfo)
+
+ verify(desktopModeEventLogger, times(1)).logTaskRemoved(eq(sessionId), any())
+ verify(desktopModeEventLogger, times(1))
+ .logSessionExit(eq(sessionId), eq(ExitReason.TASK_FINISHED))
+ verifyZeroInteractions(desktopModeEventLogger)
+ assertThat(transitionObserver.getLoggerSessionId()).isNull()
+ }
+
+ @Test
+ fun sessionExitByRecents_cancelledAnimation_sessionRestored() {
+ val sessionId = 1
+ // add a freeform task to an existing session
+ transitionObserver.addTaskInfosToCachedMap(createTaskInfo(1, WINDOWING_MODE_FREEFORM))
+ transitionObserver.setLoggerSessionId(sessionId)
+
+ // recents transition sent freeform window to back
+ val change = createChange(TRANSIT_TO_BACK, createTaskInfo(1, WINDOWING_MODE_FREEFORM))
+ val transitionInfo1 =
+ TransitionInfoBuilder(TRANSIT_TO_FRONT, TRANSIT_FLAG_IS_RECENTS).addChange(change).build()
+ callOnTransitionReady(transitionInfo1)
+ verify(desktopModeEventLogger, times(1)).logTaskRemoved(eq(sessionId), any())
+ verify(desktopModeEventLogger, times(1))
+ .logSessionExit(eq(sessionId), eq(ExitReason.RETURN_HOME_OR_OVERVIEW))
+ assertThat(transitionObserver.getLoggerSessionId()).isNull()
+
+ val transitionInfo2 = TransitionInfoBuilder(TRANSIT_NONE).build()
+ callOnTransitionReady(transitionInfo2)
+
+ verify(desktopModeEventLogger, times(1)).logSessionEnter(any(), any())
+ verify(desktopModeEventLogger, times(1)).logTaskAdded(any(), any())
+ }
+
+ @Test
+ fun sessionAlreadyStarted_newFreeformTaskAdded_logsTaskAdded() {
+ val sessionId = 1
+ // add an existing freeform task
+ transitionObserver.addTaskInfosToCachedMap(createTaskInfo(1, WINDOWING_MODE_FREEFORM))
+ transitionObserver.setLoggerSessionId(sessionId)
+
+ // new freeform task added
+ val change = createChange(TRANSIT_OPEN, createTaskInfo(2, WINDOWING_MODE_FREEFORM))
+ val transitionInfo = TransitionInfoBuilder(TRANSIT_OPEN, 0).addChange(change).build()
+ callOnTransitionReady(transitionInfo)
+
+ verify(desktopModeEventLogger, times(1)).logTaskAdded(eq(sessionId), any())
+ verify(desktopModeEventLogger, never()).logSessionEnter(any(), any())
+ }
+
+ @Test
+ fun sessionAlreadyStarted_freeformTaskRemoved_logsTaskRemoved() {
+ val sessionId = 1
+ // add two existing freeform tasks
+ transitionObserver.addTaskInfosToCachedMap(createTaskInfo(1, WINDOWING_MODE_FREEFORM))
+ transitionObserver.addTaskInfosToCachedMap(createTaskInfo(2, WINDOWING_MODE_FREEFORM))
+ transitionObserver.setLoggerSessionId(sessionId)
+
+ // new freeform task added
+ val change = createChange(TRANSIT_CLOSE, createTaskInfo(2, WINDOWING_MODE_FREEFORM))
+ val transitionInfo = TransitionInfoBuilder(TRANSIT_CLOSE, 0).addChange(change).build()
+ callOnTransitionReady(transitionInfo)
+
+ verify(desktopModeEventLogger, times(1)).logTaskRemoved(eq(sessionId), any())
+ verify(desktopModeEventLogger, never()).logSessionExit(any(), any())
+ }
+
+ /** Simulate calling the onTransitionReady() method */
+ private fun callOnTransitionReady(transitionInfo: TransitionInfo) {
+ val transition = mock(IBinder::class.java)
+ val startT = mock(SurfaceControl.Transaction::class.java)
+ val finishT = mock(SurfaceControl.Transaction::class.java)
+
+ transitionObserver.onTransitionReady(transition, transitionInfo, startT, finishT)
+ }
+
+ companion object {
+ fun createTaskInfo(taskId: Int, windowMode: Int): ActivityManager.RunningTaskInfo {
+ val taskInfo = ActivityManager.RunningTaskInfo()
+ taskInfo.taskId = taskId
+ taskInfo.configuration.windowConfiguration.windowingMode = windowMode
+
+ return taskInfo
}
- @Test
- fun testRegistersObserverAtInit() {
- verify(transitions).registerObserver(same(transitionObserver))
+ fun createChange(mode: Int, taskInfo: ActivityManager.RunningTaskInfo): Change {
+ val change =
+ Change(
+ WindowContainerToken(mock(IWindowContainerToken::class.java)),
+ mock(SurfaceControl::class.java))
+ change.mode = mode
+ change.taskInfo = taskInfo
+ return change
}
-
- @Test
- fun transitOpen_notFreeformWindow_doesNotLogTaskAddedOrSessionEnter() {
- val change = createChange(TRANSIT_OPEN, createTaskInfo(1, WINDOWING_MODE_FULLSCREEN))
- val transitionInfo = TransitionInfoBuilder(TRANSIT_OPEN, 0).addChange(change).build()
-
- callOnTransitionReady(transitionInfo)
-
- verify(desktopModeEventLogger, never()).logSessionEnter(any(), any())
- verify(desktopModeEventLogger, never()).logTaskAdded(any(), any())
- }
-
- @Test
- fun transitOpen_logTaskAddedAndEnterReasonAppFreeformIntent() {
- val change = createChange(TRANSIT_OPEN, createTaskInfo(1, WINDOWING_MODE_FREEFORM))
- val transitionInfo = TransitionInfoBuilder(TRANSIT_OPEN, 0).addChange(change).build()
-
- callOnTransitionReady(transitionInfo)
- val sessionId = transitionObserver.getLoggerSessionId()
-
- assertThat(sessionId).isNotNull()
- verify(desktopModeEventLogger, times(1))
- .logSessionEnter(eq(sessionId!!), eq(EnterReason.APP_FREEFORM_INTENT))
- verify(desktopModeEventLogger, times(1)).logTaskAdded(eq(sessionId), any())
- verifyZeroInteractions(desktopModeEventLogger)
- }
-
- @Test
- fun transitEndDragToDesktop_logTaskAddedAndEnterReasonAppHandleDrag() {
- val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(1, WINDOWING_MODE_FREEFORM))
- // task change is finalised when drag ends
- val transitionInfo =
- TransitionInfoBuilder(Transitions.TRANSIT_DESKTOP_MODE_END_DRAG_TO_DESKTOP, 0)
- .addChange(change)
- .build()
-
- callOnTransitionReady(transitionInfo)
- val sessionId = transitionObserver.getLoggerSessionId()
-
- assertThat(sessionId).isNotNull()
- verify(desktopModeEventLogger, times(1))
- .logSessionEnter(eq(sessionId!!), eq(EnterReason.APP_HANDLE_DRAG))
- verify(desktopModeEventLogger, times(1)).logTaskAdded(eq(sessionId), any())
- verifyZeroInteractions(desktopModeEventLogger)
- }
-
- @Test
- fun transitEnterDesktopByButtonTap_logTaskAddedAndEnterReasonButtonTap() {
- val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(1, WINDOWING_MODE_FREEFORM))
- val transitionInfo =
- TransitionInfoBuilder(TRANSIT_ENTER_DESKTOP_FROM_APP_HANDLE_MENU_BUTTON, 0)
- .addChange(change)
- .build()
-
- callOnTransitionReady(transitionInfo)
- val sessionId = transitionObserver.getLoggerSessionId()
-
- assertThat(sessionId).isNotNull()
- verify(desktopModeEventLogger, times(1))
- .logSessionEnter(eq(sessionId!!), eq(EnterReason.APP_HANDLE_MENU_BUTTON))
- verify(desktopModeEventLogger, times(1)).logTaskAdded(eq(sessionId), any())
- verifyZeroInteractions(desktopModeEventLogger)
- }
-
- @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 =
- TransitionInfoBuilder(TRANSIT_ENTER_DESKTOP_FROM_APP_FROM_OVERVIEW, 0)
- .addChange(change)
- .build()
-
- callOnTransitionReady(transitionInfo)
- val sessionId = transitionObserver.getLoggerSessionId()
-
- assertThat(sessionId).isNotNull()
- verify(desktopModeEventLogger, times(1))
- .logSessionEnter(eq(sessionId!!), eq(EnterReason.UNKNOWN_ENTER))
- verify(desktopModeEventLogger, times(1)).logTaskAdded(eq(sessionId), any())
- verifyZeroInteractions(desktopModeEventLogger)
- }
-
- @Test
- fun transitEnterDesktopFromKeyboardShortcut_logTaskAddedAndEnterReasonKeyboardShortcut() {
- val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(1, WINDOWING_MODE_FREEFORM))
- val transitionInfo =
- TransitionInfoBuilder(TRANSIT_ENTER_DESKTOP_FROM_KEYBOARD_SHORTCUT, 0)
- .addChange(change)
- .build()
-
- callOnTransitionReady(transitionInfo)
- val sessionId = transitionObserver.getLoggerSessionId()
-
- assertThat(sessionId).isNotNull()
- verify(desktopModeEventLogger, times(1))
- .logSessionEnter(eq(sessionId!!), eq(EnterReason.KEYBOARD_SHORTCUT_ENTER))
- verify(desktopModeEventLogger, times(1)).logTaskAdded(eq(sessionId), any())
- verifyZeroInteractions(desktopModeEventLogger)
- }
-
- @Test
- fun transitEnterDesktopFromUnknown_logTaskAddedAndEnterReasonUnknown() {
- val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(1, WINDOWING_MODE_FREEFORM))
- val transitionInfo =
- TransitionInfoBuilder(TRANSIT_ENTER_DESKTOP_FROM_UNKNOWN, 0).addChange(change).build()
-
- callOnTransitionReady(transitionInfo)
- val sessionId = transitionObserver.getLoggerSessionId()
-
- assertThat(sessionId).isNotNull()
- verify(desktopModeEventLogger, times(1))
- .logSessionEnter(eq(sessionId!!), eq(EnterReason.UNKNOWN_ENTER))
- verify(desktopModeEventLogger, times(1)).logTaskAdded(eq(sessionId), any())
- verifyZeroInteractions(desktopModeEventLogger)
- }
-
- @Test
- fun transitWake_logTaskAddedAndEnterReasonScreenOn() {
- val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(1, WINDOWING_MODE_FREEFORM))
- val transitionInfo = TransitionInfoBuilder(TRANSIT_WAKE, 0).addChange(change).build()
-
- callOnTransitionReady(transitionInfo)
- val sessionId = transitionObserver.getLoggerSessionId()
-
- assertThat(sessionId).isNotNull()
- verify(desktopModeEventLogger, times(1))
- .logSessionEnter(eq(sessionId!!), eq(EnterReason.SCREEN_ON))
- verify(desktopModeEventLogger, times(1)).logTaskAdded(eq(sessionId), any())
- verifyZeroInteractions(desktopModeEventLogger)
- }
-
- @Test
- fun transitSleep_logTaskAddedAndExitReasonScreenOff_sessionIdNull() {
- val sessionId = 1
- // add a freeform task
- transitionObserver.addTaskInfosToCachedMap(createTaskInfo(1, WINDOWING_MODE_FREEFORM))
- transitionObserver.setLoggerSessionId(sessionId)
-
- val transitionInfo = TransitionInfoBuilder(TRANSIT_SLEEP).build()
- callOnTransitionReady(transitionInfo)
-
- verify(desktopModeEventLogger, times(1)).logTaskRemoved(eq(sessionId), any())
- verify(desktopModeEventLogger, times(1))
- .logSessionExit(eq(sessionId), eq(ExitReason.SCREEN_OFF))
- verifyZeroInteractions(desktopModeEventLogger)
- assertThat(transitionObserver.getLoggerSessionId()).isNull()
- }
-
- @Test
- fun transitExitDesktopTaskDrag_logTaskRemovedAndExitReasonDragToExit_sessionIdNull() {
- val sessionId = 1
- // add a freeform task
- transitionObserver.addTaskInfosToCachedMap(createTaskInfo(1, WINDOWING_MODE_FREEFORM))
- transitionObserver.setLoggerSessionId(sessionId)
-
- // window mode changing from FREEFORM to FULLSCREEN
- val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(1, WINDOWING_MODE_FULLSCREEN))
- val transitionInfo =
- TransitionInfoBuilder(TRANSIT_EXIT_DESKTOP_MODE_TASK_DRAG).addChange(change).build()
- callOnTransitionReady(transitionInfo)
-
- verify(desktopModeEventLogger, times(1)).logTaskRemoved(eq(sessionId), any())
- verify(desktopModeEventLogger, times(1))
- .logSessionExit(eq(sessionId), eq(ExitReason.DRAG_TO_EXIT))
- verifyZeroInteractions(desktopModeEventLogger)
- assertThat(transitionObserver.getLoggerSessionId()).isNull()
- }
-
- @Test
- fun transitExitDesktopAppHandleButton_logTaskRemovedAndExitReasonButton_sessionIdNull() {
- val sessionId = 1
- // add a freeform task
- transitionObserver.addTaskInfosToCachedMap(createTaskInfo(1, WINDOWING_MODE_FREEFORM))
- transitionObserver.setLoggerSessionId(sessionId)
-
- // window mode changing from FREEFORM to FULLSCREEN
- val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(1, WINDOWING_MODE_FULLSCREEN))
- val transitionInfo =
- TransitionInfoBuilder(TRANSIT_EXIT_DESKTOP_MODE_HANDLE_MENU_BUTTON)
- .addChange(change)
- .build()
- callOnTransitionReady(transitionInfo)
-
- verify(desktopModeEventLogger, times(1)).logTaskRemoved(eq(sessionId), any())
- verify(desktopModeEventLogger, times(1))
- .logSessionExit(eq(sessionId), eq(ExitReason.APP_HANDLE_MENU_BUTTON_EXIT))
- verifyZeroInteractions(desktopModeEventLogger)
- assertThat(transitionObserver.getLoggerSessionId()).isNull()
- }
-
- @Test
- fun transitExitDesktopUsingKeyboard_logTaskRemovedAndExitReasonKeyboard_sessionIdNull() {
- val sessionId = 1
- // add a freeform task
- transitionObserver.addTaskInfosToCachedMap(createTaskInfo(1, WINDOWING_MODE_FREEFORM))
- transitionObserver.setLoggerSessionId(sessionId)
-
- // window mode changing from FREEFORM to FULLSCREEN
- val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(1, WINDOWING_MODE_FULLSCREEN))
- val transitionInfo =
- TransitionInfoBuilder(TRANSIT_EXIT_DESKTOP_MODE_KEYBOARD_SHORTCUT)
- .addChange(change)
- .build()
- callOnTransitionReady(transitionInfo)
-
- verify(desktopModeEventLogger, times(1)).logTaskRemoved(eq(sessionId), any())
- verify(desktopModeEventLogger, times(1))
- .logSessionExit(eq(sessionId), eq(ExitReason.KEYBOARD_SHORTCUT_EXIT))
- verifyZeroInteractions(desktopModeEventLogger)
- assertThat(transitionObserver.getLoggerSessionId()).isNull()
- }
-
- @Test
- fun transitExitDesktopUnknown_logTaskRemovedAndExitReasonUnknown_sessionIdNull() {
- val sessionId = 1
- // add a freeform task
- transitionObserver.addTaskInfosToCachedMap(createTaskInfo(1, WINDOWING_MODE_FREEFORM))
- transitionObserver.setLoggerSessionId(sessionId)
-
- // window mode changing from FREEFORM to FULLSCREEN
- val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(1, WINDOWING_MODE_FULLSCREEN))
- val transitionInfo =
- TransitionInfoBuilder(TRANSIT_EXIT_DESKTOP_MODE_UNKNOWN).addChange(change).build()
- callOnTransitionReady(transitionInfo)
-
- verify(desktopModeEventLogger, times(1)).logTaskRemoved(eq(sessionId), any())
- verify(desktopModeEventLogger, times(1))
- .logSessionExit(eq(sessionId), eq(ExitReason.UNKNOWN_EXIT))
- verifyZeroInteractions(desktopModeEventLogger)
- assertThat(transitionObserver.getLoggerSessionId()).isNull()
- }
-
- @Test
- fun transitToFrontWithFlagRecents_logTaskRemovedAndExitReasonOverview_sessionIdNull() {
- val sessionId = 1
- // add a freeform task
- transitionObserver.addTaskInfosToCachedMap(createTaskInfo(1, WINDOWING_MODE_FREEFORM))
- transitionObserver.setLoggerSessionId(sessionId)
-
- // recents transition
- val change = createChange(TRANSIT_TO_BACK, createTaskInfo(1, WINDOWING_MODE_FREEFORM))
- val transitionInfo =
- TransitionInfoBuilder(TRANSIT_TO_FRONT, TRANSIT_FLAG_IS_RECENTS)
- .addChange(change)
- .build()
- callOnTransitionReady(transitionInfo)
-
- verify(desktopModeEventLogger, times(1)).logTaskRemoved(eq(sessionId), any())
- verify(desktopModeEventLogger, times(1))
- .logSessionExit(eq(sessionId), eq(ExitReason.RETURN_HOME_OR_OVERVIEW))
- verifyZeroInteractions(desktopModeEventLogger)
- assertThat(transitionObserver.getLoggerSessionId()).isNull()
- }
-
- @Test
- fun transitClose_logTaskRemovedAndExitReasonTaskFinished_sessionIdNull() {
- val sessionId = 1
- // add a freeform task
- transitionObserver.addTaskInfosToCachedMap(createTaskInfo(1, WINDOWING_MODE_FREEFORM))
- transitionObserver.setLoggerSessionId(sessionId)
-
- // task closing
- val change = createChange(TRANSIT_CLOSE, createTaskInfo(1, WINDOWING_MODE_FULLSCREEN))
- val transitionInfo = TransitionInfoBuilder(TRANSIT_CLOSE).addChange(change).build()
- callOnTransitionReady(transitionInfo)
-
- verify(desktopModeEventLogger, times(1)).logTaskRemoved(eq(sessionId), any())
- verify(desktopModeEventLogger, times(1))
- .logSessionExit(eq(sessionId), eq(ExitReason.TASK_FINISHED))
- verifyZeroInteractions(desktopModeEventLogger)
- assertThat(transitionObserver.getLoggerSessionId()).isNull()
- }
-
- @Test
- fun sessionExitByRecents_cancelledAnimation_sessionRestored() {
- val sessionId = 1
- // add a freeform task to an existing session
- transitionObserver.addTaskInfosToCachedMap(createTaskInfo(1, WINDOWING_MODE_FREEFORM))
- transitionObserver.setLoggerSessionId(sessionId)
-
- // recents transition sent freeform window to back
- val change = createChange(TRANSIT_TO_BACK, createTaskInfo(1, WINDOWING_MODE_FREEFORM))
- val transitionInfo1 =
- TransitionInfoBuilder(TRANSIT_TO_FRONT, TRANSIT_FLAG_IS_RECENTS)
- .addChange(change)
- .build()
- callOnTransitionReady(transitionInfo1)
- verify(desktopModeEventLogger, times(1)).logTaskRemoved(eq(sessionId), any())
- verify(desktopModeEventLogger, times(1))
- .logSessionExit(eq(sessionId), eq(ExitReason.RETURN_HOME_OR_OVERVIEW))
- assertThat(transitionObserver.getLoggerSessionId()).isNull()
-
- val transitionInfo2 = TransitionInfoBuilder(TRANSIT_NONE).build()
- callOnTransitionReady(transitionInfo2)
-
- verify(desktopModeEventLogger, times(1)).logSessionEnter(any(), any())
- verify(desktopModeEventLogger, times(1)).logTaskAdded(any(), any())
- }
-
- @Test
- fun sessionAlreadyStarted_newFreeformTaskAdded_logsTaskAdded() {
- val sessionId = 1
- // add an existing freeform task
- transitionObserver.addTaskInfosToCachedMap(createTaskInfo(1, WINDOWING_MODE_FREEFORM))
- transitionObserver.setLoggerSessionId(sessionId)
-
- // new freeform task added
- val change = createChange(TRANSIT_OPEN, createTaskInfo(2, WINDOWING_MODE_FREEFORM))
- val transitionInfo = TransitionInfoBuilder(TRANSIT_OPEN, 0).addChange(change).build()
- callOnTransitionReady(transitionInfo)
-
- verify(desktopModeEventLogger, times(1)).logTaskAdded(eq(sessionId), any())
- verify(desktopModeEventLogger, never()).logSessionEnter(any(), any())
- }
-
- @Test
- fun sessionAlreadyStarted_freeformTaskRemoved_logsTaskRemoved() {
- val sessionId = 1
- // add two existing freeform tasks
- transitionObserver.addTaskInfosToCachedMap(createTaskInfo(1, WINDOWING_MODE_FREEFORM))
- transitionObserver.addTaskInfosToCachedMap(createTaskInfo(2, WINDOWING_MODE_FREEFORM))
- transitionObserver.setLoggerSessionId(sessionId)
-
- // new freeform task added
- val change = createChange(TRANSIT_CLOSE, createTaskInfo(2, WINDOWING_MODE_FREEFORM))
- val transitionInfo = TransitionInfoBuilder(TRANSIT_CLOSE, 0).addChange(change).build()
- callOnTransitionReady(transitionInfo)
-
- verify(desktopModeEventLogger, times(1)).logTaskRemoved(eq(sessionId), any())
- verify(desktopModeEventLogger, never()).logSessionExit(any(), any())
- }
-
- /** Simulate calling the onTransitionReady() method */
- private fun callOnTransitionReady(transitionInfo: TransitionInfo) {
- val transition = mock(IBinder::class.java)
- val startT = mock(SurfaceControl.Transaction::class.java)
- val finishT = mock(SurfaceControl.Transaction::class.java)
-
- transitionObserver.onTransitionReady(transition, transitionInfo, startT, finishT)
- }
-
- companion object {
- fun createTaskInfo(taskId: Int, windowMode: Int): ActivityManager.RunningTaskInfo {
- val taskInfo = ActivityManager.RunningTaskInfo()
- taskInfo.taskId = taskId
- taskInfo.configuration.windowConfiguration.windowingMode = windowMode
-
- return taskInfo
- }
-
- fun createChange(mode: Int, taskInfo: ActivityManager.RunningTaskInfo): Change {
- val change =
- Change(
- WindowContainerToken(mock(IWindowContainerToken::class.java)),
- mock(SurfaceControl::class.java)
- )
- change.mode = mode
- change.taskInfo = taskInfo
- return change
- }
- }
+ }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
index 56c4cea..e291c0e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
@@ -113,6 +113,8 @@
private DisplayInsetsController mDisplayInsetsController;
@Mock
private IRecentTasksListener mRecentTasksListener;
+ @Mock
+ private TaskStackTransitionObserver mTaskStackTransitionObserver;
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
@@ -139,7 +141,8 @@
mDisplayInsetsController, mMainExecutor));
mRecentTasksControllerReal = new RecentTasksController(mContext, mShellInit,
mShellController, mShellCommandHandler, mTaskStackListener, mActivityTaskManager,
- Optional.of(mDesktopModeTaskRepository), mMainExecutor);
+ Optional.of(mDesktopModeTaskRepository), mTaskStackTransitionObserver,
+ mMainExecutor);
mRecentTasksController = spy(mRecentTasksControllerReal);
mShellTaskOrganizer = new ShellTaskOrganizer(mShellInit, mShellCommandHandler,
null /* sizeCompatUI */, Optional.empty(), Optional.of(mRecentTasksController),
@@ -557,6 +560,30 @@
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
+ public void onTaskMovedToFront_TaskStackObserverEnabled_triggersOnTaskMovedToFront()
+ throws Exception {
+ mRecentTasksControllerReal.registerRecentTasksListener(mRecentTasksListener);
+ ActivityManager.RunningTaskInfo taskInfo = makeRunningTaskInfo(/* taskId= */10);
+
+ mRecentTasksControllerReal.onTaskMovedToFrontThroughTransition(taskInfo);
+
+ verify(mRecentTasksListener).onTaskMovedToFront(taskInfo);
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
+ public void onTaskMovedToFront_TaskStackObserverEnabled_doesNotTriggersOnTaskMovedToFront()
+ throws Exception {
+ mRecentTasksControllerReal.registerRecentTasksListener(mRecentTasksListener);
+ ActivityManager.RunningTaskInfo taskInfo = makeRunningTaskInfo(/* taskId= */10);
+
+ mRecentTasksControllerReal.onTaskMovedToFront(taskInfo);
+
+ verify(mRecentTasksListener, never()).onTaskMovedToFront(any());
+ }
+
+ @Test
public void getNullSplitBoundsNonSplitTask() {
SplitBounds sb = mRecentTasksController.getSplitBoundsForTaskId(3);
assertNull("splitBounds should be null for non-split task", sb);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/TaskStackTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/TaskStackTransitionObserverTest.kt
new file mode 100644
index 0000000..f959970
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/TaskStackTransitionObserverTest.kt
@@ -0,0 +1,217 @@
+/*
+ * 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.wm.shell.recents
+
+import android.app.ActivityManager
+import android.app.WindowConfiguration
+import android.os.IBinder
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.SetFlagsRule
+import android.testing.AndroidTestingRunner
+import android.view.SurfaceControl
+import android.view.WindowManager
+import android.window.IWindowContainerToken
+import android.window.TransitionInfo
+import android.window.WindowContainerToken
+import androidx.test.filters.SmallTest
+import com.android.window.flags.Flags
+import com.android.wm.shell.TestShellExecutor
+import com.android.wm.shell.common.ShellExecutor
+import com.android.wm.shell.sysui.ShellInit
+import com.android.wm.shell.transition.TransitionInfoBuilder
+import com.android.wm.shell.transition.Transitions
+import com.google.common.truth.Truth.assertThat
+import dagger.Lazy
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.same
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+
+/**
+ * Test class for {@link TaskStackTransitionObserver}
+ *
+ * Usage: atest WMShellUnitTests:TaskStackTransitionObserverTest
+ */
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class TaskStackTransitionObserverTest {
+
+ @JvmField @Rule val setFlagsRule = SetFlagsRule()
+
+ @Mock private lateinit var shellInit: ShellInit
+ @Mock lateinit var testExecutor: ShellExecutor
+ @Mock private lateinit var transitionsLazy: Lazy<Transitions>
+ @Mock private lateinit var transitions: Transitions
+ @Mock private lateinit var mockTransitionBinder: IBinder
+
+ private lateinit var transitionObserver: TaskStackTransitionObserver
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ shellInit = Mockito.spy(ShellInit(testExecutor))
+ whenever(transitionsLazy.get()).thenReturn(transitions)
+ transitionObserver = TaskStackTransitionObserver(transitionsLazy, shellInit)
+ if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+ val initRunnableCaptor = ArgumentCaptor.forClass(Runnable::class.java)
+ verify(shellInit)
+ .addInitCallback(initRunnableCaptor.capture(), same(transitionObserver))
+ initRunnableCaptor.value.run()
+ } else {
+ transitionObserver.onInit()
+ }
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
+ fun testRegistersObserverAtInit() {
+ verify(transitions).registerObserver(same(transitionObserver))
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
+ fun taskCreated_freeformWindow_listenerNotified() {
+ val listener = TestListener()
+ val executor = TestShellExecutor()
+ transitionObserver.addTaskStackTransitionObserverListener(listener, executor)
+ val change =
+ createChange(
+ WindowManager.TRANSIT_OPEN,
+ createTaskInfo(1, WindowConfiguration.WINDOWING_MODE_FREEFORM)
+ )
+ val transitionInfo =
+ TransitionInfoBuilder(WindowManager.TRANSIT_OPEN, 0).addChange(change).build()
+
+ callOnTransitionReady(transitionInfo)
+ callOnTransitionFinished()
+ executor.flushAll()
+
+ assertThat(listener.taskInfoToBeNotified.taskId).isEqualTo(change.taskInfo?.taskId)
+ assertThat(listener.taskInfoToBeNotified.windowingMode)
+ .isEqualTo(change.taskInfo?.windowingMode)
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
+ fun taskCreated_fullscreenWindow_listenerNotNotified() {
+ val listener = TestListener()
+ val executor = TestShellExecutor()
+ transitionObserver.addTaskStackTransitionObserverListener(listener, executor)
+ val change =
+ createChange(
+ WindowManager.TRANSIT_OPEN,
+ createTaskInfo(1, WindowConfiguration.WINDOWING_MODE_FULLSCREEN)
+ )
+ val transitionInfo =
+ TransitionInfoBuilder(WindowManager.TRANSIT_OPEN, 0).addChange(change).build()
+
+ callOnTransitionReady(transitionInfo)
+ callOnTransitionFinished()
+ executor.flushAll()
+
+ assertThat(listener.taskInfoToBeNotified.taskId).isEqualTo(0)
+ assertThat(listener.taskInfoToBeNotified.windowingMode)
+ .isEqualTo(WindowConfiguration.WINDOWING_MODE_UNDEFINED)
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
+ fun taskCreated_freeformWindowOnTopOfFreeform_listenerNotified() {
+ val listener = TestListener()
+ val executor = TestShellExecutor()
+ transitionObserver.addTaskStackTransitionObserverListener(listener, executor)
+ val freeformOpenChange =
+ createChange(
+ WindowManager.TRANSIT_OPEN,
+ createTaskInfo(1, WindowConfiguration.WINDOWING_MODE_FREEFORM)
+ )
+ val freeformReorderChange =
+ createChange(
+ WindowManager.TRANSIT_TO_BACK,
+ createTaskInfo(2, WindowConfiguration.WINDOWING_MODE_FREEFORM)
+ )
+ val transitionInfo =
+ TransitionInfoBuilder(WindowManager.TRANSIT_OPEN, 0)
+ .addChange(freeformOpenChange)
+ .addChange(freeformReorderChange)
+ .build()
+
+ callOnTransitionReady(transitionInfo)
+ callOnTransitionFinished()
+ executor.flushAll()
+
+ assertThat(listener.taskInfoToBeNotified.taskId)
+ .isEqualTo(freeformOpenChange.taskInfo?.taskId)
+ assertThat(listener.taskInfoToBeNotified.windowingMode)
+ .isEqualTo(freeformOpenChange.taskInfo?.windowingMode)
+ }
+
+ class TestListener : TaskStackTransitionObserver.TaskStackTransitionObserverListener {
+ var taskInfoToBeNotified = ActivityManager.RunningTaskInfo()
+
+ override fun onTaskMovedToFrontThroughTransition(
+ taskInfo: ActivityManager.RunningTaskInfo
+ ) {
+ taskInfoToBeNotified = taskInfo
+ }
+ }
+
+ /** Simulate calling the onTransitionReady() method */
+ private fun callOnTransitionReady(transitionInfo: TransitionInfo) {
+ val startT = Mockito.mock(SurfaceControl.Transaction::class.java)
+ val finishT = Mockito.mock(SurfaceControl.Transaction::class.java)
+
+ transitionObserver.onTransitionReady(mockTransitionBinder, transitionInfo, startT, finishT)
+ }
+
+ /** Simulate calling the onTransitionFinished() method */
+ private fun callOnTransitionFinished() {
+ transitionObserver.onTransitionFinished(mockTransitionBinder, false)
+ }
+
+ companion object {
+ fun createTaskInfo(taskId: Int, windowingMode: Int): ActivityManager.RunningTaskInfo {
+ val taskInfo = ActivityManager.RunningTaskInfo()
+ taskInfo.taskId = taskId
+ taskInfo.configuration.windowConfiguration.windowingMode = windowingMode
+
+ return taskInfo
+ }
+
+ fun createChange(
+ mode: Int,
+ taskInfo: ActivityManager.RunningTaskInfo
+ ): TransitionInfo.Change {
+ val change =
+ TransitionInfo.Change(
+ WindowContainerToken(Mockito.mock(IWindowContainerToken::class.java)),
+ Mockito.mock(SurfaceControl::class.java)
+ )
+ change.mode = mode
+ change.taskInfo = taskInfo
+ return change
+ }
+ }
+}
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/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
index 5245456..00fb7a1 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
@@ -80,6 +80,7 @@
Settings.System.SIP_RECEIVE_CALLS,
Settings.System.POINTER_SPEED,
Settings.System.POINTER_FILL_STYLE,
+ Settings.System.POINTER_SCALE,
Settings.System.VIBRATE_ON,
Settings.System.VIBRATE_WHEN_RINGING,
Settings.System.RINGTONE,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
index 2c3be4c..4235bc4 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
@@ -26,6 +26,8 @@
import static android.provider.settings.validators.SettingsValidators.NON_NEGATIVE_INTEGER_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.URI_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.VIBRATION_INTENSITY_VALIDATOR;
+import static android.view.PointerIcon.DEFAULT_POINTER_SCALE;
+import static android.view.PointerIcon.LARGE_POINTER_SCALE;
import static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_FILL_BEGIN;
import static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_FILL_END;
@@ -211,6 +213,8 @@
VALIDATORS.put(System.POINTER_FILL_STYLE,
new InclusiveIntegerRangeValidator(POINTER_ICON_VECTOR_STYLE_FILL_BEGIN,
POINTER_ICON_VECTOR_STYLE_FILL_END));
+ VALIDATORS.put(System.POINTER_SCALE,
+ new InclusiveFloatRangeValidator(DEFAULT_POINTER_SCALE, LARGE_POINTER_SCALE));
VALIDATORS.put(System.TOUCHPAD_POINTER_SPEED, new InclusiveIntegerRangeValidator(-7, 7));
VALIDATORS.put(System.TOUCHPAD_NATURAL_SCROLLING, BOOLEAN_VALIDATOR);
VALIDATORS.put(System.TOUCHPAD_TAP_TO_CLICK, BOOLEAN_VALIDATOR);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 625b8e4..384cb7e 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -2915,6 +2915,9 @@
dumpSetting(s, p,
Settings.System.POINTER_FILL_STYLE,
SystemSettingsProto.Pointer.POINTER_FILL_STYLE);
+ dumpSetting(s, p,
+ Settings.System.POINTER_SCALE,
+ SystemSettingsProto.Pointer.POINTER_SCALE);
p.end(pointerToken);
dumpSetting(s, p,
Settings.System.POINTER_SPEED,
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/communal.aconfig b/packages/SystemUI/aconfig/communal.aconfig
index 2e9af7e..afcd8a9 100644
--- a/packages/SystemUI/aconfig/communal.aconfig
+++ b/packages/SystemUI/aconfig/communal.aconfig
@@ -7,3 +7,13 @@
description: "Enables the communal hub experience"
bug: "304584416"
}
+
+flag {
+ name: "enable_widget_picker_size_filter"
+ namespace: "communal"
+ description: "Enables passing a size filter to the widget picker"
+ bug: "345482907"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
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/AnimateToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
index 48a348b..c2dd803 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
@@ -109,8 +109,7 @@
layoutState.transitions.interruptionHandler.onInterruption(
transitionState,
target,
- )
- ?: DefaultInterruptionHandler.onInterruption(transitionState, target)
+ ) ?: DefaultInterruptionHandler.onInterruption(transitionState, target)
val animateFrom = interruptionResult.animateFrom
if (
@@ -159,6 +158,7 @@
val transition =
if (reversed) {
OneOffTransition(
+ key = transitionKey,
fromScene = targetScene,
toScene = fromScene,
currentScene = targetScene,
@@ -167,6 +167,7 @@
)
} else {
OneOffTransition(
+ key = transitionKey,
fromScene = fromScene,
toScene = targetScene,
currentScene = targetScene,
@@ -178,7 +179,7 @@
// Change the current layout state to start this new transition. This will compute the
// TransformationSpec associated to this transition, which we need to initialize the Animatable
// that will actually animate it.
- layoutState.startTransition(transition, transitionKey, chain)
+ layoutState.startTransition(transition, chain)
// The transition now contains the transformation spec that we should use to instantiate the
// Animatable.
@@ -207,6 +208,7 @@
}
private class OneOffTransition(
+ override val key: TransitionKey?,
fromScene: SceneKey,
toScene: SceneKey,
override val currentScene: SceneKey,
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
index e9633c2..60d78fe 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
@@ -257,7 +257,7 @@
fun updateTransition(newTransition: SwipeTransition, force: Boolean = false) {
if (isDrivingTransition || force) {
- layoutState.startTransition(newTransition, newTransition.key)
+ layoutState.startTransition(newTransition)
}
swipeTransition = newTransition
@@ -555,7 +555,7 @@
val layoutImpl: SceneTransitionLayoutImpl,
val layoutState: BaseSceneTransitionLayoutState,
val coroutineScope: CoroutineScope,
- val key: TransitionKey?,
+ override val key: TransitionKey?,
val _fromScene: Scene,
val _toScene: Scene,
val userActionDistanceScope: UserActionDistanceScope,
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
index edf8943..5611c6e 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
@@ -39,6 +39,8 @@
import androidx.compose.ui.layout.Placeable
import androidx.compose.ui.node.DrawModifierNode
import androidx.compose.ui.node.ModifierNodeElement
+import androidx.compose.ui.node.TraversableNode
+import androidx.compose.ui.node.traverseDescendants
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.IntSize
@@ -165,7 +167,7 @@
private var currentTransitions: List<TransitionState.Transition>,
private var scene: Scene,
private var key: ElementKey,
-) : Modifier.Node(), DrawModifierNode, ApproachLayoutModifierNode {
+) : Modifier.Node(), DrawModifierNode, ApproachLayoutModifierNode, TraversableNode {
private var _element: Element? = null
private val element: Element
get() = _element!!
@@ -174,6 +176,8 @@
private val sceneState: Element.SceneState
get() = _sceneState!!
+ override val traverseKey: Any = ElementTraverseKey
+
override fun onAttach() {
super.onAttach()
updateElementAndSceneValues()
@@ -280,7 +284,7 @@
constraints: Constraints,
): MeasureResult {
val transitions = currentTransitions
- val transition = elementTransition(element, transitions)
+ val transition = elementTransition(layoutImpl, element, transitions)
// If this element is not supposed to be laid out now, either because it is not part of any
// ongoing transition or the other scene of its transition is overscrolling, then lay out
@@ -289,18 +293,15 @@
val isOtherSceneOverscrolling = overscrollScene != null && overscrollScene != scene.key
val isNotPartOfAnyOngoingTransitions = transitions.isNotEmpty() && transition == null
if (isNotPartOfAnyOngoingTransitions || isOtherSceneOverscrolling) {
- sceneState.lastOffset = Offset.Unspecified
- sceneState.lastScale = Scale.Unspecified
- sceneState.lastAlpha = Element.AlphaUnspecified
+ recursivelyClearPlacementValues()
+ sceneState.lastSize = Element.SizeUnspecified
val placeable = measurable.measure(constraints)
- sceneState.lastSize = placeable.size()
-
return layout(placeable.width, placeable.height) { /* Do not place */ }
}
val placeable =
- measure(layoutImpl, scene, element, transition, sceneState, measurable, constraints)
+ measure(layoutImpl, element, transition, sceneState, measurable, constraints)
sceneState.lastSize = placeable.size()
return layout(placeable.width, placeable.height) { place(transition, placeable) }
}
@@ -315,16 +316,10 @@
// scene when idle.
val coords =
coordinates ?: error("Element ${element.key} does not have any coordinates")
- val targetOffsetInScene = lookaheadScopeCoordinates.localLookaheadPositionOf(coords)
// No need to place the element in this scene if we don't want to draw it anyways.
- if (!shouldPlaceElement(layoutImpl, scene, element, transition)) {
- sceneState.lastOffset = Offset.Unspecified
- sceneState.lastScale = Scale.Unspecified
- sceneState.lastAlpha = Element.AlphaUnspecified
-
- sceneState.clearValuesBeforeInterruption()
- sceneState.clearInterruptionDeltas()
+ if (!shouldPlaceElement(layoutImpl, scene.key, element, transition)) {
+ recursivelyClearPlacementValues()
return
}
@@ -332,12 +327,11 @@
val targetOffset =
computeValue(
layoutImpl,
- scene,
+ sceneState,
element,
transition,
sceneValue = { it.targetOffset },
transformation = { it.offset },
- idleValue = targetOffsetInScene,
currentValue = { currentOffset },
isSpecified = { it != Offset.Unspecified },
::lerp,
@@ -353,7 +347,17 @@
getValueBeforeInterruption = { sceneState.offsetBeforeInterruption },
setValueBeforeInterruption = { sceneState.offsetBeforeInterruption = it },
getInterruptionDelta = { sceneState.offsetInterruptionDelta },
- setInterruptionDelta = { sceneState.offsetInterruptionDelta = it },
+ setInterruptionDelta = { delta ->
+ setPlacementInterruptionDelta(
+ element = element,
+ sceneState = sceneState,
+ transition = transition,
+ delta = delta,
+ setter = { sceneState, delta ->
+ sceneState.offsetInterruptionDelta = delta
+ },
+ )
+ },
diff = { a, b -> a - b },
add = { a, b, bProgress -> a + b * bProgress },
)
@@ -363,7 +367,7 @@
val offset = (interruptedOffset - currentOffset).round()
if (
isElementOpaque(scene, element, transition) &&
- interruptedAlpha(layoutImpl, transition, sceneState, alpha = 1f) == 1f
+ interruptedAlpha(layoutImpl, element, transition, sceneState, alpha = 1f) == 1f
) {
sceneState.lastAlpha = 1f
@@ -374,28 +378,51 @@
} else {
placeable.placeWithLayer(offset) {
// This layer might still run on its own (outside of the placement phase) even
- // if this element is not placed anymore, so we need to double check again here
- // before calling [elementAlpha] (which will update [SceneState.lastAlpha]). We
- // also need to recompute the current transition to make sure that we are using
- // the current transition and not a reference to an old one. See b/343138966 for
- // details.
- val transition = elementTransition(element, currentTransitions)
- if (!shouldPlaceElement(layoutImpl, scene, element, transition)) {
+ // if this element is not placed or composed anymore, so we need to double check
+ // again here before calling [elementAlpha] (which will update
+ // [SceneState.lastAlpha]). We also need to recompute the current transition to
+ // make sure that we are using the current transition and not a reference to an
+ // old one. See b/343138966 for details.
+ if (_element == null) {
return@placeWithLayer
}
- alpha = elementAlpha(layoutImpl, scene, element, transition, sceneState)
+ val transition = elementTransition(layoutImpl, element, currentTransitions)
+ if (!shouldPlaceElement(layoutImpl, scene.key, element, transition)) {
+ return@placeWithLayer
+ }
+
+ alpha = elementAlpha(layoutImpl, element, transition, sceneState)
compositingStrategy = CompositingStrategy.ModulateAlpha
}
}
}
}
+ /**
+ * Recursively clear the last placement values on this node and all descendants ElementNodes.
+ * This should be called when this node is not placed anymore, so that we correctly clear values
+ * for the descendants for which approachMeasure() won't be called.
+ */
+ private fun recursivelyClearPlacementValues() {
+ fun Element.SceneState.clearLastPlacementValues() {
+ lastOffset = Offset.Unspecified
+ lastScale = Scale.Unspecified
+ lastAlpha = Element.AlphaUnspecified
+ }
+
+ sceneState.clearLastPlacementValues()
+ traverseDescendants(ElementTraverseKey) { node ->
+ (node as ElementNode).sceneState.clearLastPlacementValues()
+ TraversableNode.Companion.TraverseDescendantsAction.ContinueTraversal
+ }
+ }
+
override fun ContentDrawScope.draw() {
element.wasDrawnInAnyScene = true
- val transition = elementTransition(element, currentTransitions)
- val drawScale = getDrawScale(layoutImpl, scene, element, transition, sceneState)
+ val transition = elementTransition(layoutImpl, element, currentTransitions)
+ val drawScale = getDrawScale(layoutImpl, element, transition, sceneState)
if (drawScale == Scale.Default) {
drawContent()
} else {
@@ -410,6 +437,8 @@
}
companion object {
+ private val ElementTraverseKey = Any()
+
private fun maybePruneMaps(
layoutImpl: SceneTransitionLayoutImpl,
element: Element,
@@ -435,6 +464,7 @@
* its scenes contains the element.
*/
private fun elementTransition(
+ layoutImpl: SceneTransitionLayoutImpl,
element: Element,
transitions: List<TransitionState.Transition>,
): TransitionState.Transition? {
@@ -448,7 +478,7 @@
if (transition != previousTransition && transition != null && previousTransition != null) {
// The previous transition was interrupted by another transition.
- prepareInterruption(element, transition, previousTransition)
+ prepareInterruption(layoutImpl, element, transition, previousTransition)
} else if (transition == null && previousTransition != null) {
// The transition was just finished.
element.sceneStates.values.forEach {
@@ -461,18 +491,44 @@
}
private fun prepareInterruption(
+ layoutImpl: SceneTransitionLayoutImpl,
element: Element,
transition: TransitionState.Transition,
previousTransition: TransitionState.Transition,
) {
val sceneStates = element.sceneStates
- sceneStates[previousTransition.fromScene]?.selfUpdateValuesBeforeInterruption()
- sceneStates[previousTransition.toScene]?.selfUpdateValuesBeforeInterruption()
- sceneStates[transition.fromScene]?.selfUpdateValuesBeforeInterruption()
- sceneStates[transition.toScene]?.selfUpdateValuesBeforeInterruption()
+ fun updatedSceneState(key: SceneKey): Element.SceneState? {
+ return sceneStates[key]?.also { it.selfUpdateValuesBeforeInterruption() }
+ }
+
+ val previousFromState = updatedSceneState(previousTransition.fromScene)
+ val previousToState = updatedSceneState(previousTransition.toScene)
+ val fromState = updatedSceneState(transition.fromScene)
+ val toState = updatedSceneState(transition.toScene)
reconcileStates(element, previousTransition)
reconcileStates(element, transition)
+
+ // Remove the interruption values to all scenes but the scene(s) where the element will be
+ // placed, to make sure that interruption deltas are computed only right after this interruption
+ // is prepared.
+ fun cleanInterruptionValues(sceneState: Element.SceneState) {
+ sceneState.sizeInterruptionDelta = IntSize.Zero
+ sceneState.offsetInterruptionDelta = Offset.Zero
+ sceneState.alphaInterruptionDelta = 0f
+ sceneState.scaleInterruptionDelta = Scale.Zero
+
+ if (!shouldPlaceElement(layoutImpl, sceneState.scene, element, transition)) {
+ sceneState.offsetBeforeInterruption = Offset.Unspecified
+ sceneState.alphaBeforeInterruption = Element.AlphaUnspecified
+ sceneState.scaleBeforeInterruption = Scale.Unspecified
+ }
+ }
+
+ previousFromState?.let { cleanInterruptionValues(it) }
+ previousToState?.let { cleanInterruptionValues(it) }
+ fromState?.let { cleanInterruptionValues(it) }
+ toState?.let { cleanInterruptionValues(it) }
}
/**
@@ -579,9 +635,38 @@
}
}
+/**
+ * Set the interruption delta of a *placement/drawing*-related value (offset, alpha, scale). This
+ * ensures that the delta is also set on the other scene in the transition for shared elements, so
+ * that there is no jump cut if the scene where the element is placed has changed.
+ */
+private inline fun <T> setPlacementInterruptionDelta(
+ element: Element,
+ sceneState: Element.SceneState,
+ transition: TransitionState.Transition?,
+ delta: T,
+ setter: (Element.SceneState, T) -> Unit,
+) {
+ // Set the interruption delta on the current scene.
+ setter(sceneState, delta)
+
+ if (transition == null) {
+ return
+ }
+
+ // If the element is shared, also set the delta on the other scene so that it is used by that
+ // scene if we start overscrolling it and change the scene where the element is placed.
+ val otherScene =
+ if (sceneState.scene == transition.fromScene) transition.toScene else transition.fromScene
+ val otherSceneState = element.sceneStates[otherScene] ?: return
+ if (isSharedElementEnabled(element.key, transition)) {
+ setter(otherSceneState, delta)
+ }
+}
+
private fun shouldPlaceElement(
layoutImpl: SceneTransitionLayoutImpl,
- scene: Scene,
+ scene: SceneKey,
element: Element,
transition: TransitionState.Transition?,
): Boolean {
@@ -592,7 +677,7 @@
// Don't place the element in this scene if this scene is not part of the current element
// transition.
- if (scene.key != transition.fromScene && scene.key != transition.toScene) {
+ if (scene != transition.fromScene && scene != transition.toScene) {
return false
}
@@ -610,7 +695,7 @@
return shouldPlaceOrComposeSharedElement(
layoutImpl,
- scene.key,
+ scene,
element.key,
transition,
)
@@ -714,7 +799,6 @@
*/
private fun elementAlpha(
layoutImpl: SceneTransitionLayoutImpl,
- scene: Scene,
element: Element,
transition: TransitionState.Transition?,
sceneState: Element.SceneState,
@@ -722,12 +806,11 @@
val alpha =
computeValue(
layoutImpl,
- scene,
+ sceneState,
element,
transition,
sceneValue = { 1f },
transformation = { it.alpha },
- idleValue = 1f,
currentValue = { 1f },
isSpecified = { true },
::lerp,
@@ -740,13 +823,14 @@
element.sceneStates.forEach { it.value.alphaBeforeInterruption = 0f }
}
- val interruptedAlpha = interruptedAlpha(layoutImpl, transition, sceneState, alpha)
+ val interruptedAlpha = interruptedAlpha(layoutImpl, element, transition, sceneState, alpha)
sceneState.lastAlpha = interruptedAlpha
return interruptedAlpha
}
private fun interruptedAlpha(
layoutImpl: SceneTransitionLayoutImpl,
+ element: Element,
transition: TransitionState.Transition?,
sceneState: Element.SceneState,
alpha: Float,
@@ -760,15 +844,22 @@
getValueBeforeInterruption = { sceneState.alphaBeforeInterruption },
setValueBeforeInterruption = { sceneState.alphaBeforeInterruption = it },
getInterruptionDelta = { sceneState.alphaInterruptionDelta },
- setInterruptionDelta = { sceneState.alphaInterruptionDelta = it },
+ setInterruptionDelta = { delta ->
+ setPlacementInterruptionDelta(
+ element = element,
+ sceneState = sceneState,
+ transition = transition,
+ delta = delta,
+ setter = { sceneState, delta -> sceneState.alphaInterruptionDelta = delta },
+ )
+ },
diff = { a, b -> a - b },
add = { a, b, bProgress -> a + b * bProgress },
)
}
-private fun ApproachMeasureScope.measure(
+private fun measure(
layoutImpl: SceneTransitionLayoutImpl,
- scene: Scene,
element: Element,
transition: TransitionState.Transition?,
sceneState: Element.SceneState,
@@ -783,12 +874,11 @@
val targetSize =
computeValue(
layoutImpl,
- scene,
+ sceneState,
element,
transition,
sceneValue = { it.targetSize },
transformation = { it.size },
- idleValue = lookaheadSize,
currentValue = { measurable.measure(constraints).also { maybePlaceable = it }.size() },
isSpecified = { it != Element.SizeUnspecified },
::lerp,
@@ -834,7 +924,6 @@
private fun ContentDrawScope.getDrawScale(
layoutImpl: SceneTransitionLayoutImpl,
- scene: Scene,
element: Element,
transition: TransitionState.Transition?,
sceneState: Element.SceneState,
@@ -842,12 +931,11 @@
val scale =
computeValue(
layoutImpl,
- scene,
+ sceneState,
element,
transition,
sceneValue = { Scale.Default },
transformation = { it.drawScale },
- idleValue = Scale.Default,
currentValue = { Scale.Default },
isSpecified = { true },
::lerp,
@@ -867,7 +955,15 @@
getValueBeforeInterruption = { sceneState.scaleBeforeInterruption },
setValueBeforeInterruption = { sceneState.scaleBeforeInterruption = it },
getInterruptionDelta = { sceneState.scaleInterruptionDelta },
- setInterruptionDelta = { sceneState.scaleInterruptionDelta = it },
+ setInterruptionDelta = { delta ->
+ setPlacementInterruptionDelta(
+ element = element,
+ sceneState = sceneState,
+ transition = transition,
+ delta = delta,
+ setter = { sceneState, delta -> sceneState.scaleInterruptionDelta = delta },
+ )
+ },
diff = { a, b ->
Scale(
scaleX = a.scaleX - b.scaleX,
@@ -906,11 +1002,12 @@
* Measurable.
*
* @param layoutImpl the [SceneTransitionLayoutImpl] associated to [element].
- * @param scene the scene containing [element].
+ * @param currentSceneState the scene state of the scene for which we are computing the value. Note
+ * that during interruptions, this could be the state of a scene that is neither
+ * [transition.toScene] nor [transition.fromScene].
* @param element the element being animated.
* @param sceneValue the value being animated.
* @param transformation the transformation associated to the value being animated.
- * @param idleValue the value when idle, i.e. when there is no transition happening.
* @param currentValue the value that would be used if it is not transformed. Note that this is
* different than [idleValue] even if the value is not transformed directly because it could be
* impacted by the transformations on other elements, like a parent that is being translated or
@@ -920,12 +1017,11 @@
*/
private inline fun <T> computeValue(
layoutImpl: SceneTransitionLayoutImpl,
- scene: Scene,
+ currentSceneState: Element.SceneState,
element: Element,
transition: TransitionState.Transition?,
sceneValue: (Element.SceneState) -> T,
transformation: (ElementTransformations) -> PropertyTransformation<T>?,
- idleValue: T,
currentValue: () -> T,
isSpecified: (T) -> Boolean,
lerp: (T, T, Float) -> T,
@@ -947,19 +1043,22 @@
if (fromState == null && toState == null) {
// TODO(b/311600838): Throw an exception instead once layers of disposed elements are not
// run anymore.
- return idleValue
+ return sceneValue(currentSceneState)
}
+ val currentScene = currentSceneState.scene
if (transition is TransitionState.HasOverscrollProperties) {
val overscroll = transition.currentOverscrollSpec
- if (overscroll?.scene == scene.key) {
- val elementSpec = overscroll.transformationSpec.transformations(element.key, scene.key)
+ if (overscroll?.scene == currentScene) {
+ val elementSpec =
+ overscroll.transformationSpec.transformations(element.key, currentScene)
val propertySpec = transformation(elementSpec) ?: return currentValue()
- val overscrollState = checkNotNull(if (scene.key == toScene) toState else fromState)
+ val overscrollState = checkNotNull(if (currentScene == toScene) toState else fromState)
+ val idleValue = sceneValue(overscrollState)
val targetValue =
propertySpec.transform(
layoutImpl,
- scene,
+ currentScene,
element,
overscrollState,
transition,
@@ -1003,24 +1102,30 @@
return if (start == end) start else lerp(start, end, transition.progress)
}
- val transformation =
- transformation(transition.transformationSpec.transformations(element.key, scene.key))
- // If there is no transformation explicitly associated to this element value, let's use
- // the value given by the system (like the current position and size given by the layout
- // pass).
- ?: return currentValue()
-
// Get the transformed value, i.e. the target value at the beginning (for entering elements) or
// end (for leaving elements) of the transition.
val sceneState =
checkNotNull(
when {
- isSharedElement && scene.key == fromScene -> fromState
+ isSharedElement && currentScene == fromScene -> fromState
isSharedElement -> toState
else -> fromState ?: toState
}
)
+ // The scene for which we compute the transformation. Note that this is not necessarily
+ // [currentScene] because [currentScene] could be a different scene than the transition
+ // fromScene or toScene during interruptions.
+ val scene = sceneState.scene
+
+ val transformation =
+ transformation(transition.transformationSpec.transformations(element.key, scene))
+ // If there is no transformation explicitly associated to this element value, let's use
+ // the value given by the system (like the current position and size given by the layout
+ // pass).
+ ?: return currentValue()
+
+ val idleValue = sceneValue(sceneState)
val targetValue =
transformation.transform(
layoutImpl,
@@ -1042,7 +1147,7 @@
val rangeProgress = transformation.range?.progress(progress) ?: progress
// Interpolate between the value at rest and the value before entering/after leaving.
- val isEntering = scene.key == toScene
+ val isEntering = scene == toScene
return if (isEntering) {
lerp(targetValue, idleValue, rangeProgress)
} else {
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/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
index 44affd9..a8df6f4 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
@@ -226,6 +226,12 @@
val toScene: SceneKey,
) : TransitionState {
/**
+ * The key of this transition. This should usually be null, but it can be specified to use a
+ * specific set of transformations associated to this transition.
+ */
+ open val key: TransitionKey? = null
+
+ /**
* The progress of the transition. This is usually in the `[0; 1]` range, but it can also be
* less than `0` or greater than `1` when using transitions with a spring AnimationSpec or
* when flinging quickly during a swipe gesture.
@@ -455,11 +461,7 @@
*
* Important: you *must* call [finishTransition] once the transition is finished.
*/
- internal fun startTransition(
- transition: TransitionState.Transition,
- transitionKey: TransitionKey? = null,
- chain: Boolean = true,
- ) {
+ internal fun startTransition(transition: TransitionState.Transition, chain: Boolean = true) {
checkThread()
// Compute the [TransformationSpec] when the transition starts.
@@ -469,7 +471,9 @@
// Update the transition specs.
transition.transformationSpec =
- transitions.transitionSpec(fromScene, toScene, key = transitionKey).transformationSpec()
+ transitions
+ .transitionSpec(fromScene, toScene, key = transition.key)
+ .transformationSpec()
if (orientation != null) {
transition.updateOverscrollSpecs(
fromSpec = transitions.overscrollSpec(fromScene, orientation),
@@ -568,9 +572,10 @@
originalTransition = transitionState,
fromScene = targetCurrentScene,
toScene = matchingLink.targetTo,
+ key = matchingLink.targetTransitionKey,
)
- stateLink.target.startTransition(linkedTransition, matchingLink.targetTransitionKey)
+ stateLink.target.startTransition(linkedTransition)
activeTransitionLinks[stateLink] = linkedTransition
}
}
@@ -763,7 +768,7 @@
/** A [MutableSceneTransitionLayoutState] that holds the value for the current scene. */
internal class MutableSceneTransitionLayoutStateImpl(
initialScene: SceneKey,
- override var transitions: SceneTransitions,
+ override var transitions: SceneTransitions = transitions {},
private val canChangeScene: (SceneKey) -> Boolean = { true },
stateLinks: List<StateLink> = emptyList(),
enableInterruptions: Boolean = DEFAULT_INTERRUPTIONS_ENABLED,
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredSize.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredSize.kt
index b54afae..73ee451 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredSize.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredSize.kt
@@ -20,7 +20,6 @@
import com.android.compose.animation.scene.Element
import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.ElementMatcher
-import com.android.compose.animation.scene.Scene
import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.SceneTransitionLayoutImpl
import com.android.compose.animation.scene.TransitionState
@@ -34,7 +33,7 @@
) : PropertyTransformation<IntSize> {
override fun transform(
layoutImpl: SceneTransitionLayoutImpl,
- scene: Scene,
+ scene: SceneKey,
element: Element,
sceneState: Element.SceneState,
transition: TransitionState.Transition,
@@ -60,7 +59,7 @@
// This simple implementation assumes that the size of [element] is the same as the size of
// the [anchor] in [scene], so simply transform to the size of the anchor in the other
// scene.
- return if (scene.key == transition.fromScene) {
+ return if (scene == transition.fromScene) {
anchorSizeIn(transition.toScene)
} else {
anchorSizeIn(transition.fromScene)
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredTranslate.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredTranslate.kt
index 2bab4f8..70dca4c 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredTranslate.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredTranslate.kt
@@ -21,7 +21,6 @@
import com.android.compose.animation.scene.Element
import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.ElementMatcher
-import com.android.compose.animation.scene.Scene
import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.SceneTransitionLayoutImpl
import com.android.compose.animation.scene.TransitionState
@@ -33,7 +32,7 @@
) : PropertyTransformation<Offset> {
override fun transform(
layoutImpl: SceneTransitionLayoutImpl,
- scene: Scene,
+ scene: SceneKey,
element: Element,
sceneState: Element.SceneState,
transition: TransitionState.Transition,
@@ -61,7 +60,7 @@
anchorOffsetIn(transition.toScene) ?: throwException(transition.toScene)
val offset = anchorToOffset - anchorFromOffset
- return if (scene.key == transition.toScene) {
+ return if (scene == transition.toScene) {
Offset(
value.x - offset.x,
value.y - offset.y,
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/DrawScale.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/DrawScale.kt
index 6704a3b..98c2dd3 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/DrawScale.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/DrawScale.kt
@@ -20,7 +20,7 @@
import com.android.compose.animation.scene.Element
import com.android.compose.animation.scene.ElementMatcher
import com.android.compose.animation.scene.Scale
-import com.android.compose.animation.scene.Scene
+import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.SceneTransitionLayoutImpl
import com.android.compose.animation.scene.TransitionState
@@ -37,7 +37,7 @@
override fun transform(
layoutImpl: SceneTransitionLayoutImpl,
- scene: Scene,
+ scene: SceneKey,
element: Element,
sceneState: Element.SceneState,
transition: TransitionState.Transition,
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/EdgeTranslate.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/EdgeTranslate.kt
index 191a8fb..aa8dc38 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/EdgeTranslate.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/EdgeTranslate.kt
@@ -20,7 +20,7 @@
import com.android.compose.animation.scene.Edge
import com.android.compose.animation.scene.Element
import com.android.compose.animation.scene.ElementMatcher
-import com.android.compose.animation.scene.Scene
+import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.SceneTransitionLayoutImpl
import com.android.compose.animation.scene.TransitionState
@@ -32,13 +32,13 @@
) : PropertyTransformation<Offset> {
override fun transform(
layoutImpl: SceneTransitionLayoutImpl,
- scene: Scene,
+ scene: SceneKey,
element: Element,
sceneState: Element.SceneState,
transition: TransitionState.Transition,
value: Offset
): Offset {
- val sceneSize = scene.targetSize
+ val sceneSize = layoutImpl.scene(scene).targetSize
val elementSize = sceneState.targetSize
if (elementSize == Element.SizeUnspecified) {
return value
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Fade.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Fade.kt
index 41f626e..ada814e 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Fade.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Fade.kt
@@ -18,7 +18,7 @@
import com.android.compose.animation.scene.Element
import com.android.compose.animation.scene.ElementMatcher
-import com.android.compose.animation.scene.Scene
+import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.SceneTransitionLayoutImpl
import com.android.compose.animation.scene.TransitionState
@@ -28,7 +28,7 @@
) : PropertyTransformation<Float> {
override fun transform(
layoutImpl: SceneTransitionLayoutImpl,
- scene: Scene,
+ scene: SceneKey,
element: Element,
sceneState: Element.SceneState,
transition: TransitionState.Transition,
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/ScaleSize.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/ScaleSize.kt
index f5207dc..dca8f85 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/ScaleSize.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/ScaleSize.kt
@@ -19,7 +19,7 @@
import androidx.compose.ui.unit.IntSize
import com.android.compose.animation.scene.Element
import com.android.compose.animation.scene.ElementMatcher
-import com.android.compose.animation.scene.Scene
+import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.SceneTransitionLayoutImpl
import com.android.compose.animation.scene.TransitionState
import kotlin.math.roundToInt
@@ -35,7 +35,7 @@
) : PropertyTransformation<IntSize> {
override fun transform(
layoutImpl: SceneTransitionLayoutImpl,
- scene: Scene,
+ scene: SceneKey,
element: Element,
sceneState: Element.SceneState,
transition: TransitionState.Transition,
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt
index 603f7ba..7be9ce1 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt
@@ -21,7 +21,7 @@
import androidx.compose.ui.util.fastCoerceIn
import com.android.compose.animation.scene.Element
import com.android.compose.animation.scene.ElementMatcher
-import com.android.compose.animation.scene.Scene
+import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.SceneTransitionLayoutImpl
import com.android.compose.animation.scene.TransitionState
@@ -61,7 +61,7 @@
// to these internal classes.
fun transform(
layoutImpl: SceneTransitionLayoutImpl,
- scene: Scene,
+ scene: SceneKey,
element: Element,
sceneState: Element.SceneState,
transition: TransitionState.Transition,
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Translate.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Translate.kt
index 849c9d7..f066511 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Translate.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Translate.kt
@@ -22,7 +22,7 @@
import com.android.compose.animation.scene.Element
import com.android.compose.animation.scene.ElementMatcher
import com.android.compose.animation.scene.OverscrollScope
-import com.android.compose.animation.scene.Scene
+import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.SceneTransitionLayoutImpl
import com.android.compose.animation.scene.TransitionState
@@ -33,7 +33,7 @@
) : PropertyTransformation<Offset> {
override fun transform(
layoutImpl: SceneTransitionLayoutImpl,
- scene: Scene,
+ scene: SceneKey,
element: Element,
sceneState: Element.SceneState,
transition: TransitionState.Transition,
@@ -55,7 +55,7 @@
) : PropertyTransformation<Offset> {
override fun transform(
layoutImpl: SceneTransitionLayoutImpl,
- scene: Scene,
+ scene: SceneKey,
element: Element,
sceneState: Element.SceneState,
transition: TransitionState.Transition,
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transition/link/LinkedTransition.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transition/link/LinkedTransition.kt
index 79f126d..ed98885 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transition/link/LinkedTransition.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transition/link/LinkedTransition.kt
@@ -17,6 +17,7 @@
package com.android.compose.animation.scene.transition.link
import com.android.compose.animation.scene.SceneKey
+import com.android.compose.animation.scene.TransitionKey
import com.android.compose.animation.scene.TransitionState
import kotlinx.coroutines.Job
@@ -25,6 +26,7 @@
private val originalTransition: TransitionState.Transition,
fromScene: SceneKey,
toScene: SceneKey,
+ override val key: TransitionKey? = null,
) : TransitionState.Transition(fromScene, toScene) {
override val currentScene: SceneKey
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/ElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
index 47c9b9c..a18da73 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
@@ -52,6 +52,7 @@
import androidx.compose.ui.test.assertIsNotDisplayed
import androidx.compose.ui.test.assertPositionInRootIsEqualTo
import androidx.compose.ui.test.assertTopPositionInRootIsEqualTo
+import androidx.compose.ui.test.hasTestTag
import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
@@ -639,10 +640,7 @@
// Change the current transition.
rule.runOnUiThread {
- state.startTransition(
- transition(from = SceneA, to = SceneB, progress = { 0.5f }),
- transitionKey = null,
- )
+ state.startTransition(transition(from = SceneA, to = SceneB, progress = { 0.5f }))
}
// The size of Foo should still be 20dp given that the new state was not composed yet.
@@ -1171,7 +1169,7 @@
val offsetInAToB = lerp(offsetInA, offsetInB, aToBProgress)
val sizeInAToB = lerp(sizeInA, sizeInB, aToBProgress)
val valueInAToB = lerp(valueInA, valueInB, aToBProgress)
- rule.runOnUiThread { state.startTransition(aToB, transitionKey = null) }
+ rule.runOnUiThread { state.startTransition(aToB) }
rule
.onNode(isElement(TestElements.Foo, SceneB))
.assertSizeIsEqualTo(sizeInAToB)
@@ -1191,7 +1189,7 @@
progress = { bToCProgress },
interruptionProgress = { interruptionProgress },
)
- rule.runOnUiThread { state.startTransition(bToC, transitionKey = null) }
+ rule.runOnUiThread { state.startTransition(bToC) }
// The interruption deltas, which will be multiplied by the interruption progress then added
// to the current transition offset and size.
@@ -1333,9 +1331,9 @@
interruptionProgress = { bToCInterruptionProgress },
onFinish = neverFinish(),
)
- rule.runOnUiThread { state.startTransition(aToB, transitionKey = null) }
+ rule.runOnUiThread { state.startTransition(aToB) }
rule.waitForIdle()
- rule.runOnUiThread { state.startTransition(bToC, transitionKey = null) }
+ rule.runOnUiThread { state.startTransition(bToC) }
// Foo is placed in both B and C given that the shared transition is disabled. In B, its
// offset is impacted by the interruption but in C it is not.
@@ -1371,7 +1369,7 @@
progress = { 0.7f },
interruptionProgress = { 1f },
)
- rule.runOnUiThread { state.startTransition(bToA, transitionKey = null) }
+ rule.runOnUiThread { state.startTransition(bToA) }
// Foo should have the position it had in B right before the interruption.
rule
@@ -1395,8 +1393,7 @@
to = SceneB,
progress = { -1f },
orientation = Orientation.Horizontal
- ),
- transitionKey = null,
+ )
)
}
}
@@ -1513,8 +1510,7 @@
to = SceneB,
progress = { 0.6f },
interruptionProgress = { interruptionProgress },
- ),
- transitionKey = null
+ )
)
}
rule.waitForIdle()
@@ -1632,4 +1628,313 @@
rule.onNode(hasText(fooInA)).assertIsDisplayed()
rule.onNode(hasText(fooInB)).assertDoesNotExist()
}
+
+ @Test
+ fun interruptionThenOverscroll() = runTest {
+ val state =
+ rule.runOnUiThread {
+ MutableSceneTransitionLayoutStateImpl(
+ SceneA,
+ transitions {
+ overscroll(SceneB, Orientation.Vertical) {
+ translate(TestElements.Foo, y = 15.dp)
+ }
+ }
+ )
+ }
+
+ @Composable
+ fun SceneScope.SceneWithFoo(offset: DpOffset, modifier: Modifier = Modifier) {
+ Box(modifier.fillMaxSize()) {
+ Box(Modifier.offset(offset.x, offset.y).element(TestElements.Foo).size(100.dp))
+ }
+ }
+
+ rule.setContent {
+ SceneTransitionLayout(state, Modifier.size(200.dp)) {
+ scene(SceneA) { SceneWithFoo(offset = DpOffset.Zero) }
+ scene(SceneB) { SceneWithFoo(offset = DpOffset(x = 40.dp, y = 0.dp)) }
+ scene(SceneC) { SceneWithFoo(offset = DpOffset(x = 40.dp, y = 40.dp)) }
+ }
+ }
+
+ // Start A => B at 75%.
+ rule.runOnUiThread {
+ state.startTransition(
+ transition(
+ from = SceneA,
+ to = SceneB,
+ progress = { 0.75f },
+ onFinish = neverFinish(),
+ )
+ )
+ }
+
+ // Foo should be at offset (30dp, 0dp) and placed in scene B.
+ rule.onNode(isElement(TestElements.Foo, SceneA)).assertIsNotDisplayed()
+ rule.onNode(isElement(TestElements.Foo, SceneB)).assertPositionInRootIsEqualTo(30.dp, 0.dp)
+ rule.onNode(isElement(TestElements.Foo, SceneC)).assertIsNotDisplayed()
+
+ // Interrupt A => B with B => C at 0%.
+ var progress by mutableStateOf(0f)
+ var interruptionProgress by mutableStateOf(1f)
+ rule.runOnUiThread {
+ state.startTransition(
+ transition(
+ from = SceneB,
+ to = SceneC,
+ progress = { progress },
+ interruptionProgress = { interruptionProgress },
+ orientation = Orientation.Vertical,
+ onFinish = neverFinish(),
+ )
+ )
+ }
+
+ // Because interruption progress is at 100M, Foo should still be at offset (30dp, 0dp) but
+ // placed in scene C.
+ rule.onNode(isElement(TestElements.Foo, SceneA)).assertIsNotDisplayed()
+ rule.onNode(isElement(TestElements.Foo, SceneB)).assertIsNotDisplayed()
+ rule.onNode(isElement(TestElements.Foo, SceneC)).assertPositionInRootIsEqualTo(30.dp, 0.dp)
+
+ // Overscroll B => C on scene B at -100%. Because overscrolling on B => C translates Foo
+ // vertically by -15dp and that interruptionProgress is still 100%, we should now be at
+ // (30dp, -15dp)
+ progress = -1f
+ rule.onNode(isElement(TestElements.Foo, SceneA)).assertIsNotDisplayed()
+ rule
+ .onNode(isElement(TestElements.Foo, SceneB))
+ .assertPositionInRootIsEqualTo(30.dp, -15.dp)
+ rule.onNode(isElement(TestElements.Foo, SceneC)).assertIsNotDisplayed()
+
+ // Finish the interruption, we should now be at (40dp, -15dp), still on scene B.
+ interruptionProgress = 0f
+ rule.onNode(isElement(TestElements.Foo, SceneA)).assertIsNotDisplayed()
+ rule
+ .onNode(isElement(TestElements.Foo, SceneB))
+ .assertPositionInRootIsEqualTo(40.dp, -15.dp)
+ rule.onNode(isElement(TestElements.Foo, SceneC)).assertIsNotDisplayed()
+
+ // Finish the transition, we should be at the final position (40dp, 40dp) on scene C.
+ progress = 1f
+ rule.onNode(isElement(TestElements.Foo, SceneA)).assertIsNotDisplayed()
+ rule.onNode(isElement(TestElements.Foo, SceneB)).assertIsNotDisplayed()
+ rule.onNode(isElement(TestElements.Foo, SceneC)).assertPositionInRootIsEqualTo(40.dp, 40.dp)
+ }
+
+ @Test
+ fun lastPlacementValuesAreClearedOnNestedElements() {
+ val state = rule.runOnIdle { MutableSceneTransitionLayoutStateImpl(SceneA) }
+
+ @Composable
+ fun SceneScope.NestedFooBar() {
+ Box(Modifier.element(TestElements.Foo)) {
+ Box(Modifier.element(TestElements.Bar).size(10.dp))
+ }
+ }
+
+ lateinit var layoutImpl: SceneTransitionLayoutImpl
+ rule.setContent {
+ SceneTransitionLayoutForTesting(state, onLayoutImpl = { layoutImpl = it }) {
+ scene(SceneA) { NestedFooBar() }
+ scene(SceneB) { NestedFooBar() }
+ }
+ }
+
+ // Idle on A: composed and placed only in B.
+ rule.onNode(isElement(TestElements.Foo, SceneA)).assertIsDisplayed()
+ rule.onNode(isElement(TestElements.Bar, SceneA)).assertIsDisplayed()
+ rule.onNode(isElement(TestElements.Foo, SceneB)).assertDoesNotExist()
+ rule.onNode(isElement(TestElements.Bar, SceneB)).assertDoesNotExist()
+
+ assertThat(layoutImpl.elements).containsKey(TestElements.Foo)
+ assertThat(layoutImpl.elements).containsKey(TestElements.Bar)
+ val foo = layoutImpl.elements.getValue(TestElements.Foo)
+ val bar = layoutImpl.elements.getValue(TestElements.Bar)
+
+ assertThat(foo.sceneStates).containsKey(SceneA)
+ assertThat(bar.sceneStates).containsKey(SceneA)
+ assertThat(foo.sceneStates).doesNotContainKey(SceneB)
+ assertThat(bar.sceneStates).doesNotContainKey(SceneB)
+
+ val fooInA = foo.sceneStates.getValue(SceneA)
+ val barInA = bar.sceneStates.getValue(SceneA)
+ assertThat(fooInA.lastOffset).isNotEqualTo(Offset.Unspecified)
+ assertThat(fooInA.lastAlpha).isNotEqualTo(Element.AlphaUnspecified)
+ assertThat(fooInA.lastScale).isNotEqualTo(Scale.Unspecified)
+
+ assertThat(barInA.lastOffset).isNotEqualTo(Offset.Unspecified)
+ assertThat(barInA.lastAlpha).isNotEqualTo(Element.AlphaUnspecified)
+ assertThat(barInA.lastScale).isNotEqualTo(Scale.Unspecified)
+
+ // A => B: composed in both and placed only in B.
+ rule.runOnUiThread { state.startTransition(transition(from = SceneA, to = SceneB)) }
+ rule.onNode(isElement(TestElements.Foo, SceneA)).assertExists().assertIsNotDisplayed()
+ rule.onNode(isElement(TestElements.Bar, SceneA)).assertExists().assertIsNotDisplayed()
+ rule.onNode(isElement(TestElements.Foo, SceneB)).assertIsDisplayed()
+ rule.onNode(isElement(TestElements.Bar, SceneB)).assertIsDisplayed()
+
+ assertThat(foo.sceneStates).containsKey(SceneB)
+ assertThat(bar.sceneStates).containsKey(SceneB)
+
+ val fooInB = foo.sceneStates.getValue(SceneB)
+ val barInB = bar.sceneStates.getValue(SceneB)
+ assertThat(fooInA.lastOffset).isEqualTo(Offset.Unspecified)
+ assertThat(fooInA.lastAlpha).isEqualTo(Element.AlphaUnspecified)
+ assertThat(fooInA.lastScale).isEqualTo(Scale.Unspecified)
+ assertThat(fooInB.lastOffset).isNotEqualTo(Offset.Unspecified)
+ assertThat(fooInB.lastAlpha).isNotEqualTo(Element.AlphaUnspecified)
+ assertThat(fooInB.lastScale).isNotEqualTo(Scale.Unspecified)
+
+ assertThat(barInA.lastOffset).isEqualTo(Offset.Unspecified)
+ assertThat(barInA.lastAlpha).isEqualTo(Element.AlphaUnspecified)
+ assertThat(barInA.lastScale).isEqualTo(Scale.Unspecified)
+ assertThat(barInB.lastOffset).isNotEqualTo(Offset.Unspecified)
+ assertThat(barInB.lastAlpha).isNotEqualTo(Element.AlphaUnspecified)
+ assertThat(barInB.lastScale).isNotEqualTo(Scale.Unspecified)
+ }
+
+ @Test
+ fun currentTransitionSceneIsUsedToComputeElementValues() = runTest {
+ val state =
+ rule.runOnIdle {
+ MutableSceneTransitionLayoutStateImpl(
+ SceneA,
+ transitions {
+ from(SceneB, to = SceneC) {
+ scaleSize(TestElements.Foo, width = 2f, height = 3f)
+ }
+ }
+ )
+ }
+
+ @Composable
+ fun SceneScope.Foo() {
+ Box(Modifier.testTag("fooParentIn${sceneKey.debugName}")) {
+ Box(Modifier.element(TestElements.Foo).size(20.dp))
+ }
+ }
+
+ rule.setContent {
+ SceneTransitionLayout(state, Modifier.size(200.dp)) {
+ scene(SceneA) { Foo() }
+ scene(SceneB) {}
+ scene(SceneC) { Foo() }
+ }
+ }
+
+ // We have 2 transitions:
+ // - A => B at 100%
+ // - B => C at 0%
+ // So Foo should have a size of (40dp, 60dp) in both A and C given that it is scaling its
+ // size in B => C.
+ rule.runOnUiThread {
+ state.startTransition(
+ transition(from = SceneA, to = SceneB, progress = { 1f }, onFinish = neverFinish())
+ )
+ state.startTransition(transition(from = SceneB, to = SceneC, progress = { 0f }))
+ }
+
+ rule.onNode(hasTestTag("fooParentInSceneA")).assertSizeIsEqualTo(40.dp, 60.dp)
+ rule.onNode(hasTestTag("fooParentInSceneC")).assertSizeIsEqualTo(40.dp, 60.dp)
+ }
+
+ @Test
+ fun interruptionDeltasAreProperlyCleaned() = runTest {
+ val state = rule.runOnIdle { MutableSceneTransitionLayoutStateImpl(SceneA) }
+
+ @Composable
+ fun SceneScope.Foo(offset: Dp) {
+ Box(Modifier.fillMaxSize()) {
+ Box(Modifier.offset(offset, offset).element(TestElements.Foo).size(20.dp))
+ }
+ }
+
+ rule.setContent {
+ SceneTransitionLayout(state, Modifier.size(200.dp)) {
+ scene(SceneA) { Foo(offset = 0.dp) }
+ scene(SceneB) { Foo(offset = 20.dp) }
+ scene(SceneC) { Foo(offset = 40.dp) }
+ }
+ }
+
+ // Start A => B at 50%.
+ val aToB =
+ transition(from = SceneA, to = SceneB, progress = { 0.5f }, onFinish = neverFinish())
+ rule.runOnUiThread { state.startTransition(aToB) }
+ rule.onNode(isElement(TestElements.Foo, SceneB)).assertPositionInRootIsEqualTo(10.dp, 10.dp)
+
+ // Start B => C at 0%. This will compute an interruption delta of (-10dp, -10dp) so that the
+ // position of Foo is unchanged and converges to (20dp, 20dp).
+ var interruptionProgress by mutableStateOf(1f)
+ val bToC =
+ transition(
+ from = SceneB,
+ to = SceneC,
+ progress = { 0f },
+ interruptionProgress = { interruptionProgress },
+ onFinish = neverFinish(),
+ )
+ rule.runOnUiThread { state.startTransition(bToC) }
+ rule.onNode(isElement(TestElements.Foo, SceneC)).assertPositionInRootIsEqualTo(10.dp, 10.dp)
+
+ // Finish the interruption and leave the transition progress at 0f. We should be at the same
+ // state as in B.
+ interruptionProgress = 0f
+ rule.onNode(isElement(TestElements.Foo, SceneC)).assertPositionInRootIsEqualTo(20.dp, 20.dp)
+
+ // Finish both transitions but directly start a new one B => A with interruption progress
+ // 100%. We should be at (20dp, 20dp), unless the interruption deltas have not been
+ // correctly cleaned.
+ rule.runOnUiThread {
+ state.finishTransition(aToB, idleScene = SceneB)
+ state.finishTransition(bToC, idleScene = SceneB)
+ state.startTransition(
+ transition(
+ from = SceneB,
+ to = SceneA,
+ progress = { 0f },
+ interruptionProgress = { 1f },
+ )
+ )
+ }
+ rule.onNode(isElement(TestElements.Foo, SceneB)).assertPositionInRootIsEqualTo(20.dp, 20.dp)
+ }
+
+ @Test
+ fun lastSizeIsUnspecifiedWhenOverscrollingOtherScene() = runTest {
+ val state =
+ rule.runOnIdle {
+ MutableSceneTransitionLayoutStateImpl(
+ SceneA,
+ transitions { overscroll(SceneA, Orientation.Horizontal) }
+ )
+ }
+
+ @Composable
+ fun SceneScope.Foo() {
+ Box(Modifier.element(TestElements.Foo).size(10.dp))
+ }
+
+ lateinit var layoutImpl: SceneTransitionLayoutImpl
+ rule.setContent {
+ SceneTransitionLayoutForTesting(state, onLayoutImpl = { layoutImpl = it }) {
+ scene(SceneA) { Foo() }
+ scene(SceneB) { Foo() }
+ }
+ }
+
+ // Overscroll A => B on A.
+ rule.runOnUiThread {
+ state.startTransition(
+ transition(from = SceneA, to = SceneB, progress = { -1f }, onFinish = neverFinish())
+ )
+ }
+ rule.waitForIdle()
+
+ assertThat(
+ layoutImpl.elements.getValue(TestElements.Foo).sceneStates.getValue(SceneB).lastSize
+ )
+ .isEqualTo(Element.SizeUnspecified)
+ }
}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/InterruptionHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/InterruptionHandlerTest.kt
index 85d4165..09d1a82 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/InterruptionHandlerTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/InterruptionHandlerTest.kt
@@ -40,7 +40,7 @@
val state =
MutableSceneTransitionLayoutState(
SceneA,
- transitions { /* default interruption handler */},
+ transitions { /* default interruption handler */ },
)
state.setTargetScene(SceneB, coroutineScope = this)
@@ -160,7 +160,7 @@
progressVelocity = { progressVelocity },
onFinish = { launch {} },
)
- state.startTransition(aToB, transitionKey = null)
+ state.startTransition(aToB)
// Animate back to A. The previous transition is reversed, i.e. it has the same (from, to)
// pair, and its velocity is used when animating the progress back to 0.
@@ -186,7 +186,7 @@
progressVelocity = { progressVelocity },
onFinish = { launch {} },
)
- state.startTransition(aToB, transitionKey = null)
+ state.startTransition(aToB)
// Animate to B. The previous transition is reversed, i.e. it has the same (from, to) pair,
// and its velocity is used when animating the progress to 1.
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/ObservableTransitionStateTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ObservableTransitionStateTest.kt
index 2a75e13..5543135 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ObservableTransitionStateTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ObservableTransitionStateTest.kt
@@ -135,7 +135,7 @@
var transitionCurrentScene by mutableStateOf(SceneA)
val transition =
transition(from = SceneA, to = SceneB, current = { transitionCurrentScene })
- state.startTransition(transition, transitionKey = null)
+ state.startTransition(transition)
assertThat(currentScene.value).isEqualTo(SceneA)
// Change the transition current scene.
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
index d2c8bd6..de6f1cc 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
@@ -57,7 +57,7 @@
@Test
fun isTransitioningTo_transition() {
val state = MutableSceneTransitionLayoutStateImpl(SceneA, SceneTransitions.Empty)
- state.startTransition(transition(from = SceneA, to = SceneB), transitionKey = null)
+ state.startTransition(transition(from = SceneA, to = SceneB))
assertThat(state.isTransitioning()).isTrue()
assertThat(state.isTransitioning(from = SceneA)).isTrue()
@@ -175,7 +175,7 @@
val childTransition = transition(SceneA, SceneB)
- childState.startTransition(childTransition, null)
+ childState.startTransition(childTransition)
assertThat(childState.isTransitioning(SceneA, SceneB)).isTrue()
assertThat(parentState.isTransitioning(SceneC, SceneD)).isTrue()
@@ -211,7 +211,7 @@
val childTransition = transition(SceneA, SceneB)
- childState.startTransition(childTransition, null)
+ childState.startTransition(childTransition)
assertThat(childState.isTransitioning(SceneA, SceneB)).isTrue()
assertThat(parentState.isTransitioning(SceneC, SceneD)).isTrue()
assertThat(parentParentState.isTransitioning(SceneB, SceneC)).isTrue()
@@ -229,7 +229,7 @@
var progress = 0f
val childTransition = transition(SceneA, SceneB, progress = { progress })
- childState.startTransition(childTransition, null)
+ childState.startTransition(childTransition)
assertThat(parentState.currentTransition?.progress).isEqualTo(0f)
progress = .5f
@@ -242,7 +242,7 @@
val childTransition = transition(SceneB, SceneA)
- childState.startTransition(childTransition, null)
+ childState.startTransition(childTransition)
assertThat(childState.isTransitioning(SceneB, SceneA)).isTrue()
assertThat(parentState.transitionState).isEqualTo(TransitionState.Idle(SceneC))
@@ -256,7 +256,7 @@
val (parentState, childState) = setupLinkedStates()
val childTransition = transition(SceneA, SceneB)
- childState.startTransition(childTransition, null)
+ childState.startTransition(childTransition)
childState.finishTransition(childTransition, SceneA)
assertThat(childState.transitionState).isEqualTo(TransitionState.Idle(SceneA))
@@ -268,7 +268,7 @@
val (parentState, childState) = setupLinkedStates()
val childTransition = transition(SceneA, SceneB)
- childState.startTransition(childTransition, null)
+ childState.startTransition(childTransition)
childState.finishTransition(childTransition, SceneD)
assertThat(childState.transitionState).isEqualTo(TransitionState.Idle(SceneD))
@@ -283,16 +283,16 @@
transition(
SceneA,
SceneB,
- onFinish = { launch { /* Do nothing. */} },
+ onFinish = { launch { /* Do nothing. */ } },
)
val parentTransition =
transition(
SceneC,
SceneA,
- onFinish = { launch { /* Do nothing. */} },
+ onFinish = { launch { /* Do nothing. */ } },
)
- childState.startTransition(childTransition, null)
- parentState.startTransition(parentTransition, null)
+ childState.startTransition(childTransition)
+ parentState.startTransition(parentTransition)
childState.finishTransition(childTransition, SceneB)
assertThat(childState.transitionState).isEqualTo(TransitionState.Idle(SceneB))
@@ -341,10 +341,7 @@
@Test
fun snapToIdleIfClose_snapToStart() = runMonotonicClockTest {
val state = MutableSceneTransitionLayoutStateImpl(SceneA, SceneTransitions.Empty)
- state.startTransition(
- transition(from = SceneA, to = SceneB, progress = { 0.2f }),
- transitionKey = null
- )
+ state.startTransition(transition(from = SceneA, to = SceneB, progress = { 0.2f }))
assertThat(state.isTransitioning()).isTrue()
// Ignore the request if the progress is not close to 0 or 1, using the threshold.
@@ -360,10 +357,7 @@
@Test
fun snapToIdleIfClose_snapToEnd() = runMonotonicClockTest {
val state = MutableSceneTransitionLayoutStateImpl(SceneA, SceneTransitions.Empty)
- state.startTransition(
- transition(from = SceneA, to = SceneB, progress = { 0.8f }),
- transitionKey = null
- )
+ state.startTransition(transition(from = SceneA, to = SceneB, progress = { 0.8f }))
assertThat(state.isTransitioning()).isTrue()
// Ignore the request if the progress is not close to 0 or 1, using the threshold.
@@ -385,13 +379,13 @@
from = SceneA,
to = SceneB,
progress = { 0.5f },
- onFinish = { launch { /* do nothing */} },
+ onFinish = { launch { /* do nothing */ } },
)
- state.startTransition(aToB, transitionKey = null)
+ state.startTransition(aToB)
assertThat(state.currentTransitions).containsExactly(aToB).inOrder()
val bToC = transition(from = SceneB, to = SceneC, progress = { 0.8f })
- state.startTransition(bToC, transitionKey = null)
+ state.startTransition(bToC)
assertThat(state.currentTransitions).containsExactly(aToB, bToC).inOrder()
// Ignore the request if the progress is not close to 0 or 1, using the threshold.
@@ -409,7 +403,7 @@
val (parentState, childState) = setupLinkedStates(SceneC, SceneA, null, null, null, SceneD)
val childTransition = transition(SceneA, SceneB)
- childState.startTransition(childTransition, null)
+ childState.startTransition(childTransition)
assertThat(childState.isTransitioning(SceneA, SceneB)).isTrue()
assertThat(parentState.isTransitioning(SceneC, SceneD)).isTrue()
@@ -425,7 +419,7 @@
val childTransition = transition(SceneA, SceneB)
- childState.startTransition(childTransition, null)
+ childState.startTransition(childTransition)
assertThat(childState.isTransitioning(SceneA, SceneB)).isTrue()
assertThat(parentState.isTransitioning(SceneC, SceneD)).isTrue()
@@ -440,7 +434,7 @@
setupLinkedStates(SceneC, SceneA, SceneB, null, SceneC, SceneD)
val childTransition = transition(SceneA, SceneB)
- childState.startTransition(childTransition, null)
+ childState.startTransition(childTransition)
assertThat(childState.isTransitioning(SceneA, SceneB)).isTrue()
assertThat(parentState.isTransitioning(SceneC, SceneD)).isFalse()
}
@@ -460,8 +454,7 @@
to = SceneB,
progress = progress,
orientation = Orientation.Vertical,
- ),
- transitionKey = null
+ )
)
assertThat(state.isTransitioning()).isTrue()
return state
@@ -583,19 +576,19 @@
assertThat(state.currentTransitions).isEmpty()
// A => B.
- state.startTransition(aToB, transitionKey = null)
+ state.startTransition(aToB)
assertThat(finishingTransitions).isEmpty()
assertThat(state.finishedTransitions).isEmpty()
assertThat(state.currentTransitions).containsExactly(aToB).inOrder()
// B => C. This should automatically call finish() on aToB.
- state.startTransition(bToC, transitionKey = null)
+ state.startTransition(bToC)
assertThat(finishingTransitions).containsExactly(aToB)
assertThat(state.finishedTransitions).isEmpty()
assertThat(state.currentTransitions).containsExactly(aToB, bToC).inOrder()
// C => A. This should automatically call finish() on bToC.
- state.startTransition(cToA, transitionKey = null)
+ state.startTransition(cToA)
assertThat(finishingTransitions).containsExactly(aToB, bToC)
assertThat(state.finishedTransitions).isEmpty()
assertThat(state.currentTransitions).containsExactly(aToB, bToC, cToA).inOrder()
@@ -617,8 +610,8 @@
val state = MutableSceneTransitionLayoutStateImpl(SceneA, EmptyTestTransitions)
fun startTransition() {
- val transition = transition(SceneA, SceneB, onFinish = { launch { /* do nothing */} })
- state.startTransition(transition, transitionKey = null)
+ val transition = transition(SceneA, SceneB, onFinish = { launch { /* do nothing */ } })
+ state.startTransition(transition)
}
var hasLoggedWtf = false
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/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestMatchers.kt b/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestMatchers.kt
index e743c78..6d063a0 100644
--- a/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestMatchers.kt
+++ b/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestMatchers.kt
@@ -17,7 +17,7 @@
package com.android.compose.animation.scene
import androidx.compose.ui.test.SemanticsMatcher
-import androidx.compose.ui.test.hasParent
+import androidx.compose.ui.test.hasAnyAncestor
import androidx.compose.ui.test.hasTestTag
/** A [SemanticsMatcher] that matches [element], optionally restricted to scene [scene]. */
@@ -25,6 +25,6 @@
return if (scene == null) {
hasTestTag(element.testTag)
} else {
- hasTestTag(element.testTag) and hasParent(hasTestTag(scene.testTag))
+ hasTestTag(element.testTag) and hasAnyAncestor(hasTestTag(scene.testTag))
}
}
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/FromAlternateBouncerTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorTest.kt
index cfc6b33..a12b6f8 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorTest.kt
@@ -32,8 +32,11 @@
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.systemui.Flags
import com.android.systemui.SysuiTestCase
import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
@@ -76,6 +79,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
fun transitionToGone_keyguardOccluded_biometricAuthenticated() =
testScope.runTest {
transitionRepository.sendTransitionSteps(
@@ -96,6 +100,25 @@
}
@Test
+ @EnableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
+ fun transitionToGone_keyguardOccludedThenAltBouncer_authed_wmStateRefactor() =
+ testScope.runTest {
+ transitionRepository.sendTransitionSteps(
+ from = KeyguardState.OCCLUDED,
+ to = KeyguardState.ALTERNATE_BOUNCER,
+ testScope
+ )
+ reset(transitionRepository)
+
+ // Authentication results in calling startDismissKeyguardTransition.
+ kosmos.keyguardTransitionInteractor.startDismissKeyguardTransition()
+ runCurrent()
+
+ assertThat(transitionRepository)
+ .startedTransition(from = KeyguardState.ALTERNATE_BOUNCER, to = KeyguardState.GONE)
+ }
+
+ @Test
fun noTransition_keyguardNotOccluded_biometricAuthenticated() =
testScope.runTest {
transitionRepository.sendTransitionSteps(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt
index 6c5001a..6eb9862 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt
@@ -53,6 +53,7 @@
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest
import com.android.systemui.power.domain.interactor.powerInteractor
+import com.android.systemui.statusbar.domain.interactor.keyguardOcclusionInteractor
import com.android.systemui.testKosmos
import junit.framework.Assert.assertEquals
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -299,6 +300,7 @@
fun testTransitionToOccluded_onWake() =
testScope.runTest {
kosmos.fakeKeyguardRepository.setKeyguardOccluded(true)
+ kosmos.keyguardOcclusionInteractor.setWmNotifiedShowWhenLockedActivityOnTop(true)
powerInteractor.setAwakeForTest()
advanceTimeBy(100) // account for debouncing
@@ -312,6 +314,7 @@
testScope.runTest {
kosmos.fakeKeyguardRepository.setKeyguardShowing(false)
kosmos.fakeKeyguardRepository.setKeyguardDismissible(true)
+ kosmos.keyguardTransitionInteractor.startDismissKeyguardTransition()
powerInteractor.setAwakeForTest()
advanceTimeBy(100) // account for debouncing
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/layout/super_notification_shade.xml b/packages/SystemUI/res/layout/super_notification_shade.xml
index 221b791..fbb07be 100644
--- a/packages/SystemUI/res/layout/super_notification_shade.xml
+++ b/packages/SystemUI/res/layout/super_notification_shade.xml
@@ -62,7 +62,9 @@
<com.android.systemui.keyguard.ui.view.KeyguardRootView
android:id="@id/keyguard_root_view"
android:layout_width="match_parent"
- android:layout_height="match_parent" />
+ android:layout_height="match_parent"
+ android:clipChildren="false"
+ />
<!-- Shared container for the notification stack. Can be positioned by either
the keyguard_root_view or notification_panel -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index d308c3d..d979abb 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -912,6 +912,10 @@
obvious when corner radii differ.-->
<dimen name="communal_enforced_rounded_corner_max_radius">28dp</dimen>
+ <!-- Width and height used to filter widgets displayed in the communal widget picker -->
+ <dimen name="communal_widget_picker_desired_width">360dp</dimen>
+ <dimen name="communal_widget_picker_desired_height">240dp</dimen>
+
<!-- The width/height of the unlock icon view on keyguard. -->
<dimen name="keyguard_lock_height">42dp</dimen>
<dimen name="keyguard_lock_padding">20dp</dimen>
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/shared/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimator.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimator.kt
index 7a8c82c..4fd5456 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimator.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimator.kt
@@ -37,10 +37,17 @@
private lateinit var rootView: ViewGroup
private var translationMax = 0f
+ /**
+ * Initializes the animator, it is allowed to call this method multiple times, for example
+ * to update the rootView or maximum translation
+ */
fun init(rootView: ViewGroup, translationMax: Float) {
+ if (!::rootView.isInitialized) {
+ progressProvider.addCallback(this)
+ }
+
this.rootView = rootView
this.translationMax = translationMax
- progressProvider.addCallback(this)
}
override fun onTransitionStarted() {
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/KeyguardUnfoldTransition.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt
index 7170be61..19d918f 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt
@@ -17,16 +17,21 @@
package com.android.keyguard
import android.content.Context
-import android.view.ViewGroup
-import com.android.systemui.res.R
+import android.view.View
+import com.android.systemui.keyguard.MigrateClocksToBlueprint
+import com.android.systemui.keyguard.ui.view.KeyguardRootView
import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.statusbar.StatusBarState.KEYGUARD
+import com.android.systemui.res.R
+import com.android.systemui.shared.R as sharedR
+import com.android.systemui.shade.NotificationShadeWindowView
import com.android.systemui.shared.animation.UnfoldConstantTranslateAnimator
import com.android.systemui.shared.animation.UnfoldConstantTranslateAnimator.Direction.END
import com.android.systemui.shared.animation.UnfoldConstantTranslateAnimator.Direction.START
import com.android.systemui.shared.animation.UnfoldConstantTranslateAnimator.ViewIdToTranslate
+import com.android.systemui.statusbar.StatusBarState.KEYGUARD
import com.android.systemui.unfold.SysUIUnfoldScope
-import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider
+import com.android.systemui.unfold.UnfoldTransitionProgressProvider
+import com.android.systemui.unfold.dagger.NaturalRotation
import javax.inject.Inject
/**
@@ -38,8 +43,10 @@
@Inject
constructor(
private val context: Context,
+ private val keyguardRootView: KeyguardRootView,
+ private val shadeWindowView: NotificationShadeWindowView,
statusBarStateController: StatusBarStateController,
- unfoldProgressProvider: NaturalRotationUnfoldProgressProvider,
+ @NaturalRotation unfoldProgressProvider: UnfoldTransitionProgressProvider,
) {
/** Certain views only need to move if they are not currently centered */
@@ -50,27 +57,94 @@
private val filterKeyguard: () -> Boolean = { statusBarStateController.getState() == KEYGUARD }
private val translateAnimator by lazy {
+ val smartSpaceViews = if (MigrateClocksToBlueprint.isEnabled) {
+ // Use scrollX instead of translationX as translation is already set by [AodBurnInLayer]
+ val scrollXTranslation = { view: View, translation: Float ->
+ view.scrollX = -translation.toInt()
+ }
+
+ setOf(
+ ViewIdToTranslate(
+ viewId = sharedR.id.date_smartspace_view,
+ direction = START,
+ shouldBeAnimated = filterKeyguard,
+ translateFunc = scrollXTranslation,
+ ),
+ ViewIdToTranslate(
+ viewId = sharedR.id.bc_smartspace_view,
+ direction = START,
+ shouldBeAnimated = filterKeyguard,
+ translateFunc = scrollXTranslation,
+ ),
+ ViewIdToTranslate(
+ viewId = sharedR.id.weather_smartspace_view,
+ direction = START,
+ shouldBeAnimated = filterKeyguard,
+ translateFunc = scrollXTranslation,
+ )
+ )
+ } else {
+ setOf(ViewIdToTranslate(
+ viewId = R.id.keyguard_status_area,
+ direction = START,
+ shouldBeAnimated = filterKeyguard,
+ translateFunc = { view, value ->
+ (view as? KeyguardStatusAreaView)?.translateXFromUnfold = value
+ }
+ ))
+ }
+
UnfoldConstantTranslateAnimator(
viewsIdToTranslate =
setOf(
- ViewIdToTranslate(R.id.keyguard_status_area, START, filterKeyguard,
- { view, value ->
- (view as? KeyguardStatusAreaView)?.translateXFromUnfold = value
- }),
ViewIdToTranslate(
- R.id.lockscreen_clock_view_large, START, filterKeyguardAndSplitShadeOnly),
- ViewIdToTranslate(R.id.lockscreen_clock_view, START, filterKeyguard),
+ viewId = R.id.lockscreen_clock_view_large,
+ direction = START,
+ shouldBeAnimated = filterKeyguardAndSplitShadeOnly
+ ),
ViewIdToTranslate(
- R.id.notification_stack_scroller, END, filterKeyguardAndSplitShadeOnly),
- ViewIdToTranslate(R.id.start_button, START, filterKeyguard),
- ViewIdToTranslate(R.id.end_button, END, filterKeyguard)),
- progressProvider = unfoldProgressProvider)
+ viewId = R.id.lockscreen_clock_view,
+ direction = START,
+ shouldBeAnimated = filterKeyguard
+ ),
+ ViewIdToTranslate(
+ viewId = R.id.notification_stack_scroller,
+ direction = END,
+ shouldBeAnimated = filterKeyguardAndSplitShadeOnly
+ )
+ ) + smartSpaceViews,
+ progressProvider = unfoldProgressProvider
+ )
}
- /** Relies on the [parent] to locate views to translate. */
- fun setup(parent: ViewGroup) {
+ private val shortcutButtonsAnimator by lazy {
+ UnfoldConstantTranslateAnimator(
+ viewsIdToTranslate =
+ setOf(
+ ViewIdToTranslate(
+ viewId = R.id.start_button,
+ direction = START,
+ shouldBeAnimated = filterKeyguard
+ ),
+ ViewIdToTranslate(
+ viewId = R.id.end_button,
+ direction = END,
+ shouldBeAnimated = filterKeyguard
+ )
+ ),
+ progressProvider = unfoldProgressProvider
+ )
+ }
+
+ /** Initializes the keyguard fold/unfold transition */
+ fun setup() {
val translationMax =
context.resources.getDimensionPixelSize(R.dimen.keyguard_unfold_translation_x).toFloat()
- translateAnimator.init(parent, translationMax)
+
+ translateAnimator.init(shadeWindowView, translationMax)
+
+ // Use keyguard root view as there is another instance of start/end buttons with the same ID
+ // outside of the keyguard root view
+ shortcutButtonsAnimator.init(keyguardRootView, translationMax)
}
}
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/CommunalEditModeViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
index bc65ccb..5312aec 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
@@ -24,6 +24,7 @@
import android.util.Log
import androidx.activity.result.ActivityResultLauncher
import com.android.internal.logging.UiEventLogger
+import com.android.systemui.Flags.enableWidgetPickerSizeFilter
import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor
@@ -36,6 +37,7 @@
import com.android.systemui.log.dagger.CommunalLog
import com.android.systemui.media.controls.ui.view.MediaHost
import com.android.systemui.media.dagger.MediaModule
+import com.android.systemui.res.R
import javax.inject.Inject
import javax.inject.Named
import kotlinx.coroutines.CoroutineDispatcher
@@ -138,6 +140,16 @@
return Intent(Intent.ACTION_PICK).apply {
setPackage(packageName)
+ if (enableWidgetPickerSizeFilter()) {
+ putExtra(
+ EXTRA_DESIRED_WIDGET_WIDTH,
+ resources.getDimensionPixelSize(R.dimen.communal_widget_picker_desired_width)
+ )
+ putExtra(
+ EXTRA_DESIRED_WIDGET_HEIGHT,
+ resources.getDimensionPixelSize(R.dimen.communal_widget_picker_desired_height)
+ )
+ }
putExtra(
AppWidgetManager.EXTRA_CATEGORY_FILTER,
communalSettingsInteractor.communalWidgetCategories.value
@@ -163,6 +175,8 @@
companion object {
private const val TAG = "CommunalEditModeViewModel"
+ private const val EXTRA_DESIRED_WIDGET_WIDTH = "desired_widget_width"
+ private const val EXTRA_DESIRED_WIDGET_HEIGHT = "desired_widget_height"
private const val EXTRA_UI_SURFACE_KEY = "ui_surface"
private const val EXTRA_UI_SURFACE_VALUE = "widgets_hub"
const val EXTRA_ADDED_APP_WIDGETS_KEY = "added_app_widgets"
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/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
index 7aab37e..9f0fc51 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
@@ -31,6 +31,7 @@
import com.android.systemui.dock.DockManager;
import com.android.systemui.dock.DockManagerImpl;
import com.android.systemui.doze.DozeHost;
+import com.android.systemui.keyboard.shortcut.ShortcutHelperModule;
import com.android.systemui.keyguard.ui.composable.blueprint.DefaultBlueprintModule;
import com.android.systemui.keyguard.ui.view.layout.blueprints.KeyguardBlueprintModule;
import com.android.systemui.keyguard.ui.view.layout.sections.KeyguardSectionsModule;
@@ -137,7 +138,8 @@
UnfoldTransitionModule.Startables.class,
ToastModule.class,
VolumeModule.class,
- WallpaperModule.class
+ WallpaperModule.class,
+ ShortcutHelperModule.class,
})
public abstract class ReferenceSystemUIModule {
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/keyboard/KeyboardModule.kt b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardModule.kt
index fc9406b..c6fb4f9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardModule.kt
@@ -19,13 +19,12 @@
import com.android.systemui.keyboard.data.repository.KeyboardRepository
import com.android.systemui.keyboard.data.repository.KeyboardRepositoryImpl
-import com.android.systemui.keyboard.shortcut.ShortcutHelperModule
import com.android.systemui.keyboard.stickykeys.data.repository.StickyKeysRepository
import com.android.systemui.keyboard.stickykeys.data.repository.StickyKeysRepositoryImpl
import dagger.Binds
import dagger.Module
-@Module(includes = [ShortcutHelperModule::class])
+@Module
abstract class KeyboardModule {
@Binds
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/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index 41cd2c4..99c95b5 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -24,6 +24,7 @@
import static com.android.systemui.classifier.Classifier.BACK_GESTURE;
import static com.android.systemui.navigationbar.gestural.Utilities.isTrackpadScroll;
import static com.android.systemui.navigationbar.gestural.Utilities.isTrackpadThreeFingerSwipe;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TOUCHPAD_GESTURES_DISABLED;
import static java.util.stream.Collectors.joining;
@@ -1021,8 +1022,10 @@
if (mIsTrackpadThreeFingerSwipe) {
// Trackpad back gestures don't have zones, so we don't need to check if the down
// event is within insets.
- mAllowGesture = isBackAllowedCommon && isValidTrackpadBackGesture(
- true /* isTrackpadEvent */);
+ boolean trackpadGesturesEnabled =
+ (mSysUiFlags & SYSUI_STATE_TOUCHPAD_GESTURES_DISABLED) == 0;
+ mAllowGesture = isBackAllowedCommon && trackpadGesturesEnabled
+ && isValidTrackpadBackGesture(true /* isTrackpadEvent */);
} else {
mAllowGesture = isBackAllowedCommon && !mUsingThreeButtonNav && isWithinInsets
&& isWithinTouchRegion((int) ev.getX(), (int) ev.getY())
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/NotificationPanelUnfoldAnimationController.kt b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelUnfoldAnimationController.kt
index 14659e7..f463cb5 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelUnfoldAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelUnfoldAnimationController.kt
@@ -47,6 +47,7 @@
viewsIdToTranslate =
setOf(
ViewIdToTranslate(R.id.quick_settings_panel, START, filterShade),
+ ViewIdToTranslate(R.id.qs_footer_actions, START, filterShade),
ViewIdToTranslate(R.id.notification_stack_scroller, END, filterShade)),
progressProvider = progressProvider)
}
@@ -55,9 +56,8 @@
UnfoldConstantTranslateAnimator(
viewsIdToTranslate =
setOf(
- ViewIdToTranslate(R.id.statusIcons, END, filterShade),
+ ViewIdToTranslate(R.id.shade_header_system_icons, END, filterShade),
ViewIdToTranslate(R.id.privacy_container, END, filterShade),
- ViewIdToTranslate(R.id.batteryRemainingIcon, END, filterShade),
ViewIdToTranslate(R.id.carrier_group, END, filterShade),
ViewIdToTranslate(R.id.clock, START, filterShade),
ViewIdToTranslate(R.id.date, START, filterShade)
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 3826b50..262befc 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -537,8 +537,6 @@
private final KeyguardMediaController mKeyguardMediaController;
private final Optional<KeyguardUnfoldTransition> mKeyguardUnfoldTransition;
- private final Optional<NotificationPanelUnfoldAnimationController>
- mNotificationPanelUnfoldAnimationController;
/** The drag distance required to fully expand the split shade. */
private int mSplitShadeFullTransitionDistance;
@@ -964,8 +962,6 @@
mKeyguardUnfoldTransition = unfoldComponent.map(
SysUIUnfoldComponent::getKeyguardUnfoldTransition);
- mNotificationPanelUnfoldAnimationController = unfoldComponent.map(
- SysUIUnfoldComponent::getNotificationPanelUnfoldAnimationController);
updateUserSwitcherFlags();
mKeyguardBottomAreaViewModel = keyguardBottomAreaViewModel;
@@ -1131,9 +1127,6 @@
mShadeHeaderController.init();
mShadeHeaderController.setShadeCollapseAction(
() -> collapse(/* delayed= */ false , /* speedUpFactor= */ 1.0f));
- mKeyguardUnfoldTransition.ifPresent(u -> u.setup(mView));
- mNotificationPanelUnfoldAnimationController.ifPresent(controller ->
- controller.setup(mNotificationContainerParent));
// Dreaming->Lockscreen
collectFlow(
@@ -1511,9 +1504,6 @@
if (!KeyguardBottomAreaRefactor.isEnabled()) {
setKeyguardBottomAreaVisibility(mBarState, false);
}
-
- mKeyguardUnfoldTransition.ifPresent(u -> u.setup(mView));
- mNotificationPanelUnfoldAnimationController.ifPresent(u -> u.setup(mView));
}
private void attachSplitShadeMediaPlayerContainer(FrameLayout container) {
@@ -1797,6 +1787,7 @@
private void updateKeyguardStatusViewAlignment(boolean animate) {
boolean shouldBeCentered = shouldKeyguardStatusViewBeCentered();
+ mKeyguardUnfoldTransition.ifPresent(t -> t.setStatusViewCentered(shouldBeCentered));
if (MigrateClocksToBlueprint.isEnabled()) {
mKeyguardInteractor.setClockShouldBeCentered(shouldBeCentered);
return;
@@ -1804,7 +1795,6 @@
ConstraintLayout layout = mNotificationContainerParent;
mKeyguardStatusViewController.updateAlignment(
layout, mSplitShadeEnabled, shouldBeCentered, animate);
- mKeyguardUnfoldTransition.ifPresent(t -> t.setStatusViewCentered(shouldBeCentered));
}
private boolean shouldKeyguardStatusViewBeCentered() {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index c01b7b6..e41f99b 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -32,6 +32,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.keyguard.AuthKeyguardMessageArea;
+import com.android.keyguard.KeyguardUnfoldTransition;
import com.android.keyguard.LockIconViewController;
import com.android.systemui.Dumpable;
import com.android.systemui.animation.ActivityTransitionAnimator;
@@ -72,6 +73,7 @@
import com.android.systemui.statusbar.phone.PhoneStatusBarViewController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.window.StatusBarWindowStateController;
+import com.android.systemui.unfold.SysUIUnfoldComponent;
import com.android.systemui.unfold.UnfoldTransitionProgressProvider;
import com.android.systemui.util.time.SystemClock;
@@ -174,6 +176,7 @@
DozeScrimController dozeScrimController,
NotificationShadeWindowController controller,
Optional<UnfoldTransitionProgressProvider> unfoldTransitionProgressProvider,
+ Optional<SysUIUnfoldComponent> unfoldComponent,
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
NotificationInsetsController notificationInsetsController,
AmbientState ambientState,
@@ -227,13 +230,21 @@
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,
notificationLaunchAnimationInteractor.isLaunchAnimationRunning(),
this::setExpandAnimationRunning);
+ var keyguardUnfoldTransition = unfoldComponent.map(
+ SysUIUnfoldComponent::getKeyguardUnfoldTransition);
+ var notificationPanelUnfoldAnimationController = unfoldComponent.map(
+ SysUIUnfoldComponent::getNotificationPanelUnfoldAnimationController);
+
+ keyguardUnfoldTransition.ifPresent(KeyguardUnfoldTransition::setup);
+ notificationPanelUnfoldAnimationController.ifPresent(u -> u.setup(mView));
+
mClock = clock;
if (featureFlagsClassic.isEnabled(Flags.SPLIT_SHADE_SUBPIXEL_OPTIMIZATION)) {
unfoldTransitionProgressProvider.ifPresent(
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/row/wrapper/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
index d1fabb1..9394249 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
@@ -358,11 +358,7 @@
* @param whenMillis
*/
public void setNotificationWhen(long whenMillis) {
- if (mNotificationHeader == null) {
- return;
- }
-
- final View timeView = mNotificationHeader.findViewById(com.android.internal.R.id.time);
+ final View timeView = mView.findViewById(com.android.internal.R.id.time);
if (timeView instanceof DateTimeView) {
((DateTimeView) timeView).setTime(whenMillis);
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..291903d 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt
@@ -21,6 +21,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.shade.NotificationPanelUnfoldAnimationController
import com.android.systemui.statusbar.phone.StatusBarMoveFromCenterAnimationController
+import com.android.systemui.unfold.dagger.NaturalRotation
import com.android.systemui.unfold.dagger.UnfoldBg
import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider
@@ -36,6 +37,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 +56,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>,
@@ -98,6 +109,13 @@
abstract fun bindsFoldLightRevealOverlayAnimation(
anim: FoldLightRevealOverlayAnimation
): FullscreenLightRevealAnimation
+
+ @Binds
+ @NaturalRotation
+ @SysUIUnfoldScope
+ abstract fun bindNaturalRotationUnfoldProgressProvider(
+ provider: NaturalRotationUnfoldProgressProvider
+ ): UnfoldTransitionProgressProvider
}
@SysUIUnfoldScope
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/KeyguardUnfoldTransitionTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUnfoldTransitionTest.kt
index 3afca59..336183d 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUnfoldTransitionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUnfoldTransitionTest.kt
@@ -18,26 +18,25 @@
import android.testing.AndroidTestingRunner
import android.view.View
-import android.view.ViewGroup
import androidx.test.filters.SmallTest
-import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.keyguard.ui.view.KeyguardRootView
+import com.android.systemui.kosmos.Kosmos
import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.res.R
+import com.android.systemui.shade.NotificationShadeWindowView
import com.android.systemui.statusbar.StatusBarState.KEYGUARD
import com.android.systemui.statusbar.StatusBarState.SHADE
+import com.android.systemui.unfold.FakeUnfoldTransitionProvider
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
-import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider
-import com.android.systemui.util.mockito.capture
-import com.android.systemui.util.mockito.whenever
+import com.android.systemui.unfold.fakeUnfoldTransitionProgressProvider
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.ArgumentCaptor
-import org.mockito.Captor
import org.mockito.Mock
-import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.whenever
/**
* Translates items away/towards the hinge when the device is opened/closed. This is controlled by
@@ -47,11 +46,16 @@
@RunWith(AndroidTestingRunner::class)
class KeyguardUnfoldTransitionTest : SysuiTestCase() {
- @Mock private lateinit var progressProvider: NaturalRotationUnfoldProgressProvider
+ private val kosmos = Kosmos()
- @Captor private lateinit var progressListenerCaptor: ArgumentCaptor<TransitionProgressListener>
+ private val progressProvider: FakeUnfoldTransitionProvider =
+ kosmos.fakeUnfoldTransitionProgressProvider
- @Mock private lateinit var parent: ViewGroup
+ @Mock
+ private lateinit var keyguardRootView: KeyguardRootView
+
+ @Mock
+ private lateinit var notificationShadeWindowView: NotificationShadeWindowView
@Mock private lateinit var statusBarStateController: StatusBarStateController
@@ -66,13 +70,15 @@
xTranslationMax =
context.resources.getDimensionPixelSize(R.dimen.keyguard_unfold_translation_x).toFloat()
- underTest = KeyguardUnfoldTransition(context, statusBarStateController, progressProvider)
+ underTest = KeyguardUnfoldTransition(
+ context, keyguardRootView, notificationShadeWindowView,
+ statusBarStateController, progressProvider
+ )
- underTest.setup(parent)
+ underTest.setup()
underTest.statusViewCentered = false
- verify(progressProvider).addCallback(capture(progressListenerCaptor))
- progressListener = progressListenerCaptor.value
+ progressListener = progressProvider
}
@Test
@@ -81,7 +87,9 @@
underTest.statusViewCentered = true
val view = View(context)
- whenever(parent.findViewById<View>(R.id.lockscreen_clock_view_large)).thenReturn(view)
+ whenever(keyguardRootView.findViewById<View>(R.id.lockscreen_clock_view_large)).thenReturn(
+ view
+ )
progressListener.onTransitionStarted()
assertThat(view.translationX).isZero()
@@ -101,7 +109,9 @@
whenever(statusBarStateController.getState()).thenReturn(SHADE)
val view = View(context)
- whenever(parent.findViewById<View>(R.id.lockscreen_clock_view_large)).thenReturn(view)
+ whenever(keyguardRootView.findViewById<View>(R.id.lockscreen_clock_view_large)).thenReturn(
+ view
+ )
progressListener.onTransitionStarted()
assertThat(view.translationX).isZero()
@@ -121,7 +131,10 @@
whenever(statusBarStateController.getState()).thenReturn(KEYGUARD)
val view = View(context)
- whenever(parent.findViewById<View>(R.id.lockscreen_clock_view_large)).thenReturn(view)
+ whenever(
+ notificationShadeWindowView
+ .findViewById<View>(R.id.lockscreen_clock_view_large)
+ ).thenReturn(view)
progressListener.onTransitionStarted()
assertThat(view.translationX).isZero()
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/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
index e02fb29..89e0971 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
@@ -30,7 +30,6 @@
import com.android.systemui.communal.domain.interactor.communalInteractor
import com.android.systemui.communal.domain.interactor.setCommunalAvailable
import com.android.systemui.communal.shared.model.CommunalScenes
-import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository
import com.android.systemui.dock.fakeDockManager
import com.android.systemui.flags.BrokenWithSceneContainer
import com.android.systemui.flags.DisableSceneContainer
@@ -608,31 +607,6 @@
/** This handles security method NONE and screen off with lock timeout */
@Test
- fun dozingToGoneWithKeyguardNotShowing() =
- testScope.runTest {
- // GIVEN a prior transition has run to DOZING
- runTransitionAndSetWakefulness(KeyguardState.LOCKSCREEN, KeyguardState.DOZING)
- runCurrent()
-
- // WHEN the device wakes up without a keyguard
- keyguardRepository.setKeyguardShowing(false)
- keyguardRepository.setKeyguardDismissible(true)
- kosmos.fakeDeviceEntryRepository.setLockscreenEnabled(false)
- powerInteractor.setAwakeForTest()
- advanceTimeBy(60L)
-
- assertThat(transitionRepository)
- .startedTransition(
- to = KeyguardState.GONE,
- from = KeyguardState.DOZING,
- animatorAssertion = { it.isNotNull() }
- )
-
- coroutineContext.cancelChildren()
- }
-
- /** This handles security method NONE and screen off with lock timeout */
- @Test
@DisableSceneContainer
fun dreamingToGoneWithKeyguardNotShowing() =
testScope.runTest {
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/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
index 586adbd..74a2999 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -70,6 +70,7 @@
import com.android.systemui.statusbar.phone.PhoneStatusBarViewController
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
import com.android.systemui.statusbar.window.StatusBarWindowStateController
+import com.android.systemui.unfold.SysUIUnfoldComponent
import com.android.systemui.unfold.UnfoldTransitionProgressProvider
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.util.mockito.any
@@ -85,6 +86,7 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.Answers
import org.mockito.ArgumentCaptor
import org.mockito.Mock
import org.mockito.Mockito.anyFloat
@@ -132,6 +134,8 @@
private lateinit var mLockscreenHostedDreamGestureListener: LockscreenHostedDreamGestureListener
@Mock private lateinit var notificationInsetsController: NotificationInsetsController
@Mock private lateinit var mGlanceableHubContainerController: GlanceableHubContainerController
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private lateinit var sysUiUnfoldComponent: SysUIUnfoldComponent
@Mock lateinit var keyguardBouncerComponentFactory: KeyguardBouncerComponent.Factory
@Mock lateinit var keyguardBouncerComponent: KeyguardBouncerComponent
@Mock lateinit var keyguardSecurityContainerController: KeyguardSecurityContainerController
@@ -209,6 +213,7 @@
dozeScrimController,
notificationShadeWindowController,
unfoldTransitionProgressProvider,
+ Optional.of(sysUiUnfoldComponent),
keyguardUnlockAnimationController,
notificationInsetsController,
ambientState,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
index e83a46b..31bd12f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
@@ -58,6 +58,7 @@
import com.android.systemui.statusbar.phone.DozeServiceHost
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
import com.android.systemui.statusbar.window.StatusBarWindowStateController
+import com.android.systemui.unfold.SysUIUnfoldComponent
import com.android.systemui.unfold.UnfoldTransitionProgressProvider
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.mock
@@ -112,6 +113,7 @@
@Mock private lateinit var shadeLogger: ShadeLogger
@Mock private lateinit var dumpManager: DumpManager
@Mock private lateinit var pulsingGestureListener: PulsingGestureListener
+ @Mock private lateinit var sysUiUnfoldComponent: SysUIUnfoldComponent
@Mock
private lateinit var mLockscreenHostedDreamGestureListener: LockscreenHostedDreamGestureListener
@Mock private lateinit var keyguardBouncerComponentFactory: KeyguardBouncerComponent.Factory
@@ -181,6 +183,7 @@
dozeScrimController,
notificationShadeWindowController,
unfoldTransitionProgressProvider,
+ Optional.of(sysUiUnfoldComponent),
keyguardUnlockAnimationController,
notificationInsetsController,
ambientState,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt
index a05a23b..293dc04 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt
@@ -27,6 +27,9 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
+import org.mockito.Mockito.anyFloat
+import org.mockito.Mockito.spy
+import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
@@ -78,6 +81,22 @@
}
@Test
+ fun initMultipleTimes_onTransition_translationIsSetOnlyOnce() {
+ animator.init(parent, MAX_TRANSLATION)
+ animator.init(parent, MAX_TRANSLATION)
+ animator.init(parent, MAX_TRANSLATION)
+
+ // GIVEN one view with a matching id
+ val view = spy(View(context))
+ whenever(parent.findViewById<View>(START_VIEW_ID)).thenReturn(view)
+ progressProvider.onTransitionStarted()
+
+ // WHEN the transition progresses, translation is updated once
+ progressProvider.onTransitionProgress(.5f)
+ verify(view).translationX = anyFloat()
+ }
+
+ @Test
fun onTransition_oneMovesStartWithRTL() {
// GIVEN one view with a matching id
val view = View(context)
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/dagger/NaturalRotation.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/dagger/NaturalRotation.kt
new file mode 100644
index 0000000..be02487
--- /dev/null
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/dagger/NaturalRotation.kt
@@ -0,0 +1,21 @@
+/*
+ * 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.unfold.dagger
+
+import javax.inject.Qualifier
+
+/** Qualifier annotation for a progress provider that emits animation events only when
+ * in natural rotation */
+@Qualifier @Retention(AnnotationRetention.RUNTIME) annotation class NaturalRotation
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/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index 2607ed3..89c888c 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -18,6 +18,7 @@
import static android.Manifest.permission.MANAGE_CONTENT_CAPTURE;
import static android.content.Context.CONTENT_CAPTURE_MANAGER_SERVICE;
+import static android.service.contentcapture.ContentCaptureService.ASSIST_CONTENT_ACTIVITY_START_KEY;
import static android.service.contentcapture.ContentCaptureService.setClientState;
import static android.view.contentcapture.ContentCaptureHelper.toList;
import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_ALLOWLIST_DELAY_MS;
@@ -28,6 +29,7 @@
import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_OPTIONAL_GROUPS_THRESHOLD;
import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_REQUIRED_GROUPS_CONFIG;
import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_ENABLE_CONTENT_PROTECTION_RECEIVER;
+import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_ENABLE_ACTIVITY_START_ASSIST_CONTENT;
import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_FALSE;
import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_OK;
import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_SECURITY_EXCEPTION;
@@ -44,6 +46,7 @@
import static com.android.internal.util.FrameworkStatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__DATA_SHARE_WRITE_FINISHED;
import static com.android.internal.util.FrameworkStatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__REJECT_DATA_SHARE_REQUEST;
import static com.android.internal.util.SyncResultReceiver.bundleFor;
+import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_CONTENT;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -52,10 +55,12 @@
import android.app.ActivityThread;
import android.app.admin.DevicePolicyCache;
import android.app.assist.ActivityId;
+import android.app.assist.AssistContent;
import android.content.ComponentName;
import android.content.ContentCaptureOptions;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.ActivityPresentationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -184,6 +189,9 @@
@Nullable
private boolean mDisabledByDeviceConfig;
+ @GuardedBy("mLock")
+ private boolean activityStartAssistDataEnabled;
+
// Device-config settings that are cached and passed back to apps
@GuardedBy("mLock")
int mDevCfgLoggingLevel;
@@ -451,6 +459,8 @@
case DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_AUTO_DISCONNECT_TIMEOUT:
setFineTuneParamsFromDeviceConfig();
return;
+ case DEVICE_CONFIG_ENABLE_ACTIVITY_START_ASSIST_CONTENT:
+ setActivityStartAssistDataEnabled();
default:
Slog.i(TAG, "Ignoring change on " + key);
}
@@ -639,6 +649,15 @@
final String enabled = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
ContentCaptureManager.DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED);
setDisabledByDeviceConfig(enabled);
+ setActivityStartAssistDataEnabled();
+ }
+
+ private void setActivityStartAssistDataEnabled() {
+ synchronized (mLock) {
+ this.activityStartAssistDataEnabled = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+ DEVICE_CONFIG_ENABLE_ACTIVITY_START_ASSIST_CONTENT, false);
+ }
}
private void setDisabledByDeviceConfig(@Nullable String explicitlyEnabled) {
@@ -908,6 +927,9 @@
pw.print(prefix2);
pw.print("contentProtectionAutoDisconnectTimeoutMs: ");
pw.println(mDevCfgContentProtectionAutoDisconnectTimeoutMs);
+ pw.print(prefix2);
+ pw.print("activityStartAssistDataEnabled: ");
+ pw.println(activityStartAssistDataEnabled);
pw.print(prefix);
pw.println("Global Options:");
mGlobalContentCaptureOptions.dump(prefix2, pw);
@@ -1327,6 +1349,33 @@
}
@Override
+ @SuppressWarnings("GuardedBy")
+ public boolean sendActivityStartAssistData(@UserIdInt int userId,
+ @NonNull IBinder activityToken,
+ @NonNull Intent intentData) {
+ synchronized (mLock) {
+ if (!activityStartAssistDataEnabled) {
+ return false;
+ }
+ Intent intent = new Intent(intentData);
+ intent.setFlags(intent.getFlags() & ~(Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+ | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION));
+ Bundle assistContentExtras = new Bundle();
+ assistContentExtras.putBoolean(ASSIST_CONTENT_ACTIVITY_START_KEY, true);
+ AssistContent assistContent = new AssistContent(assistContentExtras);
+ assistContent.setDefaultIntent(intent);
+
+ final Bundle activityAssistData = new Bundle();
+ activityAssistData.putParcelable(ASSIST_KEY_CONTENT, assistContent);
+ final ContentCapturePerUserService service = peekServiceForUserLocked(userId);
+ if (service != null) {
+ return service.sendActivityAssistDataLocked(activityToken, activityAssistData);
+ }
+ }
+ return false;
+ }
+
+ @Override
public boolean sendActivityAssistData(@UserIdInt int userId, @NonNull IBinder activityToken,
@NonNull Bundle data) {
synchronized (mLock) {
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 2a724cd..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),
@@ -15274,15 +15278,50 @@
BackgroundStartPrivileges backgroundStartPrivileges,
@Nullable int[] broadcastAllowList,
@Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver) {
- final int cookie = BroadcastQueue.traceBegin("broadcastIntentLockedTraced");
- final int res = broadcastIntentLockedTraced(callerApp, callerPackage, callerFeatureId,
- intent, resolvedType, resultToApp, resultTo, resultCode, resultData, resultExtras,
- requiredPermissions, excludedPermissions, excludedPackages, appOp,
- BroadcastOptions.fromBundleNullable(bOptions), ordered, sticky,
- callingPid, callingUid, realCallingUid, realCallingPid, userId,
- backgroundStartPrivileges, broadcastAllowList, filterExtrasForReceiver);
- BroadcastQueue.traceEnd(cookie);
- return res;
+ final int cookie = traceBroadcastIntentBegin(intent, resultTo, ordered, sticky,
+ callingUid, realCallingUid, userId);
+ try {
+ final int res = broadcastIntentLockedTraced(callerApp, callerPackage, callerFeatureId,
+ intent, resolvedType, resultToApp, resultTo, resultCode, resultData,
+ resultExtras, requiredPermissions, excludedPermissions, excludedPackages,
+ appOp, BroadcastOptions.fromBundleNullable(bOptions), ordered, sticky,
+ callingPid, callingUid, realCallingUid, realCallingPid, userId,
+ backgroundStartPrivileges, broadcastAllowList, filterExtrasForReceiver);
+ return res;
+ } finally {
+ traceBroadcastIntentEnd(cookie);
+ }
+ }
+
+ private static int traceBroadcastIntentBegin(Intent intent, IIntentReceiver resultTo,
+ boolean ordered, boolean sticky, int callingUid, int realCallingUid, int userId) {
+ if (!Flags.traceReceiverRegistration()) {
+ return BroadcastQueue.traceBegin("broadcastIntentLockedTraced");
+ }
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
+ final StringBuilder sb = new StringBuilder("broadcastIntent: ");
+ sb.append(callingUid); sb.append('/');
+ final String action = intent.getAction();
+ sb.append(action == null ? null : action); sb.append('/');
+ sb.append("0x"); sb.append(Integer.toHexString(intent.getFlags())); sb.append('/');
+ sb.append(ordered ? "O" : "_");
+ sb.append(sticky ? "S" : "_");
+ sb.append(resultTo != null ? "C" : "_");
+ sb.append('/');
+ sb.append('u'); sb.append(userId);
+ if (callingUid != realCallingUid) {
+ sb.append('/');
+ sb.append("sender="); sb.append(realCallingUid);
+ }
+ return BroadcastQueue.traceBegin(sb.toString());
+ }
+ return 0;
+ }
+
+ private static void traceBroadcastIntentEnd(int cookie) {
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
+ BroadcastQueue.traceEnd(cookie);
+ }
}
@GuardedBy("this")
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/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
index f9f56ee..2660932 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
@@ -316,6 +316,8 @@
if (getBiometricContext().isAwake()) {
mALSProbeCallback.getProbe().enable();
+ } else {
+ mALSProbeCallback.getProbe().disable();
}
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception", e);
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/contentcapture/ContentCaptureManagerInternal.java b/services/core/java/com/android/server/contentcapture/ContentCaptureManagerInternal.java
index 0812fd9..de7341d 100644
--- a/services/core/java/com/android/server/contentcapture/ContentCaptureManagerInternal.java
+++ b/services/core/java/com/android/server/contentcapture/ContentCaptureManagerInternal.java
@@ -21,6 +21,7 @@
import android.app.assist.ActivityId;
import android.content.ComponentName;
import android.content.ContentCaptureOptions;
+import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
import android.service.contentcapture.ActivityEvent.ActivityEventType;
@@ -40,6 +41,14 @@
public abstract boolean isContentCaptureServiceForUser(int uid, @UserIdInt int userId);
/**
+ * Notifies the intelligence service of new intent data associated with an activity start event.
+ *
+ * @return {@code false} if there was no service set for the given user
+ */
+ public abstract boolean sendActivityStartAssistData(@UserIdInt int userId,
+ @NonNull IBinder activityToken, @NonNull Intent intentData);
+
+ /**
* Notifies the intelligence service of new assist data for the given activity.
*
* @return {@code false} if there was no service set for the given user
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/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 5fd0253..2d5f38e 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -3406,6 +3406,31 @@
}
}
+ boolean requestDisplayPower(int displayId, boolean on) {
+ synchronized (mSyncRoot) {
+ final var display = mLogicalDisplayMapper.getDisplayLocked(displayId);
+ if (display == null) {
+ Slog.w(TAG, "requestDisplayPower: Cannot find a display with displayId="
+ + displayId);
+ return false;
+ }
+ final BrightnessPair brightnessPair = mDisplayBrightnesses.get(displayId);
+ var runnable = display.getPrimaryDisplayDeviceLocked().requestDisplayStateLocked(
+ on ? Display.STATE_ON : Display.STATE_OFF,
+ on ? brightnessPair.brightness : PowerManager.BRIGHTNESS_OFF_FLOAT,
+ brightnessPair.sdrBrightness,
+ display.getDisplayOffloadSessionLocked());
+ if (runnable == null) {
+ Slog.w(TAG, "requestDisplayPower: Cannot update the power state to ON=" + on
+ + " for a display with displayId=" + displayId + ", runnable is null");
+ return false;
+ }
+ runnable.run();
+ Slog.i(TAG, "requestDisplayPower(displayId=" + displayId + ", on=" + on + ")");
+ }
+ return true;
+ }
+
/**
* This is the object that everything in the display manager locks on.
* We make it an inner class within the {@link DisplayManagerService} to so that it is
@@ -4629,6 +4654,12 @@
DisplayManagerService.this.enableConnectedDisplay(displayId, false);
}
+ @EnforcePermission(MANAGE_DISPLAYS)
+ public boolean requestDisplayPower(int displayId, boolean on) {
+ requestDisplayPower_enforcePermission();
+ return DisplayManagerService.this.requestDisplayPower(displayId, on);
+ }
+
@EnforcePermission(RESTRICT_DISPLAY_MODES)
@Override // Binder call
public void requestDisplayModes(IBinder token, int displayId, @Nullable int[] modeIds) {
diff --git a/services/core/java/com/android/server/display/DisplayManagerShellCommand.java b/services/core/java/com/android/server/display/DisplayManagerShellCommand.java
index 8c39d7d..d973b71 100644
--- a/services/core/java/com/android/server/display/DisplayManagerShellCommand.java
+++ b/services/core/java/com/android/server/display/DisplayManagerShellCommand.java
@@ -106,6 +106,10 @@
return setDisplayEnabled(true);
case "disable-display":
return setDisplayEnabled(false);
+ case "power-on":
+ return requestDisplayPower(true);
+ case "power-off":
+ return requestDisplayPower(false);
default:
return handleDefaultCommands(cmd);
}
@@ -592,4 +596,21 @@
mService.enableConnectedDisplay(displayId, enable);
return 0;
}
+
+ private int requestDisplayPower(boolean enable) {
+ final String displayIdText = getNextArg();
+ if (displayIdText == null) {
+ getErrPrintWriter().println("Error: no displayId specified");
+ return 1;
+ }
+ final int displayId;
+ try {
+ displayId = Integer.parseInt(displayIdText);
+ } catch (NumberFormatException e) {
+ getErrPrintWriter().println("Error: invalid displayId: '" + displayIdText + "'");
+ return 1;
+ }
+ mService.requestDisplayPower(displayId, enable);
+ return 0;
+ }
}
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/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 0bd40d1..e5dbce9 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -3352,6 +3352,10 @@
mPointerIconCache.setPointerFillStyle(fillStyle);
}
+ void setPointerScale(float scale) {
+ mPointerIconCache.setPointerScale(scale);
+ }
+
interface KeyboardBacklightControllerInterface {
default void incrementKeyboardBacklight(int deviceId) {}
default void decrementKeyboardBacklight(int deviceId) {}
diff --git a/services/core/java/com/android/server/input/InputSettingsObserver.java b/services/core/java/com/android/server/input/InputSettingsObserver.java
index 9585b49..593b091 100644
--- a/services/core/java/com/android/server/input/InputSettingsObserver.java
+++ b/services/core/java/com/android/server/input/InputSettingsObserver.java
@@ -16,6 +16,7 @@
package com.android.server.input;
+import static android.view.PointerIcon.DEFAULT_POINTER_SCALE;
import static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_FILL_BLACK;
import static android.view.flags.Flags.enableVectorCursorA11ySettings;
@@ -101,7 +102,9 @@
Map.entry(Settings.Secure.getUriFor(Settings.Secure.STYLUS_POINTER_ICON_ENABLED),
(reason) -> updateStylusPointerIconEnabled()),
Map.entry(Settings.System.getUriFor(Settings.System.POINTER_FILL_STYLE),
- (reason) -> updatePointerFillStyleFromSettings()));
+ (reason) -> updatePointerFillStyleFromSettings()),
+ Map.entry(Settings.System.getUriFor(Settings.System.POINTER_SCALE),
+ (reason) -> updatePointerScaleFromSettings()));
}
/**
@@ -277,4 +280,14 @@
UserHandle.USER_CURRENT);
mService.setPointerFillStyle(pointerFillStyle);
}
+
+ private void updatePointerScaleFromSettings() {
+ if (!enableVectorCursorA11ySettings()) {
+ return;
+ }
+ final float pointerScale = Settings.System.getFloatForUser(mContext.getContentResolver(),
+ Settings.System.POINTER_SCALE, DEFAULT_POINTER_SCALE,
+ UserHandle.USER_CURRENT);
+ mService.setPointerScale(pointerScale);
+ }
}
diff --git a/services/core/java/com/android/server/input/PointerIconCache.java b/services/core/java/com/android/server/input/PointerIconCache.java
index 936e17f..44622d8 100644
--- a/services/core/java/com/android/server/input/PointerIconCache.java
+++ b/services/core/java/com/android/server/input/PointerIconCache.java
@@ -16,6 +16,7 @@
package com.android.server.input;
+import static android.view.PointerIcon.DEFAULT_POINTER_SCALE;
import static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_FILL_BLACK;
import android.annotation.NonNull;
@@ -63,6 +64,8 @@
@GuardedBy("mLoadedPointerIconsByDisplayAndType")
private @PointerIcon.PointerIconVectorStyleFill int mPointerIconFillStyle =
POINTER_ICON_VECTOR_STYLE_FILL_BLACK;
+ @GuardedBy("mLoadedPointerIconsByDisplayAndType")
+ private float mPointerIconScale = DEFAULT_POINTER_SCALE;
private final DisplayManager.DisplayListener mDisplayListener =
new DisplayManager.DisplayListener() {
@@ -117,6 +120,11 @@
mUiThreadHandler.post(() -> handleSetPointerFillStyle(fillStyle));
}
+ /** Set the scale for vector pointer icons. */
+ public void setPointerScale(float scale) {
+ mUiThreadHandler.post(() -> handleSetPointerScale(scale));
+ }
+
/**
* Get a loaded system pointer icon. This will fetch the icon from the cache, or load it if
* it isn't already cached.
@@ -137,7 +145,7 @@
theme.applyStyle(PointerIcon.vectorFillStyleToResource(mPointerIconFillStyle),
/* force= */ true);
icon = PointerIcon.getLoadedSystemIcon(new ContextThemeWrapper(context, theme),
- type, mUseLargePointerIcons);
+ type, mUseLargePointerIcons, mPointerIconScale);
iconsByType.put(type, icon);
}
return Objects.requireNonNull(icon);
@@ -215,6 +223,19 @@
mNative.reloadPointerIcons();
}
+ @android.annotation.UiThread
+ private void handleSetPointerScale(float scale) {
+ synchronized (mLoadedPointerIconsByDisplayAndType) {
+ if (mPointerIconScale == scale) {
+ return;
+ }
+ mPointerIconScale = scale;
+ // Clear all cached icons on all displays.
+ mLoadedPointerIconsByDisplayAndType.clear();
+ }
+ mNative.reloadPointerIcons();
+ }
+
// Updates the cached display density for the given displayId, and returns true if
// the cached density changed.
@GuardedBy("mLoadedPointerIconsByDisplayAndType")
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..1a0ffb7 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,9 +5240,9 @@
Slog.e(TAG, "buildInputMethodListLocked is not allowed until system is ready");
return;
}
- mMethodMapUpdateCount++;
- final InputMethodSettings settings = InputMethodSettingsRepository.get(mCurrentUserId);
+ final int userId = mCurrentUserId;
+ final InputMethodSettings settings = InputMethodSettingsRepository.get(userId);
boolean reenableMinimumNonAuxSystemImes = false;
// TODO: The following code should find better place to live.
@@ -5291,18 +5305,18 @@
updateDefaultVoiceImeIfNeededLocked();
// 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(), mCurrentUserId);
}
// 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();
@@ -5310,7 +5324,7 @@
// Notify InputMethodListListeners of the new installed InputMethods.
final List<InputMethodInfo> inputMethodList = settings.getMethodList();
mHandler.obtainMessage(MSG_DISPATCH_ON_INPUT_METHOD_LIST_UPDATED,
- settings.getUserId(), 0 /* unused */, inputMethodList).sendToTarget();
+ userId, 0 /* unused */, inputMethodList).sendToTarget();
}
@GuardedBy("ImfLock.class")
@@ -5446,7 +5460,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 +6066,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/locksettings/BiometricDeferredQueue.java b/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java
index f572845..966be53 100644
--- a/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java
+++ b/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java
@@ -32,6 +32,7 @@
import android.util.Slog;
import com.android.internal.widget.VerifyCredentialResponse;
+import com.android.server.biometrics.BiometricHandlerProvider;
import java.util.ArrayList;
import java.util.List;
@@ -132,9 +133,11 @@
mFaceResetLockoutTask = null;
};
- BiometricDeferredQueue(@NonNull SyntheticPasswordManager spManager, @NonNull Handler handler) {
+ BiometricDeferredQueue(@NonNull SyntheticPasswordManager spManager) {
mSpManager = spManager;
- mHandler = handler;
+
+ //Using a higher priority thread to avoid any delays and interruption of clients
+ mHandler = BiometricHandlerProvider.getInstance().getBiometricCallbackHandler();
mPendingResetLockoutsForFingerprint = new ArrayList<>();
mPendingResetLockoutsForFace = new ArrayList<>();
mPendingResetLockouts = new ArrayList<>();
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index ae3d36a..22b33dd 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -687,7 +687,7 @@
mSpManager = injector.getSyntheticPasswordManager(mStorage);
mUnifiedProfilePasswordCache = injector.getUnifiedProfilePasswordCache(mKeyStore);
- mBiometricDeferredQueue = new BiometricDeferredQueue(mSpManager, mHandler);
+ mBiometricDeferredQueue = new BiometricDeferredQueue(mSpManager);
mRebootEscrowManager = injector.getRebootEscrowManager(new RebootEscrowCallbacks(),
mStorage);
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/policy/TalkbackShortcutController.java b/services/core/java/com/android/server/policy/TalkbackShortcutController.java
index b05a421..e544ae6 100644
--- a/services/core/java/com/android/server/policy/TalkbackShortcutController.java
+++ b/services/core/java/com/android/server/policy/TalkbackShortcutController.java
@@ -117,6 +117,7 @@
}
private boolean isTalkback(ServiceInfo info) {
- return TALKBACK_LABEL.equals(info.loadLabel(mPackageManager).toString());
+ return TALKBACK_LABEL.equals(info.loadLabel(mPackageManager).toString())
+ && (info.applicationInfo.isSystemApp() || info.applicationInfo.isUpdatedSystemApp());
}
}
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 11b9e77..80c262a 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -17,6 +17,7 @@
package com.android.server.power;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.annotation.UserIdInt;
import android.app.ActivityManagerInternal;
import android.app.AppOpsManager;
@@ -197,9 +198,10 @@
FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector,
Executor backgroundExecutor, PowerManagerFlags powerManagerFlags, Injector injector) {
mContext = context;
+ mInjector = (injector == null) ? new RealInjector() : injector;
mFlags = powerManagerFlags;
mBatteryStats = batteryStats;
- mAppOps = mContext.getSystemService(AppOpsManager.class);
+ mAppOps = mInjector.getAppOpsManager(context);
mSuspendBlocker = suspendBlocker;
mPolicy = policy;
mFaceDownDetector = faceDownDetector;
@@ -230,7 +232,6 @@
mShowWirelessChargingAnimationConfig = context.getResources().getBoolean(
com.android.internal.R.bool.config_showBuiltinWirelessChargingAnim);
- mInjector = (injector == null) ? new RealInjector() : injector;
mWakeLockLog = mInjector.getWakeLockLog(context);
// Initialize interactive state for battery stats.
try {
@@ -264,6 +265,7 @@
/**
* Called when a wake lock is acquired.
*/
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public void onWakeLockAcquired(int flags, String tag, String packageName,
int ownerUid, int ownerPid, WorkSource workSource, String historyTag,
IWakeLockCallback callback) {
@@ -273,27 +275,28 @@
+ ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid
+ ", workSource=" + workSource);
}
- notifyWakeLockListener(callback, tag, true, ownerUid, flags);
- final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
- if (monitorType >= 0) {
- try {
- final boolean unimportantForLogging = ownerUid == Process.SYSTEM_UID
- && (flags & PowerManager.UNIMPORTANT_FOR_LOGGING) != 0;
- if (workSource != null) {
- mBatteryStats.noteStartWakelockFromSource(workSource, ownerPid, tag,
- historyTag, monitorType, unimportantForLogging);
- } else {
- mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, historyTag,
- monitorType, unimportantForLogging);
- // XXX need to deal with disabled operations.
- mAppOps.startOpNoThrow(AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName);
- }
- } catch (RemoteException ex) {
- // Ignore
- }
- }
-
+ notifyWakeLockListener(callback, tag, true, ownerUid, ownerPid, flags, workSource,
+ packageName, historyTag);
if (!mFlags.improveWakelockLatency()) {
+ final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
+ if (monitorType >= 0) {
+ try {
+ final boolean unimportantForLogging = ownerUid == Process.SYSTEM_UID
+ && (flags & PowerManager.UNIMPORTANT_FOR_LOGGING) != 0;
+ if (workSource != null) {
+ mBatteryStats.noteStartWakelockFromSource(workSource, ownerPid, tag,
+ historyTag, monitorType, unimportantForLogging);
+ } else {
+ mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, historyTag,
+ monitorType, unimportantForLogging);
+ // XXX need to deal with disabled operations.
+ mAppOps.startOpNoThrow(AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName,
+ false, null, null);
+ }
+ } catch (RemoteException ex) {
+ // Ignore
+ }
+ }
mWakeLockLog.onWakeLockAcquired(tag, ownerUid, flags, /*eventTime=*/ -1);
}
mWakefulnessSessionObserver.onWakeLockAcquired(flags);
@@ -404,6 +407,7 @@
/**
* Called when a wake lock is released.
*/
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public void onWakeLockReleased(int flags, String tag, String packageName,
int ownerUid, int ownerPid, WorkSource workSource, String historyTag,
IWakeLockCallback callback, int releaseReason) {
@@ -413,23 +417,24 @@
+ ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid
+ ", workSource=" + workSource);
}
- notifyWakeLockListener(callback, tag, false, ownerUid, flags);
- final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
- if (monitorType >= 0) {
- try {
- if (workSource != null) {
- mBatteryStats.noteStopWakelockFromSource(workSource, ownerPid, tag,
- historyTag, monitorType);
- } else {
- mBatteryStats.noteStopWakelock(ownerUid, ownerPid, tag,
- historyTag, monitorType);
- mAppOps.finishOp(AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName);
- }
- } catch (RemoteException ex) {
- // Ignore
- }
- }
+ notifyWakeLockListener(callback, tag, false, ownerUid, ownerPid, flags, workSource,
+ packageName, historyTag);
if (!mFlags.improveWakelockLatency()) {
+ final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
+ if (monitorType >= 0) {
+ try {
+ if (workSource != null) {
+ mBatteryStats.noteStopWakelockFromSource(workSource, ownerPid, tag,
+ historyTag, monitorType);
+ } else {
+ mBatteryStats.noteStopWakelock(ownerUid, ownerPid, tag,
+ historyTag, monitorType);
+ mAppOps.finishOp(AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName, null);
+ }
+ } catch (RemoteException ex) {
+ // Ignore
+ }
+ }
mWakeLockLog.onWakeLockReleased(tag, ownerUid, /*eventTime=*/ -1);
}
mWakefulnessSessionObserver.onWakeLockReleased(flags, releaseReason);
@@ -1049,24 +1054,75 @@
}
private void notifyWakeLockListener(IWakeLockCallback callback, String tag, boolean isEnabled,
- int ownerUid, int flags) {
- if (callback != null) {
- long currentTime = mInjector.currentTimeMillis();
- mHandler.post(() -> {
- try {
- if (mFlags.improveWakelockLatency()) {
+ int ownerUid, int ownerPid, int flags, WorkSource workSource, String packageName,
+ String historyTag) {
+ if (mFlags.improveWakelockLatency()) {
+ if (callback != null) {
+ long currentTime = mInjector.currentTimeMillis();
+ mHandler.post(() -> {
+ try {
if (isEnabled) {
- mWakeLockLog.onWakeLockAcquired(tag, ownerUid, flags, currentTime);
+ notifyWakelockAcquisition(tag, ownerUid, ownerPid, flags,
+ workSource, packageName, historyTag, currentTime);
} else {
- mWakeLockLog.onWakeLockReleased(tag, ownerUid, currentTime);
+ notifyWakelockRelease(tag, ownerUid, ownerPid, flags,
+ workSource, packageName, historyTag, currentTime);
}
+ callback.onStateChanged(isEnabled);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Wakelock.mCallback [" + tag + "] is already dead.", e);
}
- callback.onStateChanged(isEnabled);
- } catch (RemoteException e) {
- Slog.e(TAG, "Wakelock.mCallback [" + tag + "] is already dead.", e);
- }
- });
+ });
+ }
}
+
+ }
+
+ @SuppressLint("AndroidFrameworkRequiresPermission")
+ private void notifyWakelockAcquisition(String tag, int ownerUid, int ownerPid, int flags,
+ WorkSource workSource, String packageName, String historyTag, long currentTime) {
+ final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
+ if (monitorType >= 0) {
+ try {
+ final boolean unimportantForLogging = ownerUid == Process.SYSTEM_UID
+ && (flags & PowerManager.UNIMPORTANT_FOR_LOGGING) != 0;
+ if (workSource != null) {
+ mBatteryStats.noteStartWakelockFromSource(workSource, ownerPid, tag,
+ historyTag, monitorType, unimportantForLogging);
+ } else {
+ mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, historyTag,
+ monitorType, unimportantForLogging);
+ // XXX need to deal with disabled operations.
+ mAppOps.startOpNoThrow(
+ AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName,
+ false, null, null);
+ }
+ } catch (RemoteException ex) {
+ // Do Nothing
+ }
+ }
+ mWakeLockLog.onWakeLockAcquired(tag, ownerUid, flags, currentTime);
+ }
+
+ @SuppressLint("AndroidFrameworkRequiresPermission")
+ private void notifyWakelockRelease(String tag, int ownerUid, int ownerPid, int flags,
+ WorkSource workSource, String packageName, String historyTag, long currentTime) {
+ final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
+ if (monitorType >= 0) {
+ try {
+ if (workSource != null) {
+ mBatteryStats.noteStopWakelockFromSource(workSource, ownerPid, tag,
+ historyTag, monitorType);
+ } else {
+ mBatteryStats.noteStopWakelock(ownerUid, ownerPid, tag,
+ historyTag, monitorType);
+ mAppOps.finishOp(AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName, null);
+ }
+ } catch (RemoteException ex) {
+ // Ignore
+ }
+ }
+ mWakeLockLog.onWakeLockReleased(tag, ownerUid, currentTime);
}
private final class NotifierHandler extends Handler {
@@ -1114,6 +1170,11 @@
* Gets the WakeLockLog object
*/
WakeLockLog getWakeLockLog(Context context);
+
+ /**
+ * Gets the AppOpsManager system service
+ */
+ AppOpsManager getAppOpsManager(Context context);
}
static class RealInjector implements Injector {
@@ -1126,5 +1187,10 @@
public WakeLockLog getWakeLockLog(Context context) {
return new WakeLockLog(context);
}
+
+ @Override
+ public AppOpsManager getAppOpsManager(Context context) {
+ return context.getSystemService(AppOpsManager.class);
+ }
}
}
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..15f4c8c 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -156,6 +156,7 @@
import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_SIZE_COMPAT_MODE;
import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED;
import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE;
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static com.android.server.wm.ActivityRecord.State.DESTROYED;
@@ -661,7 +662,8 @@
*/
private CompatDisplayInsets mCompatDisplayInsets;
- private final TaskFragment.ConfigOverrideHint mResolveConfigHint;
+ @VisibleForTesting
+ final TaskFragment.ConfigOverrideHint mResolveConfigHint;
private final boolean mOptOutEdgeToEdge;
@@ -4032,6 +4034,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();
@@ -6027,14 +6033,7 @@
true /* activityChange */, true /* updateOomAdj */,
true /* addPendingTopUid */);
}
- final ContentCaptureManagerInternal contentCaptureService =
- LocalServices.getService(ContentCaptureManagerInternal.class);
- if (contentCaptureService != null) {
- contentCaptureService.notifyActivityEvent(mUserId, mActivityComponent,
- ActivityEvent.TYPE_ACTIVITY_STARTED,
- new ActivityId(getTask() != null ? getTask().mTaskId : INVALID_TASK_ID,
- shareableActivityToken));
- }
+ mAtmService.mH.post(this::notifyActivityStartedToContentCaptureService);
break;
case PAUSED:
mAtmService.updateBatteryStats(this, false);
@@ -6066,6 +6065,22 @@
}
}
+ private void notifyActivityStartedToContentCaptureService() {
+ final ContentCaptureManagerInternal contentCaptureService =
+ LocalServices.getService(ContentCaptureManagerInternal.class);
+ if (contentCaptureService != null) {
+ // For ACTIVITY_STARTED content capture is directly invoked to avoid persisting
+ // to UsageStats.
+ contentCaptureService.notifyActivityEvent(mUserId, mActivityComponent,
+ ActivityEvent.TYPE_ACTIVITY_STARTED,
+ new ActivityId(getTask() != null ? getTask().mTaskId : INVALID_TASK_ID,
+ shareableActivityToken));
+
+ contentCaptureService.sendActivityStartAssistData(mUserId,
+ shareableActivityToken, intent);
+ }
+ }
+
State getState() {
return mState;
}
@@ -6547,7 +6562,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 +8551,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 +8667,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 +8699,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 +8722,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 +8738,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 +8852,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 +9261,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 +9290,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 +9300,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 +9357,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/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index edbba92..70143ba 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -1077,9 +1077,6 @@
if (dc != null && dc != this) {
dc.getPendingTransaction().merge(mPendingTransaction);
}
- if (dc != this && mLocalInsetsSources != null) {
- mLocalInsetsSources.clear();
- }
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowContainer child = mChildren.get(i);
child.onDisplayChanged(dc);
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/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
index d0eb83a..211ab03 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -2569,6 +2569,63 @@
}
@Test
+ public void testPowerOnAndOffInternalDisplay() {
+ manageDisplaysPermission(/* granted= */ true);
+ DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
+ DisplayManagerService.BinderService bs = displayManager.new BinderService();
+ LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper();
+ FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
+ bs.registerCallbackWithEventMask(callback, STANDARD_AND_CONNECTION_DISPLAY_EVENTS);
+
+ callback.expectsEvent(EVENT_DISPLAY_ADDED);
+ FakeDisplayDevice displayDevice =
+ createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_INTERNAL);
+ callback.waitForExpectedEvent();
+
+ LogicalDisplay display =
+ logicalDisplayMapper.getDisplayLocked(displayDevice, /* includeDisabled= */ true);
+
+ assertThat(displayDevice.getDisplayDeviceInfoLocked().committedState)
+ .isEqualTo(Display.STATE_ON);
+
+ assertThat(displayManager.requestDisplayPower(display.getDisplayIdLocked(), false))
+ .isTrue();
+
+ assertThat(displayDevice.getDisplayDeviceInfoLocked().committedState)
+ .isEqualTo(Display.STATE_OFF);
+
+ assertThat(displayManager.requestDisplayPower(display.getDisplayIdLocked(), true))
+ .isTrue();
+
+ assertThat(displayDevice.getDisplayDeviceInfoLocked().committedState)
+ .isEqualTo(Display.STATE_ON);
+ }
+
+ @Test
+ public void testPowerOnAndOffInternalDisplay_withoutPermission_shouldThrowException() {
+ DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
+ DisplayManagerService.BinderService bs = displayManager.new BinderService();
+ LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper();
+ FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
+ bs.registerCallbackWithEventMask(callback, STANDARD_AND_CONNECTION_DISPLAY_EVENTS);
+
+ callback.expectsEvent(EVENT_DISPLAY_ADDED);
+ FakeDisplayDevice displayDevice =
+ createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_INTERNAL);
+ callback.waitForExpectedEvent();
+
+ LogicalDisplay display =
+ logicalDisplayMapper.getDisplayLocked(displayDevice, /* includeDisabled= */ true);
+ var displayId = display.getDisplayIdLocked();
+
+ assertThat(displayDevice.getDisplayDeviceInfoLocked().committedState)
+ .isEqualTo(Display.STATE_ON);
+
+ assertThrows(SecurityException.class, () -> bs.requestDisplayPower(displayId, true));
+ assertThrows(SecurityException.class, () -> bs.requestDisplayPower(displayId, false));
+ }
+
+ @Test
public void testEnableExternalDisplay_withDisplayManagement_shouldSignalDisplayAdded() {
when(mMockFlags.isConnectedDisplayManagementEnabled()).thenReturn(true);
manageDisplaysPermission(/* granted= */ true);
@@ -3529,6 +3586,7 @@
public void setDisplayDeviceInfo(DisplayDeviceInfo displayDeviceInfo) {
mDisplayDeviceInfo = displayDeviceInfo;
+ mDisplayDeviceInfo.committedState = Display.STATE_ON;
}
@Override
@@ -3558,5 +3616,14 @@
public Display.Mode getUserPreferredDisplayModeLocked() {
return mPreferredMode;
}
+
+ @Override
+ public Runnable requestDisplayStateLocked(
+ final int state,
+ final float brightnessState,
+ final float sdrBrightnessState,
+ @Nullable DisplayOffloadSessionImpl displayOffloadSession) {
+ return () -> mDisplayDeviceInfo.committedState = state;
+ }
}
}
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/powerservicetests/src/com/android/server/power/NotifierTest.java b/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java
index 4460c6a..ce2bb95 100644
--- a/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java
+++ b/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java
@@ -31,6 +31,7 @@
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
+import android.app.AppOpsManager;
import android.content.Context;
import android.content.res.Resources;
import android.hardware.SensorManager;
@@ -41,7 +42,6 @@
import android.os.Looper;
import android.os.PowerManager;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.VibrationAttributes;
import android.os.Vibrator;
import android.os.test.TestLooper;
@@ -82,8 +82,12 @@
@Mock private StatusBarManagerInternal mStatusBarManagerInternal;
@Mock private WakeLockLog mWakeLockLog;
+ @Mock private IBatteryStats mBatteryStats;
+
@Mock private PowerManagerFlags mPowerManagerFlags;
+ @Mock private AppOpsManager mAppOpsManager;
+
private PowerManagerService mService;
private Context mContextSpy;
private Resources mResourcesSpy;
@@ -230,7 +234,7 @@
public void testOnWakeLockListener_RemoteException_NoRethrow() {
when(mPowerManagerFlags.improveWakelockLatency()).thenReturn(true);
createNotifier();
-
+ clearInvocations(mWakeLockLog, mBatteryStats, mAppOpsManager);
IWakeLockCallback exceptingCallback = new IWakeLockCallback.Stub() {
@Override public void onStateChanged(boolean enabled) throws RemoteException {
throw new RemoteException("Just testing");
@@ -245,6 +249,7 @@
verifyZeroInteractions(mWakeLockLog);
mTestLooper.dispatchAll();
verify(mWakeLockLog).onWakeLockReleased("wakelockTag", uid, 1);
+
mNotifier.onWakeLockAcquired(PowerManager.PARTIAL_WAKE_LOCK, "wakelockTag",
"my.package.name", uid, pid, /* workSource= */ null, /* historyTag= */ null,
exceptingCallback);
@@ -277,6 +282,115 @@
verify(mWakeLockLog).onWakeLockReleased("wakelockTag", uid, -1);
}
+
+ @Test
+ public void testOnWakeLockListener_FullWakeLock_ProcessesOnHandler() throws RemoteException {
+ when(mPowerManagerFlags.improveWakelockLatency()).thenReturn(true);
+ createNotifier();
+
+ IWakeLockCallback exceptingCallback = new IWakeLockCallback.Stub() {
+ @Override public void onStateChanged(boolean enabled) throws RemoteException {
+ throw new RemoteException("Just testing");
+ }
+ };
+ clearInvocations(mWakeLockLog, mBatteryStats, mAppOpsManager);
+
+ final int uid = 1234;
+ final int pid = 5678;
+
+ // Release the wakelock
+ mNotifier.onWakeLockReleased(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "wakelockTag",
+ "my.package.name", uid, pid, /* workSource= */ null, /* historyTag= */ null,
+ exceptingCallback);
+
+ // No interaction because we expect that to happen in async
+ verifyZeroInteractions(mWakeLockLog, mBatteryStats, mAppOpsManager);
+
+ // Progressing the looper, and validating all the interactions
+ mTestLooper.dispatchAll();
+ verify(mWakeLockLog).onWakeLockReleased("wakelockTag", uid, 1);
+ verify(mBatteryStats).noteStopWakelock(uid, pid, "wakelockTag", /* historyTag= */ null,
+ BatteryStats.WAKE_TYPE_FULL);
+ verify(mAppOpsManager).finishOp(AppOpsManager.OP_WAKE_LOCK, uid,
+ "my.package.name", null);
+
+ clearInvocations(mWakeLockLog, mBatteryStats, mAppOpsManager);
+
+ // Acquire the wakelock
+ mNotifier.onWakeLockAcquired(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "wakelockTag",
+ "my.package.name", uid, pid, /* workSource= */ null, /* historyTag= */ null,
+ exceptingCallback);
+
+ // No interaction because we expect that to happen in async
+ verifyNoMoreInteractions(mWakeLockLog, mBatteryStats, mAppOpsManager);
+
+ // Progressing the looper, and validating all the interactions
+ mTestLooper.dispatchAll();
+ verify(mWakeLockLog).onWakeLockAcquired("wakelockTag", uid,
+ PowerManager.SCREEN_BRIGHT_WAKE_LOCK, 1);
+ verify(mBatteryStats).noteStartWakelock(uid, pid, "wakelockTag", /* historyTag= */ null,
+ BatteryStats.WAKE_TYPE_FULL, false);
+ verify(mAppOpsManager).startOpNoThrow(AppOpsManager.OP_WAKE_LOCK, uid,
+ "my.package.name", false, null, null);
+
+ // Test with improveWakelockLatency flag false, hence the wakelock log will run on the same
+ // thread
+ clearInvocations(mWakeLockLog, mBatteryStats, mAppOpsManager);
+ when(mPowerManagerFlags.improveWakelockLatency()).thenReturn(false);
+
+ mNotifier.onWakeLockAcquired(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "wakelockTag",
+ "my.package.name", uid, pid, /* workSource= */ null, /* historyTag= */ null,
+ exceptingCallback);
+ verify(mWakeLockLog).onWakeLockAcquired("wakelockTag", uid,
+ PowerManager.SCREEN_BRIGHT_WAKE_LOCK, -1);
+
+ mNotifier.onWakeLockReleased(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "wakelockTag",
+ "my.package.name", uid, pid, /* workSource= */ null, /* historyTag= */ null,
+ exceptingCallback);
+ verify(mWakeLockLog).onWakeLockReleased("wakelockTag", uid, -1);
+ }
+
+ @Test
+ public void testOnWakeLockListener_FullWakeLock_ProcessesInSync() throws RemoteException {
+ createNotifier();
+
+ IWakeLockCallback exceptingCallback = new IWakeLockCallback.Stub() {
+ @Override public void onStateChanged(boolean enabled) throws RemoteException {
+ throw new RemoteException("Just testing");
+ }
+ };
+ clearInvocations(mWakeLockLog, mBatteryStats, mAppOpsManager);
+
+ final int uid = 1234;
+ final int pid = 5678;
+
+ // Release the wakelock
+ mNotifier.onWakeLockReleased(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "wakelockTag",
+ "my.package.name", uid, pid, /* workSource= */ null, /* historyTag= */ null,
+ exceptingCallback);
+
+ verify(mWakeLockLog).onWakeLockReleased("wakelockTag", uid, -1);
+ verify(mBatteryStats).noteStopWakelock(uid, pid, "wakelockTag", /* historyTag= */ null,
+ BatteryStats.WAKE_TYPE_FULL);
+ verify(mAppOpsManager).finishOp(AppOpsManager.OP_WAKE_LOCK, uid,
+ "my.package.name", null);
+
+ clearInvocations(mWakeLockLog, mBatteryStats, mAppOpsManager);
+
+ // Acquire the wakelock
+ mNotifier.onWakeLockAcquired(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "wakelockTag",
+ "my.package.name", uid, pid, /* workSource= */ null, /* historyTag= */ null,
+ exceptingCallback);
+
+ mTestLooper.dispatchAll();
+ verify(mWakeLockLog).onWakeLockAcquired("wakelockTag", uid,
+ PowerManager.SCREEN_BRIGHT_WAKE_LOCK, -1);
+ verify(mBatteryStats).noteStartWakelock(uid, pid, "wakelockTag", /* historyTag= */ null,
+ BatteryStats.WAKE_TYPE_FULL, false);
+ verify(mAppOpsManager).startOpNoThrow(AppOpsManager.OP_WAKE_LOCK, uid,
+ "my.package.name", false, null, null);
+ }
+
private final PowerManagerService.Injector mInjector = new PowerManagerService.Injector() {
@Override
Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats,
@@ -365,13 +479,17 @@
public WakeLockLog getWakeLockLog(Context context) {
return mWakeLockLog;
}
+
+ @Override
+ public AppOpsManager getAppOpsManager(Context context) {
+ return mAppOpsManager;
+ }
};
mNotifier = new Notifier(
mTestLooper.getLooper(),
mContextSpy,
- IBatteryStats.Stub.asInterface(ServiceManager.getService(
- BatteryStats.SERVICE_NAME)),
+ mBatteryStats,
mInjector.createSuspendBlocker(mService, "testBlocker"),
null,
null,
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/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
index 40de1b2..182d603 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
@@ -320,7 +320,7 @@
}
@Test
- public void luxProbeNotEnabledOnStartWhenNotWake() throws RemoteException {
+ public void luxProbeDisabledOnStartWhenNotWake() throws RemoteException {
luxProbeEnabledOnStart(false /* isAwake */);
}
@@ -337,6 +337,7 @@
.getValue().toAidlContext());
verify(mLuxProbe, isAwake ? times(1) : never()).enable();
+ verify(mLuxProbe, isAwake ? never() : times(1)).disable();
}
@Test
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/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index 9f85acb..4ebbf49 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -960,10 +960,20 @@
assertTrue(child.handlesOrientationChangeFromDescendant(orientation));
}
+ private static void addLocalInsets(WindowContainer wc) {
+ final Binder owner = new Binder();
+ Rect genericOverlayInsetsRect1 = new Rect(0, 200, 1080, 700);
+ final InsetsFrameProvider provider1 =
+ new InsetsFrameProvider(owner, 1, WindowInsets.Type.systemOverlays())
+ .setArbitraryRectangle(genericOverlayInsetsRect1);
+ wc.addLocalInsetsFrameProvider(provider1, owner);
+ }
+
@Test
public void testOnDisplayChanged() {
final Task rootTask = createTask(mDisplayContent);
final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
+ addLocalInsets(task);
final ActivityRecord activity = createActivityRecord(mDisplayContent, task);
final DisplayContent newDc = createNewDisplay();
@@ -972,6 +982,7 @@
verify(rootTask).onDisplayChanged(newDc);
verify(task).onDisplayChanged(newDc);
+ assertTrue(task.mLocalInsetsSources.size() == 1);
verify(activity).onDisplayChanged(newDc);
assertEquals(newDc, rootTask.mDisplayContent);
assertEquals(newDc, task.mDisplayContent);
@@ -981,6 +992,7 @@
@Test
public void testOnDisplayChanged_cleanupChanging() {
final Task task = createTask(mDisplayContent);
+ addLocalInsets(task);
spyOn(task.mSurfaceFreezer);
mDisplayContent.mChangingContainers.add(task);
@@ -988,6 +1000,7 @@
// This happens on display info changed.
task.onDisplayChanged(mDisplayContent);
+ assertTrue(task.mLocalInsetsSources.size() == 1);
assertTrue(mDisplayContent.mChangingContainers.contains(task));
verify(task.mSurfaceFreezer, never()).unfreeze(any());
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/Input/assets/testPointerScale.png b/tests/Input/assets/testPointerScale.png
new file mode 100644
index 0000000..54d37c2
--- /dev/null
+++ b/tests/Input/assets/testPointerScale.png
Binary files differ
diff --git a/tests/Input/src/com/android/test/input/PointerIconLoadingTest.kt b/tests/Input/src/com/android/test/input/PointerIconLoadingTest.kt
index dac4253..d196b85 100644
--- a/tests/Input/src/com/android/test/input/PointerIconLoadingTest.kt
+++ b/tests/Input/src/com/android/test/input/PointerIconLoadingTest.kt
@@ -93,7 +93,29 @@
PointerIcon.getLoadedSystemIcon(
ContextThemeWrapper(context, theme),
PointerIcon.TYPE_ARROW,
- /* useLargeIcons= */ false)
+ /* useLargeIcons= */ false,
+ /* pointerScale= */ 1f)
+
+ pointerIcon.getBitmap().assertAgainstGolden(
+ screenshotRule,
+ testName.methodName,
+ exactScreenshotMatcher
+ )
+ }
+
+ @Test
+ fun testPointerScale() {
+ assumeTrue(enableVectorCursors())
+ assumeTrue(enableVectorCursorA11ySettings())
+
+ val pointerScale = 2f
+
+ val pointerIcon =
+ PointerIcon.getLoadedSystemIcon(
+ context,
+ PointerIcon.TYPE_ARROW,
+ /* useLargeIcons= */ false,
+ pointerScale)
pointerIcon.getBitmap().assertAgainstGolden(
screenshotRule,
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