Merge changes I3f700e02,I7e6e813f into main
* changes:
Split logs for actual BAL blocks vs potential blocks
Fix log status dump
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index 5c20aeb..3a772e1 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -60,6 +60,8 @@
":device_policy_aconfig_flags_lib{.generated_srcjars}",
":service-jobscheduler-deviceidle.flags-aconfig-java{.generated_srcjars}",
":surfaceflinger_flags_java_lib{.generated_srcjars}",
+ ":android.view.contentcapture.flags-aconfig-java{.generated_srcjars}",
+ ":android.hardware.usb.flags-aconfig-java{.generated_srcjars}",
]
filegroup {
@@ -667,3 +669,29 @@
aconfig_declarations: "surfaceflinger_flags",
defaults: ["framework-minus-apex-aconfig-java-defaults"],
}
+
+// Content Capture
+aconfig_declarations {
+ name: "android.view.contentcapture.flags-aconfig",
+ package: "android.view.contentcapture.flags",
+ srcs: ["core/java/android/view/contentcapture/flags/*.aconfig"],
+}
+
+java_aconfig_library {
+ name: "android.view.contentcapture.flags-aconfig-java",
+ aconfig_declarations: "android.view.contentcapture.flags-aconfig",
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
+// USB
+aconfig_declarations {
+ name: "android.hardware.usb.flags-aconfig",
+ package: "android.hardware.usb.flags",
+ srcs: ["core/java/android/hardware/usb/flags/*.aconfig"],
+}
+
+java_aconfig_library {
+ name: "android.hardware.usb.flags-aconfig-java",
+ aconfig_declarations: "android.hardware.usb.flags-aconfig",
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
diff --git a/api/Android.bp b/api/Android.bp
index de4435e..4d56b37 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -334,6 +334,16 @@
visibility: ["//frameworks/base/api"],
}
+// We resolve dependencies on APIs in modules by depending on a prebuilt of the whole
+// platform (sdk_system_current_android). That prebuilt does not include module-lib APIs,
+// so use the prebuilt module-lib stubs for modules that export module-lib stubs that the
+// non-updatable part depends on.
+non_updatable_api_deps_on_modules = [
+ "sdk_module-lib_current_framework-tethering",
+ "sdk_module-lib_current_framework-connectivity-t",
+ "sdk_system_current_android",
+]
+
// Defaults with module APIs in the classpath (mostly from prebuilts).
// Suitable for compiling android-non-updatable.
stubs_defaults {
@@ -345,19 +355,7 @@
"packages/modules/Media/apex/aidl/stable",
],
},
- libs: [
- "art.module.public.api",
- "sdk_module-lib_current_framework-tethering",
- "sdk_module-lib_current_framework-connectivity-t",
- "sdk_public_current_framework-bluetooth",
- // There are a few classes from modules used by the core that
- // need to be resolved by metalava. We use a prebuilt stub of the
- // full sdk to ensure we can resolve them. If a new class gets added,
- // the prebuilts/sdk/current needs to be updated.
- "sdk_system_current_android",
- // NOTE: The below can be removed once the prebuilt stub contains IKE.
- "sdk_system_current_android.net.ipsec.ike",
- ],
+ libs: non_updatable_api_deps_on_modules,
}
// Defaults for the java_sdk_libraries of unbundled jars from framework.
diff --git a/api/StubLibraries.bp b/api/StubLibraries.bp
index 5688b96..f6f6929 100644
--- a/api/StubLibraries.bp
+++ b/api/StubLibraries.bp
@@ -351,17 +351,7 @@
"android-non-updatable_from_source_defaults",
],
srcs: [":module-lib-api-stubs-docs-non-updatable"],
- libs: [
- // We cannot depend on all-modules-module-lib-stubs, because the module-lib stubs
- // depend on this stub. We resolve dependencies on APIs in modules by depending
- // on a prebuilt of the whole platform (sdk_system_current_android).
- // That prebuilt does not include module-lib APIs, so use the prebuilt module-lib
- // stubs for modules that export module-lib stubs that the non-updatable part
- // depends on.
- "sdk_module-lib_current_framework-tethering",
- "sdk_module-lib_current_framework-connectivity-t",
- "sdk_system_current_android",
- ],
+ libs: non_updatable_api_deps_on_modules,
dist: {
dir: "apistubs/android/module-lib",
},
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 441dcae..8bebd6b 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -133,6 +133,7 @@
field public static final String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
field public static final String GET_APP_METADATA = "android.permission.GET_APP_METADATA";
field public static final String GET_APP_OPS_STATS = "android.permission.GET_APP_OPS_STATS";
+ field @FlaggedApi("android.app.get_binding_uid_importance") public static final String GET_BINDING_UID_IMPORTANCE = "android.permission.GET_BINDING_UID_IMPORTANCE";
field public static final String GET_HISTORICAL_APP_OPS_STATS = "android.permission.GET_HISTORICAL_APP_OPS_STATS";
field public static final String GET_PROCESS_STATE_AND_OOM_SCORE = "android.permission.GET_PROCESS_STATE_AND_OOM_SCORE";
field public static final String GET_RUNTIME_PERMISSIONS = "android.permission.GET_RUNTIME_PERMISSIONS";
@@ -543,6 +544,7 @@
public class ActivityManager {
method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void addOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener, int);
method @RequiresPermission(android.Manifest.permission.FORCE_STOP_PACKAGES) public void forceStopPackage(String);
+ method @FlaggedApi("android.app.get_binding_uid_importance") @RequiresPermission(android.Manifest.permission.GET_BINDING_UID_IMPORTANCE) public int getBindingUidImportance(int);
method @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", "android.permission.INTERACT_ACROSS_USERS_FULL"}) public static int getCurrentUser();
method @FlaggedApi("android.app.app_start_info") @NonNull @RequiresPermission(android.Manifest.permission.DUMP) public java.util.List<android.app.ApplicationStartInfo> getExternalHistoricalProcessStartReasons(@NonNull String, @IntRange(from=0) int);
method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getPackageImportance(String);
@@ -6186,8 +6188,13 @@
method public void writeToParcel(android.os.Parcel, int);
field public static final int COMPLIANCE_WARNING_BC_1_2 = 3; // 0x3
field public static final int COMPLIANCE_WARNING_DEBUG_ACCESSORY = 2; // 0x2
+ field @FlaggedApi("android.hardware.usb.flags.enable_usb_data_compliance_warning") public static final int COMPLIANCE_WARNING_ENUMERATION_FAIL = 7; // 0x7
+ field @FlaggedApi("android.hardware.usb.flags.enable_usb_data_compliance_warning") public static final int COMPLIANCE_WARNING_FLAKY_CONNECTION = 8; // 0x8
+ field @FlaggedApi("android.hardware.usb.flags.enable_usb_data_compliance_warning") public static final int COMPLIANCE_WARNING_INPUT_POWER_LIMITED = 5; // 0x5
+ field @FlaggedApi("android.hardware.usb.flags.enable_usb_data_compliance_warning") public static final int COMPLIANCE_WARNING_MISSING_DATA_LINES = 6; // 0x6
field public static final int COMPLIANCE_WARNING_MISSING_RP = 4; // 0x4
field public static final int COMPLIANCE_WARNING_OTHER = 1; // 0x1
+ field @FlaggedApi("android.hardware.usb.flags.enable_usb_data_compliance_warning") public static final int COMPLIANCE_WARNING_UNRELIABLE_IO = 9; // 0x9
field @NonNull public static final android.os.Parcelable.Creator<android.hardware.usb.UsbPortStatus> CREATOR;
field public static final int DATA_ROLE_DEVICE = 2; // 0x2
field public static final int DATA_ROLE_HOST = 1; // 0x1
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index f68681b..8b4ebae 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -73,7 +73,6 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
@@ -4269,6 +4268,33 @@
}
/**
+ * Same as {@link #getUidImportance(int)}, but it only works on UIDs that currently
+ * have a service binding, or provider reference, to the calling UID, even if the target UID
+ * belong to another android user or profile.
+ *
+ * <p>This will return {@link RunningAppProcessInfo#IMPORTANCE_GONE} on all other UIDs,
+ * regardless of if they're valid or not.
+ *
+ * <p>Privileged system apps may prefer this API to {@link #getUidImportance(int)} to
+ * avoid requesting the permission {@link Manifest.permission#PACKAGE_USAGE_STATS}, which
+ * would allow access to APIs that return more senstive information.
+ *
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_GET_BINDING_UID_IMPORTANCE)
+ @SystemApi
+ @RequiresPermission(Manifest.permission.GET_BINDING_UID_IMPORTANCE)
+ public @RunningAppProcessInfo.Importance int getBindingUidImportance(int uid) {
+ try {
+ int procState = getService().getBindingUidProcessState(uid,
+ mContext.getOpPackageName());
+ return RunningAppProcessInfo.procStateToImportanceForClient(procState, mContext);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Callback to get reports about changes to the importance of a uid. Use with
* {@link #addOnUidImportanceListener}.
* @hide
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index dfb416a..3b6ea14 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -56,7 +56,7 @@
import android.app.backup.BackupAnnotations.OperationType;
import android.app.compat.CompatChanges;
import android.app.sdksandbox.sandboxactivity.ActivityContextInfo;
-import android.app.sdksandbox.sandboxactivity.SdkSandboxActivityAuthority;
+import android.app.sdksandbox.sandboxactivity.ActivityContextInfoProvider;
import android.app.servertransaction.ActivityLifecycleItem;
import android.app.servertransaction.ActivityLifecycleItem.LifecycleState;
import android.app.servertransaction.ActivityRelaunchItem;
@@ -2272,8 +2272,7 @@
case DUMP_HEAP: return "DUMP_HEAP";
case DUMP_ACTIVITY: return "DUMP_ACTIVITY";
case SET_CORE_SETTINGS: return "SET_CORE_SETTINGS";
- case UPDATE_PACKAGE_COMPATIBILITY_INFO:
- return "UPDATE_PACKAGE_COMPATIBILITY_INFO";
+ case UPDATE_PACKAGE_COMPATIBILITY_INFO: return "UPDATE_PACKAGE_COMPATIBILITY_INFO";
case DUMP_PROVIDER: return "DUMP_PROVIDER";
case UNSTABLE_PROVIDER_DIED: return "UNSTABLE_PROVIDER_DIED";
case REQUEST_ASSIST_CONTEXT_EXTRAS: return "REQUEST_ASSIST_CONTEXT_EXTRAS";
@@ -3777,10 +3776,8 @@
r.activityInfo.targetActivity);
}
- boolean isSandboxActivityContext =
- sandboxActivitySdkBasedContext()
- && SdkSandboxActivityAuthority.isSdkSandboxActivity(
- mSystemContext, r.intent);
+ boolean isSandboxActivityContext = sandboxActivitySdkBasedContext()
+ && r.intent.isSandboxActivity(mSystemContext);
boolean isSandboxedSdkContextUsed = false;
ContextImpl activityBaseContext;
if (isSandboxActivityContext) {
@@ -4025,12 +4022,11 @@
*/
@Nullable
private ContextImpl createBaseContextForSandboxActivity(@NonNull ActivityClientRecord r) {
- SdkSandboxActivityAuthority sdkSandboxActivityAuthority =
- SdkSandboxActivityAuthority.getInstance();
+ ActivityContextInfoProvider contextInfoProvider = ActivityContextInfoProvider.getInstance();
ActivityContextInfo contextInfo;
try {
- contextInfo = sdkSandboxActivityAuthority.getActivityContextInfo(r.intent);
+ contextInfo = contextInfoProvider.getActivityContextInfo(r.intent);
} catch (IllegalArgumentException e) {
Log.e(TAG, "Passed intent does not match an expected sandbox activity", e);
return null;
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 520bf7d..260e985 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -949,4 +949,5 @@
* @param err The binder transaction error
*/
oneway void frozenBinderTransactionDetected(int debugPid, int code, int flags, int err);
+ int getBindingUidProcessState(int uid, in String callingPackage);
}
diff --git a/core/java/android/app/activity_manager.aconfig b/core/java/android/app/activity_manager.aconfig
index 2076e85..b303ea6 100644
--- a/core/java/android/app/activity_manager.aconfig
+++ b/core/java/android/app/activity_manager.aconfig
@@ -5,4 +5,11 @@
name: "app_start_info"
description: "Control collecting of ApplicationStartInfo records and APIs."
bug: "247814855"
-}
\ No newline at end of file
+}
+
+flag {
+ namespace: "backstage_power"
+ name: "get_binding_uid_importance"
+ description: "API to get importance of UID that's binding to the caller"
+ bug: "292533010"
+}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 02e0cf6..ea54c91 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -12587,12 +12587,8 @@
return (mFlags & FLAG_ACTIVITY_NEW_DOCUMENT) == FLAG_ACTIVITY_NEW_DOCUMENT;
}
- /**
- * @deprecated Use {@link SdkSandboxActivityAuthority#isSdkSandboxActivity} instead.
- * Once the other API is finalized this method will be removed.
- * @hide
- */
- @Deprecated
+ // TODO(b/299109198): Refactor into the {@link SdkSandboxManagerLocal}
+ /** @hide */
public boolean isSandboxActivity(@NonNull Context context) {
if (mAction != null && mAction.equals(ACTION_START_SANDBOXED_ACTIVITY)) {
return true;
diff --git a/core/java/android/credentials/flags.aconfig b/core/java/android/credentials/flags.aconfig
index 9b819a7..ec96215 100644
--- a/core/java/android/credentials/flags.aconfig
+++ b/core/java/android/credentials/flags.aconfig
@@ -13,3 +13,10 @@
description: "Enables Credential Manager to work with Instant Apps"
bug: "302190269"
}
+
+flag {
+ namespace: "credential_manager"
+ name: "clear_session_enabled"
+ description: "Enables clearing of Credential Manager sessions when client process dies"
+ bug: "308470501"
+}
diff --git a/core/java/android/hardware/usb/UsbPort.java b/core/java/android/hardware/usb/UsbPort.java
index 490b128..8f0149b 100644
--- a/core/java/android/hardware/usb/UsbPort.java
+++ b/core/java/android/hardware/usb/UsbPort.java
@@ -52,6 +52,11 @@
import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_BC_1_2;
import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_MISSING_RP;
import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_OTHER;
+import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_INPUT_POWER_LIMITED;
+import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_MISSING_DATA_LINES;
+import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_ENUMERATION_FAIL;
+import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_FLAKY_CONNECTION;
+import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_UNRELIABLE_IO;
import static android.hardware.usb.DisplayPortAltModeInfo.DISPLAYPORT_ALT_MODE_STATUS_UNKNOWN;
import static android.hardware.usb.DisplayPortAltModeInfo.DISPLAYPORT_ALT_MODE_STATUS_NOT_CAPABLE;
import static android.hardware.usb.DisplayPortAltModeInfo.DISPLAYPORT_ALT_MODE_STATUS_CAPABLE_DISABLED;
@@ -789,6 +794,21 @@
case UsbPortStatus.COMPLIANCE_WARNING_MISSING_RP:
complianceWarningString.append("missing rp, ");
break;
+ case UsbPortStatus.COMPLIANCE_WARNING_INPUT_POWER_LIMITED:
+ complianceWarningString.append("input power limited, ");
+ break;
+ case UsbPortStatus.COMPLIANCE_WARNING_MISSING_DATA_LINES:
+ complianceWarningString.append("missing data lines, ");
+ break;
+ case UsbPortStatus.COMPLIANCE_WARNING_ENUMERATION_FAIL:
+ complianceWarningString.append("enumeration fail, ");
+ break;
+ case UsbPortStatus.COMPLIANCE_WARNING_FLAKY_CONNECTION:
+ complianceWarningString.append("flaky connection, ");
+ break;
+ case UsbPortStatus.COMPLIANCE_WARNING_UNRELIABLE_IO:
+ complianceWarningString.append("unreliable io, ");
+ break;
default:
complianceWarningString.append(String.format("Unknown(%d), ", warning));
break;
diff --git a/core/java/android/hardware/usb/UsbPortStatus.java b/core/java/android/hardware/usb/UsbPortStatus.java
index b4fe3a2..d959240 100644
--- a/core/java/android/hardware/usb/UsbPortStatus.java
+++ b/core/java/android/hardware/usb/UsbPortStatus.java
@@ -18,11 +18,13 @@
import android.Manifest;
import android.annotation.CheckResult;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
+import android.hardware.usb.flags.Flags;
import android.os.Parcel;
import android.os.Parcelable;
@@ -310,6 +312,54 @@
public static final int COMPLIANCE_WARNING_MISSING_RP = 4;
/**
+ * Used to indicate the charging setups on the USB ports are unable to
+ * deliver negotiated power. Introduced in Android V (API level 35)
+ * and client applicantions that target API levels lower than 35 will
+ * receive {@link #COMPLIANCE_WARNING_OTHER} instead.
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_USB_DATA_COMPLIANCE_WARNING)
+ public static final int COMPLIANCE_WARNING_INPUT_POWER_LIMITED = 5;
+
+ /**
+ * Used to indicate the cable/connector on the USB ports are missing
+ * the required wires on the data pins to make data transfer.
+ * Introduced in Android V (API level 35) and client applicantions that
+ * target API levels lower than 35 will receive
+ * {@link #COMPLIANCE_WARNING_OTHER} instead.
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_USB_DATA_COMPLIANCE_WARNING)
+ public static final int COMPLIANCE_WARNING_MISSING_DATA_LINES = 6;
+
+ /**
+ * Used to indicate enumeration failures on the USB ports, potentially due to
+ * signal integrity issues or other causes. Introduced in Android V
+ * (API level 35) and client applicantions that target API levels lower
+ * than 35 will receive {@link #COMPLIANCE_WARNING_OTHER} instead.
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_USB_DATA_COMPLIANCE_WARNING)
+ public static final int COMPLIANCE_WARNING_ENUMERATION_FAIL = 7;
+
+ /**
+ * Used to indicate unexpected data disconnection on the USB ports,
+ * potentially due to signal integrity issues or other causes.
+ * Introduced in Android V (API level 35) and client applicantions that
+ * target API levels lower than 35 will receive
+ * {@link #COMPLIANCE_WARNING_OTHER} instead.
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_USB_DATA_COMPLIANCE_WARNING)
+ public static final int COMPLIANCE_WARNING_FLAKY_CONNECTION = 8;
+
+ /**
+ * Used to indicate unreliable or slow data transfer on the USB ports,
+ * potentially due to signal integrity issues or other causes.
+ * Introduced in Android V (API level 35) and client applicantions that
+ * target API levels lower than 35 will receive
+ * {@link #COMPLIANCE_WARNING_OTHER} instead.
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_USB_DATA_COMPLIANCE_WARNING)
+ public static final int COMPLIANCE_WARNING_UNRELIABLE_IO = 9;
+
+ /**
* Indicates that the Type-C plug orientation cannot be
* determined because the connected state of the device is unknown.
*/
@@ -372,6 +422,11 @@
COMPLIANCE_WARNING_DEBUG_ACCESSORY,
COMPLIANCE_WARNING_BC_1_2,
COMPLIANCE_WARNING_MISSING_RP,
+ COMPLIANCE_WARNING_INPUT_POWER_LIMITED,
+ COMPLIANCE_WARNING_MISSING_DATA_LINES,
+ COMPLIANCE_WARNING_ENUMERATION_FAIL,
+ COMPLIANCE_WARNING_FLAKY_CONNECTION,
+ COMPLIANCE_WARNING_UNRELIABLE_IO,
})
@Retention(RetentionPolicy.SOURCE)
@interface ComplianceWarning{}
@@ -591,7 +646,12 @@
* @return array including {@link #COMPLIANCE_WARNING_OTHER},
* {@link #COMPLIANCE_WARNING_DEBUG_ACCESSORY},
* {@link #COMPLIANCE_WARNING_BC_1_2},
- * or {@link #COMPLIANCE_WARNING_MISSING_RP}
+ * {@link #COMPLIANCE_WARNING_MISSING_RP},
+ * {@link #COMPLIANCE_WARNING_INPUT_POWER_LIMITED},
+ * {@link #COMPLIANCE_WARNING_MISSING_DATA_LINES},
+ * {@link #COMPLIANCE_WARNING_ENUMERATION_FAIL},
+ * {@link #COMPLIANCE_WARNING_FLAKY_CONNECTION},
+ * {@link #COMPLIANCE_WARNING_UNRELIABLE_IO}.
*/
@CheckResult
@NonNull
diff --git a/core/java/android/hardware/usb/flags/system_sw_usb_flags.aconfig b/core/java/android/hardware/usb/flags/system_sw_usb_flags.aconfig
new file mode 100644
index 0000000..6b78d05
--- /dev/null
+++ b/core/java/android/hardware/usb/flags/system_sw_usb_flags.aconfig
@@ -0,0 +1,8 @@
+package: "android.hardware.usb.flags"
+
+flag {
+ name: "enable_usb_data_compliance_warning"
+ namespace: "system_sw_usb"
+ description: "Enable USB data compliance warnings when set"
+ bug: "296119135"
+}
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index bcda25a..27ad45d 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -3206,15 +3206,6 @@
public static final String INFRASTRUCTURE_BITMASK = "infrastructure_bitmask";
/**
- * Indicating if the APN is used for eSIM bootsrap provisioning. The default value is 0 (Not
- * used for eSIM bootstrap provisioning).
- *
- * <P>Type: INTEGER</P>
- * @hide
- */
- public static final String ESIM_BOOTSTRAP_PROVISIONING = "esim_bootstrap_provisioning";
-
- /**
* MVNO type:
* {@code SPN (Service Provider Name), IMSI, GID (Group Identifier Level 1)}.
* <P>Type: TEXT</P>
diff --git a/core/java/android/util/ArraySet.java b/core/java/android/util/ArraySet.java
index 73114e2..adebe2c 100644
--- a/core/java/android/util/ArraySet.java
+++ b/core/java/android/util/ArraySet.java
@@ -20,8 +20,6 @@
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
-import libcore.util.EmptyArray;
-
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Collection;
diff --git a/core/java/android/util/Base64.java b/core/java/android/util/Base64.java
index 33cc5e3..92abd7c 100644
--- a/core/java/android/util/Base64.java
+++ b/core/java/android/util/Base64.java
@@ -26,7 +26,6 @@
* href="http://www.ietf.org/rfc/rfc2045.txt">2045</a> and <a
* href="http://www.ietf.org/rfc/rfc3548.txt">3548</a>.
*/
-@android.ravenwood.annotations.RavenwoodWholeClassKeep
public class Base64 {
/**
* Default values for encoder/decoder flags.
diff --git a/core/java/android/util/IntArray.java b/core/java/android/util/IntArray.java
index ac76fc2..c04a71c 100644
--- a/core/java/android/util/IntArray.java
+++ b/core/java/android/util/IntArray.java
@@ -19,8 +19,6 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
-import libcore.util.EmptyArray;
-
import java.util.Arrays;
/**
diff --git a/core/java/android/util/LongArray.java b/core/java/android/util/LongArray.java
index 9f269ed..3101c0d 100644
--- a/core/java/android/util/LongArray.java
+++ b/core/java/android/util/LongArray.java
@@ -23,8 +23,6 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
-import libcore.util.EmptyArray;
-
import java.util.Arrays;
/**
diff --git a/core/java/android/util/LongArrayQueue.java b/core/java/android/util/LongArrayQueue.java
index 5c701db..354f8df 100644
--- a/core/java/android/util/LongArrayQueue.java
+++ b/core/java/android/util/LongArrayQueue.java
@@ -19,8 +19,6 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.GrowingArrayUtils;
-import libcore.util.EmptyArray;
-
import java.util.NoSuchElementException;
/**
diff --git a/core/java/android/util/LongSparseArray.java b/core/java/android/util/LongSparseArray.java
index 2f14b25..8402ab2 100644
--- a/core/java/android/util/LongSparseArray.java
+++ b/core/java/android/util/LongSparseArray.java
@@ -24,8 +24,6 @@
import com.android.internal.util.Preconditions;
import com.android.internal.util.function.LongObjPredicate;
-import libcore.util.EmptyArray;
-
import java.util.Arrays;
import java.util.Objects;
diff --git a/core/java/android/util/LongSparseLongArray.java b/core/java/android/util/LongSparseLongArray.java
index f23ec91..d4a0126 100644
--- a/core/java/android/util/LongSparseLongArray.java
+++ b/core/java/android/util/LongSparseLongArray.java
@@ -23,8 +23,6 @@
import com.android.internal.util.GrowingArrayUtils;
import com.android.internal.util.Preconditions;
-import libcore.util.EmptyArray;
-
/**
* Map of {@code long} to {@code long}. Unlike a normal array of longs, there
* can be gaps in the indices. It is intended to be more memory efficient than using a
diff --git a/core/java/android/util/Range.java b/core/java/android/util/Range.java
index 41c171a..750696b 100644
--- a/core/java/android/util/Range.java
+++ b/core/java/android/util/Range.java
@@ -19,7 +19,8 @@
import static com.android.internal.util.Preconditions.*;
import android.annotation.Nullable;
-import android.hardware.camera2.utils.HashCodeHelpers;
+
+import java.util.Objects;
/**
* Immutable class for describing the range of two numeric values.
@@ -351,7 +352,7 @@
*/
@Override
public int hashCode() {
- return HashCodeHelpers.hashCodeGeneric(mLower, mUpper);
+ return Objects.hash(mLower, mUpper);
}
private final T mLower;
diff --git a/core/java/android/util/SparseArray.java b/core/java/android/util/SparseArray.java
index cd03d83..c18cac3 100644
--- a/core/java/android/util/SparseArray.java
+++ b/core/java/android/util/SparseArray.java
@@ -22,8 +22,6 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.GrowingArrayUtils;
-import libcore.util.EmptyArray;
-
import java.util.Objects;
/**
diff --git a/core/java/android/util/SparseBooleanArray.java b/core/java/android/util/SparseBooleanArray.java
index 12a9900..795f4c9 100644
--- a/core/java/android/util/SparseBooleanArray.java
+++ b/core/java/android/util/SparseBooleanArray.java
@@ -22,8 +22,6 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.GrowingArrayUtils;
-import libcore.util.EmptyArray;
-
/**
* SparseBooleanArrays map integers to booleans.
* Unlike a normal array of booleans
diff --git a/core/java/android/util/SparseIntArray.java b/core/java/android/util/SparseIntArray.java
index 0e98c28..24d04be 100644
--- a/core/java/android/util/SparseIntArray.java
+++ b/core/java/android/util/SparseIntArray.java
@@ -21,8 +21,6 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.GrowingArrayUtils;
-import libcore.util.EmptyArray;
-
import java.util.Arrays;
/**
diff --git a/core/java/android/util/SparseLongArray.java b/core/java/android/util/SparseLongArray.java
index e86b647..4b257e6 100644
--- a/core/java/android/util/SparseLongArray.java
+++ b/core/java/android/util/SparseLongArray.java
@@ -19,8 +19,6 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.GrowingArrayUtils;
-import libcore.util.EmptyArray;
-
/**
* SparseLongArrays map integers to longs. Unlike a normal array of longs,
* there can be gaps in the indices. It is intended to be more memory efficient
diff --git a/core/java/android/view/contentcapture/flags/content_capture_flags.aconfig b/core/java/android/view/contentcapture/flags/content_capture_flags.aconfig
new file mode 100644
index 0000000..3c15518
--- /dev/null
+++ b/core/java/android/view/contentcapture/flags/content_capture_flags.aconfig
@@ -0,0 +1,8 @@
+package: "android.view.contentcapture.flags"
+
+flag {
+ name: "run_on_background_thread_enabled"
+ namespace: "machine_learning"
+ description: "Feature flag for running content capture tasks on background thread"
+ bug: "309411951"
+}
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index 1a2d202..5bfa3d7 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -55,6 +55,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* Used to communicate information about what is changing during a transition to a TransitionPlayer.
@@ -610,7 +611,7 @@
private final WindowContainerToken mContainer;
private WindowContainerToken mParent;
private WindowContainerToken mLastParent;
- private final SurfaceControl mLeash;
+ private SurfaceControl mLeash;
private @TransitionMode int mMode = TRANSIT_NONE;
private @ChangeFlags int mFlags = FLAG_NONE;
private final Rect mStartAbsBounds = new Rect();
@@ -697,6 +698,11 @@
mLastParent = lastParent;
}
+ /** Sets the animation leash for controlling this change's container */
+ public void setLeash(@NonNull SurfaceControl leash) {
+ mLeash = Objects.requireNonNull(leash);
+ }
+
/** Sets the transition mode for this change */
public void setMode(@TransitionMode int mode) {
mMode = mode;
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index b64771b..686e1fc 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -21,11 +21,10 @@
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.util.ArraySet;
+import android.util.EmptyArray;
import dalvik.system.VMRuntime;
-import libcore.util.EmptyArray;
-
import java.io.File;
import java.lang.reflect.Array;
import java.util.ArrayList;
@@ -84,6 +83,38 @@
return (T[])VMRuntime.getRuntime().newUnpaddedArray(clazz, minLen);
}
+ public static byte[] newUnpaddedByteArray$ravenwood(int minLen) {
+ return new byte[minLen];
+ }
+
+ public static char[] newUnpaddedCharArray$ravenwood(int minLen) {
+ return new char[minLen];
+ }
+
+ public static int[] newUnpaddedIntArray$ravenwood(int minLen) {
+ return new int[minLen];
+ }
+
+ public static boolean[] newUnpaddedBooleanArray$ravenwood(int minLen) {
+ return new boolean[minLen];
+ }
+
+ public static long[] newUnpaddedLongArray$ravenwood(int minLen) {
+ return new long[minLen];
+ }
+
+ public static float[] newUnpaddedFloatArray$ravenwood(int minLen) {
+ return new float[minLen];
+ }
+
+ public static Object[] newUnpaddedObjectArray$ravenwood(int minLen) {
+ return new Object[minLen];
+ }
+
+ public static <T> T[] newUnpaddedArray$ravenwood(Class<T> clazz, int minLen) {
+ return (T[]) Array.newInstance(clazz, minLen);
+ }
+
/**
* Checks if the beginnings of two byte arrays are equal.
*
diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java
index b462c21..58ee2b2 100644
--- a/core/java/com/android/internal/util/LatencyTracker.java
+++ b/core/java/com/android/internal/util/LatencyTracker.java
@@ -19,12 +19,14 @@
import static android.os.Trace.TRACE_TAG_APP;
import static android.provider.DeviceConfig.NAMESPACE_LATENCY_TRACKER;
+import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_BACK_SYSTEM_ANIMATION;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_CHECK_CREDENTIAL;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_CHECK_CREDENTIAL_UNLOCKED;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_EXPAND_PANEL;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_FACE_WAKE_AND_UNLOCK;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_FINGERPRINT_WAKE_AND_UNLOCK;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_FOLD_TO_AOD;
+import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_KEYGUARD_FPS_UNLOCK_TO_HOME;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOAD_SHARE_SHEET;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOCKSCREEN_UNLOCK;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_NOTIFICATION_BIG_PICTURE_LOADED;
@@ -222,6 +224,16 @@
*/
public static final int ACTION_NOTIFICATION_BIG_PICTURE_LOADED = 23;
+ /**
+ * Time it takes to unlock the device via udfps, until the whole launcher appears.
+ */
+ public static final int ACTION_KEYGUARD_FPS_UNLOCK_TO_HOME = 24;
+
+ /**
+ * Time it takes to start back preview surface animation after a back gesture starts.
+ */
+ public static final int ACTION_BACK_SYSTEM_ANIMATION = 25;
+
private static final int[] ACTIONS_ALL = {
ACTION_EXPAND_PANEL,
ACTION_TOGGLE_RECENTS,
@@ -247,6 +259,8 @@
ACTION_REQUEST_IME_HIDDEN,
ACTION_SMARTSPACE_DOORBELL,
ACTION_NOTIFICATION_BIG_PICTURE_LOADED,
+ ACTION_KEYGUARD_FPS_UNLOCK_TO_HOME,
+ ACTION_BACK_SYSTEM_ANIMATION,
};
/** @hide */
@@ -275,6 +289,8 @@
ACTION_REQUEST_IME_HIDDEN,
ACTION_SMARTSPACE_DOORBELL,
ACTION_NOTIFICATION_BIG_PICTURE_LOADED,
+ ACTION_KEYGUARD_FPS_UNLOCK_TO_HOME,
+ ACTION_BACK_SYSTEM_ANIMATION,
})
@Retention(RetentionPolicy.SOURCE)
public @interface Action {
@@ -306,6 +322,8 @@
UIACTION_LATENCY_REPORTED__ACTION__ACTION_REQUEST_IME_HIDDEN,
UIACTION_LATENCY_REPORTED__ACTION__ACTION_SMARTSPACE_DOORBELL,
UIACTION_LATENCY_REPORTED__ACTION__ACTION_NOTIFICATION_BIG_PICTURE_LOADED,
+ UIACTION_LATENCY_REPORTED__ACTION__ACTION_KEYGUARD_FPS_UNLOCK_TO_HOME,
+ UIACTION_LATENCY_REPORTED__ACTION__ACTION_BACK_SYSTEM_ANIMATION,
};
private final Object mLock = new Object();
@@ -492,6 +510,10 @@
return "ACTION_SMARTSPACE_DOORBELL";
case UIACTION_LATENCY_REPORTED__ACTION__ACTION_NOTIFICATION_BIG_PICTURE_LOADED:
return "ACTION_NOTIFICATION_BIG_PICTURE_LOADED";
+ case UIACTION_LATENCY_REPORTED__ACTION__ACTION_KEYGUARD_FPS_UNLOCK_TO_HOME:
+ return "ACTION_KEYGUARD_FPS_UNLOCK_TO_HOME";
+ case UIACTION_LATENCY_REPORTED__ACTION__ACTION_BACK_SYSTEM_ANIMATION:
+ return "ACTION_BACK_SYSTEM_ANIMATION";
default:
throw new IllegalArgumentException("Invalid action");
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index ab0ef7d..d5d912f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -7782,6 +7782,15 @@
<permission android:name="android.permission.WRITE_FLAGS"
android:protectionLevel="signature" />
+ <!-- @hide @SystemApi
+ @FlaggedApi("android.app.get_binding_uid_importance")
+ Allows to get the importance of an UID that has a service
+ binding to the app.
+ <p>Protection level: signature|privileged
+ -->
+ <permission android:name="android.permission.GET_BINDING_UID_IMPORTANCE"
+ android:protectionLevel="signature|privileged" />
+
<!-- @hide Allows internal applications to manage displays.
<p>This means intercept internal signals about displays being (dis-)connected
and being able to enable or disable the external displays.
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index 3a2e50a..709646b 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -34,7 +34,7 @@
http://smscoin.net/software/engine/WordPress/Paid+SMS-registration/ -->
<!-- Arab Emirates -->
- <shortcode country="ae" pattern="\\d{1,5}" free="1017|1355|3214" />
+ <shortcode country="ae" pattern="\\d{1,5}" free="1017|1355|3214|6253" />
<!-- Albania: 5 digits, known short codes listed -->
<shortcode country="al" pattern="\\d{5}" premium="15191|55[56]00" />
@@ -155,7 +155,7 @@
<shortcode country="ie" pattern="\\d{5}" premium="5[3-9]\\d{3}" free="50\\d{3}|116\\d{3}" standard="5[12]\\d{3}" />
<!-- Israel: 4 digits, known premium codes listed -->
- <shortcode country="il" pattern="\\d{4}" premium="4422|4545" />
+ <shortcode country="il" pattern="\\d{1,5}" premium="4422|4545" free="37477" />
<!-- Italy: 5 digits (premium=41xxx,42xxx), plus EU:
https://www.itu.int/dms_pub/itu-t/oth/02/02/T020200006B0001PDFE.pdf -->
@@ -198,6 +198,9 @@
<!-- Malaysia: 5 digits: http://www.skmm.gov.my/attachment/Consumer_Regulation/Mobile_Content_Services_FAQs.pdf -->
<shortcode country="my" pattern="\\d{5}" premium="32298|33776" free="22099|28288|66668" />
+ <!-- Namibia: 5 digits -->
+ <shortcode country="na" pattern="\\d{1,5}" free="40005" />
+
<!-- The Netherlands, 4 digits, known premium codes listed, plus EU -->
<shortcode country="nl" pattern="\\d{4}" premium="4466|5040" free="116\\d{3}|2223|6225|2223|1662" />
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 69aa401..ab18a50 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -529,6 +529,7 @@
<permission name="android.permission.LAUNCH_CREDENTIAL_SELECTOR"/>
<!-- Permission required for CTS test IntentRedirectionTest -->
<permission name="android.permission.QUERY_CLONED_APPS"/>
+ <permission name="android.permission.GET_BINDING_UID_IMPORTANCE"/>
</privapp-permissions>
<privapp-permissions package="com.android.statementservice">
diff --git a/framework-minus-apex-ravenwood-policies.txt b/framework-minus-apex-ravenwood-policies.txt
index c3ca122..8e76fd2 100644
--- a/framework-minus-apex-ravenwood-policies.txt
+++ b/framework-minus-apex-ravenwood-policies.txt
@@ -1,11 +1,91 @@
# Ravenwood "policy" file for framework-minus-apex.
+# Collections
class android.util.ArrayMap stubclass
+class android.util.ArraySet stubclass
+class android.util.LongSparseArray stubclass
+class android.util.SparseArrayMap stubclass
+class android.util.SparseArray stubclass
+class android.util.SparseBooleanArray stubclass
+class android.util.SparseIntArray stubclass
+class android.util.SparseLongArray stubclass
class android.util.ContainerHelpers stubclass
class android.util.EmptyArray stubclass
class android.util.MapCollections stubclass
+# Logging
class android.util.Log stubclass
class android.util.Log !com.android.hoststubgen.nativesubstitution.Log_host
+class android.util.LogPrinter stubclass
+# String Manipulation
+class android.util.Printer stubclass
+class android.util.PrintStreamPrinter stubclass
+class android.util.PrintWriterPrinter stubclass
+class android.util.StringBuilderPrinter stubclass
+
+# Properties
+class android.util.Property stubclass
+class android.util.FloatProperty stubclass
+class android.util.IntProperty stubclass
+class android.util.NoSuchPropertyException stubclass
+class android.util.ReflectiveProperty stubclass
+
+# Exceptions
+class android.util.AndroidException stubclass
+class android.util.AndroidRuntimeException stubclass
+
+# JSON
+class android.util.JsonReader stubclass
+class android.util.JsonWriter stubclass
+class android.util.MalformedJsonException stubclass
+
+# Base64
+class android.util.Base64 stubclass
+class android.util.Base64DataException stubclass
+class android.util.Base64InputStream stubclass
+class android.util.Base64OutputStream stubclass
+
+# Data Holders
+class android.util.MutableFloat stubclass
+class android.util.MutableShort stubclass
+class android.util.MutableBoolean stubclass
+class android.util.MutableByte stubclass
+class android.util.MutableChar stubclass
+class android.util.MutableDouble stubclass
+class android.util.Pair stubclass
+class android.util.Range stubclass
+class android.util.Rational stubclass
+class android.util.Size stubclass
+class android.util.SizeF stubclass
+
+# Proto
+class android.util.proto.EncodedBuffer stubclass
+class android.util.proto.ProtoInputStream stubclass
+class android.util.proto.ProtoOutputStream stubclass
+class android.util.proto.ProtoParseException stubclass
+class android.util.proto.ProtoStream stubclass
+class android.util.proto.ProtoUtils stubclass
+class android.util.proto.WireTypeMismatchException stubclass
+
+# Misc
+class android.util.Dumpable stubclass
+class android.util.DebugUtils stubclass
+class android.util.UtilConfig stubclass
+class android.util.Patterns stubclass
+
+# Internals
+class com.android.internal.util.ArrayUtils stubclass
+ method newUnpaddedByteArray (I)[B @newUnpaddedByteArray$ravenwood
+ method newUnpaddedCharArray (I)[C @newUnpaddedCharArray$ravenwood
+ method newUnpaddedIntArray (I)[I @newUnpaddedIntArray$ravenwood
+ method newUnpaddedBooleanArray (I)[Z @newUnpaddedBooleanArray$ravenwood
+ method newUnpaddedLongArray (I)[J @newUnpaddedLongArray$ravenwood
+ method newUnpaddedFloatArray (I)[F @newUnpaddedFloatArray$ravenwood
+ method newUnpaddedObjectArray (I)[Ljava/lang/Object; @newUnpaddedObjectArray$ravenwood
+ method newUnpaddedArray (Ljava/lang/Class;I)[Ljava/lang/Object; @newUnpaddedArray$ravenwood
+
+class com.android.internal.util.GrowingArrayUtils stubclass
class com.android.internal.util.LineBreakBufferedWriter stubclass
+class com.android.internal.util.Preconditions stubclass
+class com.android.internal.util.StringPool stubclass
diff --git a/libs/WindowManager/Shell/res/drawable/bubble_manage_btn_bg.xml b/libs/WindowManager/Shell/res/drawable/bubble_manage_btn_bg.xml
index d2360e9..657720e 100644
--- a/libs/WindowManager/Shell/res/drawable/bubble_manage_btn_bg.xml
+++ b/libs/WindowManager/Shell/res/drawable/bubble_manage_btn_bg.xml
@@ -21,7 +21,7 @@
<solid
android:color="?androidprv:attr/materialColorSurfaceContainerHigh"
/>
- <corners android:radius="20dp" />
+ <corners android:radius="18sp" />
<padding
android:left="20dp"
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 55a9132..de9d2a2 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -185,10 +185,11 @@
<dimen name="bubble_pointer_overlap">1dp</dimen>
<!-- Extra padding around the dismiss target for bubbles -->
<dimen name="bubble_dismiss_slop">16dp</dimen>
- <!-- Height of button allowing users to adjust settings for bubbles. -->
- <dimen name="bubble_manage_button_height">36dp</dimen>
- <!-- Height of manage button including margins. -->
- <dimen name="bubble_manage_button_total_height">68dp</dimen>
+ <!-- Height of button allowing users to adjust settings for bubbles. We use sp so that the
+ button can scale with the font size. -->
+ <dimen name="bubble_manage_button_height">36sp</dimen>
+ <!-- Touch area height of the manage button. -->
+ <dimen name="bubble_manage_button_touch_area_height">48dp</dimen>
<!-- The margin around the outside of the manage button. -->
<dimen name="bubble_manage_button_margin">16dp</dimen>
<!-- Height of an item in the bubble manage menu. -->
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
index 880579d..2ec9e8b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
@@ -88,8 +88,6 @@
public static final PathInterpolator DIM_INTERPOLATOR =
new PathInterpolator(.23f, .87f, .52f, -0.11f);
- public static final Interpolator DECELERATE = new PathInterpolator(0f, 0f, 0.5f, 1f);
-
// Create the default emphasized interpolator
private static PathInterpolator createEmphasizedInterpolator() {
Path path = new Path();
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 03c546d..5843635 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
@@ -61,6 +61,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.util.LatencyTracker;
import com.android.internal.view.AppearanceRegion;
import com.android.wm.shell.animation.FlingAnimationUtils;
import com.android.wm.shell.common.ExternalInterfaceBinder;
@@ -99,6 +100,7 @@
* Max duration to wait for an animation to finish before triggering the real back.
*/
private static final long MAX_ANIMATION_DURATION = 2000;
+ private final LatencyTracker mLatencyTracker;
/** True when a back gesture is ongoing */
private boolean mBackGestureStarted = false;
@@ -167,6 +169,7 @@
private final BackAnimationBackground mAnimationBackground;
private StatusBarCustomizer mCustomizer;
+ private boolean mTrackingLatency;
public BackAnimationController(
@NonNull ShellInit shellInit,
@@ -213,6 +216,7 @@
.setSpeedUpFactor(FLING_SPEED_UP_FACTOR)
.build();
mShellBackAnimationRegistry = shellBackAnimationRegistry;
+ mLatencyTracker = LatencyTracker.getInstance(mContext);
}
private void onInit() {
@@ -438,6 +442,7 @@
private void startBackNavigation(@NonNull TouchTracker touchTracker) {
try {
+ startLatencyTracking();
mBackNavigationInfo = mActivityTaskManager.startBackNavigation(
mNavigationObserver, mEnableAnimations.get() ? mBackAnimationAdapter : null);
onBackNavigationInfoReceived(mBackNavigationInfo, touchTracker);
@@ -452,6 +457,7 @@
ProtoLog.d(WM_SHELL_BACK_PREVIEW, "Received backNavigationInfo:%s", backNavigationInfo);
if (backNavigationInfo == null) {
ProtoLog.e(WM_SHELL_BACK_PREVIEW, "Received BackNavigationInfo is null.");
+ cancelLatencyTracking();
return;
}
final int backType = backNavigationInfo.getType();
@@ -462,6 +468,8 @@
}
} else {
mActiveCallback = mBackNavigationInfo.getOnBackInvokedCallback();
+ // App is handling back animation. Cancel system animation latency tracking.
+ cancelLatencyTracking();
dispatchOnBackStarted(mActiveCallback, touchTracker.createStartEvent(null));
}
}
@@ -808,12 +816,36 @@
ProtoLog.d(WM_SHELL_BACK_PREVIEW, "BackAnimationController: finishBackNavigation()");
mActiveCallback = null;
mShellBackAnimationRegistry.resetDefaultCrossActivity();
+ cancelLatencyTracking();
if (mBackNavigationInfo != null) {
mBackNavigationInfo.onBackNavigationFinished(triggerBack);
mBackNavigationInfo = null;
}
}
+ private void startLatencyTracking() {
+ if (mTrackingLatency) {
+ cancelLatencyTracking();
+ }
+ mLatencyTracker.onActionStart(LatencyTracker.ACTION_BACK_SYSTEM_ANIMATION);
+ mTrackingLatency = true;
+ }
+
+ private void cancelLatencyTracking() {
+ if (!mTrackingLatency) {
+ return;
+ }
+ mLatencyTracker.onActionCancel(LatencyTracker.ACTION_BACK_SYSTEM_ANIMATION);
+ mTrackingLatency = false;
+ }
+
+ private void endLatencyTracking() {
+ if (!mTrackingLatency) {
+ return;
+ }
+ mLatencyTracker.onActionEnd(LatencyTracker.ACTION_BACK_SYSTEM_ANIMATION);
+ mTrackingLatency = false;
+ }
private void createAdapter() {
IBackAnimationRunner runner =
@@ -826,6 +858,7 @@
IBackAnimationFinishedCallback finishedCallback) {
mShellExecutor.execute(
() -> {
+ endLatencyTracking();
if (mBackNavigationInfo == null) {
ProtoLog.e(WM_SHELL_BACK_PREVIEW,
"Lack of navigation info to start animation.");
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java
index 8ec297e..5a15674 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java
@@ -89,7 +89,6 @@
private final PointF mInitialTouchPos = new PointF();
private final Interpolator mPostAnimationInterpolator = Interpolators.EMPHASIZED;
- private final Interpolator mYMovementInterpolator = Interpolators.DECELERATE;
private final Interpolator mProgressInterpolator = new DecelerateInterpolator();
private final Matrix mTransformMatrix = new Matrix();
@@ -164,7 +163,7 @@
float yDirection = rawYDelta < 0 ? -1 : 1;
// limit yDelta interpretation to 1/2 of screen height in either direction
float deltaYRatio = Math.min(height / 2f, Math.abs(rawYDelta)) / (height / 2f);
- float interpolatedYRatio = mYMovementInterpolator.getInterpolation(deltaYRatio);
+ float interpolatedYRatio = mProgressInterpolator.getInterpolation(deltaYRatio);
// limit y-shift so surface never passes 8dp screen margin
float deltaY = yDirection * interpolatedYRatio * Math.max(0f,
(height - scaledHeight) / 2f - mVerticalMargin);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index 0568eda..c7ab6aa 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -57,6 +57,7 @@
import android.util.TypedValue;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
+import android.view.TouchDelegate;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
@@ -470,6 +471,17 @@
R.layout.bubble_manage_button, this /* parent */, false /* attach */);
addView(mManageButton);
mManageButton.setVisibility(visibility);
+ post(() -> {
+ int touchAreaHeight =
+ getResources().getDimensionPixelSize(
+ R.dimen.bubble_manage_button_touch_area_height);
+ Rect r = new Rect();
+ mManageButton.getHitRect(r);
+ int extraTouchArea = (touchAreaHeight - r.height()) / 2;
+ r.top -= extraTouchArea;
+ r.bottom += extraTouchArea;
+ setTouchDelegate(new TouchDelegate(r, mManageButton));
+ });
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
index 17e06e9..144c456 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
@@ -198,9 +198,10 @@
mPointerHeight = res.getDimensionPixelSize(R.dimen.bubble_pointer_height);
mPointerMargin = res.getDimensionPixelSize(R.dimen.bubble_pointer_margin);
mPointerOverlap = res.getDimensionPixelSize(R.dimen.bubble_pointer_overlap);
- mManageButtonHeightIncludingMargins =
- res.getDimensionPixelSize(R.dimen.bubble_manage_button_total_height);
mManageButtonHeight = res.getDimensionPixelSize(R.dimen.bubble_manage_button_height);
+ mManageButtonHeightIncludingMargins =
+ mManageButtonHeight
+ + 2 * res.getDimensionPixelSize(R.dimen.bubble_manage_button_margin);
mExpandedViewMinHeight = res.getDimensionPixelSize(R.dimen.bubble_expanded_default_height);
mOverflowHeight = res.getDimensionPixelSize(R.dimen.bubble_overflow_height);
mMinimumFlyoutWidthLargeScreen = res.getDimensionPixelSize(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index 9402d02..87461dc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -1829,9 +1829,12 @@
}
bubble.cleanupViews(); // cleans up the icon view
updateExpandedView(); // resets state for no expanded bubble
+ mExpandedBubble = null;
});
logBubbleEvent(bubble, FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__DISMISSED);
return;
+ } else if (getBubbleCount() == 1) {
+ mExpandedBubble = null;
}
// Remove it from the views
for (int i = 0; i < getBubbleCount(); i++) {
@@ -2420,14 +2423,13 @@
mExpandedAnimationController.notifyPreparingToCollapse();
updateOverflowDotVisibility(false /* expanding */);
- final Runnable collapseBackToStack = () -> mExpandedAnimationController.collapseBackToStack(
- mStackAnimationController
- .getStackPositionAlongNearestHorizontalEdge()
- /* collapseTo */,
- () -> {
- mBubbleContainer.setActiveController(mStackAnimationController);
- updateOverflowVisibility();
- });
+ final Runnable collapseBackToStack = () ->
+ mExpandedAnimationController.collapseBackToStack(
+ mStackAnimationController.getStackPositionAlongNearestHorizontalEdge(),
+ () -> {
+ mBubbleContainer.setActiveController(mStackAnimationController);
+ updateOverflowVisibility();
+ });
final Runnable after = () -> {
final BubbleViewProvider previouslySelected = mExpandedBubble;
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 64294c9..beae96e 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
@@ -646,11 +646,12 @@
@Provides
static KeyguardTransitionHandler provideKeyguardTransitionHandler(
ShellInit shellInit,
+ ShellController shellController,
Transitions transitions,
@ShellMainThread Handler mainHandler,
@ShellMainThread ShellExecutor mainExecutor) {
return new KeyguardTransitionHandler(
- shellInit, transitions, mainHandler, mainExecutor);
+ shellInit, shellController, transitions, mainHandler, mainExecutor);
}
@WMSingleton
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
index dba7f4b..0890861 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
@@ -50,6 +50,8 @@
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.annotations.ExternalThread;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
+import com.android.wm.shell.sysui.KeyguardChangeListener;
+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.transition.Transitions.TransitionFinishCallback;
@@ -59,10 +61,12 @@
*
* <p>This takes the highest priority.
*/
-public class KeyguardTransitionHandler implements Transitions.TransitionHandler {
+public class KeyguardTransitionHandler
+ implements Transitions.TransitionHandler, KeyguardChangeListener {
private static final String TAG = "KeyguardTransition";
private final Transitions mTransitions;
+ private final ShellController mShellController;
private final Handler mMainHandler;
private final ShellExecutor mMainExecutor;
@@ -81,6 +85,9 @@
// transition.
private boolean mIsLaunchingActivityOverLockscreen;
+ // Last value reported by {@link KeyguardChangeListener}.
+ private boolean mKeyguardShowing = true;
+
private final class StartedTransition {
final TransitionInfo mInfo;
final SurfaceControl.Transaction mFinishT;
@@ -93,12 +100,15 @@
mPlayer = player;
}
}
+
public KeyguardTransitionHandler(
@NonNull ShellInit shellInit,
+ @NonNull ShellController shellController,
@NonNull Transitions transitions,
@NonNull Handler mainHandler,
@NonNull ShellExecutor mainExecutor) {
mTransitions = transitions;
+ mShellController = shellController;
mMainHandler = mainHandler;
mMainExecutor = mainExecutor;
shellInit.addInitCallback(this::onInit, this);
@@ -106,6 +116,7 @@
private void onInit() {
mTransitions.addHandler(this);
+ mShellController.addKeyguardChangeListener(this);
}
/**
@@ -121,6 +132,16 @@
}
@Override
+ public void onKeyguardVisibilityChanged(
+ boolean visible, boolean occluded, boolean animatingDismiss) {
+ mKeyguardShowing = visible;
+ }
+
+ public boolean isKeyguardShowing() {
+ return mKeyguardShowing;
+ }
+
+ @Override
public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
index c20d23e..271a3b2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
@@ -64,6 +64,7 @@
import com.android.wm.shell.util.TransitionUtil;
import java.util.ArrayList;
+import java.util.function.Consumer;
/**
* Handles the Recents (overview) animation. Only one of these can run at a time. A recents
@@ -130,21 +131,21 @@
wct.sendPendingIntent(intent, fillIn, options);
final RecentsController controller = new RecentsController(listener);
RecentsMixedHandler mixer = null;
- Transitions.TransitionHandler mixedHandler = null;
+ Consumer<IBinder> setTransitionForMixer = null;
for (int i = 0; i < mMixers.size(); ++i) {
- mixedHandler = mMixers.get(i).handleRecentsRequest(wct);
- if (mixedHandler != null) {
+ setTransitionForMixer = mMixers.get(i).handleRecentsRequest(wct);
+ if (setTransitionForMixer != null) {
mixer = mMixers.get(i);
break;
}
}
final IBinder transition = mTransitions.startTransition(TRANSIT_TO_FRONT, wct,
- mixedHandler == null ? this : mixedHandler);
+ mixer == null ? this : mixer);
for (int i = 0; i < mStateListeners.size(); i++) {
mStateListeners.get(i).onTransitionStarted(transition);
}
if (mixer != null) {
- mixer.setRecentsTransition(transition);
+ setTransitionForMixer.accept(transition);
}
if (transition != null) {
controller.setTransition(transition);
@@ -589,6 +590,13 @@
cancel("transit_sleep");
return;
}
+ if (mKeyguardLocked) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+ "[%d] RecentsController.merge: keyguard is locked", mInstanceId);
+ // We will not accept new changes if we are swiping over the keyguard.
+ cancel(true /* toHome */, false /* withScreenshots */, "keyguard_locked");
+ return;
+ }
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
"[%d] RecentsController.merge", mInstanceId);
// Keep all tasks in one list because order matters.
@@ -1105,22 +1113,17 @@
* An interface for a mixed handler to receive information about recents requests (since these
* come into this handler directly vs from WMCore request).
*/
- public interface RecentsMixedHandler {
+ public interface RecentsMixedHandler extends Transitions.TransitionHandler {
/**
* Called when a recents request comes in. The handler can add operations to outWCT. If
- * the handler wants to "accept" the transition, it should return itself; otherwise, it
- * should return `null`.
+ * the handler wants to "accept" the transition, it should return a Consumer accepting the
+ * IBinder for the transition. If not, it should return `null`.
*
* If a mixed-handler accepts this recents, it will be the de-facto handler for this
* transition and is required to call the associated {@link #startAnimation},
* {@link #mergeAnimation}, and {@link #onTransitionConsumed} methods.
*/
- Transitions.TransitionHandler handleRecentsRequest(WindowContainerTransaction outWCT);
-
- /**
- * Reports the transition token associated with the accepted recents request. If there was
- * a problem starting the request, this will be called with `null`.
- */
- void setRecentsTransition(@Nullable IBinder transition);
+ @Nullable
+ Consumer<IBinder> handleRecentsRequest(WindowContainerTransaction outWCT);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
index 918a5a4..ce7fef2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
@@ -23,6 +23,7 @@
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_PIP;
import static android.view.WindowManager.TRANSIT_TO_BACK;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_UNOCCLUDING;
import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY;
import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
@@ -37,11 +38,13 @@
import android.annotation.Nullable;
import android.app.PendingIntent;
import android.os.IBinder;
+import android.util.ArrayMap;
import android.util.Pair;
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
+import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
import com.android.internal.protolog.common.ProtoLog;
@@ -61,7 +64,9 @@
import com.android.wm.shell.util.TransitionUtil;
import java.util.ArrayList;
+import java.util.Map;
import java.util.Optional;
+import java.util.function.Consumer;
/**
* A handler for dealing with transitions involving multiple other handlers. For example: an
@@ -79,7 +84,7 @@
private UnfoldTransitionHandler mUnfoldHandler;
private ActivityEmbeddingController mActivityEmbeddingController;
- private static class MixedTransition {
+ private class MixedTransition {
static final int TYPE_ENTER_PIP_FROM_SPLIT = 1;
/** Both the display and split-state (enter/exit) is changing */
@@ -94,14 +99,17 @@
/** Keyguard exit/occlude/unocclude transition. */
static final int TYPE_KEYGUARD = 5;
+ /** Recents transition on top of the lock screen. */
+ static final int TYPE_RECENTS_DURING_KEYGUARD = 6;
+
/** Recents Transition while in desktop mode. */
- static final int TYPE_RECENTS_DURING_DESKTOP = 6;
+ static final int TYPE_RECENTS_DURING_DESKTOP = 7;
/** Fold/Unfold transition. */
- static final int TYPE_UNFOLD = 7;
+ static final int TYPE_UNFOLD = 8;
/** Enter pip from one of the Activity Embedding windows. */
- static final int TYPE_ENTER_PIP_FROM_ACTIVITY_EMBEDDING = 8;
+ static final int TYPE_ENTER_PIP_FROM_ACTIVITY_EMBEDDING = 9;
/** The default animation for this mixed transition. */
static final int ANIM_TYPE_DEFAULT = 0;
@@ -117,7 +125,10 @@
final IBinder mTransition;
Transitions.TransitionHandler mLeftoversHandler = null;
+ TransitionInfo mInfo = null;
WindowContainerTransaction mFinishWCT = null;
+ SurfaceControl.Transaction mFinishT = null;
+ Transitions.TransitionFinishCallback mFinishCB = null;
/**
* Whether the transition has request for remote transition while mLeftoversHandler
@@ -138,6 +149,37 @@
mTransition = transition;
}
+ boolean startSubAnimation(Transitions.TransitionHandler handler, TransitionInfo info,
+ SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT) {
+ if (mInfo != null) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
+ "startSubAnimation #%d.%d", mInfo.getDebugId(), info.getDebugId());
+ }
+ mInFlightSubAnimations++;
+ if (!handler.startAnimation(
+ mTransition, info, startT, finishT, wct -> onSubAnimationFinished(info, wct))) {
+ mInFlightSubAnimations--;
+ return false;
+ }
+ return true;
+ }
+
+ void onSubAnimationFinished(TransitionInfo info, WindowContainerTransaction wct) {
+ mInFlightSubAnimations--;
+ if (mInfo != null) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
+ "onSubAnimationFinished #%d.%d remaining=%d",
+ mInfo.getDebugId(), info.getDebugId(), mInFlightSubAnimations);
+ }
+
+ joinFinishArgs(wct);
+
+ if (mInFlightSubAnimations == 0) {
+ mActiveTransitions.remove(MixedTransition.this);
+ mFinishCB.onTransitionFinished(mFinishWCT);
+ }
+ }
+
void joinFinishArgs(WindowContainerTransaction wct) {
if (wct != null) {
if (mFinishWCT == null) {
@@ -271,39 +313,46 @@
}
@Override
- public Transitions.TransitionHandler handleRecentsRequest(WindowContainerTransaction outWCT) {
+ public Consumer<IBinder> handleRecentsRequest(WindowContainerTransaction outWCT) {
if (mRecentsHandler != null) {
if (mSplitHandler.isSplitScreenVisible()) {
- return this;
+ return this::setRecentsTransitionDuringSplit;
+ } else if (mKeyguardHandler.isKeyguardShowing()) {
+ return this::setRecentsTransitionDuringKeyguard;
} else if (mDesktopTasksController != null
// Check on the default display. Recents/gesture nav is only available there
&& mDesktopTasksController.getVisibleTaskCount(DEFAULT_DISPLAY) > 0) {
- return this;
+ return this::setRecentsTransitionDuringDesktop;
}
}
return null;
}
- @Override
- public void setRecentsTransition(IBinder transition) {
- if (mSplitHandler.isSplitScreenVisible()) {
- ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a recents request while "
- + "Split-Screen is foreground, so treat it as Mixed.");
- final MixedTransition mixed = new MixedTransition(
- MixedTransition.TYPE_RECENTS_DURING_SPLIT, transition);
- mixed.mLeftoversHandler = mRecentsHandler;
- mActiveTransitions.add(mixed);
- } else if (DesktopModeStatus.isEnabled()) {
- ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a recents request while "
- + "desktop mode is active, so treat it as Mixed.");
- final MixedTransition mixed = new MixedTransition(
- MixedTransition.TYPE_RECENTS_DURING_DESKTOP, transition);
- mixed.mLeftoversHandler = mRecentsHandler;
- mActiveTransitions.add(mixed);
- } else {
- throw new IllegalStateException("Accepted a recents transition but don't know how to"
- + " handle it");
- }
+ private void setRecentsTransitionDuringSplit(IBinder transition) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a recents request while "
+ + "Split-Screen is foreground, so treat it as Mixed.");
+ final MixedTransition mixed = new MixedTransition(
+ MixedTransition.TYPE_RECENTS_DURING_SPLIT, transition);
+ mixed.mLeftoversHandler = mRecentsHandler;
+ mActiveTransitions.add(mixed);
+ }
+
+ private void setRecentsTransitionDuringKeyguard(IBinder transition) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a recents request while "
+ + "keyguard is visible, so treat it as Mixed.");
+ final MixedTransition mixed = new MixedTransition(
+ MixedTransition.TYPE_RECENTS_DURING_KEYGUARD, transition);
+ mixed.mLeftoversHandler = mRecentsHandler;
+ mActiveTransitions.add(mixed);
+ }
+
+ private void setRecentsTransitionDuringDesktop(IBinder transition) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a recents request while "
+ + "desktop mode is active, so treat it as Mixed.");
+ final MixedTransition mixed = new MixedTransition(
+ MixedTransition.TYPE_RECENTS_DURING_DESKTOP, transition);
+ mixed.mLeftoversHandler = mRecentsHandler;
+ mActiveTransitions.add(mixed);
}
private TransitionInfo subCopy(@NonNull TransitionInfo info,
@@ -410,6 +459,9 @@
} else if (mixed.mType == MixedTransition.TYPE_KEYGUARD) {
return animateKeyguard(mixed, info, startTransaction, finishTransaction,
finishCallback);
+ } else if (mixed.mType == MixedTransition.TYPE_RECENTS_DURING_KEYGUARD) {
+ return animateRecentsDuringKeyguard(mixed, info, startTransaction, finishTransaction,
+ finishCallback);
} else if (mixed.mType == MixedTransition.TYPE_RECENTS_DURING_DESKTOP) {
return animateRecentsDuringDesktop(mixed, info, startTransaction, finishTransaction,
finishCallback);
@@ -764,24 +816,28 @@
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
- final Transitions.TransitionFinishCallback finishCB = (wct) -> {
- mixed.mInFlightSubAnimations--;
- if (mixed.mInFlightSubAnimations == 0) {
- mActiveTransitions.remove(mixed);
- finishCallback.onTransitionFinished(wct);
- }
- };
- mixed.mInFlightSubAnimations++;
+ if (mixed.mFinishT == null) {
+ mixed.mFinishT = finishTransaction;
+ mixed.mFinishCB = finishCallback;
+ }
// Sync pip state.
if (mPipHandler != null) {
mPipHandler.syncPipSurfaceState(info, startTransaction, finishTransaction);
}
- if (!mKeyguardHandler.startAnimation(
- mixed.mTransition, info, startTransaction, finishTransaction, finishCB)) {
- mixed.mInFlightSubAnimations--;
- return false;
+ return mixed.startSubAnimation(mKeyguardHandler, info, startTransaction, finishTransaction);
+ }
+
+ private boolean animateRecentsDuringKeyguard(@NonNull final MixedTransition mixed,
+ @NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction startTransaction,
+ @NonNull SurfaceControl.Transaction finishTransaction,
+ @NonNull Transitions.TransitionFinishCallback finishCallback) {
+ if (mixed.mInfo == null) {
+ mixed.mInfo = info;
+ mixed.mFinishT = finishTransaction;
+ mixed.mFinishCB = finishCallback;
}
- return true;
+ return mixed.startSubAnimation(mRecentsHandler, info, startTransaction, finishTransaction);
}
private boolean animateRecentsDuringDesktop(@NonNull final MixedTransition mixed,
@@ -905,6 +961,15 @@
finishCallback);
} else if (mixed.mType == MixedTransition.TYPE_KEYGUARD) {
mKeyguardHandler.mergeAnimation(transition, info, t, mergeTarget, finishCallback);
+ } else if (mixed.mType == MixedTransition.TYPE_RECENTS_DURING_KEYGUARD) {
+ if ((info.getFlags() & TRANSIT_FLAG_KEYGUARD_UNOCCLUDING) != 0) {
+ handoverTransitionLeashes(mixed, info, t, mixed.mFinishT);
+ if (animateKeyguard(mixed, info, t, mixed.mFinishT, mixed.mFinishCB)) {
+ finishCallback.onTransitionFinished(null);
+ }
+ }
+ mixed.mLeftoversHandler.mergeAnimation(transition, info, t, mergeTarget,
+ finishCallback);
} else if (mixed.mType == MixedTransition.TYPE_RECENTS_DURING_DESKTOP) {
mixed.mLeftoversHandler.mergeAnimation(transition, info, t, mergeTarget,
finishCallback);
@@ -947,4 +1012,38 @@
mPlayer.getRemoteTransitionHandler().onTransitionConsumed(transition, aborted, finishT);
}
}
+
+ /**
+ * Update an incoming {@link TransitionInfo} with the leashes from an ongoing
+ * {@link MixedTransition} so that it can take over some parts of the animation without
+ * reparenting to new transition roots.
+ */
+ private static void handoverTransitionLeashes(@NonNull MixedTransition mixed,
+ @NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction startT,
+ @NonNull SurfaceControl.Transaction finishT) {
+
+ // Show the roots in case they contain new changes not present in the original transition.
+ for (int j = info.getRootCount() - 1; j >= 0; --j) {
+ startT.show(info.getRoot(j).getLeash());
+ }
+
+ // Find all of the leashes from the original transition.
+ Map<WindowContainerToken, TransitionInfo.Change> originalChanges = new ArrayMap<>();
+ for (TransitionInfo.Change oldChange : mixed.mInfo.getChanges()) {
+ if (oldChange.getContainer() != null) {
+ originalChanges.put(oldChange.getContainer(), oldChange);
+ }
+ }
+
+ // Merge the animation leashes by re-using the original ones if we see the same container
+ // in the new transition and the old.
+ for (TransitionInfo.Change newChange : info.getChanges()) {
+ if (originalChanges.containsKey(newChange.getContainer())) {
+ final TransitionInfo.Change oldChange = originalChanges.get(newChange.getContainer());
+ startT.reparent(newChange.getLeash(), null);
+ newChange.setLeash(oldChange.getLeash());
+ }
+ }
+ }
}
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 1941d66..652a2ed 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
@@ -70,8 +70,8 @@
private int mMarginMenuStart;
private int mMenuHeight;
private int mMenuWidth;
-
private final int mCaptionHeight;
+ private HandleMenuAnimator mHandleMenuAnimator;
HandleMenu(WindowDecoration parentDecor, int layoutResId, int captionX, int captionY,
@@ -111,20 +111,19 @@
mHandleMenuWindow = mParentDecor.addWindow(
R.layout.desktop_mode_window_decor_handle_menu, "Handle Menu",
t, ssg, x, y, mMenuWidth, mMenuHeight);
+ final View handleMenuView = mHandleMenuWindow.mWindowViewHost.getView();
+ mHandleMenuAnimator = new HandleMenuAnimator(handleMenuView, mMenuWidth, mCaptionHeight);
}
/**
* Animates the appearance of the handle menu and its three pills.
*/
private void animateHandleMenu() {
- final View handleMenuView = mHandleMenuWindow.mWindowViewHost.getView();
- final HandleMenuAnimator handleMenuAnimator = new HandleMenuAnimator(handleMenuView,
- mMenuWidth, mCaptionHeight);
if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
|| mTaskInfo.getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW) {
- handleMenuAnimator.animateCaptionHandleExpandToOpen();
+ mHandleMenuAnimator.animateCaptionHandleExpandToOpen();
} else {
- handleMenuAnimator.animateOpen();
+ mHandleMenuAnimator.animateOpen();
}
}
@@ -328,8 +327,16 @@
}
void close() {
- mHandleMenuWindow.releaseView();
- mHandleMenuWindow = null;
+ final Runnable after = () -> {
+ mHandleMenuWindow.releaseView();
+ mHandleMenuWindow = null;
+ };
+ if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
+ || mTaskInfo.getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW) {
+ mHandleMenuAnimator.animateCollapseIntoHandleClose(after);
+ } else {
+ mHandleMenuAnimator.animateClose(after);
+ }
}
static final class Builder {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuAnimator.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuAnimator.kt
index 531de1f..8c5d4a2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuAnimator.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuAnimator.kt
@@ -26,6 +26,7 @@
import android.view.View.TRANSLATION_Y
import android.view.View.TRANSLATION_Z
import android.view.ViewGroup
+import androidx.core.animation.doOnEnd
import androidx.core.view.children
import com.android.wm.shell.R
import com.android.wm.shell.animation.Interpolators
@@ -37,27 +38,36 @@
private val captionHeight: Float
) {
companion object {
- private const val MENU_Y_TRANSLATION_DURATION: Long = 150
- private const val HEADER_NONFREEFORM_SCALE_DURATION: Long = 150
- private const val HEADER_FREEFORM_SCALE_DURATION: Long = 217
- private const val HEADER_ELEVATION_DURATION: Long = 83
- private const val HEADER_CONTENT_ALPHA_DURATION: Long = 100
- private const val BODY_SCALE_DURATION: Long = 180
- private const val BODY_ALPHA_DURATION: Long = 150
- private const val BODY_ELEVATION_DURATION: Long = 83
- private const val BODY_CONTENT_ALPHA_DURATION: Long = 167
+ // Open animation constants
+ private const val MENU_Y_TRANSLATION_OPEN_DURATION: Long = 150
+ private const val HEADER_NONFREEFORM_SCALE_OPEN_DURATION: Long = 150
+ private const val HEADER_FREEFORM_SCALE_OPEN_DURATION: Long = 217
+ private const val HEADER_ELEVATION_OPEN_DURATION: Long = 83
+ private const val HEADER_CONTENT_ALPHA_OPEN_DURATION: Long = 100
+ private const val BODY_SCALE_OPEN_DURATION: Long = 180
+ private const val BODY_ALPHA_OPEN_DURATION: Long = 150
+ private const val BODY_ELEVATION_OPEN_DURATION: Long = 83
+ private const val BODY_CONTENT_ALPHA_OPEN_DURATION: Long = 167
- private const val ELEVATION_DELAY: Long = 33
- private const val HEADER_CONTENT_ALPHA_DELAY: Long = 67
- private const val BODY_SCALE_DELAY: Long = 50
- private const val BODY_ALPHA_DELAY: Long = 133
+ private const val ELEVATION_OPEN_DELAY: Long = 33
+ private const val HEADER_CONTENT_ALPHA_OPEN_DELAY: Long = 67
+ private const val BODY_SCALE_OPEN_DELAY: Long = 50
+ private const val BODY_ALPHA_OPEN_DELAY: Long = 133
private const val HALF_INITIAL_SCALE: Float = 0.5f
private const val NONFREEFORM_HEADER_INITIAL_SCALE_X: Float = 0.6f
private const val NONFREEFORM_HEADER_INITIAL_SCALE_Y: Float = 0.05f
+
+ // Close animation constants
+ private const val HEADER_CLOSE_DELAY: Long = 20
+ private const val HEADER_CLOSE_DURATION: Long = 50
+ private const val HEADER_CONTENT_OPACITY_CLOSE_DELAY: Long = 25
+ private const val HEADER_CONTENT_OPACITY_CLOSE_DURATION: Long = 25
+ private const val BODY_CLOSE_DURATION: Long = 50
}
private val animators: MutableList<Animator> = mutableListOf()
+ private var runningAnimation: AnimatorSet? = null
private val appInfoPill: ViewGroup = handleMenu.requireViewById(R.id.app_info_pill)
private val windowingPill: ViewGroup = handleMenu.requireViewById(R.id.windowing_pill)
@@ -67,9 +77,9 @@
fun animateOpen() {
prepareMenuForAnimation()
appInfoPillExpand()
- animateAppInfoPill()
- animateWindowingPill()
- animateMoreActionsPill()
+ animateAppInfoPillOpen()
+ animateWindowingPillOpen()
+ animateMoreActionsPillOpen()
runAnimations()
}
@@ -81,13 +91,44 @@
fun animateCaptionHandleExpandToOpen() {
prepareMenuForAnimation()
captionHandleExpandIntoAppInfoPill()
- animateAppInfoPill()
- animateWindowingPill()
- animateMoreActionsPill()
+ animateAppInfoPillOpen()
+ animateWindowingPillOpen()
+ animateMoreActionsPillOpen()
runAnimations()
}
/**
+ * Animates the closing of the handle menu. The windowing and more actions pill vanish. Then,
+ * the app info pill will collapse into the shape of the caption handle in full screen and split
+ * screen.
+ *
+ * @param after runs after the animation finishes.
+ */
+ fun animateCollapseIntoHandleClose(after: Runnable) {
+ appInfoCollapseToHandle()
+ animateAppInfoPillFadeOut()
+ windowingPillClose()
+ moreActionsPillClose()
+ runAnimations(after)
+ }
+
+ /**
+ * Animates the closing of the handle menu. The windowing and more actions pill vanish. Then,
+ * the app info pill will collapse into the shape of the caption handle in full screen and split
+ * screen.
+ *
+ * @param after runs after animation finishes.
+ *
+ */
+ fun animateClose(after: Runnable) {
+ appInfoPillCollapse()
+ animateAppInfoPillFadeOut()
+ windowingPillClose()
+ moreActionsPillClose()
+ runAnimations(after)
+ }
+
+ /**
* Prepares the handle menu for animation. Presets the opacity of necessary menu components.
* Presets pivots of handle menu and body pills for scaling animation.
*/
@@ -108,20 +149,20 @@
moreActionsPill.pivotY = appInfoPill.measuredHeight.toFloat()
}
- private fun animateAppInfoPill() {
+ private fun animateAppInfoPillOpen() {
// Header Elevation Animation
animators +=
ObjectAnimator.ofFloat(appInfoPill, TRANSLATION_Z, 1f).apply {
- startDelay = ELEVATION_DELAY
- duration = HEADER_ELEVATION_DURATION
+ startDelay = ELEVATION_OPEN_DELAY
+ duration = HEADER_ELEVATION_OPEN_DURATION
}
// Content Opacity Animation
appInfoPill.children.forEach {
animators +=
ObjectAnimator.ofFloat(it, ALPHA, 1f).apply {
- startDelay = HEADER_CONTENT_ALPHA_DELAY
- duration = HEADER_CONTENT_ALPHA_DURATION
+ startDelay = HEADER_CONTENT_ALPHA_OPEN_DELAY
+ duration = HEADER_CONTENT_ALPHA_OPEN_DURATION
}
}
}
@@ -130,17 +171,17 @@
// Header scaling animation
animators +=
ObjectAnimator.ofFloat(appInfoPill, SCALE_X, NONFREEFORM_HEADER_INITIAL_SCALE_X, 1f)
- .apply { duration = HEADER_NONFREEFORM_SCALE_DURATION }
+ .apply { duration = HEADER_NONFREEFORM_SCALE_OPEN_DURATION }
animators +=
ObjectAnimator.ofFloat(appInfoPill, SCALE_Y, NONFREEFORM_HEADER_INITIAL_SCALE_Y, 1f)
- .apply { duration = HEADER_NONFREEFORM_SCALE_DURATION }
+ .apply { duration = HEADER_NONFREEFORM_SCALE_OPEN_DURATION }
// Downward y-translation animation
val yStart: Float = -captionHeight / 2
animators +=
ObjectAnimator.ofFloat(handleMenu, TRANSLATION_Y, yStart, 0f).apply {
- duration = MENU_Y_TRANSLATION_DURATION
+ duration = MENU_Y_TRANSLATION_OPEN_DURATION
}
}
@@ -148,98 +189,217 @@
// Header scaling animation
animators +=
ObjectAnimator.ofFloat(appInfoPill, SCALE_X, HALF_INITIAL_SCALE, 1f).apply {
- duration = HEADER_FREEFORM_SCALE_DURATION
+ duration = HEADER_FREEFORM_SCALE_OPEN_DURATION
}
animators +=
ObjectAnimator.ofFloat(appInfoPill, SCALE_Y, HALF_INITIAL_SCALE, 1f).apply {
- duration = HEADER_FREEFORM_SCALE_DURATION
+ duration = HEADER_FREEFORM_SCALE_OPEN_DURATION
}
}
- private fun animateWindowingPill() {
+ private fun animateWindowingPillOpen() {
// Windowing X & Y Scaling Animation
animators +=
ObjectAnimator.ofFloat(windowingPill, SCALE_X, HALF_INITIAL_SCALE, 1f).apply {
- startDelay = BODY_SCALE_DELAY
- duration = BODY_SCALE_DURATION
+ startDelay = BODY_SCALE_OPEN_DELAY
+ duration = BODY_SCALE_OPEN_DURATION
}
animators +=
ObjectAnimator.ofFloat(windowingPill, SCALE_Y, HALF_INITIAL_SCALE, 1f).apply {
- startDelay = BODY_SCALE_DELAY
- duration = BODY_SCALE_DURATION
+ startDelay = BODY_SCALE_OPEN_DELAY
+ duration = BODY_SCALE_OPEN_DURATION
}
// Windowing Opacity Animation
animators +=
ObjectAnimator.ofFloat(windowingPill, ALPHA, 1f).apply {
- startDelay = BODY_ALPHA_DELAY
- duration = BODY_ALPHA_DURATION
+ startDelay = BODY_ALPHA_OPEN_DELAY
+ duration = BODY_ALPHA_OPEN_DURATION
}
// Windowing Elevation Animation
animators +=
ObjectAnimator.ofFloat(windowingPill, TRANSLATION_Z, 1f).apply {
- startDelay = ELEVATION_DELAY
- duration = BODY_ELEVATION_DURATION
+ startDelay = ELEVATION_OPEN_DELAY
+ duration = BODY_ELEVATION_OPEN_DURATION
}
// Windowing Content Opacity Animation
windowingPill.children.forEach {
animators +=
ObjectAnimator.ofFloat(it, ALPHA, 1f).apply {
- startDelay = BODY_ALPHA_DELAY
- duration = BODY_CONTENT_ALPHA_DURATION
+ startDelay = BODY_ALPHA_OPEN_DELAY
+ duration = BODY_CONTENT_ALPHA_OPEN_DURATION
interpolator = Interpolators.FAST_OUT_SLOW_IN
}
}
}
- private fun animateMoreActionsPill() {
+ private fun animateMoreActionsPillOpen() {
// More Actions X & Y Scaling Animation
animators +=
ObjectAnimator.ofFloat(moreActionsPill, SCALE_X, HALF_INITIAL_SCALE, 1f).apply {
- startDelay = BODY_SCALE_DELAY
- duration = BODY_SCALE_DURATION
+ startDelay = BODY_SCALE_OPEN_DELAY
+ duration = BODY_SCALE_OPEN_DURATION
}
animators +=
ObjectAnimator.ofFloat(moreActionsPill, SCALE_Y, HALF_INITIAL_SCALE, 1f).apply {
- startDelay = BODY_SCALE_DELAY
- duration = BODY_SCALE_DURATION
+ startDelay = BODY_SCALE_OPEN_DELAY
+ duration = BODY_SCALE_OPEN_DURATION
}
// More Actions Opacity Animation
animators +=
ObjectAnimator.ofFloat(moreActionsPill, ALPHA, 1f).apply {
- startDelay = BODY_ALPHA_DELAY
- duration = BODY_ALPHA_DURATION
+ startDelay = BODY_ALPHA_OPEN_DELAY
+ duration = BODY_ALPHA_OPEN_DURATION
}
// More Actions Elevation Animation
animators +=
ObjectAnimator.ofFloat(moreActionsPill, TRANSLATION_Z, 1f).apply {
- startDelay = ELEVATION_DELAY
- duration = BODY_ELEVATION_DURATION
+ startDelay = ELEVATION_OPEN_DELAY
+ duration = BODY_ELEVATION_OPEN_DURATION
}
// More Actions Content Opacity Animation
moreActionsPill.children.forEach {
animators +=
ObjectAnimator.ofFloat(it, ALPHA, 1f).apply {
- startDelay = BODY_ALPHA_DELAY
- duration = BODY_CONTENT_ALPHA_DURATION
+ startDelay = BODY_ALPHA_OPEN_DELAY
+ duration = BODY_CONTENT_ALPHA_OPEN_DURATION
interpolator = Interpolators.FAST_OUT_SLOW_IN
}
}
}
- /** Runs the list of animators concurrently. */
- private fun runAnimations() {
- val animatorSet = AnimatorSet()
- animatorSet.playTogether(animators)
- animatorSet.start()
- animators.clear()
+ private fun appInfoPillCollapse() {
+ // Header scaling animation
+ animators +=
+ ObjectAnimator.ofFloat(appInfoPill, SCALE_X, 0f).apply {
+ startDelay = HEADER_CLOSE_DELAY
+ duration = HEADER_CLOSE_DURATION
+ }
+
+ animators +=
+ ObjectAnimator.ofFloat(appInfoPill, SCALE_Y, 0f).apply {
+ startDelay = HEADER_CLOSE_DELAY
+ duration = HEADER_CLOSE_DURATION
+ }
+ }
+
+ private fun appInfoCollapseToHandle() {
+ // Header X & Y Scaling Animation
+ animators +=
+ ObjectAnimator.ofFloat(appInfoPill, SCALE_X, NONFREEFORM_HEADER_INITIAL_SCALE_X).apply {
+ startDelay = HEADER_CLOSE_DELAY
+ duration = HEADER_CLOSE_DURATION
+ }
+
+ animators +=
+ ObjectAnimator.ofFloat(appInfoPill, SCALE_Y, NONFREEFORM_HEADER_INITIAL_SCALE_Y).apply {
+ startDelay = HEADER_CLOSE_DELAY
+ duration = HEADER_CLOSE_DURATION
+ }
+ // Upward y-translation animation
+ val yStart: Float = -captionHeight / 2
+ animators +=
+ ObjectAnimator.ofFloat(appInfoPill, TRANSLATION_Y, yStart).apply {
+ startDelay = HEADER_CLOSE_DELAY
+ duration = HEADER_CLOSE_DURATION
+ }
+ }
+
+ private fun animateAppInfoPillFadeOut() {
+ // Header Content Opacity Animation
+ appInfoPill.children.forEach {
+ animators +=
+ ObjectAnimator.ofFloat(it, ALPHA, 0f).apply {
+ startDelay = HEADER_CONTENT_OPACITY_CLOSE_DELAY
+ duration = HEADER_CONTENT_OPACITY_CLOSE_DURATION
+ }
+ }
+ }
+
+ private fun windowingPillClose() {
+ // Windowing X & Y Scaling Animation
+ animators +=
+ ObjectAnimator.ofFloat(windowingPill, SCALE_X, HALF_INITIAL_SCALE).apply {
+ duration = BODY_CLOSE_DURATION
+ }
+
+ animators +=
+ ObjectAnimator.ofFloat(windowingPill, SCALE_Y, HALF_INITIAL_SCALE).apply {
+ duration = BODY_CLOSE_DURATION
+ }
+
+ // windowing Animation
+ animators +=
+ ObjectAnimator.ofFloat(windowingPill, ALPHA, 0f).apply {
+ duration = BODY_CLOSE_DURATION
+ }
+
+ animators +=
+ ObjectAnimator.ofFloat(windowingPill, ALPHA, 0f).apply {
+ duration = BODY_CLOSE_DURATION
+ }
+ }
+
+ private fun moreActionsPillClose() {
+ // More Actions X & Y Scaling Animation
+ animators +=
+ ObjectAnimator.ofFloat(moreActionsPill, SCALE_X, HALF_INITIAL_SCALE).apply {
+ duration = BODY_CLOSE_DURATION
+ }
+
+ animators +=
+ ObjectAnimator.ofFloat(moreActionsPill, SCALE_Y, HALF_INITIAL_SCALE).apply {
+ duration = BODY_CLOSE_DURATION
+ }
+
+ // More Actions Opacity Animation
+ animators +=
+ ObjectAnimator.ofFloat(moreActionsPill, ALPHA, 0f).apply {
+ duration = BODY_CLOSE_DURATION
+ }
+
+ animators +=
+ ObjectAnimator.ofFloat(moreActionsPill, ALPHA, 0f).apply {
+ duration = BODY_CLOSE_DURATION
+ }
+
+ // upward more actions pill y-translation animation
+ val yStart: Float = -captionHeight / 2
+ animators +=
+ ObjectAnimator.ofFloat(moreActionsPill, TRANSLATION_Y, yStart).apply {
+ duration = BODY_CLOSE_DURATION
+ }
+ }
+
+ /**
+ * Runs the list of hide animators concurrently.
+ *
+ * @param after runs after animation finishes.
+ */
+ private fun runAnimations(after: Runnable? = null) {
+ runningAnimation?.apply {
+ // Remove all listeners, so that after runnable isn't triggered upon cancel.
+ removeAllListeners()
+ // If an animation runs while running animation is triggered, gracefully cancel.
+ cancel()
+ }
+
+ runningAnimation = AnimatorSet().apply {
+ playTogether(animators)
+ animators.clear()
+ doOnEnd {
+ after?.run()
+ runningAnimation = null
+ }
+ start()
+ }
}
}
diff --git a/location/api/lint-baseline.txt b/location/api/lint-baseline.txt
new file mode 100644
index 0000000..5e3ef01
--- /dev/null
+++ b/location/api/lint-baseline.txt
@@ -0,0 +1,27 @@
+// Baseline format: 1.0
+RequiresPermission: android.location.LocationManager#addGpsStatusListener(android.location.GpsStatus.Listener):
+ Method 'addGpsStatusListener' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#addNmeaListener(android.location.OnNmeaMessageListener):
+ Method 'addNmeaListener' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#addNmeaListener(android.location.OnNmeaMessageListener, android.os.Handler):
+ Method 'addNmeaListener' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#addNmeaListener(java.util.concurrent.Executor, android.location.OnNmeaMessageListener):
+ Method 'addNmeaListener' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#addProximityAlert(double, double, float, long, android.app.PendingIntent):
+ Method 'addProximityAlert' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssMeasurementsCallback(android.location.GnssMeasurementRequest, java.util.concurrent.Executor, android.location.GnssMeasurementsEvent.Callback):
+ Method 'registerGnssMeasurementsCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback, android.os.Handler):
+ Method 'registerGnssMeasurementsCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssMeasurementsCallback(java.util.concurrent.Executor, android.location.GnssMeasurementsEvent.Callback):
+ Method 'registerGnssMeasurementsCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssNavigationMessageCallback(android.location.GnssNavigationMessage.Callback, android.os.Handler):
+ Method 'registerGnssNavigationMessageCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssNavigationMessageCallback(java.util.concurrent.Executor, android.location.GnssNavigationMessage.Callback):
+ Method 'registerGnssNavigationMessageCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssStatusCallback(android.location.GnssStatus.Callback):
+ Method 'registerGnssStatusCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssStatusCallback(android.location.GnssStatus.Callback, android.os.Handler):
+ Method 'registerGnssStatusCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssStatusCallback(java.util.concurrent.Executor, android.location.GnssStatus.Callback):
+ Method 'registerGnssStatusCallback' documentation mentions permissions already declared by @RequiresPermission
diff --git a/location/api/module-lib-lint-baseline.txt b/location/api/module-lib-lint-baseline.txt
index 7cd6a86..3b1be7db 100644
--- a/location/api/module-lib-lint-baseline.txt
+++ b/location/api/module-lib-lint-baseline.txt
@@ -1,4 +1,36 @@
// Baseline format: 1.0
+RequiresPermission: android.location.LocationManager#addGpsStatusListener(android.location.GpsStatus.Listener):
+ Method 'addGpsStatusListener' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#addNmeaListener(android.location.OnNmeaMessageListener):
+ Method 'addNmeaListener' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#addNmeaListener(android.location.OnNmeaMessageListener, android.os.Handler):
+ Method 'addNmeaListener' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#addNmeaListener(java.util.concurrent.Executor, android.location.OnNmeaMessageListener):
+ Method 'addNmeaListener' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#addProximityAlert(double, double, float, long, android.app.PendingIntent):
+ Method 'addProximityAlert' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#injectGnssMeasurementCorrections(android.location.GnssMeasurementCorrections):
+ Method 'injectGnssMeasurementCorrections' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssMeasurementsCallback(android.location.GnssMeasurementRequest, java.util.concurrent.Executor, android.location.GnssMeasurementsEvent.Callback):
+ Method 'registerGnssMeasurementsCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback, android.os.Handler):
+ Method 'registerGnssMeasurementsCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssMeasurementsCallback(android.location.GnssRequest, java.util.concurrent.Executor, android.location.GnssMeasurementsEvent.Callback):
+ Method 'registerGnssMeasurementsCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssMeasurementsCallback(java.util.concurrent.Executor, android.location.GnssMeasurementsEvent.Callback):
+ Method 'registerGnssMeasurementsCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssNavigationMessageCallback(android.location.GnssNavigationMessage.Callback, android.os.Handler):
+ Method 'registerGnssNavigationMessageCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssNavigationMessageCallback(java.util.concurrent.Executor, android.location.GnssNavigationMessage.Callback):
+ Method 'registerGnssNavigationMessageCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssStatusCallback(android.location.GnssStatus.Callback):
+ Method 'registerGnssStatusCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssStatusCallback(android.location.GnssStatus.Callback, android.os.Handler):
+ Method 'registerGnssStatusCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssStatusCallback(java.util.concurrent.Executor, android.location.GnssStatus.Callback):
+ Method 'registerGnssStatusCallback' documentation mentions permissions already declared by @RequiresPermission
+
+
SamShouldBeLast: android.location.LocationManager#addNmeaListener(android.location.OnNmeaMessageListener, android.os.Handler):
SAM-compatible parameters (such as parameter 1, "listener", in android.location.LocationManager.addNmeaListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(String, long, float, android.location.LocationListener, android.os.Looper):
diff --git a/location/api/system-lint-baseline.txt b/location/api/system-lint-baseline.txt
index 043a082..066a40a 100644
--- a/location/api/system-lint-baseline.txt
+++ b/location/api/system-lint-baseline.txt
@@ -1,4 +1,36 @@
// Baseline format: 1.0
+RequiresPermission: android.location.LocationManager#addGpsStatusListener(android.location.GpsStatus.Listener):
+ Method 'addGpsStatusListener' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#addNmeaListener(android.location.OnNmeaMessageListener):
+ Method 'addNmeaListener' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#addNmeaListener(android.location.OnNmeaMessageListener, android.os.Handler):
+ Method 'addNmeaListener' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#addNmeaListener(java.util.concurrent.Executor, android.location.OnNmeaMessageListener):
+ Method 'addNmeaListener' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#addProximityAlert(double, double, float, long, android.app.PendingIntent):
+ Method 'addProximityAlert' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#injectGnssMeasurementCorrections(android.location.GnssMeasurementCorrections):
+ Method 'injectGnssMeasurementCorrections' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssMeasurementsCallback(android.location.GnssMeasurementRequest, java.util.concurrent.Executor, android.location.GnssMeasurementsEvent.Callback):
+ Method 'registerGnssMeasurementsCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback, android.os.Handler):
+ Method 'registerGnssMeasurementsCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssMeasurementsCallback(android.location.GnssRequest, java.util.concurrent.Executor, android.location.GnssMeasurementsEvent.Callback):
+ Method 'registerGnssMeasurementsCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssMeasurementsCallback(java.util.concurrent.Executor, android.location.GnssMeasurementsEvent.Callback):
+ Method 'registerGnssMeasurementsCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssNavigationMessageCallback(android.location.GnssNavigationMessage.Callback, android.os.Handler):
+ Method 'registerGnssNavigationMessageCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssNavigationMessageCallback(java.util.concurrent.Executor, android.location.GnssNavigationMessage.Callback):
+ Method 'registerGnssNavigationMessageCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssStatusCallback(android.location.GnssStatus.Callback):
+ Method 'registerGnssStatusCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssStatusCallback(android.location.GnssStatus.Callback, android.os.Handler):
+ Method 'registerGnssStatusCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssStatusCallback(java.util.concurrent.Executor, android.location.GnssStatus.Callback):
+ Method 'registerGnssStatusCallback' documentation mentions permissions already declared by @RequiresPermission
+
+
SamShouldBeLast: android.location.LocationManager#addNmeaListener(android.location.OnNmeaMessageListener, android.os.Handler):
SAM-compatible parameters (such as parameter 1, "listener", in android.location.LocationManager.addNmeaListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(String, long, float, android.location.LocationListener, android.os.Looper):
diff --git a/media/tests/projection/Android.bp b/media/tests/projection/Android.bp
index 48cd8b6..c9a8864 100644
--- a/media/tests/projection/Android.bp
+++ b/media/tests/projection/Android.bp
@@ -26,6 +26,7 @@
"androidx.test.runner",
"androidx.test.rules",
"androidx.test.ext.junit",
+ "frameworks-base-testutils",
"mockito-target-extended-minus-junit4",
"platform-test-annotations",
"testng",
diff --git a/media/tests/projection/src/android/media/projection/FakeIMediaProjection.java b/media/tests/projection/src/android/media/projection/FakeIMediaProjection.java
index 4952e01..774de5f 100644
--- a/media/tests/projection/src/android/media/projection/FakeIMediaProjection.java
+++ b/media/tests/projection/src/android/media/projection/FakeIMediaProjection.java
@@ -16,7 +16,11 @@
package android.media.projection;
+import static android.Manifest.permission.MANAGE_MEDIA_PROJECTION;
+
+import android.annotation.EnforcePermission;
import android.os.IBinder;
+import android.os.PermissionEnforcer;
import android.os.RemoteException;
/**
@@ -28,6 +32,10 @@
IBinder mLaunchCookie = null;
IMediaProjectionCallback mIMediaProjectionCallback = null;
+ FakeIMediaProjection(PermissionEnforcer enforcer) {
+ super(enforcer);
+ }
+
@Override
public void start(IMediaProjectionCallback callback) throws RemoteException {
mIMediaProjectionCallback = callback;
@@ -56,7 +64,9 @@
}
@Override
+ @EnforcePermission(MANAGE_MEDIA_PROJECTION)
public int applyVirtualDisplayFlags(int flags) throws RemoteException {
+ applyVirtualDisplayFlags_enforcePermission();
return 0;
}
@@ -69,22 +79,30 @@
}
@Override
+ @EnforcePermission(MANAGE_MEDIA_PROJECTION)
public IBinder getLaunchCookie() throws RemoteException {
+ getLaunchCookie_enforcePermission();
return mLaunchCookie;
}
@Override
+ @EnforcePermission(MANAGE_MEDIA_PROJECTION)
public void setLaunchCookie(IBinder launchCookie) throws RemoteException {
+ setLaunchCookie_enforcePermission();
mLaunchCookie = launchCookie;
}
@Override
+ @EnforcePermission(MANAGE_MEDIA_PROJECTION)
public boolean isValid() throws RemoteException {
+ isValid_enforcePermission();
return true;
}
@Override
+ @EnforcePermission(MANAGE_MEDIA_PROJECTION)
public void notifyVirtualDisplayCreated(int displayId) throws RemoteException {
+ notifyVirtualDisplayCreated_enforcePermission();
}
}
diff --git a/media/tests/projection/src/android/media/projection/MediaProjectionTest.java b/media/tests/projection/src/android/media/projection/MediaProjectionTest.java
index 2a5674e..2e0396f 100644
--- a/media/tests/projection/src/android/media/projection/MediaProjectionTest.java
+++ b/media/tests/projection/src/android/media/projection/MediaProjectionTest.java
@@ -16,7 +16,7 @@
package android.media.projection;
-
+import static android.Manifest.permission.MANAGE_MEDIA_PROJECTION;
import static android.media.projection.MediaProjection.MEDIA_PROJECTION_REQUIRES_CALLBACK;
import static android.view.Display.DEFAULT_DISPLAY;
@@ -42,6 +42,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
+import android.os.test.FakePermissionEnforcer;
import android.platform.test.annotations.Presubmit;
import android.testing.TestableContext;
import android.view.Display;
@@ -80,7 +81,7 @@
private final Handler mHandler = new Handler(Looper.getMainLooper());
// Fake the connection to the system server.
- private final FakeIMediaProjection mFakeIMediaProjection = new FakeIMediaProjection();
+ private FakeIMediaProjection mFakeIMediaProjection;
// Callback registered by an app.
private MediaProjection mMediaProjection;
@@ -112,7 +113,10 @@
.strictness(Strictness.LENIENT)
.startMocking();
+ FakePermissionEnforcer permissionEnforcer = new FakePermissionEnforcer();
+ permissionEnforcer.grant(MANAGE_MEDIA_PROJECTION);
// Support the MediaProjection instance.
+ mFakeIMediaProjection = new FakeIMediaProjection(permissionEnforcer);
mFakeIMediaProjection.setLaunchCookie(mock(IBinder.class));
mMediaProjection = new MediaProjection(mTestableContext, mFakeIMediaProjection,
mDisplayManager);
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/scaffold/SearchScaffoldPageProvider.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/scaffold/SearchScaffoldPageProvider.kt
index a1ab35b..eac06e3 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/scaffold/SearchScaffoldPageProvider.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/scaffold/SearchScaffoldPageProvider.kt
@@ -50,7 +50,7 @@
@Composable
private fun Page() {
- SearchScaffold(title = TITLE) { bottomPadding, searchQuery ->
- PlaceholderTitle("Search query: ${searchQuery.value}")
+ SearchScaffold(title = TITLE) { _, searchQuery ->
+ PlaceholderTitle("Search query: ${searchQuery()}")
}
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/RuntimeUtils.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/RuntimeUtils.kt
index ba88546..b97fb9c 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/RuntimeUtils.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/RuntimeUtils.kt
@@ -29,12 +29,6 @@
}
/**
- * Remember the [State] initialized with the [this].
- */
-@Composable
-fun <T> T.toState(): State<T> = remember { stateOf(this) }
-
-/**
* Return a new [State] initialized with the passed in [value].
*/
fun <T> stateOf(value: T) = object : State<T> {
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/StateFlowBridge.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/StateFlowBridge.kt
index 494e69b..7842948 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/StateFlowBridge.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/StateFlowBridge.kt
@@ -18,11 +18,10 @@
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.State
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.filterNotNull
-/** A StateFlow holder which value could be set or sync from [State]. */
+/** A StateFlow holder which value could be set or sync from callback. */
class StateFlowBridge<T> {
private val stateFlow = MutableStateFlow<T?>(null)
val flow = stateFlow.filterNotNull()
@@ -34,9 +33,10 @@
}
@Composable
- fun Sync(state: State<T>) {
- LaunchedEffect(state.value) {
- stateFlow.value = state.value
+ fun Sync(callback: () -> T) {
+ val value = callback()
+ LaunchedEffect(value) {
+ stateFlow.value = value
}
}
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt
index 696e877..c87178d 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt
@@ -37,8 +37,6 @@
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.State
-import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@@ -72,7 +70,7 @@
fun SearchScaffold(
title: String,
actions: @Composable RowScope.() -> Unit = {},
- content: @Composable (bottomPadding: Dp, searchQuery: State<String>) -> Unit,
+ content: @Composable (bottomPadding: Dp, searchQuery: () -> String) -> Unit,
) {
ActivityTitle(title)
var isSearchMode by rememberSaveable { mutableStateOf(false) }
@@ -100,12 +98,9 @@
.focusable()
.fillMaxSize()
) {
- content(
- paddingValues.calculateBottomPadding(),
- remember {
- derivedStateOf { if (isSearchMode) viewModel.searchQuery.text else "" }
- },
- )
+ content(paddingValues.calculateBottomPadding()) {
+ if (isSearchMode) viewModel.searchQuery.text else ""
+ }
}
}
}
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/util/StateFlowBridgeTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/util/StateFlowBridgeTest.kt
index f0e57b9..9b7ef08 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/util/StateFlowBridgeTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/util/StateFlowBridgeTest.kt
@@ -18,7 +18,6 @@
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.test.ext.junit.runners.AndroidJUnit4
-import com.android.settingslib.spa.framework.compose.stateOf
import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
@@ -56,7 +55,7 @@
val stateFlowBridge = StateFlowBridge<String>()
composeTestRule.setContent {
- stateFlowBridge.Sync(stateOf("A"))
+ stateFlowBridge.Sync { "A" }
}
val first = stateFlowBridge.flow.firstWithTimeoutOrNull()
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/SearchScaffoldTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/SearchScaffoldTest.kt
index c3e1d54..826a0d4 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/SearchScaffoldTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/SearchScaffoldTest.kt
@@ -19,7 +19,6 @@
import android.content.Context
import androidx.appcompat.R
import androidx.compose.runtime.SideEffect
-import androidx.compose.runtime.State
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithContentDescription
@@ -60,7 +59,7 @@
fun initialState_searchQueryIsEmpty() {
val searchQuery = setContent()
- assertThat(searchQuery.value).isEqualTo("")
+ assertThat(searchQuery()).isEqualTo("")
}
@Test
@@ -72,7 +71,7 @@
composeTestRule.onNodeWithText(TITLE).assertDoesNotExist()
onSearchHint().assertIsDisplayed()
onClearButton().assertDoesNotExist()
- assertThat(searchQuery.value).isEqualTo("")
+ assertThat(searchQuery()).isEqualTo("")
}
@Test
@@ -87,7 +86,7 @@
composeTestRule.onNodeWithText(TITLE).assertIsDisplayed()
onSearchHint().assertDoesNotExist()
onClearButton().assertDoesNotExist()
- assertThat(searchQuery.value).isEqualTo("")
+ assertThat(searchQuery()).isEqualTo("")
}
@Test
@@ -98,7 +97,7 @@
onSearchHint().performTextInput(QUERY)
onClearButton().assertIsDisplayed()
- assertThat(searchQuery.value).isEqualTo(QUERY)
+ assertThat(searchQuery()).isEqualTo(QUERY)
}
@Test
@@ -110,11 +109,11 @@
onClearButton().performClick()
onClearButton().assertDoesNotExist()
- assertThat(searchQuery.value).isEqualTo("")
+ assertThat(searchQuery()).isEqualTo("")
}
- private fun setContent(): State<String> {
- lateinit var actualSearchQuery: State<String>
+ private fun setContent(): () -> String {
+ lateinit var actualSearchQuery: () -> String
composeTestRule.setContent {
SearchScaffold(title = TITLE) { _, searchQuery ->
SideEffect {
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt
index 7c45b64..68da143 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt
@@ -65,8 +65,8 @@
)
data class AppListState(
- val showSystem: State<Boolean>,
- val searchQuery: State<String>,
+ val showSystem: () -> Boolean,
+ val searchQuery: () -> String,
)
data class AppListInput<T : AppRecord>(
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListPage.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListPage.kt
index 07e4235..c69b5df 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListPage.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListPage.kt
@@ -17,8 +17,10 @@
package com.android.settingslib.spaprivileged.template.app
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.runtime.setValue
import androidx.compose.ui.res.stringResource
import com.android.settingslib.spa.widget.scaffold.MoreOptionsAction
import com.android.settingslib.spa.widget.scaffold.MoreOptionsScope
@@ -47,13 +49,13 @@
header: @Composable () -> Unit = {},
appList: @Composable AppListInput<T>.() -> Unit = { AppList() },
) {
- val showSystem = rememberSaveable { mutableStateOf(false) }
+ var showSystem by rememberSaveable { mutableStateOf(false) }
SearchScaffold(
title = title,
actions = {
if (!noMoreOptions) {
MoreOptionsAction {
- ShowSystemAction(showSystem.value) { showSystem.value = it }
+ ShowSystemAction(showSystem) { showSystem = it }
moreOptions()
}
}
@@ -68,7 +70,7 @@
),
listModel = listModel,
state = AppListState(
- showSystem = showSystem,
+ showSystem = { showSystem },
searchQuery = searchQuery,
),
header = header,
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListPageTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListPageTest.kt
index 82fbee9..4d90076 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListPageTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListPageTest.kt
@@ -55,8 +55,8 @@
val inputState by setContent()
val state = inputState!!.state
- assertThat(state.showSystem.value).isFalse()
- assertThat(state.searchQuery.value).isEqualTo("")
+ assertThat(state.showSystem()).isFalse()
+ assertThat(state.searchQuery()).isEqualTo("")
}
@Test
@@ -67,7 +67,7 @@
composeTestRule.onNodeWithText(context.getString(R.string.menu_show_system)).performClick()
val state = inputState!!.state
- assertThat(state.showSystem.value).isTrue()
+ assertThat(state.showSystem()).isTrue()
}
@Test
@@ -94,7 +94,7 @@
val inputState by setContent(noMoreOptions = true)
val state = inputState!!.state
- assertThat(state.showSystem.value).isFalse()
+ assertThat(state.showSystem()).isFalse()
}
private fun setContent(
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt
index 124ced6..c6409e7 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt
@@ -30,7 +30,6 @@
import androidx.compose.ui.unit.dp
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
-import com.android.settingslib.spa.framework.compose.stateOf
import com.android.settingslib.spa.widget.ui.SpinnerOption
import com.android.settingslib.spaprivileged.R
import com.android.settingslib.spaprivileged.model.app.AppEntry
@@ -140,7 +139,7 @@
matchAnyUserForAdmin = false,
),
listModel = TestAppListModel(enableGrouping = enableGrouping),
- state = AppListState(showSystem = stateOf(false), searchQuery = stateOf("")),
+ state = AppListState(showSystem = { false }, searchQuery = { "" }),
header = header,
bottomPadding = 0.dp,
)
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryUtils.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryUtils.java
index 88dcc0d..83c106b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryUtils.java
@@ -16,9 +16,16 @@
package com.android.settingslib.fuelgauge;
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.provider.Settings;
+import android.util.ArraySet;
+import android.view.accessibility.AccessibilityManager;
+
+import java.util.List;
public final class BatteryUtils {
@@ -30,4 +37,35 @@
return context.registerReceiver(
/*receiver=*/ null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
}
+
+ /** Gets the current active accessibility related packages. */
+ public static ArraySet<String> getA11yPackageNames(Context context) {
+ context = context.getApplicationContext();
+ final ArraySet<String> packageNames = new ArraySet<>();
+ final String defaultTtsPackageName = Settings.Secure.getString(
+ context.getContentResolver(), Settings.Secure.TTS_DEFAULT_SYNTH);
+ if (defaultTtsPackageName != null) {
+ packageNames.add(defaultTtsPackageName);
+ }
+ // Checks the current active packages.
+ final AccessibilityManager accessibilityManager =
+ context.getSystemService(AccessibilityManager.class);
+ if (!accessibilityManager.isEnabled()) {
+ return packageNames;
+ }
+ final List<AccessibilityServiceInfo> serviceInfoList =
+ accessibilityManager.getEnabledAccessibilityServiceList(
+ AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
+ if (serviceInfoList == null || serviceInfoList.isEmpty()) {
+ return packageNames;
+ }
+ for (AccessibilityServiceInfo serviceInfo : serviceInfoList) {
+ final ComponentName serviceComponent = ComponentName.unflattenFromString(
+ serviceInfo.getId());
+ if (serviceComponent != null) {
+ packageNames.add(serviceComponent.getPackageName());
+ }
+ }
+ return packageNames;
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatteryUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatteryUtilsTest.java
new file mode 100644
index 0000000..c3e0c0b
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatteryUtilsTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.fuelgauge;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.robolectric.Shadows.shadowOf;
+
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.provider.Settings;
+import android.view.accessibility.AccessibilityManager;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.shadows.ShadowAccessibilityManager;
+
+import java.util.Arrays;
+
+@RunWith(RobolectricTestRunner.class)
+public class BatteryUtilsTest {
+ private static final String DEFAULT_TTS_PACKAGE = "com.abc.talkback";
+ private static final String ACCESSIBILITY_PACKAGE = "com.def.talkback";
+
+ private Context mContext;
+ private AccessibilityManager mAccessibilityManager;
+ private ShadowAccessibilityManager mShadowAccessibilityManager;
+
+ @Mock
+ private AccessibilityServiceInfo mAccessibilityServiceInfo1;
+ @Mock
+ private AccessibilityServiceInfo mAccessibilityServiceInfo2;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ doReturn(mContext).when(mContext).getApplicationContext();
+ mAccessibilityManager = spy(mContext.getSystemService(AccessibilityManager.class));
+ mShadowAccessibilityManager = shadowOf(mAccessibilityManager);
+ doReturn(mAccessibilityManager).when(mContext)
+ .getSystemService(AccessibilityManager.class);
+
+ setTtsPackageName(DEFAULT_TTS_PACKAGE);
+ doReturn(Arrays.asList(mAccessibilityServiceInfo1, mAccessibilityServiceInfo2))
+ .when(mAccessibilityManager)
+ .getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
+ doReturn(ACCESSIBILITY_PACKAGE + "/.TalkbackService").when(mAccessibilityServiceInfo1)
+ .getId();
+ doReturn("dummy_package_name").when(mAccessibilityServiceInfo2).getId();
+ }
+
+ @Test
+ public void getBatteryIntent_registerReceiver() {
+ BatteryUtils.getBatteryIntent(mContext);
+ verify(mContext).registerReceiver(eq(null), any(IntentFilter.class));
+ }
+
+ @Test
+ public void getA11yPackageNames_returnDefaultTtsPackageName() {
+ mShadowAccessibilityManager.setEnabled(false);
+
+ assertThat(BatteryUtils.getA11yPackageNames(mContext))
+ .containsExactly(DEFAULT_TTS_PACKAGE);
+ }
+
+ @Test
+ public void getA11yPackageNames_returnExpectedPackageNames() {
+ mShadowAccessibilityManager.setEnabled(true);
+
+ assertThat(BatteryUtils.getA11yPackageNames(mContext))
+ .containsExactly(DEFAULT_TTS_PACKAGE, ACCESSIBILITY_PACKAGE);
+ }
+
+ private void setTtsPackageName(String defaultTtsPackageName) {
+ Settings.Secure.putString(mContext.getContentResolver(),
+ Settings.Secure.TTS_DEFAULT_SYNTH, defaultTtsPackageName);
+ }
+}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index c7e5bf9..36e1bfa 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -864,6 +864,7 @@
<!-- Permissions required for CTS test - CtsVoiceInteractionTestCases -->
<uses-permission android:name="android.permission.RESET_HOTWORD_TRAINING_DATA_EGRESS_COUNT" />
<uses-permission android:name="android.permission.RECEIVE_SANDBOXED_DETECTION_TRAINING_DATA" />
+ <uses-permission android:name="android.permission.GET_BINDING_UID_IMPORTANCE" />
<application
android:label="@string/app_label"
diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING
index 28539dd..0480b9d 100644
--- a/packages/SystemUI/TEST_MAPPING
+++ b/packages/SystemUI/TEST_MAPPING
@@ -88,20 +88,6 @@
"include-filter": "android.permissionui.cts.CameraMicIndicatorsPermissionTest"
}
]
- },
- {
- "name": "SystemUIGoogleScreenshotTests",
- "options": [
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "android.platform.test.annotations.FlakyTest"
- },
- {
- "include-annotation": "android.platform.test.annotations.Postsubmit"
- }
- ]
}
],
@@ -171,12 +157,6 @@
},
{
"include-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "include-annotation": "android.platform.test.annotations.FlakyTest"
- },
- {
- "include-annotation": "android.platform.test.annotations.Postsubmit"
}
]
},
@@ -188,28 +168,18 @@
},
{
"include-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "include-annotation": "android.platform.test.annotations.FlakyTest"
- },
- {
- "include-annotation": "android.platform.test.annotations.Postsubmit"
}
]
},
- { "name": "SystemUIGoogleBiometricsScreenshotTests",
+ {
+ // TODO(b/251476085): Consider merging with SystemUIGoogleScreenshotTests (in U+)
+ "name": "SystemUIGoogleBiometricsScreenshotTests",
"options": [
{
"exclude-annotation": "org.junit.Ignore"
},
{
"include-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "include-annotation": "android.platform.test.annotations.FlakyTest"
- },
- {
- "include-annotation": "android.platform.test.annotations.Postsubmit"
}
]
}
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 041fc48..009f8bb 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
@@ -36,7 +36,7 @@
fun SceneScope.animateSharedIntAsState(
value: Int,
key: ValueKey,
- element: ElementKey,
+ element: ElementKey?,
canOverflow: Boolean = true,
): State<Int> {
return animateSharedValueAsState(value, key, element, ::lerp, canOverflow)
@@ -65,7 +65,7 @@
fun SceneScope.animateSharedFloatAsState(
value: Float,
key: ValueKey,
- element: ElementKey,
+ element: ElementKey?,
canOverflow: Boolean = true,
): State<Float> {
return animateSharedValueAsState(value, key, element, ::lerp, canOverflow)
@@ -94,7 +94,7 @@
fun SceneScope.animateSharedDpAsState(
value: Dp,
key: ValueKey,
- element: ElementKey,
+ element: ElementKey?,
canOverflow: Boolean = true,
): State<Dp> {
return animateSharedValueAsState(value, key, element, ::lerp, canOverflow)
@@ -123,7 +123,7 @@
fun SceneScope.animateSharedColorAsState(
value: Color,
key: ValueKey,
- element: ElementKey,
+ element: ElementKey?,
): State<Color> {
return animateSharedValueAsState(value, key, element, ::lerp, canOverflow = false)
}
@@ -145,7 +145,7 @@
internal fun <T> animateSharedValueAsState(
layoutImpl: SceneTransitionLayoutImpl,
scene: Scene,
- element: Element,
+ element: Element?,
key: ValueKey,
value: T,
lerp: (T, T, Float) -> T,
@@ -153,9 +153,9 @@
): State<T> {
val sharedValue =
Snapshot.withoutReadObservation {
- element.sceneValues.getValue(scene.key).sharedValues.getOrPut(key) {
- Element.SharedValue(key, value)
- } as Element.SharedValue<T>
+ val sharedValues =
+ element?.sceneValues?.getValue(scene.key)?.sharedValues ?: scene.sharedValues
+ sharedValues.getOrPut(key) { Element.SharedValue(key, value) } as Element.SharedValue<T>
}
if (value != sharedValue.value) {
@@ -169,7 +169,7 @@
private fun <T> computeValue(
layoutImpl: SceneTransitionLayoutImpl,
- element: Element,
+ element: Element?,
sharedValue: Element.SharedValue<T>,
lerp: (T, T, Float) -> T,
canOverflow: Boolean,
@@ -184,8 +184,14 @@
}
fun sceneValue(scene: SceneKey): Element.SharedValue<T>? {
- val sceneValues = element.sceneValues[scene] ?: return null
- val value = sceneValues.sharedValues[sharedValue.key] ?: return null
+ val sharedValues =
+ if (element == null) {
+ layoutImpl.scene(scene).sharedValues
+ } else {
+ element.sceneValues[scene]?.sharedValues
+ }
+ ?: return null
+ val value = sharedValues[sharedValue.key] ?: return null
return value as Element.SharedValue<T>
}
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 abc62c4..eb10afc 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
@@ -29,6 +29,7 @@
import androidx.compose.runtime.snapshots.SnapshotStateMap
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
+import androidx.compose.ui.composed
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.isSpecified
@@ -110,13 +111,12 @@
}
/** The implementation of [SceneScope.element]. */
-@Composable
@OptIn(ExperimentalComposeUiApi::class)
internal fun Modifier.element(
layoutImpl: SceneTransitionLayoutImpl,
scene: Scene,
key: ElementKey,
-): Modifier {
+): Modifier = composed {
val sceneValues = remember(scene, key) { Element.TargetValues() }
val element =
// Get the element associated to [key] if it was already composed in another scene,
@@ -160,7 +160,7 @@
}
}
- return drawWithContent {
+ drawWithContent {
if (shouldDrawElement(layoutImpl, scene, element)) {
drawContent()
}
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 97d3fff..d0a5f5b 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
@@ -23,11 +23,11 @@
import androidx.compose.foundation.gestures.awaitVerticalTouchSlopOrCancellation
import androidx.compose.foundation.gestures.horizontalDrag
import androidx.compose.foundation.gestures.verticalDrag
-import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.Modifier
+import androidx.compose.ui.composed
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.input.pointer.PointerEventPass
import androidx.compose.ui.input.pointer.PointerId
@@ -56,7 +56,6 @@
* change in the future.
*/
// TODO(b/291055080): Migrate to the Modifier.Node API.
-@Composable
internal fun Modifier.multiPointerDraggable(
orientation: Orientation,
enabled: Boolean,
@@ -64,7 +63,7 @@
onDragStarted: (startedPosition: Offset, pointersDown: Int) -> Unit,
onDragDelta: (Float) -> Unit,
onDragStopped: (velocity: Float) -> Unit,
-): Modifier {
+): Modifier = composed {
val onDragStarted by rememberUpdatedState(onDragStarted)
val onDragStopped by rememberUpdatedState(onDragStopped)
val onDragDelta by rememberUpdatedState(onDragDelta)
@@ -77,7 +76,7 @@
Velocity(maxF, maxF)
}
- return this.pointerInput(enabled, orientation, maxFlingVelocity) {
+ pointerInput(enabled, orientation, maxFlingVelocity) {
if (!enabled) {
return@pointerInput
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Scene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Scene.kt
index 3fd6828..2e50a71 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Scene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Scene.kt
@@ -23,6 +23,7 @@
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
+import androidx.compose.runtime.snapshots.SnapshotStateMap
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.onPlaced
import androidx.compose.ui.platform.testTag
@@ -44,6 +45,9 @@
var zIndex by mutableFloatStateOf(zIndex)
var size by mutableStateOf(IntSize.Zero)
+ /** The shared values in this scene that are not tied to a specific element. */
+ val sharedValues = SnapshotStateMap<ValueKey, Element.SharedValue<*>>()
+
@Composable
fun Content(modifier: Modifier = Modifier) {
Box(modifier.zIndex(zIndex).onPlaced { size = it.size }.testTag(key.testTag)) {
@@ -60,7 +64,6 @@
private val layoutImpl: SceneTransitionLayoutImpl,
private val scene: Scene,
) : SceneScope {
- @Composable
override fun Modifier.element(key: ElementKey): Modifier {
return element(layoutImpl, scene, key)
}
@@ -69,16 +72,18 @@
override fun <T> animateSharedValueAsState(
value: T,
key: ValueKey,
- element: ElementKey,
+ element: ElementKey?,
lerp: (T, T, Float) -> T,
canOverflow: Boolean
): State<T> {
val element =
- layoutImpl.elements[element]
- ?: error(
- "Element $element is not composed. Make sure to call animateSharedXAsState " +
- "*after* Modifier.element(key)."
- )
+ element?.let { key ->
+ layoutImpl.elements[key]
+ ?: error(
+ "Element $key is not composed. Make sure to call animateSharedXAsState " +
+ "*after* Modifier.element(key)."
+ )
+ }
return animateSharedValueAsState(
layoutImpl,
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt
new file mode 100644
index 0000000..7563e27
--- /dev/null
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt
@@ -0,0 +1,659 @@
+package com.android.compose.animation.scene
+
+import android.util.Log
+import androidx.annotation.VisibleForTesting
+import androidx.compose.animation.core.Animatable
+import androidx.compose.animation.core.Spring
+import androidx.compose.animation.core.spring
+import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableFloatStateOf
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.unit.Velocity
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.round
+import com.android.compose.nestedscroll.PriorityNestedScrollConnection
+import kotlin.math.absoluteValue
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.launch
+
+@VisibleForTesting
+class SceneGestureHandler(
+ private val layoutImpl: SceneTransitionLayoutImpl,
+ internal val orientation: Orientation,
+ private val coroutineScope: CoroutineScope,
+) : GestureHandler {
+ override val draggable: DraggableHandler = SceneDraggableHandler(this)
+
+ override val nestedScroll: SceneNestedScrollHandler = SceneNestedScrollHandler(this)
+
+ private var transitionState
+ get() = layoutImpl.state.transitionState
+ set(value) {
+ layoutImpl.state.transitionState = value
+ }
+
+ /**
+ * The transition controlled by this gesture handler. It will be set as the [transitionState] in
+ * the [SceneTransitionLayoutImpl] whenever this handler is driving the current transition.
+ *
+ * Note: the initialScene here does not matter, it's only used for initializing the transition
+ * and will be replaced when a drag event starts.
+ */
+ private val swipeTransition = SwipeTransition(initialScene = currentScene)
+
+ internal val currentScene: Scene
+ get() = layoutImpl.scene(transitionState.currentScene)
+
+ @VisibleForTesting
+ val isDrivingTransition
+ get() = transitionState == swipeTransition
+
+ @VisibleForTesting
+ var isAnimatingOffset
+ get() = swipeTransition.isAnimatingOffset
+ private set(value) {
+ swipeTransition.isAnimatingOffset = value
+ }
+
+ internal val swipeTransitionToScene
+ get() = swipeTransition._toScene
+
+ /**
+ * The velocity threshold at which the intent of the user is to swipe up or down. It is the same
+ * as SwipeableV2Defaults.VelocityThreshold.
+ */
+ @VisibleForTesting val velocityThreshold = with(layoutImpl.density) { 125.dp.toPx() }
+
+ /**
+ * The positional threshold at which the intent of the user is to swipe to the next scene. It is
+ * the same as SwipeableV2Defaults.PositionalThreshold.
+ */
+ private val positionalThreshold = with(layoutImpl.density) { 56.dp.toPx() }
+
+ internal var gestureWithPriority: Any? = null
+
+ internal fun onDragStarted(pointersDown: Int, startedPosition: Offset?) {
+ if (isDrivingTransition) {
+ // This [transition] was already driving the animation: simply take over it.
+ // Stop animating and start from where the current offset.
+ swipeTransition.stopOffsetAnimation()
+ return
+ }
+
+ val transition = transitionState
+ if (transition is TransitionState.Transition) {
+ // TODO(b/290184746): Better handle interruptions here if state != idle.
+ Log.w(
+ TAG,
+ "start from TransitionState.Transition is not fully supported: from" +
+ " ${transition.fromScene} to ${transition.toScene} " +
+ "(progress ${transition.progress})"
+ )
+ }
+
+ val fromScene = currentScene
+
+ swipeTransition._currentScene = fromScene
+ swipeTransition._fromScene = fromScene
+
+ // We don't know where we are transitioning to yet given that the drag just started, so set
+ // it to fromScene, which will effectively be treated the same as Idle(fromScene).
+ swipeTransition._toScene = fromScene
+
+ swipeTransition.stopOffsetAnimation()
+ swipeTransition.dragOffset = 0f
+
+ // Use the layout size in the swipe orientation for swipe distance.
+ // TODO(b/290184746): Also handle custom distances for transitions. With smaller distances,
+ // we will also have to make sure that we correctly handle overscroll.
+ swipeTransition.absoluteDistance =
+ when (orientation) {
+ Orientation.Horizontal -> layoutImpl.size.width
+ Orientation.Vertical -> layoutImpl.size.height
+ }.toFloat()
+
+ val fromEdge =
+ startedPosition?.let { position ->
+ layoutImpl.edgeDetector.edge(
+ layoutImpl.size,
+ position.round(),
+ layoutImpl.density,
+ orientation,
+ )
+ }
+
+ swipeTransition.actionUpOrLeft =
+ Swipe(
+ direction =
+ when (orientation) {
+ Orientation.Horizontal -> SwipeDirection.Left
+ Orientation.Vertical -> SwipeDirection.Up
+ },
+ pointerCount = pointersDown,
+ fromEdge = fromEdge,
+ )
+
+ swipeTransition.actionDownOrRight =
+ Swipe(
+ direction =
+ when (orientation) {
+ Orientation.Horizontal -> SwipeDirection.Right
+ Orientation.Vertical -> SwipeDirection.Down
+ },
+ pointerCount = pointersDown,
+ fromEdge = fromEdge,
+ )
+
+ if (fromEdge == null) {
+ swipeTransition.actionUpOrLeftNoEdge = null
+ swipeTransition.actionDownOrRightNoEdge = null
+ } else {
+ swipeTransition.actionUpOrLeftNoEdge =
+ (swipeTransition.actionUpOrLeft as Swipe).copy(fromEdge = null)
+ swipeTransition.actionDownOrRightNoEdge =
+ (swipeTransition.actionDownOrRight as Swipe).copy(fromEdge = null)
+ }
+
+ if (swipeTransition.absoluteDistance > 0f) {
+ transitionState = swipeTransition
+ }
+ }
+
+ internal fun onDrag(delta: Float) {
+ if (delta == 0f) return
+
+ swipeTransition.dragOffset += delta
+
+ // First check transition.fromScene should be changed for the case where the user quickly
+ // swiped twice in a row to accelerate the transition and go from A => B then B => C really
+ // fast.
+ maybeHandleAcceleratedSwipe()
+
+ val offset = swipeTransition.dragOffset
+ val fromScene = swipeTransition._fromScene
+
+ // Compute the target scene depending on the current offset.
+ val target = fromScene.findTargetSceneAndDistance(offset)
+
+ if (swipeTransition._toScene.key != target.sceneKey) {
+ swipeTransition._toScene = layoutImpl.scenes.getValue(target.sceneKey)
+ }
+
+ if (swipeTransition._distance != target.distance) {
+ swipeTransition._distance = target.distance
+ }
+ }
+
+ /**
+ * Change fromScene in the case where the user quickly swiped multiple times in the same
+ * direction to accelerate the transition from A => B then B => C.
+ */
+ private fun maybeHandleAcceleratedSwipe() {
+ val toScene = swipeTransition._toScene
+ val fromScene = swipeTransition._fromScene
+
+ // If the swipe was not committed, don't do anything.
+ if (fromScene == toScene || swipeTransition._currentScene != toScene) {
+ return
+ }
+
+ // If the offset is past the distance then let's change fromScene so that the user can swipe
+ // to the next screen or go back to the previous one.
+ val offset = swipeTransition.dragOffset
+ val absoluteDistance = swipeTransition.absoluteDistance
+ if (offset <= -absoluteDistance && swipeTransition.upOrLeft(fromScene) == toScene.key) {
+ swipeTransition.dragOffset += absoluteDistance
+ swipeTransition._fromScene = toScene
+ } else if (
+ offset >= absoluteDistance && swipeTransition.downOrRight(fromScene) == toScene.key
+ ) {
+ swipeTransition.dragOffset -= absoluteDistance
+ swipeTransition._fromScene = toScene
+ }
+
+ // Important note: toScene and distance will be updated right after this function is called,
+ // using fromScene and dragOffset.
+ }
+
+ private class TargetScene(
+ val sceneKey: SceneKey,
+ val distance: Float,
+ )
+
+ private fun Scene.findTargetSceneAndDistance(directionOffset: Float): TargetScene {
+ val upOrLeft = swipeTransition.upOrLeft(this)
+ val downOrRight = swipeTransition.downOrRight(this)
+
+ // Compute the target scene depending on the current offset.
+ return when {
+ directionOffset < 0f && upOrLeft != null -> {
+ TargetScene(
+ sceneKey = upOrLeft,
+ distance = -swipeTransition.absoluteDistance,
+ )
+ }
+ directionOffset > 0f && downOrRight != null -> {
+ TargetScene(
+ sceneKey = downOrRight,
+ distance = swipeTransition.absoluteDistance,
+ )
+ }
+ else -> {
+ TargetScene(
+ sceneKey = key,
+ distance = 0f,
+ )
+ }
+ }
+ }
+
+ internal fun onDragStopped(velocity: Float, canChangeScene: Boolean) {
+ // The state was changed since the drag started; don't do anything.
+ if (!isDrivingTransition) {
+ return
+ }
+
+ fun animateTo(targetScene: Scene, targetOffset: Float) {
+ // If the effective current scene changed, it should be reflected right now in the
+ // current scene state, even before the settle animation is ongoing. That way all the
+ // swipeables and back handlers will be refreshed and the user can for instance quickly
+ // swipe vertically from A => B then horizontally from B => C, or swipe from A => B then
+ // immediately go back B => A.
+ if (targetScene != swipeTransition._currentScene) {
+ swipeTransition._currentScene = targetScene
+ layoutImpl.onChangeScene(targetScene.key)
+ }
+
+ animateOffset(
+ initialVelocity = velocity,
+ targetOffset = targetOffset,
+ targetScene = targetScene.key
+ )
+ }
+
+ val fromScene = swipeTransition._fromScene
+ if (canChangeScene) {
+ // If we are halfway between two scenes, we check what the target will be based on the
+ // velocity and offset of the transition, then we launch the animation.
+
+ val toScene = swipeTransition._toScene
+ if (fromScene == toScene) {
+ // We were not animating.
+ transitionState = TransitionState.Idle(fromScene.key)
+ return
+ }
+
+ // Compute the destination scene (and therefore offset) to settle in.
+ val offset = swipeTransition.dragOffset
+ val distance = swipeTransition.distance
+ if (
+ shouldCommitSwipe(
+ offset,
+ distance,
+ velocity,
+ wasCommitted = swipeTransition._currentScene == toScene,
+ )
+ ) {
+ // Animate to the next scene
+ animateTo(targetScene = toScene, targetOffset = distance)
+ } else {
+ // Animate to the initial scene
+ animateTo(targetScene = fromScene, targetOffset = 0f)
+ }
+ } else {
+ // We are doing an overscroll animation between scenes. In this case, we can also start
+ // from the idle position.
+
+ val startFromIdlePosition = swipeTransition.dragOffset == 0f
+
+ if (startFromIdlePosition) {
+ // If there is a next scene, we start the overscroll animation.
+ val target = fromScene.findTargetSceneAndDistance(velocity)
+ val isValidTarget = target.distance != 0f && target.sceneKey != fromScene.key
+ if (isValidTarget) {
+ swipeTransition._toScene = layoutImpl.scene(target.sceneKey)
+ swipeTransition._distance = target.distance
+
+ animateTo(targetScene = fromScene, targetOffset = 0f)
+ } else {
+ // We will not animate
+ transitionState = TransitionState.Idle(fromScene.key)
+ }
+ } else {
+ // We were between two scenes: animate to the initial scene.
+ animateTo(targetScene = fromScene, targetOffset = 0f)
+ }
+ }
+ }
+
+ /**
+ * Whether the swipe to the target scene should be committed or not. This is inspired by
+ * SwipeableV2.computeTarget().
+ */
+ private fun shouldCommitSwipe(
+ offset: Float,
+ distance: Float,
+ velocity: Float,
+ wasCommitted: Boolean,
+ ): Boolean {
+ fun isCloserToTarget(): Boolean {
+ return (offset - distance).absoluteValue < offset.absoluteValue
+ }
+
+ // Swiping up or left.
+ if (distance < 0f) {
+ return if (offset > 0f || velocity >= velocityThreshold) {
+ false
+ } else {
+ velocity <= -velocityThreshold ||
+ (offset <= -positionalThreshold && !wasCommitted) ||
+ isCloserToTarget()
+ }
+ }
+
+ // Swiping down or right.
+ return if (offset < 0f || velocity <= -velocityThreshold) {
+ false
+ } else {
+ velocity >= velocityThreshold ||
+ (offset >= positionalThreshold && !wasCommitted) ||
+ isCloserToTarget()
+ }
+ }
+
+ private fun animateOffset(
+ initialVelocity: Float,
+ targetOffset: Float,
+ targetScene: SceneKey,
+ ) {
+ swipeTransition.startOffsetAnimation {
+ coroutineScope.launch {
+ if (!isAnimatingOffset) {
+ swipeTransition.offsetAnimatable.snapTo(swipeTransition.dragOffset)
+ }
+ isAnimatingOffset = true
+
+ swipeTransition.offsetAnimatable.animateTo(
+ targetOffset,
+ // TODO(b/290184746): Make this spring spec configurable.
+ spring(
+ stiffness = Spring.StiffnessMediumLow,
+ visibilityThreshold = OffsetVisibilityThreshold
+ ),
+ initialVelocity = initialVelocity,
+ )
+
+ isAnimatingOffset = false
+
+ // Now that the animation is done, the state should be idle. Note that if the state
+ // was changed since this animation started, some external code changed it and we
+ // shouldn't do anything here. Note also that this job will be cancelled in the case
+ // where the user intercepts this swipe.
+ if (isDrivingTransition) {
+ transitionState = TransitionState.Idle(targetScene)
+ }
+ }
+ }
+ }
+
+ private class SwipeTransition(initialScene: Scene) : TransitionState.Transition {
+ var _currentScene by mutableStateOf(initialScene)
+ override val currentScene: SceneKey
+ get() = _currentScene.key
+
+ var _fromScene by mutableStateOf(initialScene)
+ override val fromScene: SceneKey
+ get() = _fromScene.key
+
+ var _toScene by mutableStateOf(initialScene)
+ override val toScene: SceneKey
+ get() = _toScene.key
+
+ override val progress: Float
+ get() {
+ val offset = if (isAnimatingOffset) offsetAnimatable.value else dragOffset
+ if (distance == 0f) {
+ // This can happen only if fromScene == toScene.
+ error(
+ "Transition.progress should be called only when Transition.fromScene != " +
+ "Transition.toScene"
+ )
+ }
+ return offset / distance
+ }
+
+ override val isInitiatedByUserInput = true
+
+ /** The current offset caused by the drag gesture. */
+ var dragOffset by mutableFloatStateOf(0f)
+
+ /**
+ * Whether the offset is animated (the user lifted their finger) or if it is driven by
+ * gesture.
+ */
+ var isAnimatingOffset by mutableStateOf(false)
+
+ // If we are not animating offset, it means the offset is being driven by the user's finger.
+ override val isUserInputOngoing: Boolean
+ get() = !isAnimatingOffset
+
+ /** The animatable used to animate the offset once the user lifted its finger. */
+ val offsetAnimatable = Animatable(0f, OffsetVisibilityThreshold)
+
+ /** Job to check that there is at most one offset animation in progress. */
+ private var offsetAnimationJob: Job? = null
+
+ /** Ends any previous [offsetAnimationJob] and runs the new [job]. */
+ fun startOffsetAnimation(job: () -> Job) {
+ stopOffsetAnimation()
+ offsetAnimationJob = job()
+ }
+
+ /** Stops any ongoing offset animation. */
+ fun stopOffsetAnimation() {
+ offsetAnimationJob?.cancel()
+
+ if (isAnimatingOffset) {
+ isAnimatingOffset = false
+ dragOffset = offsetAnimatable.value
+ }
+ }
+
+ /** The absolute distance between [fromScene] and [toScene]. */
+ var absoluteDistance = 0f
+
+ /**
+ * The signed distance between [fromScene] and [toScene]. It is negative if [fromScene] is
+ * above or to the left of [toScene].
+ */
+ var _distance by mutableFloatStateOf(0f)
+ val distance: Float
+ get() = _distance
+
+ /** The [UserAction]s associated to this swipe. */
+ var actionUpOrLeft: UserAction = Back
+ var actionDownOrRight: UserAction = Back
+ var actionUpOrLeftNoEdge: UserAction? = null
+ var actionDownOrRightNoEdge: UserAction? = null
+
+ fun upOrLeft(scene: Scene): SceneKey? {
+ return scene.userActions[actionUpOrLeft]
+ ?: actionUpOrLeftNoEdge?.let { scene.userActions[it] }
+ }
+
+ fun downOrRight(scene: Scene): SceneKey? {
+ return scene.userActions[actionDownOrRight]
+ ?: actionDownOrRightNoEdge?.let { scene.userActions[it] }
+ }
+ }
+
+ companion object {
+ private const val TAG = "SceneGestureHandler"
+ }
+}
+
+private class SceneDraggableHandler(
+ private val gestureHandler: SceneGestureHandler,
+) : DraggableHandler {
+ override fun onDragStarted(startedPosition: Offset, pointersDown: Int) {
+ gestureHandler.gestureWithPriority = this
+ gestureHandler.onDragStarted(pointersDown, startedPosition)
+ }
+
+ override fun onDelta(pixels: Float) {
+ if (gestureHandler.gestureWithPriority == this) {
+ gestureHandler.onDrag(delta = pixels)
+ }
+ }
+
+ override fun onDragStopped(velocity: Float) {
+ if (gestureHandler.gestureWithPriority == this) {
+ gestureHandler.gestureWithPriority = null
+ gestureHandler.onDragStopped(velocity = velocity, canChangeScene = true)
+ }
+ }
+}
+
+@VisibleForTesting
+class SceneNestedScrollHandler(
+ private val gestureHandler: SceneGestureHandler,
+) : NestedScrollHandler {
+ override val connection: PriorityNestedScrollConnection = nestedScrollConnection()
+
+ private fun Offset.toAmount() =
+ when (gestureHandler.orientation) {
+ Orientation.Horizontal -> x
+ Orientation.Vertical -> y
+ }
+
+ private fun Velocity.toAmount() =
+ when (gestureHandler.orientation) {
+ Orientation.Horizontal -> x
+ Orientation.Vertical -> y
+ }
+
+ private fun Float.toOffset() =
+ when (gestureHandler.orientation) {
+ Orientation.Horizontal -> Offset(x = this, y = 0f)
+ Orientation.Vertical -> Offset(x = 0f, y = this)
+ }
+
+ private fun nestedScrollConnection(): PriorityNestedScrollConnection {
+ // The next potential scene is calculated during the canStart
+ var nextScene: SceneKey? = null
+
+ // This is the scene on which we will have priority during the scroll gesture.
+ var priorityScene: SceneKey? = null
+
+ // If we performed a long gesture before entering priority mode, we would have to avoid
+ // moving on to the next scene.
+ var gestureStartedOnNestedChild = false
+
+ val actionUpOrLeft =
+ Swipe(
+ direction =
+ when (gestureHandler.orientation) {
+ Orientation.Horizontal -> SwipeDirection.Left
+ Orientation.Vertical -> SwipeDirection.Up
+ },
+ pointerCount = 1,
+ )
+
+ val actionDownOrRight =
+ Swipe(
+ direction =
+ when (gestureHandler.orientation) {
+ Orientation.Horizontal -> SwipeDirection.Right
+ Orientation.Vertical -> SwipeDirection.Down
+ },
+ pointerCount = 1,
+ )
+
+ fun findNextScene(amount: Float): SceneKey? {
+ val fromScene = gestureHandler.currentScene
+ return when {
+ amount < 0f -> fromScene.userActions[actionUpOrLeft]
+ amount > 0f -> fromScene.userActions[actionDownOrRight]
+ else -> null
+ }
+ }
+
+ return PriorityNestedScrollConnection(
+ canStartPreScroll = { offsetAvailable, offsetBeforeStart ->
+ gestureStartedOnNestedChild = offsetBeforeStart != Offset.Zero
+
+ val canInterceptPreScroll =
+ gestureHandler.isDrivingTransition &&
+ !gestureStartedOnNestedChild &&
+ offsetAvailable.toAmount() != 0f
+
+ if (!canInterceptPreScroll) return@PriorityNestedScrollConnection false
+
+ nextScene = gestureHandler.swipeTransitionToScene.key
+
+ true
+ },
+ canStartPostScroll = { offsetAvailable, offsetBeforeStart ->
+ val amount = offsetAvailable.toAmount()
+ if (amount == 0f) return@PriorityNestedScrollConnection false
+
+ gestureStartedOnNestedChild = offsetBeforeStart != Offset.Zero
+ nextScene = findNextScene(amount)
+ nextScene != null
+ },
+ canStartPostFling = { velocityAvailable ->
+ val amount = velocityAvailable.toAmount()
+ if (amount == 0f) return@PriorityNestedScrollConnection false
+
+ // We could start an overscroll animation
+ gestureStartedOnNestedChild = true
+ nextScene = findNextScene(amount)
+ nextScene != null
+ },
+ canContinueScroll = { priorityScene == gestureHandler.swipeTransitionToScene.key },
+ onStart = {
+ gestureHandler.gestureWithPriority = this
+ priorityScene = nextScene
+ gestureHandler.onDragStarted(pointersDown = 1, startedPosition = null)
+ },
+ onScroll = { offsetAvailable ->
+ if (gestureHandler.gestureWithPriority != this) {
+ return@PriorityNestedScrollConnection Offset.Zero
+ }
+
+ val amount = offsetAvailable.toAmount()
+
+ // TODO(b/297842071) We should handle the overscroll or slow drag if the gesture is
+ // initiated in a nested child.
+ gestureHandler.onDrag(amount)
+
+ amount.toOffset()
+ },
+ onStop = { velocityAvailable ->
+ if (gestureHandler.gestureWithPriority != this) {
+ return@PriorityNestedScrollConnection Velocity.Zero
+ }
+
+ priorityScene = null
+
+ gestureHandler.onDragStopped(
+ velocity = velocityAvailable.toAmount(),
+ canChangeScene = !gestureStartedOnNestedChild
+ )
+
+ // The onDragStopped animation consumes any remaining velocity.
+ velocityAvailable
+ },
+ )
+ }
+}
+
+/**
+ * The number of pixels below which there won't be a visible difference in the transition and from
+ * which the animation can stop.
+ */
+private const val OffsetVisibilityThreshold = 0.5f
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
index 1f38e70..35d1f90 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
@@ -117,7 +117,7 @@
* TODO(b/291566282): Migrate this to the new Modifier Node API and remove the @Composable
* constraint.
*/
- @Composable fun Modifier.element(key: ElementKey): Modifier
+ fun Modifier.element(key: ElementKey): Modifier
/**
* Create a *movable* element identified by [key].
@@ -142,7 +142,9 @@
*
* @param value the value of this shared value in the current scene.
* @param key the key of this shared value.
- * @param element the element associated with this value.
+ * @param element the element associated with this value. If `null`, this value will be
+ * associated at the scene level, which means that [key] should be used maximum once in the
+ * same scene.
* @param lerp the *linear* interpolation function that should be used to interpolate between
* two different values. Note that it has to be linear because the [fraction] passed to this
* interpolator is already interpolated.
@@ -157,7 +159,7 @@
fun <T> animateSharedValueAsState(
value: T,
key: ValueKey,
- element: ElementKey,
+ element: ElementKey?,
lerp: (start: T, stop: T, fraction: Float) -> T,
canOverflow: Boolean,
): State<T>
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 fd62659..6618eb0 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
@@ -30,7 +30,6 @@
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshots.SnapshotStateMap
-import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.layout.LookaheadScope
@@ -131,15 +130,19 @@
}
@Composable
- @OptIn(ExperimentalComposeUiApi::class)
internal fun Content(modifier: Modifier) {
+ val horizontalGestureHandler =
+ rememberSceneGestureHandler(layoutImpl = this, Orientation.Horizontal)
+ val verticalGestureHandler =
+ rememberSceneGestureHandler(layoutImpl = this, Orientation.Vertical)
+
Box(
modifier
// Handle horizontal and vertical swipes on this layout.
// Note: order here is important and will give a slight priority to the vertical
// swipes.
- .swipeToScene(layoutImpl = this, Orientation.Horizontal)
- .swipeToScene(layoutImpl = this, Orientation.Vertical)
+ .swipeToScene(horizontalGestureHandler)
+ .swipeToScene(verticalGestureHandler)
.onSizeChanged { size = it }
) {
LookaheadScope {
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
index 877ac09..8980df8 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
@@ -16,47 +16,24 @@
package com.android.compose.animation.scene
-import android.util.Log
-import androidx.annotation.VisibleForTesting
-import androidx.compose.animation.core.Animatable
-import androidx.compose.animation.core.Spring
-import androidx.compose.animation.core.spring
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableFloatStateOf
-import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
-import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
-import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.input.nestedscroll.nestedScroll
-import androidx.compose.ui.unit.Velocity
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.round
-import com.android.compose.nestedscroll.PriorityNestedScrollConnection
-import kotlin.math.absoluteValue
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Job
-import kotlinx.coroutines.launch
/**
* Configures the swipeable behavior of a [SceneTransitionLayout] depending on the current state.
*/
-@Composable
-internal fun Modifier.swipeToScene(
- layoutImpl: SceneTransitionLayoutImpl,
- orientation: Orientation,
-): Modifier {
- val gestureHandler = rememberSceneGestureHandler(layoutImpl, orientation)
-
+internal fun Modifier.swipeToScene(gestureHandler: SceneGestureHandler): Modifier {
/** Whether swipe should be enabled in the given [orientation]. */
fun Scene.shouldEnableSwipes(orientation: Orientation): Boolean =
userActions.keys.any { it is Swipe && it.direction.orientation == orientation }
val currentScene = gestureHandler.currentScene
+ val orientation = gestureHandler.orientation
val canSwipe = currentScene.shouldEnableSwipes(orientation)
val canOppositeSwipe =
currentScene.shouldEnableSwipes(
@@ -84,7 +61,7 @@
}
@Composable
-private fun rememberSceneGestureHandler(
+internal fun rememberSceneGestureHandler(
layoutImpl: SceneTransitionLayoutImpl,
orientation: Orientation,
): SceneGestureHandler {
@@ -101,641 +78,3 @@
return gestureHandler
}
-
-@VisibleForTesting
-class SceneGestureHandler(
- private val layoutImpl: SceneTransitionLayoutImpl,
- internal val orientation: Orientation,
- private val coroutineScope: CoroutineScope,
-) : GestureHandler {
- override val draggable: DraggableHandler = SceneDraggableHandler(this)
-
- override val nestedScroll: SceneNestedScrollHandler = SceneNestedScrollHandler(this)
-
- private var transitionState
- get() = layoutImpl.state.transitionState
- set(value) {
- layoutImpl.state.transitionState = value
- }
-
- /**
- * The transition controlled by this gesture handler. It will be set as the [transitionState] in
- * the [SceneTransitionLayoutImpl] whenever this handler is driving the current transition.
- *
- * Note: the initialScene here does not matter, it's only used for initializing the transition
- * and will be replaced when a drag event starts.
- */
- private val swipeTransition = SwipeTransition(initialScene = currentScene)
-
- internal val currentScene: Scene
- get() = layoutImpl.scene(transitionState.currentScene)
-
- @VisibleForTesting
- val isDrivingTransition
- get() = transitionState == swipeTransition
-
- @VisibleForTesting
- var isAnimatingOffset
- get() = swipeTransition.isAnimatingOffset
- private set(value) {
- swipeTransition.isAnimatingOffset = value
- }
-
- internal val swipeTransitionToScene
- get() = swipeTransition._toScene
-
- /**
- * The velocity threshold at which the intent of the user is to swipe up or down. It is the same
- * as SwipeableV2Defaults.VelocityThreshold.
- */
- @VisibleForTesting val velocityThreshold = with(layoutImpl.density) { 125.dp.toPx() }
-
- /**
- * The positional threshold at which the intent of the user is to swipe to the next scene. It is
- * the same as SwipeableV2Defaults.PositionalThreshold.
- */
- private val positionalThreshold = with(layoutImpl.density) { 56.dp.toPx() }
-
- internal var gestureWithPriority: Any? = null
-
- internal fun onDragStarted(pointersDown: Int, startedPosition: Offset?) {
- if (isDrivingTransition) {
- // This [transition] was already driving the animation: simply take over it.
- // Stop animating and start from where the current offset.
- swipeTransition.stopOffsetAnimation()
- return
- }
-
- val transition = transitionState
- if (transition is TransitionState.Transition) {
- // TODO(b/290184746): Better handle interruptions here if state != idle.
- Log.w(
- TAG,
- "start from TransitionState.Transition is not fully supported: from" +
- " ${transition.fromScene} to ${transition.toScene} " +
- "(progress ${transition.progress})"
- )
- }
-
- val fromScene = currentScene
-
- swipeTransition._currentScene = fromScene
- swipeTransition._fromScene = fromScene
-
- // We don't know where we are transitioning to yet given that the drag just started, so set
- // it to fromScene, which will effectively be treated the same as Idle(fromScene).
- swipeTransition._toScene = fromScene
-
- swipeTransition.stopOffsetAnimation()
- swipeTransition.dragOffset = 0f
-
- // Use the layout size in the swipe orientation for swipe distance.
- // TODO(b/290184746): Also handle custom distances for transitions. With smaller distances,
- // we will also have to make sure that we correctly handle overscroll.
- swipeTransition.absoluteDistance =
- when (orientation) {
- Orientation.Horizontal -> layoutImpl.size.width
- Orientation.Vertical -> layoutImpl.size.height
- }.toFloat()
-
- val fromEdge =
- startedPosition?.let { position ->
- layoutImpl.edgeDetector.edge(
- layoutImpl.size,
- position.round(),
- layoutImpl.density,
- orientation,
- )
- }
-
- swipeTransition.actionUpOrLeft =
- Swipe(
- direction =
- when (orientation) {
- Orientation.Horizontal -> SwipeDirection.Left
- Orientation.Vertical -> SwipeDirection.Up
- },
- pointerCount = pointersDown,
- fromEdge = fromEdge,
- )
-
- swipeTransition.actionDownOrRight =
- Swipe(
- direction =
- when (orientation) {
- Orientation.Horizontal -> SwipeDirection.Right
- Orientation.Vertical -> SwipeDirection.Down
- },
- pointerCount = pointersDown,
- fromEdge = fromEdge,
- )
-
- if (fromEdge == null) {
- swipeTransition.actionUpOrLeftNoEdge = null
- swipeTransition.actionDownOrRightNoEdge = null
- } else {
- swipeTransition.actionUpOrLeftNoEdge =
- (swipeTransition.actionUpOrLeft as Swipe).copy(fromEdge = null)
- swipeTransition.actionDownOrRightNoEdge =
- (swipeTransition.actionDownOrRight as Swipe).copy(fromEdge = null)
- }
-
- if (swipeTransition.absoluteDistance > 0f) {
- transitionState = swipeTransition
- }
- }
-
- internal fun onDrag(delta: Float) {
- if (delta == 0f) return
-
- swipeTransition.dragOffset += delta
-
- // First check transition.fromScene should be changed for the case where the user quickly
- // swiped twice in a row to accelerate the transition and go from A => B then B => C really
- // fast.
- maybeHandleAcceleratedSwipe()
-
- val offset = swipeTransition.dragOffset
- val fromScene = swipeTransition._fromScene
-
- // Compute the target scene depending on the current offset.
- val target = fromScene.findTargetSceneAndDistance(offset)
-
- if (swipeTransition._toScene.key != target.sceneKey) {
- swipeTransition._toScene = layoutImpl.scenes.getValue(target.sceneKey)
- }
-
- if (swipeTransition._distance != target.distance) {
- swipeTransition._distance = target.distance
- }
- }
-
- /**
- * Change fromScene in the case where the user quickly swiped multiple times in the same
- * direction to accelerate the transition from A => B then B => C.
- */
- private fun maybeHandleAcceleratedSwipe() {
- val toScene = swipeTransition._toScene
- val fromScene = swipeTransition._fromScene
-
- // If the swipe was not committed, don't do anything.
- if (fromScene == toScene || swipeTransition._currentScene != toScene) {
- return
- }
-
- // If the offset is past the distance then let's change fromScene so that the user can swipe
- // to the next screen or go back to the previous one.
- val offset = swipeTransition.dragOffset
- val absoluteDistance = swipeTransition.absoluteDistance
- if (offset <= -absoluteDistance && swipeTransition.upOrLeft(fromScene) == toScene.key) {
- swipeTransition.dragOffset += absoluteDistance
- swipeTransition._fromScene = toScene
- } else if (
- offset >= absoluteDistance && swipeTransition.downOrRight(fromScene) == toScene.key
- ) {
- swipeTransition.dragOffset -= absoluteDistance
- swipeTransition._fromScene = toScene
- }
-
- // Important note: toScene and distance will be updated right after this function is called,
- // using fromScene and dragOffset.
- }
-
- private class TargetScene(
- val sceneKey: SceneKey,
- val distance: Float,
- )
-
- private fun Scene.findTargetSceneAndDistance(directionOffset: Float): TargetScene {
- val upOrLeft = swipeTransition.upOrLeft(this)
- val downOrRight = swipeTransition.downOrRight(this)
-
- // Compute the target scene depending on the current offset.
- return when {
- directionOffset < 0f && upOrLeft != null -> {
- TargetScene(
- sceneKey = upOrLeft,
- distance = -swipeTransition.absoluteDistance,
- )
- }
- directionOffset > 0f && downOrRight != null -> {
- TargetScene(
- sceneKey = downOrRight,
- distance = swipeTransition.absoluteDistance,
- )
- }
- else -> {
- TargetScene(
- sceneKey = key,
- distance = 0f,
- )
- }
- }
- }
-
- internal fun onDragStopped(velocity: Float, canChangeScene: Boolean) {
- // The state was changed since the drag started; don't do anything.
- if (!isDrivingTransition) {
- return
- }
-
- fun animateTo(targetScene: Scene, targetOffset: Float) {
- // If the effective current scene changed, it should be reflected right now in the
- // current scene state, even before the settle animation is ongoing. That way all the
- // swipeables and back handlers will be refreshed and the user can for instance quickly
- // swipe vertically from A => B then horizontally from B => C, or swipe from A => B then
- // immediately go back B => A.
- if (targetScene != swipeTransition._currentScene) {
- swipeTransition._currentScene = targetScene
- layoutImpl.onChangeScene(targetScene.key)
- }
-
- animateOffset(
- initialVelocity = velocity,
- targetOffset = targetOffset,
- targetScene = targetScene.key
- )
- }
-
- val fromScene = swipeTransition._fromScene
- if (canChangeScene) {
- // If we are halfway between two scenes, we check what the target will be based on the
- // velocity and offset of the transition, then we launch the animation.
-
- val toScene = swipeTransition._toScene
- if (fromScene == toScene) {
- // We were not animating.
- transitionState = TransitionState.Idle(fromScene.key)
- return
- }
-
- // Compute the destination scene (and therefore offset) to settle in.
- val offset = swipeTransition.dragOffset
- val distance = swipeTransition.distance
- if (
- shouldCommitSwipe(
- offset,
- distance,
- velocity,
- wasCommitted = swipeTransition._currentScene == toScene,
- )
- ) {
- // Animate to the next scene
- animateTo(targetScene = toScene, targetOffset = distance)
- } else {
- // Animate to the initial scene
- animateTo(targetScene = fromScene, targetOffset = 0f)
- }
- } else {
- // We are doing an overscroll animation between scenes. In this case, we can also start
- // from the idle position.
-
- val startFromIdlePosition = swipeTransition.dragOffset == 0f
-
- if (startFromIdlePosition) {
- // If there is a next scene, we start the overscroll animation.
- val target = fromScene.findTargetSceneAndDistance(velocity)
- val isValidTarget = target.distance != 0f && target.sceneKey != fromScene.key
- if (isValidTarget) {
- swipeTransition._toScene = layoutImpl.scene(target.sceneKey)
- swipeTransition._distance = target.distance
-
- animateTo(targetScene = fromScene, targetOffset = 0f)
- } else {
- // We will not animate
- transitionState = TransitionState.Idle(fromScene.key)
- }
- } else {
- // We were between two scenes: animate to the initial scene.
- animateTo(targetScene = fromScene, targetOffset = 0f)
- }
- }
- }
-
- /**
- * Whether the swipe to the target scene should be committed or not. This is inspired by
- * SwipeableV2.computeTarget().
- */
- private fun shouldCommitSwipe(
- offset: Float,
- distance: Float,
- velocity: Float,
- wasCommitted: Boolean,
- ): Boolean {
- fun isCloserToTarget(): Boolean {
- return (offset - distance).absoluteValue < offset.absoluteValue
- }
-
- // Swiping up or left.
- if (distance < 0f) {
- return if (offset > 0f || velocity >= velocityThreshold) {
- false
- } else {
- velocity <= -velocityThreshold ||
- (offset <= -positionalThreshold && !wasCommitted) ||
- isCloserToTarget()
- }
- }
-
- // Swiping down or right.
- return if (offset < 0f || velocity <= -velocityThreshold) {
- false
- } else {
- velocity >= velocityThreshold ||
- (offset >= positionalThreshold && !wasCommitted) ||
- isCloserToTarget()
- }
- }
-
- private fun animateOffset(
- initialVelocity: Float,
- targetOffset: Float,
- targetScene: SceneKey,
- ) {
- swipeTransition.startOffsetAnimation {
- coroutineScope.launch {
- if (!isAnimatingOffset) {
- swipeTransition.offsetAnimatable.snapTo(swipeTransition.dragOffset)
- }
- isAnimatingOffset = true
-
- swipeTransition.offsetAnimatable.animateTo(
- targetOffset,
- // TODO(b/290184746): Make this spring spec configurable.
- spring(
- stiffness = Spring.StiffnessMediumLow,
- visibilityThreshold = OffsetVisibilityThreshold
- ),
- initialVelocity = initialVelocity,
- )
-
- isAnimatingOffset = false
-
- // Now that the animation is done, the state should be idle. Note that if the state
- // was changed since this animation started, some external code changed it and we
- // shouldn't do anything here. Note also that this job will be cancelled in the case
- // where the user intercepts this swipe.
- if (isDrivingTransition) {
- transitionState = TransitionState.Idle(targetScene)
- }
- }
- }
- }
-
- private class SwipeTransition(initialScene: Scene) : TransitionState.Transition {
- var _currentScene by mutableStateOf(initialScene)
- override val currentScene: SceneKey
- get() = _currentScene.key
-
- var _fromScene by mutableStateOf(initialScene)
- override val fromScene: SceneKey
- get() = _fromScene.key
-
- var _toScene by mutableStateOf(initialScene)
- override val toScene: SceneKey
- get() = _toScene.key
-
- override val progress: Float
- get() {
- val offset = if (isAnimatingOffset) offsetAnimatable.value else dragOffset
- if (distance == 0f) {
- // This can happen only if fromScene == toScene.
- error(
- "Transition.progress should be called only when Transition.fromScene != " +
- "Transition.toScene"
- )
- }
- return offset / distance
- }
-
- override val isInitiatedByUserInput = true
-
- /** The current offset caused by the drag gesture. */
- var dragOffset by mutableFloatStateOf(0f)
-
- /**
- * Whether the offset is animated (the user lifted their finger) or if it is driven by
- * gesture.
- */
- var isAnimatingOffset by mutableStateOf(false)
-
- // If we are not animating offset, it means the offset is being driven by the user's finger.
- override val isUserInputOngoing: Boolean
- get() = !isAnimatingOffset
-
- /** The animatable used to animate the offset once the user lifted its finger. */
- val offsetAnimatable = Animatable(0f, OffsetVisibilityThreshold)
-
- /** Job to check that there is at most one offset animation in progress. */
- private var offsetAnimationJob: Job? = null
-
- /** Ends any previous [offsetAnimationJob] and runs the new [job]. */
- fun startOffsetAnimation(job: () -> Job) {
- stopOffsetAnimation()
- offsetAnimationJob = job()
- }
-
- /** Stops any ongoing offset animation. */
- fun stopOffsetAnimation() {
- offsetAnimationJob?.cancel()
-
- if (isAnimatingOffset) {
- isAnimatingOffset = false
- dragOffset = offsetAnimatable.value
- }
- }
-
- /** The absolute distance between [fromScene] and [toScene]. */
- var absoluteDistance = 0f
-
- /**
- * The signed distance between [fromScene] and [toScene]. It is negative if [fromScene] is
- * above or to the left of [toScene].
- */
- var _distance by mutableFloatStateOf(0f)
- val distance: Float
- get() = _distance
-
- /** The [UserAction]s associated to this swipe. */
- var actionUpOrLeft: UserAction = Back
- var actionDownOrRight: UserAction = Back
- var actionUpOrLeftNoEdge: UserAction? = null
- var actionDownOrRightNoEdge: UserAction? = null
-
- fun upOrLeft(scene: Scene): SceneKey? {
- return scene.userActions[actionUpOrLeft]
- ?: actionUpOrLeftNoEdge?.let { scene.userActions[it] }
- }
-
- fun downOrRight(scene: Scene): SceneKey? {
- return scene.userActions[actionDownOrRight]
- ?: actionDownOrRightNoEdge?.let { scene.userActions[it] }
- }
- }
-
- companion object {
- private const val TAG = "SceneGestureHandler"
- }
-}
-
-private class SceneDraggableHandler(
- private val gestureHandler: SceneGestureHandler,
-) : DraggableHandler {
- override fun onDragStarted(startedPosition: Offset, pointersDown: Int) {
- gestureHandler.gestureWithPriority = this
- gestureHandler.onDragStarted(pointersDown, startedPosition)
- }
-
- override fun onDelta(pixels: Float) {
- if (gestureHandler.gestureWithPriority == this) {
- gestureHandler.onDrag(delta = pixels)
- }
- }
-
- override fun onDragStopped(velocity: Float) {
- if (gestureHandler.gestureWithPriority == this) {
- gestureHandler.gestureWithPriority = null
- gestureHandler.onDragStopped(velocity = velocity, canChangeScene = true)
- }
- }
-}
-
-@VisibleForTesting
-class SceneNestedScrollHandler(
- private val gestureHandler: SceneGestureHandler,
-) : NestedScrollHandler {
- override val connection: PriorityNestedScrollConnection = nestedScrollConnection()
-
- private fun Offset.toAmount() =
- when (gestureHandler.orientation) {
- Orientation.Horizontal -> x
- Orientation.Vertical -> y
- }
-
- private fun Velocity.toAmount() =
- when (gestureHandler.orientation) {
- Orientation.Horizontal -> x
- Orientation.Vertical -> y
- }
-
- private fun Float.toOffset() =
- when (gestureHandler.orientation) {
- Orientation.Horizontal -> Offset(x = this, y = 0f)
- Orientation.Vertical -> Offset(x = 0f, y = this)
- }
-
- private fun nestedScrollConnection(): PriorityNestedScrollConnection {
- // The next potential scene is calculated during the canStart
- var nextScene: SceneKey? = null
-
- // This is the scene on which we will have priority during the scroll gesture.
- var priorityScene: SceneKey? = null
-
- // If we performed a long gesture before entering priority mode, we would have to avoid
- // moving on to the next scene.
- var gestureStartedOnNestedChild = false
-
- val actionUpOrLeft =
- Swipe(
- direction =
- when (gestureHandler.orientation) {
- Orientation.Horizontal -> SwipeDirection.Left
- Orientation.Vertical -> SwipeDirection.Up
- },
- pointerCount = 1,
- )
-
- val actionDownOrRight =
- Swipe(
- direction =
- when (gestureHandler.orientation) {
- Orientation.Horizontal -> SwipeDirection.Right
- Orientation.Vertical -> SwipeDirection.Down
- },
- pointerCount = 1,
- )
-
- fun findNextScene(amount: Float): SceneKey? {
- val fromScene = gestureHandler.currentScene
- return when {
- amount < 0f -> fromScene.userActions[actionUpOrLeft]
- amount > 0f -> fromScene.userActions[actionDownOrRight]
- else -> null
- }
- }
-
- return PriorityNestedScrollConnection(
- canStartPreScroll = { offsetAvailable, offsetBeforeStart ->
- gestureStartedOnNestedChild = offsetBeforeStart != Offset.Zero
-
- val canInterceptPreScroll =
- gestureHandler.isDrivingTransition &&
- !gestureStartedOnNestedChild &&
- offsetAvailable.toAmount() != 0f
-
- if (!canInterceptPreScroll) return@PriorityNestedScrollConnection false
-
- nextScene = gestureHandler.swipeTransitionToScene.key
-
- true
- },
- canStartPostScroll = { offsetAvailable, offsetBeforeStart ->
- val amount = offsetAvailable.toAmount()
- if (amount == 0f) return@PriorityNestedScrollConnection false
-
- gestureStartedOnNestedChild = offsetBeforeStart != Offset.Zero
- nextScene = findNextScene(amount)
- nextScene != null
- },
- canStartPostFling = { velocityAvailable ->
- val amount = velocityAvailable.toAmount()
- if (amount == 0f) return@PriorityNestedScrollConnection false
-
- // We could start an overscroll animation
- gestureStartedOnNestedChild = true
- nextScene = findNextScene(amount)
- nextScene != null
- },
- canContinueScroll = { priorityScene == gestureHandler.swipeTransitionToScene.key },
- onStart = {
- gestureHandler.gestureWithPriority = this
- priorityScene = nextScene
- gestureHandler.onDragStarted(pointersDown = 1, startedPosition = null)
- },
- onScroll = { offsetAvailable ->
- if (gestureHandler.gestureWithPriority != this) {
- return@PriorityNestedScrollConnection Offset.Zero
- }
-
- val amount = offsetAvailable.toAmount()
-
- // TODO(b/297842071) We should handle the overscroll or slow drag if the gesture is
- // initiated in a nested child.
- gestureHandler.onDrag(amount)
-
- amount.toOffset()
- },
- onStop = { velocityAvailable ->
- if (gestureHandler.gestureWithPriority != this) {
- return@PriorityNestedScrollConnection Velocity.Zero
- }
-
- priorityScene = null
-
- gestureHandler.onDragStopped(
- velocity = velocityAvailable.toAmount(),
- canChangeScene = !gestureStartedOnNestedChild
- )
-
- // The onDragStopped animation consumes any remaining velocity.
- velocityAvailable
- },
- )
- }
-}
-
-/**
- * The number of pixels below which there won't be a visible difference in the transition and from
- * which the animation can stop.
- */
-private const val OffsetVisibilityThreshold = 0.5f
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 7b7695e..5473186 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
@@ -66,7 +66,8 @@
val int by animateSharedIntAsState(targetValues.int, TestValues.Value1, key)
val float by animateSharedFloatAsState(targetValues.float, TestValues.Value2, key)
val dp by animateSharedDpAsState(targetValues.dp, TestValues.Value3, key)
- val color by animateSharedColorAsState(targetValues.color, TestValues.Value4, key)
+ val color by
+ animateSharedColorAsState(targetValues.color, TestValues.Value4, element = null)
// Make sure we read the values during composition, so that we recompose and call
// onCurrentValueChanged() with the latest values.
diff --git a/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestSceneScope.kt b/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestSceneScope.kt
new file mode 100644
index 0000000..de46f72
--- /dev/null
+++ b/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestSceneScope.kt
@@ -0,0 +1,38 @@
+/*
+ * 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.compose.animation.scene
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+
+/** `SceneScope` for tests, which allows a single scene to be drawn in a [SceneTransitionLayout]. */
+@Composable
+fun TestSceneScope(
+ modifier: Modifier = Modifier,
+ content: @Composable SceneScope.() -> Unit,
+) {
+ val currentScene = remember { SceneKey("current") }
+ SceneTransitionLayout(
+ currentScene,
+ onChangeScene = { /* do nothing */},
+ transitions = remember { transitions {} },
+ modifier,
+ ) {
+ scene(currentScene, content = content)
+ }
+}
diff --git a/packages/SystemUI/proguard_common.flags b/packages/SystemUI/proguard_common.flags
index 445bdc2..73ae59a 100644
--- a/packages/SystemUI/proguard_common.flags
+++ b/packages/SystemUI/proguard_common.flags
@@ -20,8 +20,6 @@
public <init>(android.content.Context, android.util.AttributeSet);
}
--keep class com.android.systemui.tuner.*
-
# The plugins and core log subpackages act as shared libraries that might be referenced in
# dynamically-loaded plugin APKs.
-keep class com.android.systemui.plugins.** {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButton.java b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButton.java
index b44bf39..fec96c6 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButton.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButton.java
@@ -16,6 +16,8 @@
package com.android.systemui.shared.rotation;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
+
import android.annotation.DimenRes;
import android.annotation.IdRes;
import android.annotation.LayoutRes;
@@ -87,15 +89,15 @@
@DimenRes int roundedContentPadding, @DimenRes int taskbarLeftMargin,
@DimenRes int taskbarBottomMargin, @DimenRes int buttonDiameter,
@DimenRes int rippleMaxWidth, @BoolRes int floatingRotationBtnPositionLeftResource) {
- mWindowManager = context.getSystemService(WindowManager.class);
- mKeyButtonContainer = (ViewGroup) LayoutInflater.from(context).inflate(layout, null);
+ mContext = context.createWindowContext(context.getDisplay(), TYPE_NAVIGATION_BAR_PANEL,
+ null);
+ mWindowManager = mContext.getSystemService(WindowManager.class);
+ mKeyButtonContainer = (ViewGroup) LayoutInflater.from(mContext).inflate(layout, null);
mKeyButtonView = mKeyButtonContainer.findViewById(keyButtonId);
mKeyButtonView.setVisibility(View.VISIBLE);
- mKeyButtonView.setContentDescription(context.getString(contentDescriptionResource));
+ mKeyButtonView.setContentDescription(mContext.getString(contentDescriptionResource));
mKeyButtonView.setRipple(rippleMaxWidth);
- mContext = context;
-
mContentDescriptionResource = contentDescriptionResource;
mMinMarginResource = minMargin;
mRoundedContentPaddingResource = roundedContentPadding;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index f9eb686..6b8009d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -47,6 +47,7 @@
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.ui.binder.KeyguardRootViewBinder;
+import com.android.systemui.keyguard.ui.view.InWindowLauncherUnlockAnimationManager;
import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel;
import com.android.systemui.log.LogBuffer;
import com.android.systemui.log.core.LogLevel;
@@ -123,6 +124,7 @@
private View mSmartspaceView;
private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
+ private final InWindowLauncherUnlockAnimationManager mInWindowLauncherUnlockAnimationManager;
private boolean mShownOnSecondaryDisplay = false;
private boolean mOnlyClock = false;
@@ -190,7 +192,8 @@
AlwaysOnDisplayNotificationIconViewStore aodIconViewStore,
KeyguardInteractor keyguardInteractor,
KeyguardClockInteractor keyguardClockInteractor,
- FeatureFlagsClassic featureFlags) {
+ FeatureFlagsClassic featureFlags,
+ InWindowLauncherUnlockAnimationManager inWindowLauncherUnlockAnimationManager) {
super(keyguardClockSwitch);
mStatusBarStateController = statusBarStateController;
mClockRegistry = clockRegistry;
@@ -214,6 +217,7 @@
mFeatureFlags = featureFlags;
mKeyguardInteractor = keyguardInteractor;
mKeyguardClockInteractor = keyguardClockInteractor;
+ mInWindowLauncherUnlockAnimationManager = inWindowLauncherUnlockAnimationManager;
mClockChangedListener = new ClockRegistry.ClockChangeListener() {
@Override
@@ -438,6 +442,8 @@
mSmartspaceView.setPaddingRelative(startPadding, 0, endPadding, 0);
mKeyguardUnlockAnimationController.setLockscreenSmartspace(mSmartspaceView);
+ mInWindowLauncherUnlockAnimationManager.setLockscreenSmartspace(mSmartspaceView);
+
mView.setSmartspace(mSmartspaceView);
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/IRadiiAnimationListener.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/IRadiiAnimationListener.java
index 72935f7..d92b506 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/IRadiiAnimationListener.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/IRadiiAnimationListener.java
@@ -18,4 +18,8 @@
interface IRadiiAnimationListener {
void onRadiiAnimationUpdate(float[] radii);
+
+ void onRadiiAnimationStart();
+
+ void onRadiiAnimationStop();
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java
index 761551c..34d7cec 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java
@@ -94,7 +94,19 @@
mFadeOutAnimator.setDuration(FADE_OUT_DURATION_MS);
mFadeOutAnimator.addUpdateListener(
(animation) -> menuView.setAlpha((float) animation.getAnimatedValue()));
- mRadiiAnimator = new RadiiAnimator(mMenuViewAppearance.getMenuRadii(), mMenuView::setRadii);
+ mRadiiAnimator = new RadiiAnimator(mMenuViewAppearance.getMenuRadii(),
+ new IRadiiAnimationListener() {
+ @Override
+ public void onRadiiAnimationUpdate(float[] radii) {
+ mMenuView.setRadii(radii);
+ }
+
+ @Override
+ public void onRadiiAnimationStart() {}
+
+ @Override
+ public void onRadiiAnimationStop() {}
+ });
}
void moveToPosition(PointF position) {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/RadiiAnimator.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/RadiiAnimator.java
index acad36e..4aa0d89 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/RadiiAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/RadiiAnimator.java
@@ -55,15 +55,19 @@
@Override
public void onAnimationStart(@NonNull Animator animation) {
animationListener.onRadiiAnimationUpdate(evaluate(/* t = */ 0.0f));
+ animationListener.onRadiiAnimationStart();
}
@Override
- public void onAnimationEnd(@NonNull Animator animation) {}
+ public void onAnimationEnd(@NonNull Animator animation) {
+ animationListener.onRadiiAnimationStop();
+ }
@Override
public void onAnimationCancel(@NonNull Animator animation) {
animationListener.onRadiiAnimationUpdate(
evaluate(mAnimationDriver.getAnimatedFraction()));
+ animationListener.onRadiiAnimationStop();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/FpsUnlockTracker.kt b/packages/SystemUI/src/com/android/systemui/biometrics/FpsUnlockTracker.kt
new file mode 100644
index 0000000..cf699a2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/FpsUnlockTracker.kt
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.biometrics
+
+import android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_START
+import android.hardware.biometrics.BiometricSourceType
+import android.hardware.biometrics.BiometricSourceType.FINGERPRINT
+import android.util.Log
+import com.android.app.tracing.TraceStateLogger
+import com.android.internal.util.LatencyTracker
+import com.android.internal.util.LatencyTracker.ACTION_KEYGUARD_FPS_UNLOCK_TO_HOME
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.keyguard.KeyguardUpdateMonitorCallback
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.KeyguardUnlockAnimationController
+import com.android.systemui.keyguard.KeyguardUnlockAnimationController.KeyguardUnlockAnimationListener
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import javax.inject.Inject
+
+private const val TAG = "FpsUnlockTracker"
+private const val TRACE_COUNTER_NAME = "FpsUnlockStage"
+private const val TRACE_TAG_AOD = "AOD"
+private const val TRACE_TAG_KEYGUARD = "KEYGUARD"
+private const val DEBUG = true
+
+/** This is a class for monitoring unlock latency of fps and logging stages in perfetto. */
+@SysUISingleton
+class FpsUnlockTracker
+@Inject
+constructor(
+ private val statusBarStateController: StatusBarStateController,
+ private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
+ private val keyguardUnlockAnimationController: KeyguardUnlockAnimationController,
+ private val latencyTracker: LatencyTracker,
+) {
+ private val fpsTraceStateLogger = TraceStateLogger(TRACE_COUNTER_NAME)
+ private var fpsAuthenticated: Boolean = false
+
+ private val keyguardUpdateMonitorCallback =
+ object : KeyguardUpdateMonitorCallback() {
+ override fun onBiometricAcquired(
+ biometricSourceType: BiometricSourceType?,
+ acquireInfo: Int
+ ) {
+ if (keyguardUpdateMonitor.isUnlockingWithFingerprintAllowed) {
+ onHalAuthenticationStage(acquireInfo)
+ }
+ }
+
+ override fun onBiometricAuthenticated(
+ userId: Int,
+ biometricSourceType: BiometricSourceType?,
+ isStrongBiometric: Boolean
+ ) {
+ if (biometricSourceType == FINGERPRINT) {
+ fpsAuthenticated = true
+ onExitKeyguard()
+ }
+ }
+
+ override fun onBiometricError(
+ msgId: Int,
+ errString: String?,
+ biometricSourceType: BiometricSourceType?
+ ) {
+ if (biometricSourceType == FINGERPRINT) {
+ latencyTracker.onActionCancel(ACTION_KEYGUARD_FPS_UNLOCK_TO_HOME)
+ }
+ }
+
+ override fun onBiometricRunningStateChanged(
+ running: Boolean,
+ biometricSourceType: BiometricSourceType?
+ ) {
+ if (biometricSourceType != FINGERPRINT || !running) {
+ return
+ }
+ onWaitForAuthenticationStage()
+ }
+ }
+
+ private val keyguardUnlockAnimationListener =
+ object : KeyguardUnlockAnimationListener {
+ override fun onUnlockAnimationFinished() = onUnlockedStage()
+ }
+
+ /** Start tracking the fps unlock. */
+ fun startTracking() {
+ keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
+ keyguardUnlockAnimationController.addKeyguardUnlockAnimationListener(
+ keyguardUnlockAnimationListener
+ )
+ }
+
+ /** Stop tracking the fps unlock. */
+ fun stopTracking() {
+ keyguardUpdateMonitor.removeCallback(keyguardUpdateMonitorCallback)
+ keyguardUnlockAnimationController.removeKeyguardUnlockAnimationListener(
+ keyguardUnlockAnimationListener
+ )
+ }
+
+ /**
+ * The stage when the devices is locked and is possible to be unlocked via fps. However, in some
+ * situations, it might be unlocked only via bouncer.
+ */
+ fun onWaitForAuthenticationStage() {
+ val stage =
+ if (keyguardUpdateMonitor.isUnlockingWithFingerprintAllowed)
+ FpsUnlockStage.WAIT_FOR_AUTHENTICATION.name
+ else FpsUnlockStage.WAIT_FOR_AUTHENTICATION.name + "(Not allowed)"
+ fpsTraceStateLogger.log(stage)
+ if (DEBUG) {
+ Log.d(TAG, "onWaitForAuthenticationStage: stage=$stage")
+ }
+ }
+
+ /**
+ * The stage dedicated to UDFPS, SFPS should not enter this stage. The only place where invokes
+ * this function is UdfpsController#onFingerDown.
+ */
+ fun onUiReadyStage() {
+ if (!keyguardUpdateMonitor.isUdfpsSupported || !keyguardUpdateMonitor.isUdfpsEnrolled) {
+ return
+ }
+ fpsTraceStateLogger.log(FpsUnlockStage.UI_READY.name)
+ startLatencyTracker()
+ if (DEBUG) {
+ Log.d(TAG, "onUiReadyStage: dozing=${statusBarStateController.isDozing}")
+ }
+ }
+
+ /** The stage when the HAL is authenticating the fingerprint. */
+ fun onHalAuthenticationStage(acquire: Int) {
+ fpsTraceStateLogger.log("${FpsUnlockStage.HAL_AUTHENTICATION.name}($acquire)")
+ // Start latency tracker here only for SFPS, UDFPS should start at onUiReadyStage.
+ if (
+ keyguardUpdateMonitor.isSfpsSupported &&
+ keyguardUpdateMonitor.isSfpsEnrolled &&
+ acquire == FINGERPRINT_ACQUIRED_START
+ ) {
+ startLatencyTracker()
+ }
+ if (DEBUG) {
+ Log.d(
+ TAG,
+ "onHalAuthenticationStage: acquire=$acquire" +
+ ", sfpsSupported=${keyguardUpdateMonitor.isSfpsSupported}" +
+ ", sfpsEnrolled=${keyguardUpdateMonitor.isSfpsEnrolled}"
+ )
+ }
+ }
+
+ /** The stage when the authentication is succeeded and is going to exit keyguard. */
+ fun onExitKeyguard() {
+ fpsTraceStateLogger.log(FpsUnlockStage.EXIT_KEYGUARD.name)
+ if (DEBUG) {
+ Log.d(TAG, "onExitKeyguard: fpsAuthenticated=$fpsAuthenticated")
+ }
+ }
+
+ /**
+ * The stage when the unlock animation is finished which means the user can start interacting
+ * with the device.
+ */
+ fun onUnlockedStage() {
+ fpsTraceStateLogger.log(FpsUnlockStage.UNLOCKED.name)
+ if (fpsAuthenticated) {
+ // The device is unlocked successfully via fps, end the instrument.
+ latencyTracker.onActionEnd(ACTION_KEYGUARD_FPS_UNLOCK_TO_HOME)
+ } else {
+ // The device is unlocked but not via fps, maybe bouncer? Cancel the instrument.
+ latencyTracker.onActionCancel(ACTION_KEYGUARD_FPS_UNLOCK_TO_HOME)
+ }
+ if (DEBUG) {
+ Log.d(TAG, "onUnlockedStage: fpsAuthenticated=$fpsAuthenticated")
+ }
+ fpsAuthenticated = false
+ }
+
+ private fun startLatencyTracker() {
+ latencyTracker.onActionCancel(ACTION_KEYGUARD_FPS_UNLOCK_TO_HOME)
+ val tag = if (statusBarStateController.isDozing) TRACE_TAG_AOD else TRACE_TAG_KEYGUARD
+ latencyTracker.onActionStart(ACTION_KEYGUARD_FPS_UNLOCK_TO_HOME, tag)
+ }
+}
+
+private enum class FpsUnlockStage {
+ WAIT_FOR_AUTHENTICATION,
+ UI_READY,
+ HAL_AUTHENTICATION,
+ EXIT_KEYGUARD,
+ UNLOCKED
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
index 10e7227..8f61dbf 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
@@ -91,7 +91,8 @@
@Main private val handler: Handler,
private val alternateBouncerInteractor: AlternateBouncerInteractor,
@Application private val scope: CoroutineScope,
- dumpManager: DumpManager
+ dumpManager: DumpManager,
+ fpsUnlockTracker: FpsUnlockTracker
) : Dumpable {
private val requests: HashSet<SideFpsUiRequestSource> = HashSet()
@@ -167,6 +168,7 @@
}
init {
+ fpsUnlockTracker.startTracking()
fingerprintManager?.setSidefpsController(
object : ISidefpsController.Stub() {
override fun show(
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 3944ac2..4175937 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -24,6 +24,7 @@
import static android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_ENROLLING;
import static android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_FIND_SENSOR;
+import static com.android.internal.util.LatencyTracker.ACTION_UDFPS_ILLUMINATE;
import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.systemui.classifier.Classifier.UDFPS_AUTHENTICATION;
@@ -167,6 +168,7 @@
@NonNull private final InputManager mInputManager;
@NonNull private final UdfpsKeyguardAccessibilityDelegate mUdfpsKeyguardAccessibilityDelegate;
@NonNull private final SelectedUserInteractor mSelectedUserInteractor;
+ @NonNull private final FpsUnlockTracker mFpsUnlockTracker;
private final boolean mIgnoreRefreshRate;
// Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple
@@ -646,7 +648,8 @@
@NonNull KeyguardFaceAuthInteractor keyguardFaceAuthInteractor,
@NonNull UdfpsKeyguardAccessibilityDelegate udfpsKeyguardAccessibilityDelegate,
@NonNull Provider<UdfpsKeyguardViewModels> udfpsKeyguardViewModelsProvider,
- @NonNull SelectedUserInteractor selectedUserInteractor) {
+ @NonNull SelectedUserInteractor selectedUserInteractor,
+ @NonNull FpsUnlockTracker fpsUnlockTracker) {
mContext = context;
mExecution = execution;
mVibrator = vibrator;
@@ -690,6 +693,8 @@
mInputManager = inputManager;
mUdfpsKeyguardAccessibilityDelegate = udfpsKeyguardAccessibilityDelegate;
mSelectedUserInteractor = selectedUserInteractor;
+ mFpsUnlockTracker = fpsUnlockTracker;
+ mFpsUnlockTracker.startTracking();
mTouchProcessor = singlePointerTouchProcessor;
mSessionTracker = sessionTracker;
@@ -974,7 +979,10 @@
return;
}
if (isOptical()) {
- mLatencyTracker.onActionStart(LatencyTracker.ACTION_UDFPS_ILLUMINATE);
+ mLatencyTracker.onActionStart(ACTION_UDFPS_ILLUMINATE);
+ }
+ if (getBiometricSessionType() == SESSION_KEYGUARD) {
+ mFpsUnlockTracker.onUiReadyStage();
}
// Refresh screen timeout and boost process priority if possible.
mPowerManager.userActivity(mSystemClock.uptimeMillis(),
diff --git a/packages/SystemUI/src/com/android/systemui/display/ui/view/MirroringConfirmationDialog.kt b/packages/SystemUI/src/com/android/systemui/display/ui/view/MirroringConfirmationDialog.kt
index 87b0f01..d500d1c2 100644
--- a/packages/SystemUI/src/com/android/systemui/display/ui/view/MirroringConfirmationDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/ui/view/MirroringConfirmationDialog.kt
@@ -20,7 +20,6 @@
import android.view.View
import android.widget.TextView
import androidx.core.view.updatePadding
-import com.android.systemui.biometrics.Utils
import com.android.systemui.res.R
import com.android.systemui.statusbar.phone.SystemUIBottomSheetDialog
import com.android.systemui.statusbar.policy.ConfigurationController
@@ -36,6 +35,7 @@
context: Context,
private val onStartMirroringClickListener: View.OnClickListener,
private val onCancelMirroring: View.OnClickListener,
+ private val navbarBottomInsetsProvider: () -> Int,
configurationController: ConfigurationController? = null,
theme: Int = R.style.Theme_SystemUI_Dialog,
) : SystemUIBottomSheetDialog(context, configurationController, theme) {
@@ -67,12 +67,12 @@
private fun setupInsets() {
// This avoids overlap between dialog content and navigation bars.
requireViewById<View>(R.id.cd_bottom_sheet).apply {
- val navbarInsets = Utils.getNavbarInsets(context)
+ val navbarInsets = navbarBottomInsetsProvider()
val defaultDialogBottomInset =
context.resources.getDimensionPixelSize(R.dimen.dialog_bottom_padding)
// we only care about the bottom inset as in all other configuration where navigations
// are in other display sides there is no overlap with the dialog.
- updatePadding(bottom = max(navbarInsets.bottom, defaultDialogBottomInset))
+ updatePadding(bottom = max(navbarInsets, defaultDialogBottomInset))
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/display/ui/viewmodel/ConnectingDisplayViewModel.kt b/packages/SystemUI/src/com/android/systemui/display/ui/viewmodel/ConnectingDisplayViewModel.kt
index 91f535d..19b4d22 100644
--- a/packages/SystemUI/src/com/android/systemui/display/ui/viewmodel/ConnectingDisplayViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/ui/viewmodel/ConnectingDisplayViewModel.kt
@@ -17,6 +17,7 @@
import android.app.Dialog
import android.content.Context
+import com.android.systemui.biometrics.Utils
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
@@ -74,7 +75,8 @@
scope.launch(bgDispatcher) { pendingDisplay.ignore() }
hideDialog()
},
- configurationController
+ navbarBottomInsetsProvider = { Utils.getNavbarInsets(context).bottom },
+ configurationController,
)
.apply { show() }
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 5a38906..77384c4 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -68,9 +68,6 @@
"notification_drag_to_contents"
)
- // TODO(b/254512538): Tracking Bug
- val INSTANT_VOICE_REPLY = unreleasedFlag("instant_voice_reply")
-
/**
* This flag controls whether we register a listener for StatsD notification memory reports.
* For statsd to actually call the listener however, a server-side toggle needs to be
@@ -394,7 +391,7 @@
@JvmField val SIGNAL_CALLBACK_DEPRECATION = releasedFlag("signal_callback_deprecation")
// TODO(b/301610137): Tracking bug
- @JvmField val NEW_NETWORK_SLICE_UI = unreleasedFlag("new_network_slice_ui", teamfood = true)
+ @JvmField val NEW_NETWORK_SLICE_UI = releasedFlag("new_network_slice_ui")
// TODO(b/308138154): Tracking bug
val FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS =
@@ -792,17 +789,13 @@
@JvmField
val SHARE_WIFI_QS_BUTTON = releasedFlag("share_wifi_qs_button")
- /** Enable haptic slider component in the brightness slider */
- @JvmField
- val HAPTIC_BRIGHTNESS_SLIDER = unreleasedFlag("haptic_brightness_slider", teamfood = true)
-
// TODO(b/287205379): Tracking bug
@JvmField
val QS_CONTAINER_GRAPH_OPTIMIZER = releasedFlag( "qs_container_graph_optimizer")
/** Enable showing a dialog when clicking on Quick Settings bluetooth tile. */
@JvmField
- val BLUETOOTH_QS_TILE_DIALOG = unreleasedFlag("bluetooth_qs_tile_dialog", teamfood = true)
+ val BLUETOOTH_QS_TILE_DIALOG = unreleasedFlag("bluetooth_qs_tile_dialog")
// TODO(b/300995746): Tracking Bug
/** A resource flag for whether the communal service is enabled. */
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/InWindowLauncherUnlockAnimationRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/InWindowLauncherUnlockAnimationRepository.kt
new file mode 100644
index 0000000..d23899b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/InWindowLauncherUnlockAnimationRepository.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.data.repository
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.domain.interactor.InWindowLauncherUnlockAnimationInteractor
+import com.android.systemui.shared.system.smartspace.ILauncherUnlockAnimationController
+import com.android.systemui.shared.system.smartspace.SmartspaceState
+import javax.inject.Inject
+import kotlinx.coroutines.flow.MutableStateFlow
+
+/**
+ * State related to System UI's handling of the in-window Launcher unlock animations. This includes
+ * the staggered icon entry animation that plays during unlock, as well as the smartspace shared
+ * element animation, if supported.
+ *
+ * While the animations themselves occur fully in the Launcher window, System UI is responsible for
+ * preparing/starting the animations, as well as synchronizing the smartspace state so that the two
+ * smartspaces appear visually identical for the shared element animation.
+ */
+@SysUISingleton
+class InWindowLauncherUnlockAnimationRepository @Inject constructor() {
+
+ /**
+ * Whether we have called [ILauncherUnlockAnimationController.playUnlockAnimation] during this
+ * unlock sequence. This value is set back to false once
+ * [InWindowLauncherUnlockAnimationInteractor.shouldStartInWindowAnimation] reverts to false,
+ * which happens when we're no longer in transition to GONE or if the remote animation ends or
+ * is cancelled.
+ */
+ val startedUnlockAnimation = MutableStateFlow(false)
+
+ /**
+ * The unlock amount we've explicitly passed to
+ * [ILauncherUnlockAnimationController.setUnlockAmount]. This is used whenever System UI is
+ * directly controlling the amount of the unlock animation, such as during a manual swipe to
+ * unlock gesture.
+ *
+ * This value is *not* updated if we called
+ * [ILauncherUnlockAnimationController.playUnlockAnimation] to ask Launcher to animate all the
+ * way unlocked, since that animator is running in the Launcher window.
+ */
+ val manualUnlockAmount: MutableStateFlow<Float?> = MutableStateFlow(null)
+
+ /**
+ * The class name of the Launcher activity that provided us with a
+ * [ILauncherUnlockAnimationController], if applicable. We can use this to check if that
+ * launcher is underneath the lockscreen before playing in-window animations.
+ *
+ * If null, we have not been provided with a launcher unlock animation controller.
+ */
+ val launcherActivityClass: MutableStateFlow<String?> = MutableStateFlow(null)
+
+ /**
+ * Information about the Launcher's smartspace, which is passed to us via
+ * [ILauncherUnlockAnimationController].
+ */
+ val launcherSmartspaceState: MutableStateFlow<SmartspaceState?> = MutableStateFlow(null)
+
+ fun setStartedUnlockAnimation(started: Boolean) {
+ startedUnlockAnimation.value = started
+ }
+
+ fun setManualUnlockAmount(amount: Float?) {
+ manualUnlockAmount.value = amount
+ }
+
+ fun setLauncherActivityClass(className: String) {
+ launcherActivityClass.value = className
+ }
+
+ fun setLauncherSmartspaceState(state: SmartspaceState?) {
+ launcherSmartspaceState.value = state
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardSurfaceBehindRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardSurfaceBehindRepository.kt
index 014b7fa..6121b633 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardSurfaceBehindRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardSurfaceBehindRepository.kt
@@ -31,8 +31,14 @@
/** Whether we're running animations on the surface. */
val isAnimatingSurface: Flow<Boolean>
+ /** Whether we have a RemoteAnimationTarget to run animations on the surface. */
+ val isSurfaceRemoteAnimationTargetAvailable: Flow<Boolean>
+
/** Set whether we're running animations on the surface. */
fun setAnimatingSurface(animating: Boolean)
+
+ /** Set whether we have a RemoteAnimationTarget with which to run animations on the surface. */
+ fun setSurfaceRemoteAnimationTargetAvailable(available: Boolean)
}
@SysUISingleton
@@ -40,7 +46,15 @@
private val _isAnimatingSurface = MutableStateFlow(false)
override val isAnimatingSurface = _isAnimatingSurface.asStateFlow()
+ private val _isSurfaceRemoteAnimationTargetAvailable = MutableStateFlow(false)
+ override val isSurfaceRemoteAnimationTargetAvailable =
+ _isSurfaceRemoteAnimationTargetAvailable.asStateFlow()
+
override fun setAnimatingSurface(animating: Boolean) {
_isAnimatingSurface.value = animating
}
+
+ override fun setSurfaceRemoteAnimationTargetAvailable(available: Boolean) {
+ _isSurfaceRemoteAnimationTargetAvailable.value = available
+ }
}
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 c4962a1..ea40ba0 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
@@ -35,6 +35,7 @@
import com.android.systemui.util.kotlin.Utils.Companion.toQuad
import com.android.systemui.util.kotlin.Utils.Companion.toTriple
import com.android.systemui.util.kotlin.sample
+import dagger.Lazy
import java.util.UUID
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
@@ -56,6 +57,7 @@
private val flags: FeatureFlags,
private val shadeRepository: ShadeRepository,
private val powerInteractor: PowerInteractor,
+ inWindowLauncherUnlockAnimationInteractor: Lazy<InWindowLauncherUnlockAnimationInteractor>,
) :
TransitionInteractor(
fromState = KeyguardState.LOCKSCREEN,
@@ -104,12 +106,21 @@
val surfaceBehindModel: Flow<KeyguardSurfaceBehindModel?> =
combine(
transitionInteractor.startedKeyguardTransitionStep,
- transitionInteractor.transitionStepsFromState(KeyguardState.LOCKSCREEN)
- ) { startedStep, fromLockscreenStep ->
+ transitionInteractor.transitionStepsFromState(KeyguardState.LOCKSCREEN),
+ inWindowLauncherUnlockAnimationInteractor
+ .get()
+ .transitioningToGoneWithInWindowAnimation,
+ ) { startedStep, fromLockscreenStep, transitioningToGoneWithInWindowAnimation ->
if (startedStep.to != KeyguardState.GONE) {
// Only LOCKSCREEN -> GONE has specific surface params (for the unlock
// animation).
return@combine null
+ } else if (transitioningToGoneWithInWindowAnimation) {
+ // If we're prepared for the in-window unlock, we're going to play an animation
+ // in the window. Make it fully visible.
+ KeyguardSurfaceBehindModel(
+ alpha = 1f,
+ )
} else if (fromLockscreenStep.value > 0.5f) {
// Start the animation once we're 50% transitioned to GONE.
KeyguardSurfaceBehindModel(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/InWindowLauncherUnlockAnimationInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/InWindowLauncherUnlockAnimationInteractor.kt
new file mode 100644
index 0000000..e7d74a5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/InWindowLauncherUnlockAnimationInteractor.kt
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.keyguard.data.repository.InWindowLauncherUnlockAnimationRepository
+import com.android.systemui.keyguard.data.repository.KeyguardSurfaceBehindRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.shared.system.ActivityManagerWrapper
+import com.android.systemui.shared.system.smartspace.SmartspaceState
+import com.android.systemui.util.kotlin.sample
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
+
+@SysUISingleton
+class InWindowLauncherUnlockAnimationInteractor
+@Inject
+constructor(
+ private val repository: InWindowLauncherUnlockAnimationRepository,
+ @Application scope: CoroutineScope,
+ transitionInteractor: KeyguardTransitionInteractor,
+ surfaceBehindRepository: dagger.Lazy<KeyguardSurfaceBehindRepository>,
+ private val activityManager: ActivityManagerWrapper,
+) {
+ val startedUnlockAnimation = repository.startedUnlockAnimation.asStateFlow()
+
+ /**
+ * Whether we've STARTED but not FINISHED a transition to GONE, and the preconditions are met to
+ * play the in-window unlock animation.
+ */
+ val transitioningToGoneWithInWindowAnimation: StateFlow<Boolean> =
+ transitionInteractor
+ .isInTransitionToState(KeyguardState.GONE)
+ .sample(repository.launcherActivityClass, ::Pair)
+ .map { (isTransitioningToGone, launcherActivityClass) ->
+ isTransitioningToGone && isActivityClassUnderneath(launcherActivityClass)
+ }
+ .stateIn(scope, SharingStarted.Eagerly, false)
+
+ /**
+ * Whether we should start the in-window unlock animation.
+ *
+ * This emits true once the Launcher surface becomes available while we're
+ * [transitioningToGoneWithInWindowAnimation].
+ */
+ val shouldStartInWindowAnimation: StateFlow<Boolean> =
+ combine(
+ transitioningToGoneWithInWindowAnimation,
+ surfaceBehindRepository.get().isSurfaceRemoteAnimationTargetAvailable,
+ ) { transitioningWithInWindowAnimation, isSurfaceAvailable ->
+ transitioningWithInWindowAnimation && isSurfaceAvailable
+ }
+ .stateIn(scope, SharingStarted.Eagerly, false)
+
+ /** Sets whether we've started */
+ fun setStartedUnlockAnimation(started: Boolean) {
+ repository.setStartedUnlockAnimation(started)
+ }
+
+ fun setManualUnlockAmount(amount: Float) {
+ repository.setManualUnlockAmount(amount)
+ }
+
+ fun setLauncherActivityClass(className: String) {
+ repository.setLauncherActivityClass(className)
+ }
+
+ fun setLauncherSmartspaceState(state: SmartspaceState?) {
+ repository.setLauncherSmartspaceState(state)
+ }
+
+ /**
+ * Whether an activity with the given [activityClass] name is currently underneath the
+ * lockscreen (it's at the top of the activity task stack).
+ */
+ private fun isActivityClassUnderneath(activityClass: String?): Boolean {
+ return activityClass?.let {
+ activityManager.runningTask?.topActivity?.className?.equals(it)
+ }
+ ?: false
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractor.kt
index bf04f8f..efbe261 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractor.kt
@@ -20,13 +20,13 @@
import com.android.systemui.keyguard.data.repository.KeyguardSurfaceBehindRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.KeyguardSurfaceBehindModel
+import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
-import javax.inject.Inject
@SysUISingleton
class KeyguardSurfaceBehindInteractor
@@ -40,19 +40,18 @@
@OptIn(ExperimentalCoroutinesApi::class)
val viewParams: Flow<KeyguardSurfaceBehindModel> =
- transitionInteractor.isInTransitionToAnyState
- .flatMapLatest { isInTransition ->
- if (!isInTransition) {
- defaultParams
- } else {
- combine(
- transitionSpecificViewParams,
- defaultParams,
- ) { transitionParams, defaultParams ->
- transitionParams ?: defaultParams
- }
+ transitionInteractor.isInTransitionToAnyState.flatMapLatest { isInTransition ->
+ if (!isInTransition) {
+ defaultParams
+ } else {
+ combine(
+ transitionSpecificViewParams,
+ defaultParams,
+ ) { transitionParams, defaultParams ->
+ transitionParams ?: defaultParams
}
}
+ }
val isAnimatingSurface = repository.isAnimatingSurface
@@ -86,4 +85,8 @@
fun setAnimatingSurface(animating: Boolean) {
repository.setAnimatingSurface(animating)
}
+
+ fun setSurfaceRemoteAnimationTargetAvailable(available: Boolean) {
+ repository.setSurfaceRemoteAnimationTargetAvailable(available)
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/InWindowLauncherAnimationViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/InWindowLauncherAnimationViewBinder.kt
new file mode 100644
index 0000000..56a6e9b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/InWindowLauncherAnimationViewBinder.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.binder
+
+import com.android.systemui.keyguard.ui.view.InWindowLauncherUnlockAnimationManager
+import com.android.systemui.keyguard.ui.viewmodel.InWindowLauncherAnimationViewModel
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+
+/**
+ * Binds the [InWindowLauncherUnlockAnimationManager] "view", which manages the lifecycle and state
+ * of the in-window Launcher animation.
+ */
+object InWindowLauncherAnimationViewBinder {
+
+ @JvmStatic
+ fun bind(
+ viewModel: InWindowLauncherAnimationViewModel,
+ inWindowLauncherUnlockAnimationManager: InWindowLauncherUnlockAnimationManager,
+ scope: CoroutineScope
+ ) {
+ scope.launch {
+ viewModel.shouldPrepareForInWindowAnimation.collect { shouldPrepare ->
+ if (shouldPrepare) {
+ inWindowLauncherUnlockAnimationManager.prepareForUnlock()
+ } else {
+ // If we no longer meet the conditions to prepare for unlock, we'll need to
+ // manually set Launcher unlocked if we didn't start the unlock animation, or it
+ // will remain "prepared" (blank) forever.
+ inWindowLauncherUnlockAnimationManager.ensureUnlockedOrAnimatingUnlocked()
+ }
+ }
+ }
+
+ scope.launch {
+ viewModel.shouldStartInWindowAnimation.collect { shouldStart ->
+ if (shouldStart) {
+ inWindowLauncherUnlockAnimationManager.playUnlockAnimation(unlocked = true)
+ } else {
+ // Once the conditions to start the animation are no longer met, clear whether
+ // we started the animation, since we'll need to start it again if the
+ // conditions become true again.
+ inWindowLauncherUnlockAnimationManager.clearStartedUnlockAnimation()
+ }
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindParamsApplier.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindParamsApplier.kt
index c8dab32..8587022 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindParamsApplier.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindParamsApplier.kt
@@ -51,6 +51,11 @@
private val interactor: KeyguardSurfaceBehindInteractor,
) {
private var surfaceBehind: RemoteAnimationTarget? = null
+ set(value) {
+ field = value
+ interactor.setSurfaceRemoteAnimationTargetAvailable(value != null)
+ }
+
private val surfaceTransactionApplier: SyncRtSurfaceTransactionApplier
get() = SyncRtSurfaceTransactionApplier(keyguardViewController.viewRootImpl.view)
@@ -66,7 +71,7 @@
dampingRatio = 1f
}
addUpdateListener { _, _, _ -> applyToSurfaceBehind() }
- addEndListener { _, _, _, _ ->
+ addEndListener { _, _, _, _ ->
try {
updateIsAnimatingSurface()
} catch (e: NullPointerException) {
@@ -112,6 +117,7 @@
fun applyParamsToSurface(surface: RemoteAnimationTarget) {
this.surfaceBehind = surface
startOrUpdateAnimators()
+ applyToSurfaceBehind()
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/InWindowLauncherUnlockAnimationManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/InWindowLauncherUnlockAnimationManager.kt
new file mode 100644
index 0000000..eb005f2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/InWindowLauncherUnlockAnimationManager.kt
@@ -0,0 +1,199 @@
+/*
+ *
+ * * Copyright (C) 2023 The Android Open Source Project
+ * *
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * http://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ *
+ *
+ */
+package com.android.systemui.keyguard.ui.view
+
+import android.graphics.Rect
+import android.util.Log
+import android.view.View
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.keyguard.domain.interactor.InWindowLauncherUnlockAnimationInteractor
+import com.android.systemui.keyguard.ui.binder.InWindowLauncherAnimationViewBinder
+import com.android.systemui.keyguard.ui.viewmodel.InWindowLauncherAnimationViewModel
+import com.android.systemui.shared.system.smartspace.ILauncherUnlockAnimationController
+import com.android.systemui.shared.system.smartspace.ISysuiUnlockAnimationController
+import com.android.systemui.shared.system.smartspace.SmartspaceState
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+
+private val TAG = InWindowLauncherUnlockAnimationManager::class.simpleName
+private const val UNLOCK_ANIMATION_DURATION = 633L
+private const val UNLOCK_START_DELAY = 100L
+
+/**
+ * Handles interactions between System UI and Launcher related to the in-window unlock animation.
+ *
+ * Launcher registers its unlock controller with us here, and we use that to prepare for and start
+ * the unlock animation.
+ */
+@SysUISingleton
+class InWindowLauncherUnlockAnimationManager
+@Inject
+constructor(
+ val interactor: InWindowLauncherUnlockAnimationInteractor,
+ val viewModel: InWindowLauncherAnimationViewModel,
+ @Application val scope: CoroutineScope,
+) : ISysuiUnlockAnimationController.Stub() {
+
+ /**
+ * The smartspace view on the lockscreen. This is used to perform the shared element animation
+ * between the lockscreen smartspace and the launcher one.
+ */
+ var lockscreenSmartspace: View? = null
+
+ private var launcherAnimationController: ILauncherUnlockAnimationController? = null
+
+ /**
+ * Whether we've called [ILauncherUnlockAnimationController.prepareForUnlock], and have *not*
+ * subsequently called [ILauncherUnlockAnimationController.playUnlockAnimation] or
+ * [ILauncherUnlockAnimationController.setUnlockAmount].
+ */
+ private var preparedForUnlock = false
+
+ /**
+ * Most recent value passed to [ILauncherUnlockAnimationController.setUnlockAmount] during this
+ * unlock.
+ *
+ * Null if we have not set a manual unlock amount, or once [ensureUnlockedOrAnimatingUnlocked]
+ * has been called.
+ */
+ private var manualUnlockAmount: Float? = null
+
+ /**
+ * Called from [OverviewProxyService] to provide us with the launcher unlock animation
+ * controller, which can be used to start and update the unlock animation in the launcher
+ * process.
+ */
+ override fun setLauncherUnlockController(
+ activityClass: String,
+ launcherController: ILauncherUnlockAnimationController,
+ ) {
+ interactor.setLauncherActivityClass(activityClass)
+ launcherAnimationController = launcherController
+
+ // Bind once we have a launcher controller.
+ InWindowLauncherAnimationViewBinder.bind(viewModel, this, scope)
+ }
+
+ /**
+ * Called from the launcher process when their smartspace state updates something we should know
+ * about.
+ */
+ override fun onLauncherSmartspaceStateUpdated(state: SmartspaceState?) {
+ interactor.setLauncherSmartspaceState(state)
+ }
+
+ /**
+ * Requests that the launcher prepare for unlock by becoming blank and optionally positioning
+ * its smartspace at the same position as the lockscreen smartspace.
+ *
+ * This state is dangerous - the launcher will remain blank until we ask it to animate unlocked,
+ * either via [playUnlockAnimation] or [setUnlockAmount]. If you don't want to get funny but bad
+ * bugs titled "tiny launcher" or "Expected: launcher icons; Actual: no icons ever", be very
+ * careful here.
+ */
+ fun prepareForUnlock() {
+ launcherAnimationController?.let { launcher ->
+ if (!preparedForUnlock) {
+ preparedForUnlock = true
+ manualUnlockAmount = null
+
+ launcher.prepareForUnlock(
+ false,
+ Rect(),
+ 0
+ ) // TODO(b/293894758): Add smartspace animation support.
+ }
+ }
+ }
+
+ /** Ensures that the launcher is either fully visible, or animating to be fully visible. */
+ fun ensureUnlockedOrAnimatingUnlocked() {
+ val preparedButDidNotStartAnimation =
+ preparedForUnlock && !interactor.startedUnlockAnimation.value
+ val manualUnlockSetButNotFullyVisible =
+ manualUnlockAmount != null && manualUnlockAmount != 1f
+
+ if (preparedButDidNotStartAnimation) {
+ Log.e(
+ TAG,
+ "Called prepareForUnlock(), but not playUnlockAnimation(). " +
+ "Failing-safe by calling setUnlockAmount(1f)"
+ )
+ setUnlockAmount(1f, forceIfAnimating = true)
+ } else if (manualUnlockSetButNotFullyVisible) {
+ Log.e(
+ TAG,
+ "Unlock has ended, but manual unlock amount != 1f. " +
+ "Failing-safe by calling setUnlockAmount(1f)"
+ )
+ setUnlockAmount(1f, forceIfAnimating = true)
+ }
+
+ manualUnlockAmount = null // Un-set the manual unlock amount as we're now visible.
+ }
+
+ /**
+ * Asks launcher to play the in-window unlock animation with the specified parameters.
+ *
+ * Once this is called, we're no longer [preparedForUnlock] as unlock is underway.
+ */
+ fun playUnlockAnimation(
+ unlocked: Boolean,
+ duration: Long = UNLOCK_ANIMATION_DURATION,
+ startDelay: Long = UNLOCK_START_DELAY,
+ ) {
+ if (preparedForUnlock) {
+ launcherAnimationController?.let { launcher ->
+ launcher.playUnlockAnimation(unlocked, duration, startDelay)
+ interactor.setStartedUnlockAnimation(true)
+ }
+ } else {
+ Log.e(TAG, "Attempted to call playUnlockAnimation() before prepareToUnlock().")
+ }
+
+ preparedForUnlock = false
+ }
+
+ /**
+ * Clears the played unlock animation flag. Since we don't have access to an onAnimationEnd
+ * event for the launcher animation (since it's in a different process), this is called whenever
+ * the transition to GONE ends or the surface becomes unavailable. In both cases, we'd need to
+ * play the animation next time we unlock.
+ */
+ fun clearStartedUnlockAnimation() {
+ interactor.setStartedUnlockAnimation(false)
+ }
+
+ /**
+ * Manually sets the unlock amount on launcher. This is used to explicitly set us to fully
+ * unlocked, or to manually control the animation (such as during a swipe to unlock).
+ *
+ * Once this is called, we're no longer [preparedForUnlock] since the Launcher icons are not
+ * configured to be invisible for the start of the unlock animation.
+ */
+ fun setUnlockAmount(amount: Float, forceIfAnimating: Boolean) {
+ preparedForUnlock = false
+
+ launcherAnimationController?.let {
+ manualUnlockAmount = amount
+ it.setUnlockAmount(amount, forceIfAnimating)
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/InWindowLauncherAnimationViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/InWindowLauncherAnimationViewModel.kt
new file mode 100644
index 0000000..2807558
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/InWindowLauncherAnimationViewModel.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.domain.interactor.InWindowLauncherUnlockAnimationInteractor
+import javax.inject.Inject
+
+@SysUISingleton
+class InWindowLauncherAnimationViewModel
+@Inject
+constructor(interactor: InWindowLauncherUnlockAnimationInteractor) {
+
+ /**
+ * Whether we should call [ILauncherUnlockAnimationController.prepareForUnlock] to set up the
+ * Launcher icons for the in-window unlock.
+ *
+ * We'll do this as soon as we're transitioning to GONE when the necessary preconditions are
+ * met.
+ */
+ val shouldPrepareForInWindowAnimation = interactor.transitioningToGoneWithInWindowAnimation
+
+ /**
+ * Whether we should call [ILauncherUnlockAnimationController.playUnlockAnimation] to start the
+ * in-window unlock animation.
+ */
+ val shouldStartInWindowAnimation = interactor.shouldStartInWindowAnimation
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandler.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandler.kt
index 905d8ef..840db26 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandler.kt
@@ -29,12 +29,18 @@
* Provides a shortcut to start an activity from [QSTileUserActionInteractor]. It supports keyguard
* dismissing and tile from-view animations.
*/
-@SysUISingleton
-class QSTileIntentUserInputHandler
-@Inject
-constructor(private val activityStarter: ActivityStarter) {
+interface QSTileIntentUserInputHandler {
- fun handle(view: View?, intent: Intent) {
+ fun handle(view: View?, intent: Intent)
+ fun handle(view: View?, pendingIntent: PendingIntent)
+}
+
+@SysUISingleton
+class QSTileIntentUserInputHandlerImpl
+@Inject
+constructor(private val activityStarter: ActivityStarter) : QSTileIntentUserInputHandler {
+
+ override fun handle(view: View?, intent: Intent) {
val animationController: ActivityLaunchAnimator.Controller? =
view?.let {
ActivityLaunchAnimator.Controller.fromView(
@@ -46,7 +52,7 @@
}
// TODO(b/249804373): make sure to allow showing activities over the lockscreen. See b/292112939
- fun handle(view: View?, pendingIntent: PendingIntent) {
+ override fun handle(view: View?, pendingIntent: PendingIntent) {
if (!pendingIntent.isActivity) {
return
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/di/QSTilesModule.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/di/QSTilesModule.kt
index 32522ad..94137c8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/di/QSTilesModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/di/QSTilesModule.kt
@@ -16,6 +16,8 @@
package com.android.systemui.qs.tiles.di
+import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandler
+import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandlerImpl
import com.android.systemui.qs.tiles.impl.custom.di.CustomTileComponent
import com.android.systemui.qs.tiles.viewmodel.QSTileConfig
import com.android.systemui.qs.tiles.viewmodel.QSTileConfigProvider
@@ -45,4 +47,9 @@
@Multibinds fun tileViewModelMap(): Map<String, QSTileViewModel>
@Binds fun bindQSTileConfigProvider(impl: QSTileConfigProviderImpl): QSTileConfigProvider
+
+ @Binds
+ fun bindQSTileIntentUserInputHandler(
+ impl: QSTileIntentUserInputHandlerImpl
+ ): QSTileIntentUserInputHandler
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 1334660..377803f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -85,8 +85,10 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.keyguard.ui.view.InWindowLauncherUnlockAnimationManager;
import com.android.systemui.model.SysUiState;
import com.android.systemui.navigationbar.NavigationBar;
import com.android.systemui.navigationbar.NavigationBarController;
@@ -102,6 +104,7 @@
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.system.QuickStepContract;
+import com.android.systemui.shared.system.smartspace.ISysuiUnlockAnimationController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.StatusBarWindowCallback;
@@ -109,8 +112,6 @@
import com.android.systemui.unfold.progress.UnfoldTransitionProgressForwarder;
import com.android.wm.shell.sysui.ShellInterface;
-import dagger.Lazy;
-
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
@@ -122,6 +123,8 @@
import javax.inject.Inject;
import javax.inject.Provider;
+import dagger.Lazy;
+
/**
* Class to send information from overview to launcher with a binder.
*/
@@ -160,7 +163,7 @@
private final ScreenshotHelper mScreenshotHelper;
private final CommandQueue mCommandQueue;
private final UserTracker mUserTracker;
- private final KeyguardUnlockAnimationController mSysuiUnlockAnimationController;
+ private final ISysuiUnlockAnimationController mSysuiUnlockAnimationController;
private final Optional<UnfoldTransitionProgressForwarder> mUnfoldTransitionProgressForwarder;
private final UiEventLogger mUiEventLogger;
private final DisplayTracker mDisplayTracker;
@@ -580,6 +583,7 @@
UiEventLogger uiEventLogger,
DisplayTracker displayTracker,
KeyguardUnlockAnimationController sysuiUnlockAnimationController,
+ InWindowLauncherUnlockAnimationManager inWindowLauncherUnlockAnimationManager,
AssistUtils assistUtils,
FeatureFlags featureFlags,
SceneContainerFlags sceneContainerFlags,
@@ -613,7 +617,12 @@
mUiEventLogger = uiEventLogger;
mDisplayTracker = displayTracker;
mUnfoldTransitionProgressForwarder = unfoldTransitionProgressForwarder;
- mSysuiUnlockAnimationController = sysuiUnlockAnimationController;
+
+ if (!featureFlags.isEnabled(Flags.KEYGUARD_WM_STATE_REFACTOR)) {
+ mSysuiUnlockAnimationController = sysuiUnlockAnimationController;
+ } else {
+ mSysuiUnlockAnimationController = inWindowLauncherUnlockAnimationManager;
+ }
dumpManager.registerDumpable(getClass().getSimpleName(), this);
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java
index 6fa592c..b30bc56 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java
@@ -16,7 +16,7 @@
package com.android.systemui.settings.brightness;
-import static com.android.systemui.flags.Flags.HAPTIC_BRIGHTNESS_SLIDER;
+import static com.android.systemui.Flags.hapticBrightnessSlider;
import android.content.Context;
import android.view.LayoutInflater;
@@ -32,7 +32,6 @@
import com.android.systemui.Gefingerpoken;
import com.android.systemui.classifier.Classifier;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.flags.FeatureFlagsClassic;
import com.android.systemui.haptics.slider.SeekableSliderEventProducer;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
@@ -280,7 +279,6 @@
private final FalsingManager mFalsingManager;
private final UiEventLogger mUiEventLogger;
- private final FeatureFlagsClassic mFeatureFlags;
private final VibratorHelper mVibratorHelper;
private final SystemClock mSystemClock;
private final CoroutineDispatcher mMainDispatcher;
@@ -292,12 +290,10 @@
UiEventLogger uiEventLogger,
VibratorHelper vibratorHelper,
SystemClock clock,
- FeatureFlagsClassic featureFlags,
@Main CoroutineDispatcher mainDispatcher,
ActivityStarter activityStarter) {
mFalsingManager = falsingManager;
mUiEventLogger = uiEventLogger;
- mFeatureFlags = featureFlags;
mVibratorHelper = vibratorHelper;
mSystemClock = clock;
mMainDispatcher = mainDispatcher;
@@ -320,7 +316,7 @@
root.setActivityStarter(mActivityStarter);
BrightnessSliderHapticPlugin plugin;
- if (mFeatureFlags.isEnabled(HAPTIC_BRIGHTNESS_SLIDER)) {
+ if (hapticBrightnessSlider()) {
plugin = new BrightnessSliderHapticPluginImpl(
mVibratorHelper,
mSystemClock,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt
index db0fa99..65b798a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt
@@ -251,7 +251,7 @@
val replacingIcons =
iconsDiff.groupReplacements.mapValuesNotNullTo(ArrayMap()) { (_, v) ->
- viewStore.iconView(v.notifKey)?.statusBarIcon
+ viewStore.iconView(v.notifKey).statusBarIcon
}
view.setReplacingIcons(replacingIcons)
@@ -264,7 +264,7 @@
.mapNotNull { key -> childrenByNotifKey[key] }
.forEach { child -> view.removeView(child) }
- val toAdd = iconsDiff.added.mapNotNull { viewStore.iconView(it.notifKey) }
+ val toAdd = iconsDiff.added.map { viewStore.iconView(it.notifKey) }
for ((i, sbiv) in toAdd.withIndex()) {
// The view might still be transiently added if it was just removed
// and added again
@@ -277,7 +277,7 @@
val childCount = view.childCount
for (i in 0 until childCount) {
val actual = view.getChildAt(i)
- val expected = viewStore.iconView(iconsData.visibleKeys[i].notifKey)!!
+ val expected = viewStore.iconView(iconsData.visibleKeys[i].notifKey)
if (actual === expected) {
continue
}
@@ -314,7 +314,7 @@
/** External storage for [StatusBarIconView] instances. */
fun interface IconViewStore {
- fun iconView(key: String): StatusBarIconView?
+ fun iconView(key: String): StatusBarIconView
}
@ColorInt private val DEFAULT_AOD_ICON_COLOR = Color.WHITE
@@ -326,8 +326,10 @@
constructor(
private val notifCollection: NotifCollection,
) : IconViewStore {
- override fun iconView(key: String): StatusBarIconView? =
- notifCollection.getEntry(key)?.icons?.shelfIcon
+ override fun iconView(key: String): StatusBarIconView {
+ val entry = notifCollection.getEntry(key) ?: error("No entry found for key: $key")
+ return entry.icons.shelfIcon ?: error("No shelf IconView found for key: $key")
+ }
}
/** [IconViewStore] for the always-on display. */
@@ -336,8 +338,10 @@
constructor(
private val notifCollection: NotifCollection,
) : IconViewStore {
- override fun iconView(key: String): StatusBarIconView? =
- notifCollection.getEntry(key)?.icons?.aodIcon
+ override fun iconView(key: String): StatusBarIconView {
+ val entry = notifCollection.getEntry(key) ?: error("No entry found for key: $key")
+ return entry.icons.aodIcon ?: error("No AOD IconView found for key: $key")
+ }
}
/** [IconViewStore] for the status bar. */
@@ -346,8 +350,10 @@
constructor(
private val notifCollection: NotifCollection,
) : IconViewStore {
- override fun iconView(key: String): StatusBarIconView? =
- notifCollection.getEntry(key)?.icons?.statusBarIcon
+ override fun iconView(key: String): StatusBarIconView {
+ val entry = notifCollection.getEntry(key) ?: error("No entry found for key: $key")
+ return entry.icons.statusBarIcon ?: error("No status bar IconView found for key: $key")
+ }
}
private val View.viewBounds: Rect
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/LockscreenFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/LockscreenFragment.java
index 771a8c8..799e5af 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/LockscreenFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/LockscreenFragment.java
@@ -48,6 +48,8 @@
import com.android.systemui.statusbar.policy.ExtensionController.TunerFactory;
import com.android.systemui.tuner.ShortcutParser.Shortcut;
import com.android.systemui.tuner.TunerService.Tunable;
+import com.android.tools.r8.keepanno.annotations.KeepTarget;
+import com.android.tools.r8.keepanno.annotations.UsesReflection;
import java.util.ArrayList;
import java.util.Map;
@@ -69,6 +71,9 @@
private TunerService mTunerService;
private Handler mHandler;
+ // aapt doesn't generate keep rules for android:fragment references in <Preference> tags, so
+ // explicitly declare references per usage in `R.xml.lockscreen_settings`. See b/120445169.
+ @UsesReflection(@KeepTarget(classConstant = ShortcutPicker.class))
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
mTunerService = Dependency.get(TunerService.class);
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/OtherPrefs.java b/packages/SystemUI/src/com/android/systemui/tuner/OtherPrefs.java
index 32b1b26..8d85999 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/OtherPrefs.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/OtherPrefs.java
@@ -19,8 +19,13 @@
import androidx.preference.PreferenceFragment;
import com.android.systemui.res.R;
+import com.android.tools.r8.keepanno.annotations.KeepTarget;
+import com.android.tools.r8.keepanno.annotations.UsesReflection;
public class OtherPrefs extends PreferenceFragment {
+ // aapt doesn't generate keep rules for android:fragment references in <Preference> tags, so
+ // explicitly declare references per usage in `R.xml.other_settings`. See b/120445169.
+ @UsesReflection(@KeepTarget(classConstant = PowerNotificationControlsFragment.class))
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.other_settings);
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
index 9cc526a..873b6d5 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
@@ -35,6 +35,8 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.res.R;
import com.android.systemui.shared.plugins.PluginPrefs;
+import com.android.tools.r8.keepanno.annotations.KeepTarget;
+import com.android.tools.r8.keepanno.annotations.UsesReflection;
public class TunerFragment extends PreferenceFragment {
@@ -77,6 +79,13 @@
getActivity().getActionBar().setDisplayHomeAsUpEnabled(true);
}
+ // aapt doesn't generate keep rules for android:fragment references in <Preference> tags, so
+ // explicitly declare references per usage in `R.xml.tuner_prefs`. See b/120445169.
+ @UsesReflection({
+ @KeepTarget(classConstant = LockscreenFragment.class),
+ @KeepTarget(classConstant = NavBarTuner.class),
+ @KeepTarget(classConstant = PluginFragment.class),
+ })
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.tuner_prefs);
diff --git a/packages/SystemUI/tests/src/com/android/TestMocksModule.kt b/packages/SystemUI/tests/src/com/android/TestMocksModule.kt
index 0cb913b..fd50f15 100644
--- a/packages/SystemUI/tests/src/com/android/TestMocksModule.kt
+++ b/packages/SystemUI/tests/src/com/android/TestMocksModule.kt
@@ -38,6 +38,7 @@
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.DarkIconDispatcher
import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.shared.system.ActivityManagerWrapper
import com.android.systemui.statusbar.LockscreenShadeTransitionController
import com.android.systemui.statusbar.NotificationListener
import com.android.systemui.statusbar.NotificationLockscreenUserManager
@@ -66,6 +67,7 @@
@Module(includes = [TestMocksModule.Bindings::class])
data class TestMocksModule(
@get:Provides val activityStarter: ActivityStarter = mock(),
+ @get:Provides val activityManagerWrapper: ActivityManagerWrapper = mock(),
@get:Provides val ambientState: AmbientState = mock(),
@get:Provides val bubbles: Optional<Bubbles> = Optional.of(mock()),
@get:Provides val darkIconDispatcher: DarkIconDispatcher = mock(),
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java
index aabe633..a38ba00 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java
@@ -43,6 +43,7 @@
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory;
+import com.android.systemui.keyguard.ui.view.InWindowLauncherUnlockAnimationManager;
import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel;
import com.android.systemui.log.LogBuffer;
import com.android.systemui.plugins.ClockAnimations;
@@ -204,7 +205,8 @@
mock(AlwaysOnDisplayNotificationIconViewStore.class),
KeyguardInteractorFactory.create(mFakeFeatureFlags).getKeyguardInteractor(),
mKeyguardClockInteractor,
- mFakeFeatureFlags
+ mFakeFeatureFlags,
+ mock(InWindowLauncherUnlockAnimationManager.class)
);
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
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 e3a2c59..d77a80a 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
@@ -31,42 +31,60 @@
import org.junit.runner.RunWith;
import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicBoolean;
/** Tests for {@link RadiiAnimator}. */
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class RadiiAnimatorTest extends SysuiTestCase {
float[] mResultRadii = new float[RadiiAnimator.RADII_COUNT];
+ final AtomicBoolean mAnimationStarted = new AtomicBoolean(false);
+ final AtomicBoolean mAnimationStopped = new AtomicBoolean(false);
+ final IRadiiAnimationListener mRadiiAnimationListener = new IRadiiAnimationListener() {
+ @Override
+ public void onRadiiAnimationUpdate(float[] radii) {
+ mResultRadii = radii;
+ }
+
+ @Override
+ public void onRadiiAnimationStart() {
+ mAnimationStarted.set(true);
+ }
+
+ @Override
+ public void onRadiiAnimationStop() {
+ mAnimationStopped.set(true);
+ }
+ };
@Test
public void constructor() {
final float[] radii = generateRadii(0.0f);
- final RadiiAnimator radiiAnimator = new RadiiAnimator(radii, newRadii -> {});
-
+ final RadiiAnimator radiiAnimator = new RadiiAnimator(radii, mRadiiAnimationListener);
assertThat(radiiAnimator.evaluate(0.0f)).isEqualTo(radii);
}
@Test
- public void skip_updates_to_end() {
+ public void skipAnimation_updatesToEnd() {
final float[] startRadii = generateRadii(0.0f);
final float[] endRadii = generateRadii(1.0f);
final RadiiAnimator radiiAnimator = setupAnimator(startRadii);
+ mAnimationStarted.set(false);
+ mAnimationStopped.set(false);
new Handler(Looper.getMainLooper()).post(() -> radiiAnimator.startAnimation(endRadii));
- TestUtils.waitForCondition(radiiAnimator::isStarted, "Animation did not start.");
+ TestUtils.waitForCondition(mAnimationStarted::get, "Animation did not start.");
TestUtils.waitForCondition(() -> Arrays.equals(radiiAnimator.evaluate(0.0f), startRadii)
- && Arrays.equals(radiiAnimator.evaluate(1.0f), endRadii),
+ && Arrays.equals(radiiAnimator.evaluate(1.0f), endRadii),
"Animator did not initialize to start and end values");
-
new Handler(Looper.getMainLooper()).post(radiiAnimator::skipAnimationToEnd);
- TestUtils.waitForCondition(
- () -> !radiiAnimator.isStarted(), "Animation did not end.");
+ TestUtils.waitForCondition(mAnimationStopped::get, "Animation did not stop.");
assertThat(mResultRadii).usingTolerance(0.001).containsExactly(endRadii);
}
@Test
- public void animation_can_repeat() {
+ public void finishedAnimation_canRepeat() {
final float[] startRadii = generateRadii(0.0f);
final float[] midRadii = generateRadii(1.0f);
final float[] endRadii = generateRadii(2.0f);
@@ -88,15 +106,15 @@
private RadiiAnimator setupAnimator(float[] startRadii) {
mResultRadii = new float[RadiiAnimator.RADII_COUNT];
- return new RadiiAnimator(startRadii,
- newRadii -> mResultRadii = newRadii);
+ return new RadiiAnimator(startRadii, mRadiiAnimationListener);
}
private void playAndSkipAnimation(RadiiAnimator animator, float[] endRadii) {
+ mAnimationStarted.set(false);
+ mAnimationStopped.set(false);
new Handler(Looper.getMainLooper()).post(() -> animator.startAnimation(endRadii));
- TestUtils.waitForCondition(animator::isStarted, "Animation did not start.");
+ TestUtils.waitForCondition(mAnimationStarted::get, "Animation did not start.");
new Handler(Looper.getMainLooper()).post(animator::skipAnimationToEnd);
- TestUtils.waitForCondition(
- () -> !animator.isStarted(), "Animation did not end.");
+ TestUtils.waitForCondition(mAnimationStopped::get, "Animation did not stop.");
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
index ef06e0e..b4b02a2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
@@ -52,7 +52,6 @@
import androidx.test.filters.SmallTest
import com.airbnb.lottie.LottieAnimationView
import com.android.keyguard.KeyguardUpdateMonitor
-import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.SysuiTestableContext
import com.android.systemui.biometrics.data.repository.FakeDisplayStateRepository
@@ -64,6 +63,7 @@
import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.res.R
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
@@ -111,6 +111,7 @@
@Mock lateinit var displayManager: DisplayManager
@Mock lateinit var handler: Handler
@Mock lateinit var dumpManager: DumpManager
+ @Mock lateinit var fpsUnlockTracker: FpsUnlockTracker
@Captor lateinit var overlayCaptor: ArgumentCaptor<View>
@Captor lateinit var overlayViewParamsCaptor: ArgumentCaptor<WindowManager.LayoutParams>
@@ -269,7 +270,8 @@
handler,
alternateBouncerInteractor,
TestCoroutineScope(),
- dumpManager
+ dumpManager,
+ fpsUnlockTracker
)
displayStateRepository.setIsInRearDisplayMode(inRearDisplayMode)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index cbde78b..675ca63 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -235,6 +235,8 @@
private InputManager mInputManager;
@Mock
private ViewRootImpl mViewRootImpl;
+ @Mock
+ private FpsUnlockTracker mFpsUnlockTracker;
@Before
public void setUp() {
@@ -326,7 +328,8 @@
mock(KeyguardFaceAuthInteractor.class),
mUdfpsKeyguardAccessibilityDelegate,
mUdfpsKeyguardViewModels,
- mSelectedUserInteractor
+ mSelectedUserInteractor,
+ mFpsUnlockTracker
);
verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture());
mOverlayController = mOverlayCaptor.getValue();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/ui/view/MirroringConfirmationDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/display/ui/view/MirroringConfirmationDialogTest.kt
index dcc15ae..b25fb6e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/display/ui/view/MirroringConfirmationDialogTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/display/ui/view/MirroringConfirmationDialogTest.kt
@@ -20,8 +20,8 @@
import android.testing.TestableLooper
import android.view.View
import androidx.test.filters.SmallTest
-import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.res.R
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.mock
import org.junit.After
@@ -45,7 +45,13 @@
fun setUp() {
MockitoAnnotations.initMocks(this)
- dialog = MirroringConfirmationDialog(context, onStartMirroringCallback, onCancelCallback)
+ dialog =
+ MirroringConfirmationDialog(
+ context,
+ onStartMirroringCallback,
+ onCancelCallback,
+ navbarBottomInsetsProvider = { 0 },
+ )
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorTest.kt
index 4f6ec71..b439fcf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorTest.kt
@@ -18,23 +18,34 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.SysUITestModule
+import com.android.TestMocksModule
+import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectValues
-import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.data.repository.FakeKeyguardSurfaceBehindRepository
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.InWindowLauncherUnlockAnimationRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
-import com.android.systemui.power.domain.interactor.PowerInteractorFactory
-import com.android.systemui.shade.data.repository.FakeShadeRepository
+import com.android.systemui.keyguard.util.mockTopActivityClassName
+import com.android.systemui.shared.system.ActivityManagerWrapper
+import dagger.BindsInstance
+import dagger.Component
import dagger.Lazy
import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertTrue
import junit.framework.Assert.fail
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@@ -49,20 +60,30 @@
underTest
}
+ private lateinit var testComponent: TestComponent
+ @Mock private lateinit var activityManagerWrapper: ActivityManagerWrapper
+
+ private var topActivityClassName = "launcher"
+
@Before
override fun setUp() {
super.setUp()
+ MockitoAnnotations.initMocks(this)
- underTest =
- FromLockscreenTransitionInteractor(
- transitionRepository = super.transitionRepository,
- transitionInteractor = super.transitionInteractor,
- scope = super.testScope.backgroundScope,
- keyguardInteractor = super.keyguardInteractor,
- flags = FakeFeatureFlags(),
- shadeRepository = FakeShadeRepository(),
- powerInteractor = PowerInteractorFactory.create().powerInteractor,
- )
+ testComponent =
+ DaggerFromLockscreenTransitionInteractorTest_TestComponent.factory()
+ .create(
+ test = this,
+ mocks =
+ TestMocksModule(
+ activityManagerWrapper = activityManagerWrapper,
+ ),
+ )
+ underTest = testComponent.underTest
+ testScope = testComponent.testScope
+ transitionRepository = testComponent.transitionRepository
+
+ activityManagerWrapper.mockTopActivityClassName(topActivityClassName)
}
@Test
@@ -189,4 +210,73 @@
fail("surfaceBehindModel was unexpectedly null.")
}
}
+
+ @Test
+ fun testSurfaceBehindModel_alpha1_whenTransitioningWithInWindowAnimation() =
+ testScope.runTest {
+ testComponent.inWindowLauncherUnlockAnimationRepository.setLauncherActivityClass(
+ topActivityClassName
+ )
+ runCurrent()
+
+ val values by collectValues(underTest.surfaceBehindModel)
+ runCurrent()
+
+ transitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.STARTED,
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ )
+ )
+ runCurrent()
+
+ assertEquals(1f, values[values.size - 1]?.alpha)
+ }
+
+ @Test
+ fun testSurfaceBehindModel_alphaZero_whenNotTransitioningWithInWindowAnimation() =
+ testScope.runTest {
+ testComponent.inWindowLauncherUnlockAnimationRepository.setLauncherActivityClass(
+ "not_launcher"
+ )
+ runCurrent()
+
+ val values by collectValues(underTest.surfaceBehindModel)
+ runCurrent()
+
+ transitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.STARTED,
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ )
+ )
+ runCurrent()
+
+ assertEquals(0f, values[values.size - 1]?.alpha)
+ }
+
+ @SysUISingleton
+ @Component(
+ modules =
+ [
+ SysUITestModule::class,
+ ]
+ )
+ interface TestComponent {
+ val underTest: FromLockscreenTransitionInteractor
+ val testScope: TestScope
+ val transitionRepository: FakeKeyguardTransitionRepository
+ val surfaceBehindRepository: FakeKeyguardSurfaceBehindRepository
+ val inWindowLauncherUnlockAnimationRepository: InWindowLauncherUnlockAnimationRepository
+
+ @Component.Factory
+ interface Factory {
+ fun create(
+ @BindsInstance test: SysuiTestCase,
+ mocks: TestMocksModule,
+ ): TestComponent
+ }
+ }
}
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
new file mode 100644
index 0000000..7fb0dd5
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/InWindowLauncherUnlockAnimationInteractorTest.kt
@@ -0,0 +1,454 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.domain.interactor
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.SysUITestModule
+import com.android.TestMocksModule
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.data.repository.FakeKeyguardSurfaceBehindRepository
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.InWindowLauncherUnlockAnimationRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.keyguard.util.mockTopActivityClassName
+import com.android.systemui.shared.system.ActivityManagerWrapper
+import dagger.BindsInstance
+import dagger.Component
+import junit.framework.Assert.assertEquals
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@kotlinx.coroutines.ExperimentalCoroutinesApi
+class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() {
+ private lateinit var underTest: InWindowLauncherUnlockAnimationInteractor
+
+ private lateinit var testComponent: TestComponent
+ private lateinit var testScope: TestScope
+ private lateinit var transitionRepository: FakeKeyguardTransitionRepository
+ @Mock private lateinit var activityManagerWrapper: ActivityManagerWrapper
+
+ private val launcherClassName = "launcher"
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ testComponent =
+ DaggerInWindowLauncherUnlockAnimationInteractorTest_TestComponent.factory()
+ .create(
+ test = this,
+ mocks =
+ TestMocksModule(
+ activityManagerWrapper = activityManagerWrapper,
+ ),
+ )
+ underTest = testComponent.underTest
+ testScope = testComponent.testScope
+ transitionRepository = testComponent.transitionRepository
+
+ activityManagerWrapper.mockTopActivityClassName(launcherClassName)
+ }
+
+ @Test
+ fun testTransitioningToGoneWithInWindowAnimation_trueIfTopActivityIsLauncher_andTransitioningToGone() =
+ testScope.runTest {
+ val values by collectValues(underTest.transitioningToGoneWithInWindowAnimation)
+ runCurrent()
+
+ assertEquals(
+ listOf(
+ false, // False by default.
+ ),
+ values
+ )
+
+ // Put launcher on top
+ testComponent.inWindowLauncherUnlockAnimationRepository.setLauncherActivityClass(
+ launcherClassName
+ )
+ activityManagerWrapper.mockTopActivityClassName(launcherClassName)
+ runCurrent()
+
+ // Should still be false since we're not transitioning to GONE.
+ assertEquals(
+ listOf(
+ false, // False by default.
+ ),
+ values
+ )
+
+ transitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.STARTED,
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ )
+ )
+ runCurrent()
+
+ assertEquals(
+ listOf(
+ false,
+ true, // -> GONE + launcher is behind
+ ),
+ values
+ )
+
+ activityManagerWrapper.mockTopActivityClassName("not_launcher")
+ transitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.RUNNING,
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ )
+ )
+ runCurrent()
+
+ assertEquals(
+ listOf(
+ false,
+ true, // Top activity should be sampled, if it changes midway it should not
+ // matter.
+ ),
+ values
+ )
+
+ transitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.FINISHED,
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ )
+ )
+ runCurrent()
+
+ assertEquals(
+ listOf(
+ false,
+ true,
+ false, // False once we're not transitioning anymore.
+ ),
+ values
+ )
+ }
+
+ @Test
+ fun testTransitioningToGoneWithInWindowAnimation_falseIfTopActivityIsLauncherPartwayThrough() =
+ testScope.runTest {
+ val values by collectValues(underTest.transitioningToGoneWithInWindowAnimation)
+ runCurrent()
+
+ assertEquals(
+ listOf(
+ false, // False by default.
+ ),
+ values
+ )
+
+ // Put not launcher on top
+ testComponent.inWindowLauncherUnlockAnimationRepository.setLauncherActivityClass(
+ launcherClassName
+ )
+ activityManagerWrapper.mockTopActivityClassName("not_launcher")
+ runCurrent()
+
+ assertEquals(
+ listOf(
+ false,
+ ),
+ values
+ )
+
+ transitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.STARTED,
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ )
+ )
+ runCurrent()
+
+ assertEquals(
+ listOf(
+ false,
+ ),
+ values
+ )
+
+ activityManagerWrapper.mockTopActivityClassName(launcherClassName)
+ transitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.RUNNING,
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ )
+ )
+ runCurrent()
+
+ assertEquals(
+ listOf(
+ false,
+ ),
+ values
+ )
+
+ transitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.FINISHED,
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ )
+ )
+ runCurrent()
+
+ assertEquals(
+ listOf(
+ false,
+ ),
+ values
+ )
+ }
+
+ @Test
+ fun testTransitioningToGoneWithInWindowAnimation_falseIfTopActivityIsLauncherWhileNotTransitioningToGone() =
+ testScope.runTest {
+ val values by collectValues(underTest.transitioningToGoneWithInWindowAnimation)
+ runCurrent()
+
+ assertEquals(
+ listOf(
+ false, // False by default.
+ ),
+ values
+ )
+
+ // Put launcher on top
+ testComponent.inWindowLauncherUnlockAnimationRepository.setLauncherActivityClass(
+ launcherClassName
+ )
+ activityManagerWrapper.mockTopActivityClassName(launcherClassName)
+ runCurrent()
+
+ assertEquals(
+ listOf(
+ false,
+ ),
+ values
+ )
+
+ transitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.STARTED,
+ from = KeyguardState.AOD,
+ to = KeyguardState.LOCKSCREEN,
+ )
+ )
+ runCurrent()
+
+ assertEquals(
+ listOf(
+ false,
+ ),
+ values
+ )
+ }
+
+ @Test
+ fun testShouldStartInWindowAnimation_trueOnceSurfaceAvailable_falseWhenTransitionEnds() =
+ testScope.runTest {
+ val values by collectValues(underTest.shouldStartInWindowAnimation)
+ runCurrent()
+
+ assertEquals(
+ listOf(
+ false, // False by default.
+ ),
+ values
+ )
+
+ // Put Launcher on top and begin transitioning to GONE.
+ testComponent.inWindowLauncherUnlockAnimationRepository.setLauncherActivityClass(
+ launcherClassName
+ )
+ activityManagerWrapper.mockTopActivityClassName(launcherClassName)
+ transitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.STARTED,
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ )
+ )
+ runCurrent()
+
+ assertEquals(
+ listOf(
+ false,
+ ),
+ values
+ )
+
+ testComponent.surfaceBehindRepository.setSurfaceRemoteAnimationTargetAvailable(true)
+ runCurrent()
+
+ assertEquals(
+ listOf(
+ false,
+ true, // The surface is now available, so we should start the animation.
+ ),
+ values
+ )
+
+ transitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.FINISHED,
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ )
+ )
+ runCurrent()
+
+ assertEquals(
+ listOf(
+ false,
+ true,
+ false,
+ ),
+ values
+ )
+ }
+
+ @Test
+ fun testShouldStartInWindowAnimation_neverTrueIfSurfaceNotAvailable() =
+ testScope.runTest {
+ val values by collectValues(underTest.shouldStartInWindowAnimation)
+ runCurrent()
+
+ assertEquals(
+ listOf(
+ false, // False by default.
+ ),
+ values
+ )
+
+ // Put Launcher on top and begin transitioning to GONE.
+ testComponent.inWindowLauncherUnlockAnimationRepository.setLauncherActivityClass(
+ launcherClassName
+ )
+ activityManagerWrapper.mockTopActivityClassName(launcherClassName)
+ transitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.STARTED,
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ )
+ )
+ transitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.FINISHED,
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ )
+ )
+ runCurrent()
+
+ assertEquals(
+ listOf(
+ false,
+ ),
+ values
+ )
+ }
+
+ @Test
+ fun testShouldStartInWindowAnimation_falseIfSurfaceAvailable_afterTransitionInterrupted() =
+ testScope.runTest {
+ val values by collectValues(underTest.shouldStartInWindowAnimation)
+ runCurrent()
+
+ assertEquals(
+ listOf(
+ false, // False by default.
+ ),
+ values
+ )
+
+ // Put Launcher on top and begin transitioning to GONE.
+ testComponent.inWindowLauncherUnlockAnimationRepository.setLauncherActivityClass(
+ launcherClassName
+ )
+ activityManagerWrapper.mockTopActivityClassName(launcherClassName)
+ transitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.STARTED,
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ )
+ )
+ transitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.STARTED,
+ from = KeyguardState.GONE,
+ to = KeyguardState.AOD,
+ )
+ )
+ testComponent.surfaceBehindRepository.setSurfaceRemoteAnimationTargetAvailable(true)
+ runCurrent()
+
+ assertEquals(
+ listOf(
+ false,
+ ),
+ values
+ )
+ }
+
+ @SysUISingleton
+ @Component(
+ modules =
+ [
+ SysUITestModule::class,
+ ]
+ )
+ interface TestComponent {
+ val underTest: InWindowLauncherUnlockAnimationInteractor
+ val testScope: TestScope
+ val transitionRepository: FakeKeyguardTransitionRepository
+ val surfaceBehindRepository: FakeKeyguardSurfaceBehindRepository
+ val inWindowLauncherUnlockAnimationRepository: InWindowLauncherUnlockAnimationRepository
+
+ @Component.Factory
+ interface Factory {
+ fun create(
+ @BindsInstance test: SysuiTestCase,
+ mocks: TestMocksModule,
+ ): TestComponent
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTestCase.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTestCase.kt
index 8db19ae..339fd22 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTestCase.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTestCase.kt
@@ -26,7 +26,7 @@
open class KeyguardTransitionInteractorTestCase : SysuiTestCase() {
val testDispatcher = StandardTestDispatcher()
- val testScope = TestScope(testDispatcher)
+ var testScope = TestScope(testDispatcher)
lateinit var keyguardRepository: FakeKeyguardRepository
lateinit var transitionRepository: FakeKeyguardTransitionRepository
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 275ac80..c292102 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
@@ -27,7 +27,9 @@
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.repository.FakeCommandQueue
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.FakeKeyguardSurfaceBehindRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.InWindowLauncherUnlockAnimationRepository
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
import com.android.systemui.keyguard.shared.model.DozeStateModel
import com.android.systemui.keyguard.shared.model.DozeTransitionModel
@@ -44,6 +46,7 @@
import com.android.systemui.shade.domain.model.ShadeModel
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.mockito.withArgCaptor
import com.google.common.truth.Truth.assertThat
@@ -147,6 +150,15 @@
flags = featureFlags,
shadeRepository = shadeRepository,
powerInteractor = powerInteractor,
+ inWindowLauncherUnlockAnimationInteractor = {
+ InWindowLauncherUnlockAnimationInteractor(
+ InWindowLauncherUnlockAnimationRepository(),
+ testScope,
+ transitionInteractor,
+ { FakeKeyguardSurfaceBehindRepository() },
+ mock(),
+ )
+ },
)
.apply { start() }
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
new file mode 100644
index 0000000..570dfb3
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/InWindowLauncherUnlockAnimationManagerTest.kt
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.binder
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.SysUITestModule
+import com.android.systemui.SysuiTestCase
+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.util.mockito.any
+import dagger.BindsInstance
+import dagger.Component
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.anyBoolean
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyNoMoreInteractions
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@kotlinx.coroutines.ExperimentalCoroutinesApi
+class InWindowLauncherUnlockAnimationManagerTest : SysuiTestCase() {
+ private lateinit var underTest: InWindowLauncherUnlockAnimationManager
+
+ private lateinit var testComponent: TestComponent
+ private lateinit var testScope: TestScope
+
+ @Mock private lateinit var launcherUnlockAnimationController: ILauncherUnlockAnimationController
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ testComponent =
+ DaggerInWindowLauncherUnlockAnimationManagerTest_TestComponent.factory()
+ .create(
+ test = this,
+ )
+ underTest = testComponent.underTest
+ testScope = testComponent.testScope
+
+ underTest.setLauncherUnlockController("launcherClass", launcherUnlockAnimationController)
+ }
+
+ @Test
+ fun testPrepareForUnlock_calledOnlyOnce() =
+ testScope.runTest {
+ underTest.prepareForUnlock()
+ underTest.prepareForUnlock()
+
+ verify(launcherUnlockAnimationController)
+ .prepareForUnlock(anyBoolean(), any(), anyInt())
+ }
+
+ @Test
+ fun testPlayUnlockAnimation_onlyCalledIfPrepared() =
+ testScope.runTest {
+ underTest.playUnlockAnimation(true, 200, 0)
+ verify(launcherUnlockAnimationController, never())
+ .playUnlockAnimation(any(), any(), any())
+ }
+
+ @Test
+ fun testForceUnlocked_ifPreparedButNeverStarted() =
+ testScope.runTest {
+ underTest.prepareForUnlock()
+ underTest.ensureUnlockedOrAnimatingUnlocked()
+
+ verify(launcherUnlockAnimationController).setUnlockAmount(1f, true)
+ }
+
+ @Test
+ fun testForceUnlocked_ifManualUnlockAmountLessThan1() =
+ testScope.runTest {
+ underTest.prepareForUnlock()
+ underTest.setUnlockAmount(0.5f, false)
+ underTest.ensureUnlockedOrAnimatingUnlocked()
+
+ verify(launcherUnlockAnimationController).prepareForUnlock(any(), any(), any())
+ verify(launcherUnlockAnimationController).setUnlockAmount(0.5f, false)
+ verify(launcherUnlockAnimationController).setUnlockAmount(1f, true)
+ verifyNoMoreInteractions(launcherUnlockAnimationController)
+ }
+
+ @Test
+ fun testDoesNotForceUnlocked_ifNeverPrepared() =
+ testScope.runTest {
+ underTest.ensureUnlockedOrAnimatingUnlocked()
+
+ verifyNoMoreInteractions(launcherUnlockAnimationController)
+ }
+
+ @SysUISingleton
+ @Component(
+ modules =
+ [
+ SysUITestModule::class,
+ ]
+ )
+ interface TestComponent {
+ val underTest: InWindowLauncherUnlockAnimationManager
+ val testScope: TestScope
+
+ @Component.Factory
+ interface Factory {
+ fun create(
+ @BindsInstance test: SysuiTestCase,
+ ): TestComponent
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/util/ActivityManagerWrapperMock.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/util/ActivityManagerWrapperMock.kt
new file mode 100644
index 0000000..2cb7e65
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/util/ActivityManagerWrapperMock.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyguard.util
+
+import android.app.ActivityManager
+import android.content.ComponentName
+import com.android.systemui.shared.system.ActivityManagerWrapper
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+
+/**
+ * Configures an ActivityManagerWrapper mock to return the given class name whenever we ask for the
+ * running task's top activity class name.
+ */
+fun ActivityManagerWrapper.mockTopActivityClassName(name: String) {
+ val topActivityMock = mock<ComponentName>().apply { whenever(className).thenReturn(name) }
+
+ whenever(runningTask)
+ .thenReturn(ActivityManager.RunningTaskInfo().apply { topActivity = topActivityMock })
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerTest.kt
index 95ee3b7..bd1c310 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerTest.kt
@@ -41,7 +41,7 @@
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
- underTest = QSTileIntentUserInputHandler(activityStarted)
+ underTest = QSTileIntentUserInputHandlerImpl(activityStarted)
}
@Test
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 6d358db..70a48f5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt
@@ -30,8 +30,10 @@
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.KeyguardUnlockAnimationController
import com.android.systemui.keyguard.WakefulnessLifecycle
+import com.android.systemui.keyguard.ui.view.InWindowLauncherUnlockAnimationManager
import com.android.systemui.model.SysUiState
import com.android.systemui.navigationbar.NavigationBarController
import com.android.systemui.navigationbar.NavigationModeController
@@ -100,6 +102,9 @@
@Mock private lateinit var userTracker: UserTracker
@Mock private lateinit var uiEventLogger: UiEventLogger
@Mock private lateinit var sysuiUnlockAnimationController: KeyguardUnlockAnimationController
+ @Mock
+ private lateinit var inWindowLauncherUnlockAnimationManager:
+ InWindowLauncherUnlockAnimationManager
@Mock private lateinit var assistUtils: AssistUtils
@Mock
private lateinit var unfoldTransitionProgressForwarder:
@@ -126,6 +131,7 @@
whenever(packageManager.resolveServiceAsUser(any(), anyInt(), anyInt()))
.thenReturn(mock(ResolveInfo::class.java))
+ featureFlags.set(Flags.KEYGUARD_WM_STATE_REFACTOR, false)
subject =
OverviewProxyService(
context,
@@ -144,6 +150,7 @@
uiEventLogger,
displayTracker,
sysuiUnlockAnimationController,
+ inWindowLauncherUnlockAnimationManager,
assistUtils,
featureFlags,
FakeSceneContainerFlags(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
index 55a44ae..a7e1e9d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
@@ -59,9 +59,12 @@
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.data.repository.FakeCommandQueue;
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository;
+import com.android.systemui.keyguard.data.repository.FakeKeyguardSurfaceBehindRepository;
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository;
+import com.android.systemui.keyguard.data.repository.InWindowLauncherUnlockAnimationRepository;
import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor;
import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor;
+import com.android.systemui.keyguard.domain.interactor.InWindowLauncherUnlockAnimationInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -76,6 +79,7 @@
import com.android.systemui.scene.shared.logger.SceneLogger;
import com.android.systemui.shade.data.repository.FakeShadeRepository;
import com.android.systemui.shade.domain.interactor.ShadeInteractor;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFlagsRepository;
@@ -207,7 +211,16 @@
keyguardInteractor,
featureFlags,
shadeRepository,
- powerInteractor);
+ powerInteractor,
+ () ->
+ new InWindowLauncherUnlockAnimationInteractor(
+ new InWindowLauncherUnlockAnimationRepository(),
+ mTestScope.getBackgroundScope(),
+ keyguardTransitionInteractor,
+ () -> new FakeKeyguardSurfaceBehindRepository(),
+ mock(ActivityManagerWrapper.class)
+ )
+ );
mFromPrimaryBouncerTransitionInteractor = new FromPrimaryBouncerTransitionInteractor(
keyguardTransitionRepository,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
index d4b35a9..6d04887 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
@@ -45,9 +45,12 @@
import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.keyguard.data.repository.FakeCommandQueue;
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository;
+import com.android.systemui.keyguard.data.repository.FakeKeyguardSurfaceBehindRepository;
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository;
+import com.android.systemui.keyguard.data.repository.InWindowLauncherUnlockAnimationRepository;
import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor;
import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor;
+import com.android.systemui.keyguard.domain.interactor.InWindowLauncherUnlockAnimationInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
@@ -68,6 +71,7 @@
import com.android.systemui.shade.data.repository.FakeShadeRepository;
import com.android.systemui.shade.domain.interactor.ShadeInteractor;
import com.android.systemui.shade.transition.ShadeTransitionController;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShadeDepthController;
@@ -241,7 +245,16 @@
keyguardInteractor,
featureFlags,
mShadeRepository,
- powerInteractor);
+ powerInteractor,
+ () ->
+ new InWindowLauncherUnlockAnimationInteractor(
+ new InWindowLauncherUnlockAnimationRepository(),
+ mTestScope.getBackgroundScope(),
+ keyguardTransitionInteractor,
+ () -> new FakeKeyguardSurfaceBehindRepository(),
+ mock(ActivityManagerWrapper.class)
+ )
+ );
mFromPrimaryBouncerTransitionInteractor = new FromPrimaryBouncerTransitionInteractor(
keyguardTransitionRepository,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
index d6dfc5e..4b79a49 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
@@ -29,9 +29,12 @@
import com.android.systemui.flags.FakeFeatureFlagsClassic
import com.android.systemui.keyguard.data.repository.FakeCommandQueue
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.FakeKeyguardSurfaceBehindRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.InWindowLauncherUnlockAnimationRepository
import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor
import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor
+import com.android.systemui.keyguard.domain.interactor.InWindowLauncherUnlockAnimationInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.plugins.statusbar.StatusBarStateController
@@ -131,7 +134,16 @@
keyguardInteractor,
featureFlags,
shadeRepository,
- powerInteractor)
+ powerInteractor,
+ {
+ InWindowLauncherUnlockAnimationInteractor(
+ InWindowLauncherUnlockAnimationRepository(),
+ testScope,
+ keyguardTransitionInteractor,
+ { FakeKeyguardSurfaceBehindRepository() },
+ mock(),
+ )
+ })
fromPrimaryBouncerTransitionInteractor = FromPrimaryBouncerTransitionInteractor(
keyguardTransitionRepository,
keyguardTransitionInteractor,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index 2e191b1..4f19742 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -102,9 +102,12 @@
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.data.repository.FakeCommandQueue;
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository;
+import com.android.systemui.keyguard.data.repository.FakeKeyguardSurfaceBehindRepository;
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository;
+import com.android.systemui.keyguard.data.repository.InWindowLauncherUnlockAnimationRepository;
import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor;
import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor;
+import com.android.systemui.keyguard.domain.interactor.InWindowLauncherUnlockAnimationInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.model.SysUiState;
@@ -126,6 +129,7 @@
import com.android.systemui.shade.ShadeWindowLogger;
import com.android.systemui.shade.data.repository.FakeShadeRepository;
import com.android.systemui.shade.domain.interactor.ShadeInteractor;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.NotificationEntryHelper;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -429,7 +433,16 @@
keyguardInteractor,
featureFlags,
shadeRepository,
- powerInteractor);
+ powerInteractor,
+ () ->
+ new InWindowLauncherUnlockAnimationInteractor(
+ new InWindowLauncherUnlockAnimationRepository(),
+ mTestScope.getBackgroundScope(),
+ keyguardTransitionInteractor,
+ () -> new FakeKeyguardSurfaceBehindRepository(),
+ mock(ActivityManagerWrapper.class)
+ )
+ );
mFromPrimaryBouncerTransitionInteractor = new FromPrimaryBouncerTransitionInteractor(
keyguardTransitionRepository,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/FakeKeyguardDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/FakeKeyguardDataLayerModule.kt
index abf72af..6838e76 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/FakeKeyguardDataLayerModule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/FakeKeyguardDataLayerModule.kt
@@ -17,6 +17,7 @@
import com.android.systemui.keyguard.data.repository.FakeCommandQueueModule
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepositoryModule
+import com.android.systemui.keyguard.data.repository.FakeKeyguardSurfaceBehindRepositoryModule
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepositoryModule
import dagger.Module
@@ -26,6 +27,7 @@
FakeCommandQueueModule::class,
FakeKeyguardRepositoryModule::class,
FakeKeyguardTransitionRepositoryModule::class,
+ FakeKeyguardSurfaceBehindRepositoryModule::class,
]
)
object FakeKeyguardDataLayerModule
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardSurfaceBehindRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardSurfaceBehindRepository.kt
index 823f29a..70de05f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardSurfaceBehindRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardSurfaceBehindRepository.kt
@@ -16,14 +16,31 @@
package com.android.systemui.keyguard.data.repository
+import com.android.systemui.dagger.SysUISingleton
+import dagger.Binds
+import dagger.Module
+import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
-class FakeKeyguardSurfaceBehindRepository : KeyguardSurfaceBehindRepository {
+@SysUISingleton
+class FakeKeyguardSurfaceBehindRepository @Inject constructor() : KeyguardSurfaceBehindRepository {
private val _isAnimatingSurface = MutableStateFlow(false)
override val isAnimatingSurface = _isAnimatingSurface.asStateFlow()
+ private val _isSurfaceAvailable = MutableStateFlow(false)
+ override val isSurfaceRemoteAnimationTargetAvailable = _isSurfaceAvailable.asStateFlow()
+
override fun setAnimatingSurface(animating: Boolean) {
_isAnimatingSurface.value = animating
}
+
+ override fun setSurfaceRemoteAnimationTargetAvailable(available: Boolean) {
+ _isSurfaceAvailable.value = available
+ }
+}
+
+@Module
+interface FakeKeyguardSurfaceBehindRepositoryModule {
+ @Binds fun bindFake(fake: FakeKeyguardSurfaceBehindRepository): KeyguardSurfaceBehindRepository
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/actions/FakeQSTileIntentUserInputHandler.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/actions/FakeQSTileIntentUserInputHandler.kt
new file mode 100644
index 0000000..1185f2e
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/actions/FakeQSTileIntentUserInputHandler.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.base.actions
+
+import android.app.PendingIntent
+import android.content.Intent
+import android.view.View
+
+/**
+ * Fake implementation of [QSTileIntentUserInputHandler] interface. Consider using this alongside
+ * [QSTileIntentUserInputHandlerSubject].
+ */
+class FakeQSTileIntentUserInputHandler : QSTileIntentUserInputHandler {
+
+ val handledInputs: List<Input>
+ get() = mutableInputs
+
+ private val mutableInputs = mutableListOf<Input>()
+
+ override fun handle(view: View?, intent: Intent) {
+ mutableInputs.add(Input.Intent(view, intent))
+ }
+
+ override fun handle(view: View?, pendingIntent: PendingIntent) {
+ mutableInputs.add(Input.PendingIntent(view, pendingIntent))
+ }
+
+ sealed interface Input {
+ data class Intent(val view: View?, val intent: android.content.Intent) : Input
+ data class PendingIntent(val view: View?, val pendingIntent: android.app.PendingIntent) :
+ Input
+ }
+}
+
+val FakeQSTileIntentUserInputHandler.intentInputs
+ get() = handledInputs.mapNotNull { it as? FakeQSTileIntentUserInputHandler.Input.Intent }
+val FakeQSTileIntentUserInputHandler.pendingIntentInputs
+ get() = handledInputs.mapNotNull { it as? FakeQSTileIntentUserInputHandler.Input.PendingIntent }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerSubject.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerSubject.kt
new file mode 100644
index 0000000..e09f280
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerSubject.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.base.actions
+
+import com.google.common.truth.FailureMetadata
+import com.google.common.truth.Subject
+import com.google.common.truth.Truth
+
+/** [Truth] [Subject] to assert inputs handled by [FakeQSTileIntentUserInputHandler] */
+class QSTileIntentUserInputHandlerSubject
+private constructor(
+ failureMetadata: FailureMetadata,
+ private val subject: FakeQSTileIntentUserInputHandler
+) : Subject(failureMetadata, subject) {
+
+ fun handledOneIntentInput(
+ intentAssertions: (FakeQSTileIntentUserInputHandler.Input.Intent) -> Unit = {},
+ ) {
+ // check that there are no other inputs
+ check("handledInputs").that(subject.handledInputs).hasSize(1)
+ // check there is an intent input
+ check("intentInputs").that(subject.intentInputs).hasSize(1)
+
+ intentAssertions(subject.intentInputs.first())
+ }
+
+ fun handledOnePendingIntentInput(
+ intentAssertions: (FakeQSTileIntentUserInputHandler.Input.PendingIntent) -> Unit = {},
+ ) {
+ // check that there are no other inputs
+ check("handledInputs").that(subject.handledInputs).hasSize(1)
+ // check there is a pending intent input
+ check("intentInputs").that(subject.pendingIntentInputs).hasSize(1)
+
+ intentAssertions(subject.pendingIntentInputs.first())
+ }
+
+ fun handledNoInputs() {
+ check("handledInputs").that(subject.handledInputs).isEmpty()
+ }
+
+ companion object {
+
+ /**
+ * [Truth.assertThat]-like factory to initialize the assertion. Example:
+ * ```
+ * assertThat(inputHandler).handledOneIntentInput {
+ * assertThat(it.intent.action).isEqualTo("action.Test")
+ * }
+ * ```
+ */
+ fun assertThat(
+ handler: FakeQSTileIntentUserInputHandler
+ ): QSTileIntentUserInputHandlerSubject =
+ Truth.assertAbout {
+ failureMetadata: FailureMetadata,
+ subject: FakeQSTileIntentUserInputHandler ->
+ QSTileIntentUserInputHandlerSubject(failureMetadata, subject)
+ }
+ .that(handler)
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/interactor/QSTileInputTestKtx.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/interactor/QSTileInputTestKtx.kt
new file mode 100644
index 0000000..832b07a
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/interactor/QSTileInputTestKtx.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.base.interactor
+
+import android.os.UserHandle
+import android.view.View
+import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction
+
+object QSTileInputTestKtx {
+
+ fun <T> click(
+ data: T,
+ user: UserHandle = UserHandle.CURRENT,
+ view: View? = null,
+ ): QSTileInput<T> = QSTileInput(user, QSTileUserAction.Click(view), data)
+
+ fun <T> longClick(
+ data: T,
+ user: UserHandle = UserHandle.CURRENT,
+ view: View? = null,
+ ): QSTileInput<T> = QSTileInput(user, QSTileUserAction.LongClick(view), data)
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
index 10110e2..f97d6b3 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
@@ -16,6 +16,7 @@
package com.android.systemui.scene
+import android.content.Context
import android.content.pm.UserInfo
import android.graphics.Bitmap
import android.graphics.drawable.BitmapDrawable
@@ -81,8 +82,10 @@
*/
@OptIn(ExperimentalCoroutinesApi::class)
class SceneTestUtils(
- test: SysuiTestCase,
+ private val context: Context,
) {
+ constructor(test: SysuiTestCase) : this(context = test.context)
+
val kosmos = Kosmos()
val testDispatcher = kosmos.testDispatcher
val testScope = kosmos.testScope
@@ -115,8 +118,6 @@
}
}
- private val context = test.context
-
private val falsingCollectorFake: FalsingCollector by lazy { FalsingCollectorFake() }
private var falsingInteractor: FalsingInteractor? = null
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 1566113..514be15 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -79,6 +79,7 @@
import static android.os.PowerExemptionManager.REASON_BACKGROUND_ACTIVITY_PERMISSION;
import static android.os.PowerExemptionManager.REASON_BOOT_COMPLETED;
import static android.os.PowerExemptionManager.REASON_COMPANION_DEVICE_MANAGER;
+import static android.os.PowerExemptionManager.REASON_DENIED;
import static android.os.PowerExemptionManager.REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION;
import static android.os.PowerExemptionManager.REASON_LOCKED_BOOT_COMPLETED;
import static android.os.PowerExemptionManager.REASON_PROC_STATE_BTOP;
@@ -7715,14 +7716,100 @@
"getUidProcessState", callingPackage); // Ignore return value
synchronized (mProcLock) {
- if (mPendingStartActivityUids.isPendingTopUid(uid)) {
- return PROCESS_STATE_TOP;
- }
- return mProcessList.getUidProcStateLOSP(uid);
+ return getUidProcessStateInnerLOSP(uid);
}
}
@Override
+ public int getBindingUidProcessState(int targetUid, String callingPackage) {
+ if (!hasUsageStatsPermission(callingPackage)) {
+ enforceCallingPermission(android.Manifest.permission.GET_BINDING_UID_IMPORTANCE,
+ "getBindingUidProcessState");
+ }
+ // We don't need to do a cross-user check here (unlike getUidProcessState),
+ // because we only allow to see UIDs that are actively communicating with the caller.
+
+ final int callingUid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (this) {
+ final boolean allowed = (callingUid == targetUid)
+ || hasServiceBindingOrProviderUseLocked(callingUid, targetUid);
+ if (!allowed) {
+ return PROCESS_STATE_NONEXISTENT;
+ }
+ return getUidProcessStateInnerLOSP(targetUid);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @GuardedBy(anyOf = {"this", "mProcLock"})
+ private int getUidProcessStateInnerLOSP(int uid) {
+ if (mPendingStartActivityUids.isPendingTopUid(uid)) {
+ return PROCESS_STATE_TOP;
+ }
+ return mProcessList.getUidProcStateLOSP(uid);
+ }
+
+ /**
+ * Ensure that {@code clientUid} has a bound service client to {@code callingUid}
+ */
+ @GuardedBy("this")
+ private boolean hasServiceBindingOrProviderUseLocked(int callingUid, int clientUid) {
+ // See if there's a service binding
+ final Boolean hasBinding = mProcessList.searchEachLruProcessesLOSP(
+ false, pr -> {
+ if (pr.uid == callingUid) {
+ final ProcessServiceRecord psr = pr.mServices;
+ final int serviceCount = psr.mServices.size();
+ for (int svc = 0; svc < serviceCount; svc++) {
+ final ArrayMap<IBinder, ArrayList<ConnectionRecord>> conns =
+ psr.mServices.valueAt(svc).getConnections();
+ final int size = conns.size();
+ for (int conni = 0; conni < size; conni++) {
+ final ArrayList<ConnectionRecord> crs = conns.valueAt(conni);
+ for (int con = 0; con < crs.size(); con++) {
+ final ConnectionRecord cr = crs.get(con);
+ final ProcessRecord clientPr = cr.binding.client;
+
+ if (clientPr.uid == clientUid) {
+ return Boolean.TRUE;
+ }
+ }
+ }
+ }
+ }
+ return null;
+ });
+ if (Boolean.TRUE.equals(hasBinding)) {
+ return true;
+ }
+
+ final Boolean hasProviderClient = mProcessList.searchEachLruProcessesLOSP(
+ false, pr -> {
+ if (pr.uid == callingUid) {
+ final ProcessProviderRecord ppr = pr.mProviders;
+ for (int provi = ppr.numberOfProviders() - 1; provi >= 0; provi--) {
+ ContentProviderRecord cpr = ppr.getProviderAt(provi);
+
+ for (int i = cpr.connections.size() - 1; i >= 0; i--) {
+ ContentProviderConnection conn = cpr.connections.get(i);
+ ProcessRecord client = conn.client;
+ if (client.uid == clientUid) {
+ return Boolean.TRUE;
+ }
+ }
+ }
+ }
+ return null;
+ });
+
+ return Boolean.TRUE.equals(hasProviderClient);
+ }
+
+ @Override
public @ProcessCapability int getUidProcessCapabilities(int uid, String callingPackage) {
if (!hasUsageStatsPermission(callingPackage)) {
enforceCallingPermission(android.Manifest.permission.PACKAGE_USAGE_STATS,
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index f0698be..f462efc 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -125,7 +125,6 @@
import static com.android.server.wm.Task.REPARENT_KEEP_ROOT_TASK_AT_FRONT;
import static com.android.server.wm.WindowManagerService.MY_PID;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
-import static com.android.sdksandbox.flags.Flags.sandboxActivitySdkBasedContext;
import android.Manifest;
import android.annotation.IntDef;
@@ -166,7 +165,6 @@
import android.app.assist.AssistContent;
import android.app.assist.AssistStructure;
import android.app.compat.CompatChanges;
-import android.app.sdksandbox.sandboxactivity.SdkSandboxActivityAuthority;
import android.app.usage.UsageStatsManagerInternal;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
@@ -1260,13 +1258,6 @@
true /*validateIncomingUser*/);
}
- static boolean isSdkSandboxActivity(Context context, Intent intent) {
- return intent != null
- && (sandboxActivitySdkBasedContext()
- ? SdkSandboxActivityAuthority.isSdkSandboxActivity(context, intent)
- : intent.isSandboxActivity(context));
- }
-
private int startActivityAsUser(IApplicationThread caller, String callingPackage,
@Nullable String callingFeatureId, Intent intent, String resolvedType,
IBinder resultTo, String resultWho, int requestCode, int startFlags,
@@ -1277,7 +1268,7 @@
assertPackageMatchesCallingUid(callingPackage);
enforceNotIsolatedCaller("startActivityAsUser");
- if (isSdkSandboxActivity(mContext, intent)) {
+ if (intent != null && intent.isSandboxActivity(mContext)) {
SdkSandboxManagerLocal sdkSandboxManagerLocal = LocalManagerRegistry.getManager(
SdkSandboxManagerLocal.class);
sdkSandboxManagerLocal.enforceAllowedToHostSandboxedActivity(
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index e5eb303..777b5cd 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -1089,7 +1089,7 @@
// Remove the process record so it won't be considered as alive.
mService.mProcessNames.remove(wpc.mName, wpc.mUid);
mService.mProcessMap.remove(wpc.getPid());
- } else if (ActivityTaskManagerService.isSdkSandboxActivity(mService.mContext, r.intent)) {
+ } else if (r.intent.isSandboxActivity(mService.mContext)) {
Slog.e(TAG, "Abort sandbox activity launching as no sandbox process to host it.");
r.finishIfPossible("No sandbox process for the activity", false /* oomAdj */);
r.launchFailed = true;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index c716879..7f80807 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -2436,13 +2436,14 @@
// AppBounds at the root level should mirror the app screen size.
outConfig.windowConfiguration.setAppBounds(info.mNonDecorFrame);
outConfig.windowConfiguration.setRotation(rotation);
- outConfig.orientation = (dw <= dh) ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
final float density = mDisplayMetrics.density;
outConfig.screenWidthDp = (int) (info.mConfigFrame.width() / density + 0.5f);
outConfig.screenHeightDp = (int) (info.mConfigFrame.height() / density + 0.5f);
outConfig.compatScreenWidthDp = (int) (outConfig.screenWidthDp / mCompatibleScreenScale);
outConfig.compatScreenHeightDp = (int) (outConfig.screenHeightDp / mCompatibleScreenScale);
+ outConfig.orientation = (outConfig.screenWidthDp <= outConfig.screenHeightDp)
+ ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
outConfig.screenLayout = computeScreenLayout(
Configuration.resetScreenLayout(outConfig.screenLayout),
outConfig.screenWidthDp, outConfig.screenHeightDp);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 6d67c8b..5b88c8c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -970,6 +970,13 @@
assertEquals(
"Screen orientation must be defined by the window even on close-to-square display.",
window.mAttrs.screenOrientation, dc.getOrientation());
+
+ // Assume that a decor window occupies the display height, so the configuration orientation
+ // should be landscape.
+ dc.getDisplayPolicy().getDecorInsetsInfo(ROTATION_0, dc.mBaseDisplayHeight,
+ dc.mBaseDisplayWidth).mConfigFrame.set(0, 0, 1000, 990);
+ dc.computeScreenConfiguration(config, ROTATION_0);
+ assertEquals(Configuration.ORIENTATION_LANDSCAPE, config.orientation);
}
@Test
diff --git a/services/usb/Android.bp b/services/usb/Android.bp
index 9f3b52e..1dc5dcf 100644
--- a/services/usb/Android.bp
+++ b/services/usb/Android.bp
@@ -33,6 +33,6 @@
"android.hardware.usb-V1.1-java",
"android.hardware.usb-V1.2-java",
"android.hardware.usb-V1.3-java",
- "android.hardware.usb-V2-java",
+ "android.hardware.usb-V3-java",
],
}
diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
index 35e2fcf..fb13b33 100644
--- a/services/usb/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -1285,12 +1285,17 @@
pw.println(" dumpsys usb add-port \"matrix\" dual --compliance-warnings");
pw.println(" dumpsys usb set-compliance-reasons \"matrix\" <reason-list>");
pw.println(" dumpsys usb clear-compliance-reasons \"matrix\"");
- pw.println("<reason-list> is expected to be formatted as \"1, ..., 4\"");
+ pw.println("<reason-list> is expected to be formatted as \"1, ..., N\"");
pw.println("with reasons that need to be simulated.");
pw.println(" 1: other");
pw.println(" 2: debug accessory");
pw.println(" 3: bc12");
pw.println(" 4: missing rp");
+ pw.println(" 5: input power limited");
+ pw.println(" 6: missing data lines");
+ pw.println(" 7: enumeration fail");
+ pw.println(" 8: flaky connection");
+ pw.println(" 9: unreliable io");
pw.println();
pw.println("Example simulate DisplayPort Alt Mode Changes:");
pw.println(" dumpsys usb add-port \"matrix\" dual --displayport");
diff --git a/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java b/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java
index c7a7a9b..45b623b 100644
--- a/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java
+++ b/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java
@@ -39,6 +39,7 @@
import android.hardware.usb.AltModeData;
import android.hardware.usb.AltModeData.DisplayPortAltModeData;
import android.hardware.usb.DisplayPortAltModePinAssignment;
+import android.hardware.usb.flags.Flags;
import android.os.Build;
import android.os.ServiceManager;
import android.os.IBinder;
@@ -593,11 +594,21 @@
for (int warning : complianceWarnings) {
if (newComplianceWarnings.indexOf(warning) == -1
&& warning >= UsbPortStatus.COMPLIANCE_WARNING_OTHER) {
- // ComplianceWarnings range from [1, 4] in Android U
- if (warning > UsbPortStatus.COMPLIANCE_WARNING_MISSING_RP) {
- newComplianceWarnings.add(UsbPortStatus.COMPLIANCE_WARNING_OTHER);
+ if (Flags.enableUsbDataComplianceWarning()) {
+ // ComplianceWarnings range extends to [1, 9] when feature flag is on
+ if (warning
+ > UsbPortStatus.COMPLIANCE_WARNING_UNRELIABLE_IO) {
+ newComplianceWarnings.add(UsbPortStatus.COMPLIANCE_WARNING_OTHER);
+ } else {
+ newComplianceWarnings.add(warning);
+ }
} else {
- newComplianceWarnings.add(warning);
+ // ComplianceWarnings range from [1, 4] in Android U
+ if (warning > UsbPortStatus.COMPLIANCE_WARNING_MISSING_RP) {
+ newComplianceWarnings.add(UsbPortStatus.COMPLIANCE_WARNING_OTHER);
+ } else {
+ newComplianceWarnings.add(warning);
+ }
}
}
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
index 216f45a..d722f2f 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -279,6 +279,7 @@
mFullyBound = mContext.bindServiceAsUser(mBindIntent, mFullConnection,
Context.BIND_AUTO_CREATE | Context.BIND_TREAT_LIKE_ACTIVITY
| Context.BIND_SCHEDULE_LIKE_TOP_APP
+ | Context.BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE
| Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS,
new UserHandle(mUser));
}
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index cb7926c..11cbcb1 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -568,7 +568,6 @@
private final int mSkip464Xlat;
private final boolean mAlwaysOn;
private final @InfrastructureBitmask int mInfrastructureBitmask;
- private final boolean mEsimBootstrapProvisioning;
/**
* Returns the default MTU (Maximum Transmission Unit) size in bytes of the IPv4 routes brought
@@ -980,18 +979,6 @@
return mInfrastructureBitmask;
}
- /**
- * Returns esim bootstrap provisioning flag for which the APN can be used on. For example,
- * some APNs are only allowed to bring up network, when the device esim bootstrap provisioning
- * is being activated.
- *
- * {@code true} if the APN is used for eSIM bootstrap provisioning, {@code false} otherwise.
- * @hide
- */
- public boolean isEsimBootstrapProvisioning() {
- return mEsimBootstrapProvisioning;
- }
-
private ApnSetting(Builder builder) {
this.mEntryName = builder.mEntryName;
this.mApnName = builder.mApnName;
@@ -1029,7 +1016,6 @@
this.mSkip464Xlat = builder.mSkip464Xlat;
this.mAlwaysOn = builder.mAlwaysOn;
this.mInfrastructureBitmask = builder.mInfrastructureBitmask;
- this.mEsimBootstrapProvisioning = builder.mEsimBootstrapProvisioning;
}
/**
@@ -1111,8 +1097,6 @@
.setAlwaysOn(cursor.getInt(cursor.getColumnIndexOrThrow(Carriers.ALWAYS_ON)) == 1)
.setInfrastructureBitmask(cursor.getInt(cursor.getColumnIndexOrThrow(
Telephony.Carriers.INFRASTRUCTURE_BITMASK)))
- .setEsimBootstrapProvisioning(cursor.getInt(
- cursor.getColumnIndexOrThrow(Carriers.ESIM_BOOTSTRAP_PROVISIONING)) == 1)
.buildWithoutCheck();
}
@@ -1153,7 +1137,6 @@
.setSkip464Xlat(apn.mSkip464Xlat)
.setAlwaysOn(apn.mAlwaysOn)
.setInfrastructureBitmask(apn.mInfrastructureBitmask)
- .setEsimBootstrapProvisioning(apn.mEsimBootstrapProvisioning)
.buildWithoutCheck();
}
@@ -1201,7 +1184,6 @@
sb.append(", ").append(mAlwaysOn);
sb.append(", ").append(mInfrastructureBitmask);
sb.append(", ").append(Objects.hash(mUser, mPassword));
- sb.append(", ").append(mEsimBootstrapProvisioning);
return sb.toString();
}
@@ -1265,7 +1247,7 @@
mProtocol, mRoamingProtocol, mMtuV4, mMtuV6, mCarrierEnabled, mNetworkTypeBitmask,
mLingeringNetworkTypeBitmask, mProfileId, mPersistent, mMaxConns, mWaitTime,
mMaxConnsTime, mMvnoType, mMvnoMatchData, mApnSetId, mCarrierId, mSkip464Xlat,
- mAlwaysOn, mInfrastructureBitmask, mEsimBootstrapProvisioning);
+ mAlwaysOn, mInfrastructureBitmask);
}
@Override
@@ -1307,8 +1289,7 @@
&& mCarrierId == other.mCarrierId
&& mSkip464Xlat == other.mSkip464Xlat
&& mAlwaysOn == other.mAlwaysOn
- && mInfrastructureBitmask == other.mInfrastructureBitmask
- && Objects.equals(mEsimBootstrapProvisioning, other.mEsimBootstrapProvisioning);
+ && mInfrastructureBitmask == other.mInfrastructureBitmask;
}
/**
@@ -1359,8 +1340,7 @@
&& Objects.equals(mCarrierId, other.mCarrierId)
&& Objects.equals(mSkip464Xlat, other.mSkip464Xlat)
&& Objects.equals(mAlwaysOn, other.mAlwaysOn)
- && Objects.equals(mInfrastructureBitmask, other.mInfrastructureBitmask)
- && Objects.equals(mEsimBootstrapProvisioning, other.mEsimBootstrapProvisioning);
+ && Objects.equals(mInfrastructureBitmask, other.mInfrastructureBitmask);
}
/**
@@ -1398,9 +1378,7 @@
&& Objects.equals(this.mCarrierId, other.mCarrierId)
&& Objects.equals(this.mSkip464Xlat, other.mSkip464Xlat)
&& Objects.equals(this.mAlwaysOn, other.mAlwaysOn)
- && Objects.equals(this.mInfrastructureBitmask, other.mInfrastructureBitmask)
- && Objects.equals(this.mEsimBootstrapProvisioning,
- other.mEsimBootstrapProvisioning);
+ && Objects.equals(this.mInfrastructureBitmask, other.mInfrastructureBitmask);
}
// Equal or one is null.
@@ -1473,7 +1451,6 @@
apnValue.put(Telephony.Carriers.SKIP_464XLAT, mSkip464Xlat);
apnValue.put(Telephony.Carriers.ALWAYS_ON, mAlwaysOn);
apnValue.put(Telephony.Carriers.INFRASTRUCTURE_BITMASK, mInfrastructureBitmask);
- apnValue.put(Carriers.ESIM_BOOTSTRAP_PROVISIONING, mEsimBootstrapProvisioning);
return apnValue;
}
@@ -1747,7 +1724,6 @@
dest.writeInt(mSkip464Xlat);
dest.writeBoolean(mAlwaysOn);
dest.writeInt(mInfrastructureBitmask);
- dest.writeBoolean(mEsimBootstrapProvisioning);
}
private static ApnSetting readFromParcel(Parcel in) {
@@ -1784,7 +1760,6 @@
.setSkip464Xlat(in.readInt())
.setAlwaysOn(in.readBoolean())
.setInfrastructureBitmask(in.readInt())
- .setEsimBootstrapProvisioning(in.readBoolean())
.buildWithoutCheck();
}
@@ -1867,7 +1842,6 @@
private int mSkip464Xlat = Carriers.SKIP_464XLAT_DEFAULT;
private boolean mAlwaysOn;
private int mInfrastructureBitmask = INFRASTRUCTURE_CELLULAR;
- private boolean mEsimBootstrapProvisioning;
/**
* Default constructor for Builder.
@@ -2306,19 +2280,6 @@
}
/**
- * Sets esim bootstrap provisioning flag
- *
- * @param esimBootstrapProvisioning {@code true} if the APN is used for eSIM bootstrap
- * provisioning, {@code false} otherwise.
- * @hide
- */
- @NonNull
- public Builder setEsimBootstrapProvisioning(boolean esimBootstrapProvisioning) {
- this.mEsimBootstrapProvisioning = esimBootstrapProvisioning;
- return this;
- }
-
- /**
* Builds {@link ApnSetting} from this builder.
*
* @return {@code null} if {@link #setApnName(String)} or {@link #setEntryName(String)}
diff --git a/tests/FlickerTests/ActivityEmbedding/Android.bp b/tests/FlickerTests/ActivityEmbedding/Android.bp
new file mode 100644
index 0000000..9eeec7c
--- /dev/null
+++ b/tests/FlickerTests/ActivityEmbedding/Android.bp
@@ -0,0 +1,34 @@
+//
+// Copyright (C) 2018 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 {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "FlickerTestsOther",
+ defaults: ["FlickerTestsDefault"],
+ manifest: "AndroidManifest.xml",
+ package_name: "com.android.server.wm.flicker",
+ instrumentation_target_package: "com.android.server.wm.flicker",
+ srcs: ["src/**/*"],
+ static_libs: ["FlickerTestsBase"],
+}
diff --git a/tests/FlickerTests/manifests/AndroidManifest.xml b/tests/FlickerTests/ActivityEmbedding/AndroidManifest.xml
similarity index 91%
copy from tests/FlickerTests/manifests/AndroidManifest.xml
copy to tests/FlickerTests/ActivityEmbedding/AndroidManifest.xml
index 6bc7cbe..f867ffb 100644
--- a/tests/FlickerTests/manifests/AndroidManifest.xml
+++ b/tests/FlickerTests/ActivityEmbedding/AndroidManifest.xml
@@ -17,7 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
- package="com.android.server.wm.flicker">
+ package="com.android.server.wm.flick">
<uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/>
<!-- Read and write traces from external storage -->
@@ -59,4 +59,9 @@
android:authorities="${applicationId}.androidx-startup"
tools:node="remove" />
</application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.server.wm.flicker"
+ android:label="WindowManager Flicker Tests">
+ </instrumentation>
</manifest>
diff --git a/tests/FlickerTests/AndroidTestTemplate.xml b/tests/FlickerTests/ActivityEmbedding/AndroidTestTemplate.xml
similarity index 86%
copy from tests/FlickerTests/AndroidTestTemplate.xml
copy to tests/FlickerTests/ActivityEmbedding/AndroidTestTemplate.xml
index ed71531..439cf13 100644
--- a/tests/FlickerTests/AndroidTestTemplate.xml
+++ b/tests/FlickerTests/ActivityEmbedding/AndroidTestTemplate.xml
@@ -84,20 +84,6 @@
<option name="pull-pattern-keys" value="perfetto_file_path"/>
<option name="directory-keys"
value="/data/user/0/com.android.server.wm.flicker/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.close/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.ime/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.launch/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.quickswitch/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.rotation/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.notification/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.service/files"/>
<option name="collect-on-run-ended-only" value="true"/>
<option name="clean-up" value="true"/>
</metrics_collector>
diff --git a/tests/FlickerTests/ActivityEmbedding/res/anim/show_hide_show_3000ms.xml b/tests/FlickerTests/ActivityEmbedding/res/anim/show_hide_show_3000ms.xml
new file mode 100644
index 0000000..7b3f07e
--- /dev/null
+++ b/tests/FlickerTests/ActivityEmbedding/res/anim/show_hide_show_3000ms.xml
@@ -0,0 +1,31 @@
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fillAfter="true">
+
+ <alpha
+ android:fromAlpha="1.0"
+ android:toAlpha="0.0"
+ android:duration="1000" />
+
+ <alpha
+ android:startOffset="2000"
+ android:fromAlpha="1.0"
+ android:toAlpha="1.0"
+ android:duration="1000" />
+</set>
\ No newline at end of file
diff --git a/tests/FlickerTests/manifests/AndroidManifestOther.xml b/tests/FlickerTests/ActivityEmbedding/res/xml/network_security_config.xml
similarity index 63%
rename from tests/FlickerTests/manifests/AndroidManifestOther.xml
rename to tests/FlickerTests/ActivityEmbedding/res/xml/network_security_config.xml
index 47749b8..4bd9ca0 100644
--- a/tests/FlickerTests/manifests/AndroidManifestOther.xml
+++ b/tests/FlickerTests/ActivityEmbedding/res/xml/network_security_config.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2023 The Android Open Source Project
~
@@ -14,11 +15,8 @@
~ limitations under the License.
-->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.wm.flicker">
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.server.wm.flicker"
- android:label="WindowManager Flicker Tests">
- </instrumentation>
-</manifest>
+<network-security-config>
+ <domain-config cleartextTrafficPermitted="true">
+ <domain includeSubdomains="true">localhost</domain>
+ </domain-config>
+</network-security-config>
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt
rename to tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt
rename to tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/layoutchange/HorizontalSplitChangeRatioTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/layoutchange/HorizontalSplitChangeRatioTest.kt
similarity index 99%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/layoutchange/HorizontalSplitChangeRatioTest.kt
rename to tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/layoutchange/HorizontalSplitChangeRatioTest.kt
index adff579..955e801 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/layoutchange/HorizontalSplitChangeRatioTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/layoutchange/HorizontalSplitChangeRatioTest.kt
@@ -23,9 +23,9 @@
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.FlakyTest
+import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
-import androidx.test.filters.RequiresDevice
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt
rename to tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingPlaceholderSplitTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingPlaceholderSplitTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingPlaceholderSplitTest.kt
rename to tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingPlaceholderSplitTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingSecondaryToSplitTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingSecondaryToSplitTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingSecondaryToSplitTest.kt
rename to tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingSecondaryToSplitTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenThirdActivityOverSplitTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenThirdActivityOverSplitTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenThirdActivityOverSplitTest.kt
rename to tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenThirdActivityOverSplitTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt
rename to tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt
similarity index 93%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt
rename to tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt
index 47d6d23..790da34 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt
@@ -36,9 +36,8 @@
/**
* Test launching a secondary Activity into Picture-In-Picture mode.
*
- * Setup: Start from a split A|B.
- * Transition: B enters PIP, observe the window first goes fullscreen then shrink to the bottom
- * right corner on screen.
+ * Setup: Start from a split A|B. Transition: B enters PIP, observe the window first goes fullscreen
+ * then shrink to the bottom right corner on screen.
*
* To run this test: `atest FlickerTestsOther:SecondaryActivityEnterPipTest`
*/
@@ -64,16 +63,10 @@
}
}
- /**
- * We expect the background layer to be visible during this transition.
- */
- @Presubmit
- @Test
- override fun backgroundLayerNeverVisible(): Unit {}
+ /** We expect the background layer to be visible during this transition. */
+ @Presubmit @Test override fun backgroundLayerNeverVisible() {}
- /**
- * Main and secondary activity start from a split each taking half of the screen.
- */
+ /** Main and secondary activity start from a split each taking half of the screen. */
@Presubmit
@Test
fun layersStartFromEqualSplit() {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt
similarity index 97%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt
rename to tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt
index 4f7d8a4..e8389d19 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt
@@ -23,9 +23,7 @@
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
-import com.android.server.wm.flicker.rotation.RotationTransition
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotationTransition.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotationTransition.kt
new file mode 100644
index 0000000..1123c5b
--- /dev/null
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotationTransition.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.activityembedding.rotation
+
+import android.platform.test.annotations.Presubmit
+import android.tools.common.traces.component.ComponentNameMatcher
+import android.tools.device.apphelpers.StandardAppHelper
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import com.android.server.wm.flicker.BaseTest
+import com.android.server.wm.flicker.helpers.setRotation
+import org.junit.Test
+
+/** Base class for app rotation tests */
+abstract class RotationTransition(flicker: LegacyFlickerTest) : BaseTest(flicker) {
+ protected abstract val testApp: StandardAppHelper
+
+ /** {@inheritDoc} */
+ override val transition: FlickerBuilder.() -> Unit = {
+ setup { this.setRotation(flicker.scenario.startRotation) }
+ teardown { testApp.exit(wmHelper) }
+ transitions { this.setRotation(flicker.scenario.endRotation) }
+ }
+
+ /** {@inheritDoc} */
+ @Presubmit
+ @Test
+ override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ flicker.assertLayers {
+ this.visibleLayersShownMoreThanOneConsecutiveEntry(
+ ignoreLayers =
+ listOf(
+ ComponentNameMatcher.SPLASH_SCREEN,
+ ComponentNameMatcher.SNAPSHOT,
+ ComponentNameMatcher("", "SecondaryHomeHandle")
+ )
+ )
+ }
+ }
+
+ /** Checks that [testApp] layer covers the entire screen at the start of the transition */
+ @Presubmit
+ @Test
+ open fun appLayerRotates_StartingPos() {
+ flicker.assertLayersStart {
+ this.entry.displays.map { display ->
+ this.visibleRegion(testApp).coversExactly(display.layerStackSpace)
+ }
+ }
+ }
+
+ /** Checks that [testApp] layer covers the entire screen at the end of the transition */
+ @Presubmit
+ @Test
+ open fun appLayerRotates_EndingPos() {
+ flicker.assertLayersEnd {
+ this.entry.displays.map { display ->
+ this.visibleRegion(testApp).coversExactly(display.layerStackSpace)
+ }
+ }
+ }
+
+ override fun cujCompleted() {
+ super.cujCompleted()
+ appLayerRotates_StartingPos()
+ appLayerRotates_EndingPos()
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/rtl/RTLStartSecondaryWithPlaceholderTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rtl/RTLStartSecondaryWithPlaceholderTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/rtl/RTLStartSecondaryWithPlaceholderTest.kt
rename to tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rtl/RTLStartSecondaryWithPlaceholderTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt
similarity index 63%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt
rename to tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt
index 93a5bf5..576eec8 100644
--- a/tests/FlickerTests/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,8 +24,8 @@
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.traces.parsers.toFlickerComponent
-import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
+import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
import com.android.server.wm.flicker.testapp.ActivityOptions
import com.android.wm.shell.flicker.utils.SPLIT_SCREEN_DIVIDER_COMPONENT
import com.android.wm.shell.flicker.utils.SplitScreenUtils
@@ -39,11 +39,11 @@
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
-/***
+/**
* Test entering System SplitScreen with Activity Embedding Split and another app.
*
- * Setup: Launch A|B in split and secondaryApp, return to home.
- * Transitions: Let AE Split A|B enter splitscreen with secondaryApp. Resulting in A|B|secondaryApp.
+ * Setup: Launch A|B in split and secondaryApp, return to home. Transitions: Let AE Split A|B enter
+ * splitscreen with secondaryApp. Resulting in A|B|secondaryApp.
*
* To run this test: `atest FlickerTestsOther:EnterSystemSplitTest`
*/
@@ -51,8 +51,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class EnterSystemSplitTest(flicker: LegacyFlickerTest) :
- ActivityEmbeddingTestBase(flicker) {
+class EnterSystemSplitTest(flicker: LegacyFlickerTest) : ActivityEmbeddingTestBase(flicker) {
private val secondaryApp = SplitScreenUtils.getPrimary(instrumentation)
override val transition: FlickerBuilder.() -> Unit = {
@@ -62,17 +61,22 @@
secondaryApp.launchViaIntent(wmHelper)
tapl.goHome()
wmHelper
- .StateSyncBuilder()
- .withAppTransitionIdle()
- .withHomeActivityVisible()
- .waitForAndVerify()
+ .StateSyncBuilder()
+ .withAppTransitionIdle()
+ .withHomeActivityVisible()
+ .waitForAndVerify()
startDisplayBounds =
- wmHelper.currentState.layerState.physicalDisplayBounds
- ?: error("Display not found")
+ wmHelper.currentState.layerState.physicalDisplayBounds ?: error("Display not found")
}
transitions {
- SplitScreenUtils.enterSplit(wmHelper, tapl, device, testApp, secondaryApp,
- flicker.scenario.startRotation)
+ SplitScreenUtils.enterSplit(
+ wmHelper,
+ tapl,
+ device,
+ testApp,
+ secondaryApp,
+ flicker.scenario.startRotation
+ )
SplitScreenUtils.waitForSplitComplete(wmHelper, testApp, secondaryApp)
}
}
@@ -85,7 +89,10 @@
@Test
fun activityEmbeddingSplitLayerBecomesVisible() {
flicker.splitAppLayerBoundsIsVisibleAtEnd(
- testApp, landscapePosLeft = tapl.isTablet, portraitPosTop = false)
+ testApp,
+ landscapePosLeft = tapl.isTablet,
+ portraitPosTop = false
+ )
}
@Presubmit
@@ -96,7 +103,10 @@
@Test
fun secondaryLayerBecomesVisible() {
flicker.splitAppLayerBoundsIsVisibleAtEnd(
- secondaryApp, landscapePosLeft = !tapl.isTablet, portraitPosTop = true)
+ secondaryApp,
+ landscapePosLeft = !tapl.isTablet,
+ portraitPosTop = true
+ )
}
@Presubmit
@@ -105,73 +115,73 @@
/**
* After the transition there should be both ActivityEmbedding activities,
- * SplitScreenPrimaryActivity and the system split divider on screen.
- * Verify the layers are in expected sizes.
+ * SplitScreenPrimaryActivity and the system split divider on screen. Verify the layers are in
+ * expected sizes.
*/
@Presubmit
@Test
fun activityEmbeddingSplitSurfaceAreEven() {
flicker.assertLayersEnd {
val leftAELayerRegion =
- visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+ visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
val rightAELayerRegion =
- visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
val secondaryAppLayerRegion =
- visibleRegion(
- ActivityOptions.SplitScreen.Primary.COMPONENT.toFlickerComponent())
+ visibleRegion(ActivityOptions.SplitScreen.Primary.COMPONENT.toFlickerComponent())
val systemDivider = visibleRegion(SPLIT_SCREEN_DIVIDER_COMPONENT)
leftAELayerRegion
- .plus(rightAELayerRegion.region)
- .plus(secondaryAppLayerRegion.region)
- .plus(systemDivider.region)
- .coversExactly(startDisplayBounds)
+ .plus(rightAELayerRegion.region)
+ .plus(secondaryAppLayerRegion.region)
+ .plus(systemDivider.region)
+ .coversExactly(startDisplayBounds)
check { "ActivityEmbeddingSplitHeight" }
- .that(leftAELayerRegion.region.height)
- .isEqual(rightAELayerRegion.region.height)
+ .that(leftAELayerRegion.region.height)
+ .isEqual(rightAELayerRegion.region.height)
check { "SystemSplitHeight" }
- .that(rightAELayerRegion.region.height)
- .isEqual(secondaryAppLayerRegion.region.height)
+ .that(rightAELayerRegion.region.height)
+ .isEqual(secondaryAppLayerRegion.region.height)
// TODO(b/292283182): Remove this special case handling.
check { "ActivityEmbeddingSplitWidth" }
- .that(Math.abs(
- leftAELayerRegion.region.width - rightAELayerRegion.region.width))
- .isLower(2)
+ .that(Math.abs(leftAELayerRegion.region.width - rightAELayerRegion.region.width))
+ .isLower(2)
check { "SystemSplitWidth" }
- .that(Math.abs(secondaryAppLayerRegion.region.width -
- 2 * rightAELayerRegion.region.width))
- .isLower(2)
+ .that(
+ Math.abs(
+ secondaryAppLayerRegion.region.width - 2 * rightAELayerRegion.region.width
+ )
+ )
+ .isLower(2)
}
}
- /**
- * Verify the windows are in expected sizes.
- */
+ /** Verify the windows are in expected sizes. */
@Presubmit
@Test
fun activityEmbeddingSplitWindowsAreEven() {
flicker.assertWmEnd {
val leftAEWindowRegion =
- visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+ visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
val rightAEWindowRegion =
- visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
// There's no window for the divider bar.
val secondaryAppLayerRegion =
- visibleRegion(
- ActivityOptions.SplitScreen.Primary.COMPONENT.toFlickerComponent())
+ visibleRegion(ActivityOptions.SplitScreen.Primary.COMPONENT.toFlickerComponent())
check { "ActivityEmbeddingSplitHeight" }
- .that(leftAEWindowRegion.region.height)
- .isEqual(rightAEWindowRegion.region.height)
+ .that(leftAEWindowRegion.region.height)
+ .isEqual(rightAEWindowRegion.region.height)
check { "SystemSplitHeight" }
- .that(rightAEWindowRegion.region.height)
- .isEqual(secondaryAppLayerRegion.region.height)
+ .that(rightAEWindowRegion.region.height)
+ .isEqual(secondaryAppLayerRegion.region.height)
check { "ActivityEmbeddingSplitWidth" }
- .that(Math.abs(
- leftAEWindowRegion.region.width - rightAEWindowRegion.region.width))
- .isLower(2)
+ .that(Math.abs(leftAEWindowRegion.region.width - rightAEWindowRegion.region.width))
+ .isLower(2)
check { "SystemSplitWidth" }
- .that(Math.abs(secondaryAppLayerRegion.region.width -
- 2 * rightAEWindowRegion.region.width))
- .isLower(2)
+ .that(
+ Math.abs(
+ secondaryAppLayerRegion.region.width - 2 * rightAEWindowRegion.region.width
+ )
+ )
+ .isLower(2)
}
}
@@ -191,4 +201,4 @@
@JvmStatic
fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
-}
\ No newline at end of file
+}
diff --git a/tests/FlickerTests/trace_config/trace_config.textproto b/tests/FlickerTests/ActivityEmbedding/trace_config/trace_config.textproto
similarity index 100%
copy from tests/FlickerTests/trace_config/trace_config.textproto
copy to tests/FlickerTests/ActivityEmbedding/trace_config/trace_config.textproto
diff --git a/tests/FlickerTests/Android.bp b/tests/FlickerTests/Android.bp
index 3d49d81..514f895 100644
--- a/tests/FlickerTests/Android.bp
+++ b/tests/FlickerTests/Android.bp
@@ -24,75 +24,14 @@
}
filegroup {
- name: "FlickerTestsBase-src",
- srcs: ["src/com/android/server/wm/flicker/*.kt"],
-}
-
-filegroup {
- name: "FlickerTestsAppClose-src",
- srcs: ["src/**/close/*.kt"],
-}
-
-filegroup {
- name: "FlickerTestsActivityEmbedding-src",
- srcs: [
- "src/**/activityembedding/*.kt",
- "src/**/activityembedding/open/*.kt",
- "src/**/activityembedding/close/*.kt",
- "src/**/activityembedding/layoutchange/*.kt",
- "src/**/activityembedding/pip/*.kt",
- "src/**/activityembedding/rotation/*.kt",
- "src/**/activityembedding/rtl/*.kt",
- "src/**/activityembedding/splitscreen/*.kt",
- ],
-}
-
-filegroup {
- name: "FlickerTestsIme-src",
- srcs: ["src/**/ime/*.kt"],
-}
-
-filegroup {
- name: "FlickerTestsAppLaunchCommon-src",
- srcs: ["src/**/launch/common/*.kt"],
-}
-
-filegroup {
- name: "FlickerTestsAppLaunch1-src",
- srcs: ["src/**/launch/OpenApp*.kt"],
-}
-
-filegroup {
- name: "FlickerTestsAppLaunch2-src",
- srcs: ["src/**/launch/*.kt"],
-}
-
-filegroup {
- name: "FlickerTestsNotification-src",
- srcs: ["src/**/notification/*.kt"],
-}
-
-filegroup {
- name: "FlickerTestsQuickswitch-src",
- srcs: ["src/**/quickswitch/*.kt"],
-}
-
-filegroup {
- name: "FlickerTestsRotation-src",
- srcs: ["src/**/rotation/*.kt"],
-}
-
-filegroup {
name: "FlickerServiceTests-src",
srcs: [
- "src/com/android/server/wm/flicker/service/**/*.kt",
+ "src/**/*",
],
}
java_defaults {
name: "FlickerTestsDefault",
- manifest: "manifests/AndroidManifest.xml",
- test_config_template: "AndroidTestTemplate.xml",
platform_apis: true,
certificate: "platform",
optimize: {
@@ -116,139 +55,6 @@
],
}
-android_test {
- name: "FlickerTestsOther",
- defaults: ["FlickerTestsDefault"],
- additional_manifests: ["manifests/AndroidManifestOther.xml"],
- package_name: "com.android.server.wm.flicker",
- instrumentation_target_package: "com.android.server.wm.flicker",
- srcs: [
- "src/**/*.java",
- "src/**/*.kt",
- ],
- exclude_srcs: [
- ":FlickerTestsAppClose-src",
- ":FlickerTestsIme-src",
- ":FlickerTestsAppLaunch1-src",
- ":FlickerTestsAppLaunch2-src",
- ":FlickerTestsQuickswitch-src",
- ":FlickerTestsRotation-src",
- ":FlickerTestsNotification-src",
- ":FlickerServiceTests-src",
- ],
-}
-
-android_test {
- name: "FlickerTestsAppClose",
- defaults: ["FlickerTestsDefault"],
- additional_manifests: ["manifests/AndroidManifestAppClose.xml"],
- package_name: "com.android.server.wm.flicker.close",
- instrumentation_target_package: "com.android.server.wm.flicker.close",
- srcs: [
- ":FlickerTestsBase-src",
- ":FlickerTestsAppClose-src",
- ],
- exclude_srcs: [
- ":FlickerTestsActivityEmbedding-src",
- ],
-}
-
-android_test {
- name: "FlickerTestsIme",
- defaults: ["FlickerTestsDefault"],
- additional_manifests: ["manifests/AndroidManifestIme.xml"],
- package_name: "com.android.server.wm.flicker.ime",
- instrumentation_target_package: "com.android.server.wm.flicker.ime",
- srcs: [
- ":FlickerTestsBase-src",
- ":FlickerTestsIme-src",
- ],
-}
-
-android_test {
- name: "FlickerTestsAppLaunch1",
- defaults: ["FlickerTestsDefault"],
- additional_manifests: ["manifests/AndroidManifestAppLaunch.xml"],
- package_name: "com.android.server.wm.flicker.launch",
- instrumentation_target_package: "com.android.server.wm.flicker.launch",
- srcs: [
- ":FlickerTestsBase-src",
- ":FlickerTestsAppLaunchCommon-src",
- ":FlickerTestsAppLaunch1-src",
- ],
- exclude_srcs: [
- ":FlickerTestsActivityEmbedding-src",
- ],
-}
-
-android_test {
- name: "FlickerTestsAppLaunch2",
- defaults: ["FlickerTestsDefault"],
- additional_manifests: ["manifests/AndroidManifestAppLaunch.xml"],
- package_name: "com.android.server.wm.flicker.launch",
- instrumentation_target_package: "com.android.server.wm.flicker.launch",
- srcs: [
- ":FlickerTestsBase-src",
- ":FlickerTestsAppLaunchCommon-src",
- ":FlickerTestsAppLaunch2-src",
- ],
- exclude_srcs: [
- ":FlickerTestsActivityEmbedding-src",
- ":FlickerTestsAppLaunch1-src",
- ],
-}
-
-android_test {
- name: "FlickerTestsNotification",
- defaults: ["FlickerTestsDefault"],
- additional_manifests: ["manifests/AndroidManifestNotification.xml"],
- package_name: "com.android.server.wm.flicker.notification",
- instrumentation_target_package: "com.android.server.wm.flicker.notification",
- srcs: [
- ":FlickerTestsBase-src",
- ":FlickerTestsNotification-src",
- ],
-}
-
-android_test {
- name: "FlickerTestsQuickswitch",
- defaults: ["FlickerTestsDefault"],
- additional_manifests: ["manifests/AndroidManifestQuickswitch.xml"],
- package_name: "com.android.server.wm.flicker.quickswitch",
- instrumentation_target_package: "com.android.server.wm.flicker.quickswitch",
- srcs: [
- ":FlickerTestsBase-src",
- ":FlickerTestsQuickswitch-src",
- ],
-}
-
-android_test {
- name: "FlickerTestsRotation",
- defaults: ["FlickerTestsDefault"],
- additional_manifests: ["manifests/AndroidManifestRotation.xml"],
- package_name: "com.android.server.wm.flicker.rotation",
- instrumentation_target_package: "com.android.server.wm.flicker.rotation",
- srcs: [
- ":FlickerTestsBase-src",
- ":FlickerTestsRotation-src",
- ],
- exclude_srcs: [
- ":FlickerTestsActivityEmbedding-src",
- ],
-}
-
-android_test {
- name: "FlickerServiceTests",
- defaults: ["FlickerTestsDefault"],
- additional_manifests: ["manifests/AndroidManifestService.xml"],
- package_name: "com.android.server.wm.flicker.service",
- instrumentation_target_package: "com.android.server.wm.flicker.service",
- srcs: [
- ":FlickerTestsBase-src",
- ":FlickerServiceTests-src",
- ],
-}
-
java_library {
name: "wm-flicker-common-assertions",
platform_apis: true,
@@ -259,9 +65,6 @@
"src/**/*Assertions.java",
"src/**/*Assertions.kt",
],
- exclude_srcs: [
- "**/helpers/*",
- ],
static_libs: [
"flickerlib",
"flickerlib-helpers",
@@ -270,26 +73,6 @@
],
}
-java_library {
- name: "wm-flicker-common-app-helpers",
- platform_apis: true,
- optimize: {
- enabled: false,
- },
- srcs: [
- "**/helpers/*",
- ],
- static_libs: [
- "flickertestapplib",
- "flickerlib",
- "flickerlib-apphelpers",
- "flickerlib-helpers",
- "truth",
- "app-helpers-core",
- "wm-flicker-window-extensions",
- ],
-}
-
android_library_import {
name: "wm-flicker-window-extensions_nodeps",
aars: ["libs/window-extensions-release.aar"],
@@ -304,3 +87,9 @@
],
installable: false,
}
+
+java_library {
+ name: "FlickerTestsBase",
+ defaults: ["FlickerTestsDefault"],
+ srcs: ["src/**/*"],
+}
diff --git a/tests/FlickerTests/AppClose/Android.bp b/tests/FlickerTests/AppClose/Android.bp
new file mode 100644
index 0000000..151d12f
--- /dev/null
+++ b/tests/FlickerTests/AppClose/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2018 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 {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "FlickerTestsAppClose",
+ defaults: ["FlickerTestsDefault"],
+ manifest: "AndroidManifest.xml",
+ test_config_template: "AndroidTestTemplate.xml",
+ srcs: ["src/**/*"],
+ static_libs: ["FlickerTestsBase"],
+}
diff --git a/tests/FlickerTests/manifests/AndroidManifest.xml b/tests/FlickerTests/AppClose/AndroidManifest.xml
similarity index 91%
copy from tests/FlickerTests/manifests/AndroidManifest.xml
copy to tests/FlickerTests/AppClose/AndroidManifest.xml
index 6bc7cbe..e75e178 100644
--- a/tests/FlickerTests/manifests/AndroidManifest.xml
+++ b/tests/FlickerTests/AppClose/AndroidManifest.xml
@@ -17,7 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
- package="com.android.server.wm.flicker">
+ package="com.android.server.wm.flicker.close">
<uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/>
<!-- Read and write traces from external storage -->
@@ -59,4 +59,9 @@
android:authorities="${applicationId}.androidx-startup"
tools:node="remove" />
</application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.server.wm.flicker.close"
+ android:label="WindowManager Flicker Tests">
+ </instrumentation>
</manifest>
diff --git a/tests/FlickerTests/AndroidTestTemplate.xml b/tests/FlickerTests/AppClose/AndroidTestTemplate.xml
similarity index 86%
copy from tests/FlickerTests/AndroidTestTemplate.xml
copy to tests/FlickerTests/AppClose/AndroidTestTemplate.xml
index ed71531..4b6224e 100644
--- a/tests/FlickerTests/AndroidTestTemplate.xml
+++ b/tests/FlickerTests/AppClose/AndroidTestTemplate.xml
@@ -83,21 +83,7 @@
<metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
<option name="pull-pattern-keys" value="perfetto_file_path"/>
<option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker/files"/>
- <option name="directory-keys"
value="/data/user/0/com.android.server.wm.flicker.close/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.ime/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.launch/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.quickswitch/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.rotation/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.notification/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.service/files"/>
<option name="collect-on-run-ended-only" value="true"/>
<option name="clean-up" value="true"/>
</metrics_collector>
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/OWNERS b/tests/FlickerTests/AppClose/OWNERS
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/close/OWNERS
rename to tests/FlickerTests/AppClose/OWNERS
diff --git a/tests/FlickerTests/AppClose/res/anim/show_hide_show_3000ms.xml b/tests/FlickerTests/AppClose/res/anim/show_hide_show_3000ms.xml
new file mode 100644
index 0000000..7b3f07e
--- /dev/null
+++ b/tests/FlickerTests/AppClose/res/anim/show_hide_show_3000ms.xml
@@ -0,0 +1,31 @@
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fillAfter="true">
+
+ <alpha
+ android:fromAlpha="1.0"
+ android:toAlpha="0.0"
+ android:duration="1000" />
+
+ <alpha
+ android:startOffset="2000"
+ android:fromAlpha="1.0"
+ android:toAlpha="1.0"
+ android:duration="1000" />
+</set>
\ No newline at end of file
diff --git a/tests/FlickerTests/manifests/AndroidManifestOther.xml b/tests/FlickerTests/AppClose/res/xml/network_security_config.xml
similarity index 63%
copy from tests/FlickerTests/manifests/AndroidManifestOther.xml
copy to tests/FlickerTests/AppClose/res/xml/network_security_config.xml
index 47749b8..4bd9ca0 100644
--- a/tests/FlickerTests/manifests/AndroidManifestOther.xml
+++ b/tests/FlickerTests/AppClose/res/xml/network_security_config.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2023 The Android Open Source Project
~
@@ -14,11 +15,8 @@
~ limitations under the License.
-->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.wm.flicker">
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.server.wm.flicker"
- android:label="WindowManager Flicker Tests">
- </instrumentation>
-</manifest>
+<network-security-config>
+ <domain-config cleartextTrafficPermitted="true">
+ <domain includeSubdomains="true">localhost</domain>
+ </domain-config>
+</network-security-config>
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
similarity index 98%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
rename to tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
index 288558ae..64dd44d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
+++ b/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 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.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt b/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
similarity index 98%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
rename to tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
index 32305c6..eb256b5 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
+++ b/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 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.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt b/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
similarity index 98%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
rename to tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
index 8d752cc..ea025c7 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
+++ b/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 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.
diff --git a/tests/FlickerTests/trace_config/trace_config.textproto b/tests/FlickerTests/AppClose/trace_config/trace_config.textproto
similarity index 100%
copy from tests/FlickerTests/trace_config/trace_config.textproto
copy to tests/FlickerTests/AppClose/trace_config/trace_config.textproto
diff --git a/tests/FlickerTests/AppLaunch/Android.bp b/tests/FlickerTests/AppLaunch/Android.bp
new file mode 100644
index 0000000..f33384d
--- /dev/null
+++ b/tests/FlickerTests/AppLaunch/Android.bp
@@ -0,0 +1,69 @@
+//
+// Copyright (C) 2018 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 {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+filegroup {
+ name: "FlickerTestsAppLaunchCommon-src",
+ srcs: ["src/**/common/*"],
+}
+
+filegroup {
+ name: "FlickerTestsAppLaunch1-src",
+ srcs: ["src/**/OpenApp*"],
+}
+
+java_library {
+ name: "FlickerTestsAppLaunchCommon",
+ defaults: ["FlickerTestsDefault"],
+ srcs: [":FlickerTestsAppLaunchCommon-src"],
+ static_libs: ["FlickerTestsBase"],
+}
+
+android_test {
+ name: "FlickerTestsAppLaunch1",
+ defaults: ["FlickerTestsDefault"],
+ manifest: "AndroidManifest.xml",
+ test_config_template: "AndroidTestTemplate.xml",
+ srcs: [":FlickerTestsAppLaunch1-src"],
+ static_libs: [
+ "FlickerTestsBase",
+ "FlickerTestsAppLaunchCommon",
+ ],
+}
+
+android_test {
+ name: "FlickerTestsAppLaunch2",
+ defaults: ["FlickerTestsDefault"],
+ manifest: "AndroidManifest.xml",
+ test_config_template: "AndroidTestTemplate.xml",
+ srcs: ["src/**/*"],
+ exclude_srcs: [
+ ":FlickerTestsAppLaunchCommon-src",
+ ":FlickerTestsAppLaunch1-src",
+ ],
+ static_libs: [
+ "FlickerTestsBase",
+ "FlickerTestsAppLaunchCommon",
+ ],
+}
diff --git a/tests/FlickerTests/manifests/AndroidManifest.xml b/tests/FlickerTests/AppLaunch/AndroidManifest.xml
similarity index 91%
copy from tests/FlickerTests/manifests/AndroidManifest.xml
copy to tests/FlickerTests/AppLaunch/AndroidManifest.xml
index 6bc7cbe..b89af1a 100644
--- a/tests/FlickerTests/manifests/AndroidManifest.xml
+++ b/tests/FlickerTests/AppLaunch/AndroidManifest.xml
@@ -17,7 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
- package="com.android.server.wm.flicker">
+ package="com.android.server.wm.flicker.launch">
<uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/>
<!-- Read and write traces from external storage -->
@@ -59,4 +59,9 @@
android:authorities="${applicationId}.androidx-startup"
tools:node="remove" />
</application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.server.wm.flicker.launch"
+ android:label="WindowManager Flicker Tests">
+ </instrumentation>
</manifest>
diff --git a/tests/FlickerTests/AndroidTestTemplate.xml b/tests/FlickerTests/AppLaunch/AndroidTestTemplate.xml
similarity index 86%
rename from tests/FlickerTests/AndroidTestTemplate.xml
rename to tests/FlickerTests/AppLaunch/AndroidTestTemplate.xml
index ed71531..583bcb7 100644
--- a/tests/FlickerTests/AndroidTestTemplate.xml
+++ b/tests/FlickerTests/AppLaunch/AndroidTestTemplate.xml
@@ -83,21 +83,7 @@
<metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
<option name="pull-pattern-keys" value="perfetto_file_path"/>
<option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.close/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.ime/files"/>
- <option name="directory-keys"
value="/data/user/0/com.android.server.wm.flicker.launch/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.quickswitch/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.rotation/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.notification/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.service/files"/>
<option name="collect-on-run-ended-only" value="true"/>
<option name="clean-up" value="true"/>
</metrics_collector>
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OWNERS b/tests/FlickerTests/AppLaunch/OWNERS
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/OWNERS
rename to tests/FlickerTests/AppLaunch/OWNERS
diff --git a/tests/FlickerTests/AppLaunch/res/anim/show_hide_show_3000ms.xml b/tests/FlickerTests/AppLaunch/res/anim/show_hide_show_3000ms.xml
new file mode 100644
index 0000000..7b3f07e
--- /dev/null
+++ b/tests/FlickerTests/AppLaunch/res/anim/show_hide_show_3000ms.xml
@@ -0,0 +1,31 @@
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fillAfter="true">
+
+ <alpha
+ android:fromAlpha="1.0"
+ android:toAlpha="0.0"
+ android:duration="1000" />
+
+ <alpha
+ android:startOffset="2000"
+ android:fromAlpha="1.0"
+ android:toAlpha="1.0"
+ android:duration="1000" />
+</set>
\ No newline at end of file
diff --git a/tests/FlickerTests/manifests/AndroidManifestOther.xml b/tests/FlickerTests/AppLaunch/res/xml/network_security_config.xml
similarity index 63%
copy from tests/FlickerTests/manifests/AndroidManifestOther.xml
copy to tests/FlickerTests/AppLaunch/res/xml/network_security_config.xml
index 47749b8..4bd9ca0 100644
--- a/tests/FlickerTests/manifests/AndroidManifestOther.xml
+++ b/tests/FlickerTests/AppLaunch/res/xml/network_security_config.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2023 The Android Open Source Project
~
@@ -14,11 +15,8 @@
~ limitations under the License.
-->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.wm.flicker">
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.server.wm.flicker"
- android:label="WindowManager Flicker Tests">
- </instrumentation>
-</manifest>
+<network-security-config>
+ <domain-config cleartextTrafficPermitted="true">
+ <domain includeSubdomains="true">localhost</domain>
+ </domain-config>
+</network-security-config>
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivityTransitionTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/ActivityTransitionTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivityTransitionTest.kt
rename to tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/ActivityTransitionTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt
similarity index 98%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt
rename to tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt
index f788efa..413767c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 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.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt
similarity index 97%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt
rename to tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt
index d86dc50..4168bdc 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 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.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt
similarity index 98%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt
rename to tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt
index be07053..9c55c98 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 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.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt
similarity index 98%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt
rename to tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt
index f66eff9..fc6cdb1 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 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.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt
similarity index 99%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt
rename to tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt
index 65214764..de666dd 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 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.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
similarity index 98%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
rename to tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
index 4d31c28..f8a9961 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 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.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt
similarity index 98%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt
rename to tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt
index 42e34b3..0aceb35 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 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.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenTransferSplashscreenAppFromLauncherTransition.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenTransferSplashscreenAppFromLauncherTransition.kt
similarity index 97%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenTransferSplashscreenAppFromLauncherTransition.kt
rename to tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenTransferSplashscreenAppFromLauncherTransition.kt
index 97ba99e..f41a2a2 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenTransferSplashscreenAppFromLauncherTransition.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenTransferSplashscreenAppFromLauncherTransition.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.wm.flicker.launch.common
+package com.android.server.wm.flicker.launch
import android.platform.test.annotations.Presubmit
import android.tools.common.traces.component.ComponentNameMatcher
@@ -24,6 +24,7 @@
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.TransferSplashscreenAppHelper
+import com.android.server.wm.flicker.launch.common.OpenAppFromIconTransition
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt
similarity index 98%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt
rename to tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt
index 98e3646..93ca41c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt
@@ -31,7 +31,6 @@
import android.tools.device.helpers.wakeUpAndGoToHomeScreen
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.R
import com.android.server.wm.flicker.helpers.SimpleAppHelper
import com.android.server.wm.flicker.helpers.setRotation
import org.junit.FixMethodOrder
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
similarity index 99%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
rename to tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
index b82a129..9c2899ac 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 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.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenAppFromIconTransition.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromIconTransition.kt
similarity index 99%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenAppFromIconTransition.kt
rename to tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromIconTransition.kt
index c854701..802c755 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenAppFromIconTransition.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromIconTransition.kt
@@ -44,4 +44,4 @@
}
teardown { testApp.exit(wmHelper) }
}
-}
\ No newline at end of file
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenAppFromLauncherTransition.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromLauncherTransition.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenAppFromLauncherTransition.kt
rename to tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromLauncherTransition.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenAppFromLockscreenTransition.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromLockscreenTransition.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenAppFromLockscreenTransition.kt
rename to tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromLockscreenTransition.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenAppTransition.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppTransition.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenAppTransition.kt
rename to tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppTransition.kt
diff --git a/tests/FlickerTests/trace_config/trace_config.textproto b/tests/FlickerTests/AppLaunch/trace_config/trace_config.textproto
similarity index 100%
copy from tests/FlickerTests/trace_config/trace_config.textproto
copy to tests/FlickerTests/AppLaunch/trace_config/trace_config.textproto
diff --git a/tests/FlickerTests/FlickerService/Android.bp b/tests/FlickerTests/FlickerService/Android.bp
new file mode 100644
index 0000000..1a38115
--- /dev/null
+++ b/tests/FlickerTests/FlickerService/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2018 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 {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "FlickerServiceTests",
+ defaults: ["FlickerTestsDefault"],
+ manifest: "AndroidManifest.xml",
+ test_config_template: "AndroidTestTemplate.xml",
+ srcs: ["src/**/*"],
+ static_libs: ["FlickerTestsBase"],
+}
diff --git a/tests/FlickerTests/manifests/AndroidManifest.xml b/tests/FlickerTests/FlickerService/AndroidManifest.xml
similarity index 91%
rename from tests/FlickerTests/manifests/AndroidManifest.xml
rename to tests/FlickerTests/FlickerService/AndroidManifest.xml
index 6bc7cbe..f31e820 100644
--- a/tests/FlickerTests/manifests/AndroidManifest.xml
+++ b/tests/FlickerTests/FlickerService/AndroidManifest.xml
@@ -17,7 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
- package="com.android.server.wm.flicker">
+ package="com.android.server.wm.flicker.service">
<uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/>
<!-- Read and write traces from external storage -->
@@ -59,4 +59,9 @@
android:authorities="${applicationId}.androidx-startup"
tools:node="remove" />
</application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.server.wm.flicker.service"
+ android:label="WindowManager Flicker Tests">
+ </instrumentation>
</manifest>
diff --git a/tests/FlickerTests/AndroidTestTemplate.xml b/tests/FlickerTests/FlickerService/AndroidTestTemplate.xml
similarity index 86%
copy from tests/FlickerTests/AndroidTestTemplate.xml
copy to tests/FlickerTests/FlickerService/AndroidTestTemplate.xml
index ed71531..d6ae2b3 100644
--- a/tests/FlickerTests/AndroidTestTemplate.xml
+++ b/tests/FlickerTests/FlickerService/AndroidTestTemplate.xml
@@ -83,20 +83,6 @@
<metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
<option name="pull-pattern-keys" value="perfetto_file_path"/>
<option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.close/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.ime/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.launch/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.quickswitch/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.rotation/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.notification/files"/>
- <option name="directory-keys"
value="/data/user/0/com.android.server.wm.flicker.service/files"/>
<option name="collect-on-run-ended-only" value="true"/>
<option name="clean-up" value="true"/>
diff --git a/tests/FlickerTests/FlickerService/res/anim/show_hide_show_3000ms.xml b/tests/FlickerTests/FlickerService/res/anim/show_hide_show_3000ms.xml
new file mode 100644
index 0000000..7b3f07e
--- /dev/null
+++ b/tests/FlickerTests/FlickerService/res/anim/show_hide_show_3000ms.xml
@@ -0,0 +1,31 @@
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fillAfter="true">
+
+ <alpha
+ android:fromAlpha="1.0"
+ android:toAlpha="0.0"
+ android:duration="1000" />
+
+ <alpha
+ android:startOffset="2000"
+ android:fromAlpha="1.0"
+ android:toAlpha="1.0"
+ android:duration="1000" />
+</set>
\ No newline at end of file
diff --git a/tests/FlickerTests/manifests/AndroidManifestOther.xml b/tests/FlickerTests/FlickerService/res/xml/network_security_config.xml
similarity index 63%
copy from tests/FlickerTests/manifests/AndroidManifestOther.xml
copy to tests/FlickerTests/FlickerService/res/xml/network_security_config.xml
index 47749b8..4bd9ca0 100644
--- a/tests/FlickerTests/manifests/AndroidManifestOther.xml
+++ b/tests/FlickerTests/FlickerService/res/xml/network_security_config.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2023 The Android Open Source Project
~
@@ -14,11 +15,8 @@
~ limitations under the License.
-->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.wm.flicker">
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.server.wm.flicker"
- android:label="WindowManager Flicker Tests">
- </instrumentation>
-</manifest>
+<network-security-config>
+ <domain-config cleartextTrafficPermitted="true">
+ <domain includeSubdomains="true">localhost</domain>
+ </domain-config>
+</network-security-config>
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/Utils.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/Utils.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/Utils.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/Utils.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonLandscape.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonLandscape.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonLandscape.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonPortrait.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonPortrait.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonPortrait.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavLandscape.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavLandscape.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavLandscape.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavPortrait.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavPortrait.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavPortrait.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonLandscape.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonLandscape.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonLandscape.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonPortrait.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonPortrait.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonPortrait.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavLandscape.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavLandscape.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavLandscape.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavPortrait.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavPortrait.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavPortrait.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppBackButton.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppBackButton.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppBackButton.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppBackButton.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppHomeButton.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppHomeButton.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppHomeButton.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppHomeButton.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppSwipeToHome.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppSwipeToHome.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppSwipeToHome.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppSwipeToHome.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavLandscape.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavLandscape.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavLandscape.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavPortrait.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavPortrait.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavPortrait.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavLandscape.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavLandscape.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavLandscape.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavPortrait.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavPortrait.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavPortrait.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavLandscape.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavLandscape.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavLandscape.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavPortrait.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavPortrait.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavPortrait.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavLandscape.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavLandscape.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavLandscape.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavPortrait.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavPortrait.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavPortrait.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavLandscape.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavLandscape.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavLandscape.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavPortrait.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavPortrait.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavPortrait.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavLandscape.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavLandscape.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavLandscape.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavPortrait.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavPortrait.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavPortrait.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavLandscape.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavLandscape.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavLandscape.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavPortrait.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavPortrait.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavPortrait.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavLandscape.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavLandscape.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavLandscape.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavPortrait.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavPortrait.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavPortrait.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavLandscape.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavLandscape.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavLandscape.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavPortrait.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavPortrait.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavPortrait.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavLandscape.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavLandscape.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavLandscape.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavPortrait.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavPortrait.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavPortrait.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/NotificationUtils.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/NotificationUtils.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/NotificationUtils.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/NotificationUtils.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationCold.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationCold.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationCold.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationCold.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWarm.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWarm.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWarm.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWarm.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWithOverlayApp.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWithOverlayApp.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWithOverlayApp.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWithOverlayApp.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationCold.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationCold.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationCold.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationCold.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationWarm.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationWarm.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationWarm.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationWarm.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavLandscape.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavLandscape.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavLandscape.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavPortrait.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavPortrait.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavPortrait.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavLandscape.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavLandscape.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavLandscape.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavPortrait.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavPortrait.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavPortrait.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavLandscape.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavLandscape.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavLandscape.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavPortrait.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavPortrait.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavPortrait.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsBack.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsBack.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsBack.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsBack.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsForward.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsForward.kt
similarity index 99%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsForward.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsForward.kt
index 3cae1c4..fcf442a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsForward.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsForward.kt
@@ -19,6 +19,7 @@
import android.app.Instrumentation
import android.tools.common.NavBar
import android.tools.common.Rotation
+import android.tools.device.flicker.rules.ChangeDisplayOrientationRule
import android.tools.device.traces.parsers.WindowManagerStateHelper
import androidx.test.platform.app.InstrumentationRegistry
import com.android.launcher3.tapl.LauncherInstrumentation
@@ -30,7 +31,6 @@
import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
-import android.tools.device.flicker.rules.ChangeDisplayOrientationRule
@Ignore("Base Test Class")
abstract class QuickSwitchBetweenTwoAppsForward(val rotation: Rotation = Rotation.ROTATION_0) {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchFromLauncher.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchFromLauncher.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchFromLauncher.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchFromLauncher.kt
diff --git a/tests/FlickerTests/trace_config/trace_config.textproto b/tests/FlickerTests/FlickerService/trace_config/trace_config.textproto
similarity index 100%
copy from tests/FlickerTests/trace_config/trace_config.textproto
copy to tests/FlickerTests/FlickerService/trace_config/trace_config.textproto
diff --git a/tests/FlickerTests/IME/Android.bp b/tests/FlickerTests/IME/Android.bp
new file mode 100644
index 0000000..057d9fc
--- /dev/null
+++ b/tests/FlickerTests/IME/Android.bp
@@ -0,0 +1,78 @@
+//
+// Copyright (C) 2018 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 {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+filegroup {
+ name: "FlickerTestsImeCommon-src",
+ srcs: ["src/**/common/*"],
+}
+
+filegroup {
+ name: "FlickerTestsIme1-src",
+ srcs: ["src/**/Close*"],
+}
+
+android_test {
+ name: "FlickerTestsIme",
+ defaults: ["FlickerTestsDefault"],
+ manifest: "AndroidManifest.xml",
+ test_config_template: "AndroidTestTemplate.xml",
+ srcs: ["src/**/*"],
+ static_libs: ["FlickerTestsBase"],
+}
+
+java_library {
+ name: "FlickerTestsImeCommon",
+ defaults: ["FlickerTestsDefault"],
+ srcs: [":FlickerTestsImeCommon-src"],
+ static_libs: ["FlickerTestsBase"],
+}
+
+android_test {
+ name: "FlickerTestsIme1",
+ defaults: ["FlickerTestsDefault"],
+ manifest: "AndroidManifest.xml",
+ test_config_template: "AndroidTestTemplate.xml",
+ srcs: [":FlickerTestsIme1-src"],
+ static_libs: [
+ "FlickerTestsBase",
+ "FlickerTestsImeCommon",
+ ],
+}
+
+android_test {
+ name: "FlickerTestsIme2",
+ defaults: ["FlickerTestsDefault"],
+ manifest: "AndroidManifest.xml",
+ test_config_template: "AndroidTestTemplate.xml",
+ srcs: ["src/**/*"],
+ exclude_srcs: [
+ ":FlickerTestsIme1-src",
+ ":FlickerTestsImeCommon-src",
+ ],
+ static_libs: [
+ "FlickerTestsBase",
+ "FlickerTestsImeCommon",
+ ],
+}
diff --git a/tests/FlickerTests/manifests/AndroidManifest.xml b/tests/FlickerTests/IME/AndroidManifest.xml
similarity index 91%
copy from tests/FlickerTests/manifests/AndroidManifest.xml
copy to tests/FlickerTests/IME/AndroidManifest.xml
index 6bc7cbe..d6ca683 100644
--- a/tests/FlickerTests/manifests/AndroidManifest.xml
+++ b/tests/FlickerTests/IME/AndroidManifest.xml
@@ -17,7 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
- package="com.android.server.wm.flicker">
+ package="com.android.server.wm.flicker.ime">
<uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/>
<!-- Read and write traces from external storage -->
@@ -59,4 +59,9 @@
android:authorities="${applicationId}.androidx-startup"
tools:node="remove" />
</application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.server.wm.flicker.ime"
+ android:label="WindowManager Flicker Tests">
+ </instrumentation>
</manifest>
diff --git a/tests/FlickerTests/AndroidTestTemplate.xml b/tests/FlickerTests/IME/AndroidTestTemplate.xml
similarity index 86%
copy from tests/FlickerTests/AndroidTestTemplate.xml
copy to tests/FlickerTests/IME/AndroidTestTemplate.xml
index ed71531..988f76f 100644
--- a/tests/FlickerTests/AndroidTestTemplate.xml
+++ b/tests/FlickerTests/IME/AndroidTestTemplate.xml
@@ -83,21 +83,7 @@
<metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
<option name="pull-pattern-keys" value="perfetto_file_path"/>
<option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.close/files"/>
- <option name="directory-keys"
value="/data/user/0/com.android.server.wm.flicker.ime/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.launch/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.quickswitch/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.rotation/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.notification/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.service/files"/>
<option name="collect-on-run-ended-only" value="true"/>
<option name="clean-up" value="true"/>
</metrics_collector>
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OWNERS b/tests/FlickerTests/IME/OWNERS
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/ime/OWNERS
rename to tests/FlickerTests/IME/OWNERS
diff --git a/tests/FlickerTests/IME/res/anim/show_hide_show_3000ms.xml b/tests/FlickerTests/IME/res/anim/show_hide_show_3000ms.xml
new file mode 100644
index 0000000..7b3f07e
--- /dev/null
+++ b/tests/FlickerTests/IME/res/anim/show_hide_show_3000ms.xml
@@ -0,0 +1,31 @@
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fillAfter="true">
+
+ <alpha
+ android:fromAlpha="1.0"
+ android:toAlpha="0.0"
+ android:duration="1000" />
+
+ <alpha
+ android:startOffset="2000"
+ android:fromAlpha="1.0"
+ android:toAlpha="1.0"
+ android:duration="1000" />
+</set>
\ No newline at end of file
diff --git a/tests/FlickerTests/manifests/AndroidManifestOther.xml b/tests/FlickerTests/IME/res/xml/network_security_config.xml
similarity index 63%
copy from tests/FlickerTests/manifests/AndroidManifestOther.xml
copy to tests/FlickerTests/IME/res/xml/network_security_config.xml
index 47749b8..4bd9ca0 100644
--- a/tests/FlickerTests/manifests/AndroidManifestOther.xml
+++ b/tests/FlickerTests/IME/res/xml/network_security_config.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2023 The Android Open Source Project
~
@@ -14,11 +15,8 @@
~ limitations under the License.
-->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.wm.flicker">
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.server.wm.flicker"
- android:label="WindowManager Flicker Tests">
- </instrumentation>
-</manifest>
+<network-security-config>
+ <domain-config cleartextTrafficPermitted="true">
+ <domain includeSubdomains="true">localhost</domain>
+ </domain-config>
+</network-security-config>
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt
rename to tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt
rename to tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt
rename to tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt
rename to tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt
rename to tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt
rename to tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt
rename to tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt
rename to tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt
rename to tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt
rename to tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt
rename to tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt
rename to tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt
rename to tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt
rename to tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/common/CommonAssertions.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt
rename to tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/common/CommonAssertions.kt
diff --git a/tests/FlickerTests/trace_config/trace_config.textproto b/tests/FlickerTests/IME/trace_config/trace_config.textproto
similarity index 100%
rename from tests/FlickerTests/trace_config/trace_config.textproto
rename to tests/FlickerTests/IME/trace_config/trace_config.textproto
diff --git a/tests/FlickerTests/Notification/Android.bp b/tests/FlickerTests/Notification/Android.bp
new file mode 100644
index 0000000..5bed568
--- /dev/null
+++ b/tests/FlickerTests/Notification/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2018 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 {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "FlickerTestsNotification",
+ defaults: ["FlickerTestsDefault"],
+ manifest: "AndroidManifest.xml",
+ test_config_template: "AndroidTestTemplate.xml",
+ srcs: ["src/**/*"],
+ static_libs: ["FlickerTestsBase"],
+}
diff --git a/tests/FlickerTests/manifests/AndroidManifest.xml b/tests/FlickerTests/Notification/AndroidManifest.xml
similarity index 90%
copy from tests/FlickerTests/manifests/AndroidManifest.xml
copy to tests/FlickerTests/Notification/AndroidManifest.xml
index 6bc7cbe..d212c10 100644
--- a/tests/FlickerTests/manifests/AndroidManifest.xml
+++ b/tests/FlickerTests/Notification/AndroidManifest.xml
@@ -17,7 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
- package="com.android.server.wm.flicker">
+ package="com.android.server.wm.flicker.notification">
<uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/>
<!-- Read and write traces from external storage -->
@@ -59,4 +59,9 @@
android:authorities="${applicationId}.androidx-startup"
tools:node="remove" />
</application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.server.wm.flicker.notification"
+ android:label="WindowManager Flicker Tests">
+ </instrumentation>
</manifest>
diff --git a/tests/FlickerTests/AndroidTestTemplate.xml b/tests/FlickerTests/Notification/AndroidTestTemplate.xml
similarity index 86%
copy from tests/FlickerTests/AndroidTestTemplate.xml
copy to tests/FlickerTests/Notification/AndroidTestTemplate.xml
index ed71531..4036858 100644
--- a/tests/FlickerTests/AndroidTestTemplate.xml
+++ b/tests/FlickerTests/Notification/AndroidTestTemplate.xml
@@ -83,21 +83,7 @@
<metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
<option name="pull-pattern-keys" value="perfetto_file_path"/>
<option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.close/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.ime/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.launch/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.quickswitch/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.rotation/files"/>
- <option name="directory-keys"
value="/data/user/0/com.android.server.wm.flicker.notification/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.service/files"/>
<option name="collect-on-run-ended-only" value="true"/>
<option name="clean-up" value="true"/>
</metrics_collector>
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OWNERS b/tests/FlickerTests/Notification/OWNERS
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/notification/OWNERS
rename to tests/FlickerTests/Notification/OWNERS
diff --git a/tests/FlickerTests/Notification/res/anim/show_hide_show_3000ms.xml b/tests/FlickerTests/Notification/res/anim/show_hide_show_3000ms.xml
new file mode 100644
index 0000000..7b3f07e
--- /dev/null
+++ b/tests/FlickerTests/Notification/res/anim/show_hide_show_3000ms.xml
@@ -0,0 +1,31 @@
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fillAfter="true">
+
+ <alpha
+ android:fromAlpha="1.0"
+ android:toAlpha="0.0"
+ android:duration="1000" />
+
+ <alpha
+ android:startOffset="2000"
+ android:fromAlpha="1.0"
+ android:toAlpha="1.0"
+ android:duration="1000" />
+</set>
\ No newline at end of file
diff --git a/tests/FlickerTests/manifests/AndroidManifestOther.xml b/tests/FlickerTests/Notification/res/xml/network_security_config.xml
similarity index 63%
copy from tests/FlickerTests/manifests/AndroidManifestOther.xml
copy to tests/FlickerTests/Notification/res/xml/network_security_config.xml
index 47749b8..4bd9ca0 100644
--- a/tests/FlickerTests/manifests/AndroidManifestOther.xml
+++ b/tests/FlickerTests/Notification/res/xml/network_security_config.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2023 The Android Open Source Project
~
@@ -14,11 +15,8 @@
~ limitations under the License.
-->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.wm.flicker">
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.server.wm.flicker"
- android:label="WindowManager Flicker Tests">
- </instrumentation>
-</manifest>
+<network-security-config>
+ <domain-config cleartextTrafficPermitted="true">
+ <domain includeSubdomains="true">localhost</domain>
+ </domain-config>
+</network-security-config>
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/notification/Consts.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/Consts.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/notification/Consts.kt
rename to tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/Consts.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationColdTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationColdTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationColdTest.kt
rename to tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationColdTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWarmTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWarmTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWarmTest.kt
rename to tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWarmTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt
rename to tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationColdTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationColdTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationColdTest.kt
rename to tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationColdTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt
rename to tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppTransition.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppTransition.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppTransition.kt
rename to tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppTransition.kt
diff --git a/tests/FlickerTests/trace_config/trace_config.textproto b/tests/FlickerTests/Notification/trace_config/trace_config.textproto
similarity index 100%
copy from tests/FlickerTests/trace_config/trace_config.textproto
copy to tests/FlickerTests/Notification/trace_config/trace_config.textproto
diff --git a/tests/FlickerTests/QuickSwitch/Android.bp b/tests/FlickerTests/QuickSwitch/Android.bp
new file mode 100644
index 0000000..64f7183
--- /dev/null
+++ b/tests/FlickerTests/QuickSwitch/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2018 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 {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "FlickerTestsQuickswitch",
+ defaults: ["FlickerTestsDefault"],
+ manifest: "AndroidManifest.xml",
+ test_config_template: "AndroidTestTemplate.xml",
+ srcs: ["src/**/*"],
+ static_libs: ["FlickerTestsBase"],
+}
diff --git a/tests/FlickerTests/manifests/AndroidManifest.xml b/tests/FlickerTests/QuickSwitch/AndroidManifest.xml
similarity index 90%
copy from tests/FlickerTests/manifests/AndroidManifest.xml
copy to tests/FlickerTests/QuickSwitch/AndroidManifest.xml
index 6bc7cbe..41b0cd4 100644
--- a/tests/FlickerTests/manifests/AndroidManifest.xml
+++ b/tests/FlickerTests/QuickSwitch/AndroidManifest.xml
@@ -17,7 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
- package="com.android.server.wm.flicker">
+ package="com.android.server.wm.flicker.quickswitch">
<uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/>
<!-- Read and write traces from external storage -->
@@ -59,4 +59,9 @@
android:authorities="${applicationId}.androidx-startup"
tools:node="remove" />
</application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.server.wm.flicker.quickswitch"
+ android:label="WindowManager Flicker Tests">
+ </instrumentation>
</manifest>
diff --git a/tests/FlickerTests/AndroidTestTemplate.xml b/tests/FlickerTests/QuickSwitch/AndroidTestTemplate.xml
similarity index 86%
copy from tests/FlickerTests/AndroidTestTemplate.xml
copy to tests/FlickerTests/QuickSwitch/AndroidTestTemplate.xml
index ed71531..797ca4e 100644
--- a/tests/FlickerTests/AndroidTestTemplate.xml
+++ b/tests/FlickerTests/QuickSwitch/AndroidTestTemplate.xml
@@ -83,21 +83,7 @@
<metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
<option name="pull-pattern-keys" value="perfetto_file_path"/>
<option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.close/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.ime/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.launch/files"/>
- <option name="directory-keys"
value="/data/user/0/com.android.server.wm.flicker.quickswitch/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.rotation/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.notification/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.service/files"/>
<option name="collect-on-run-ended-only" value="true"/>
<option name="clean-up" value="true"/>
</metrics_collector>
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/OWNERS b/tests/FlickerTests/QuickSwitch/OWNERS
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/OWNERS
rename to tests/FlickerTests/QuickSwitch/OWNERS
diff --git a/tests/FlickerTests/QuickSwitch/res/anim/show_hide_show_3000ms.xml b/tests/FlickerTests/QuickSwitch/res/anim/show_hide_show_3000ms.xml
new file mode 100644
index 0000000..7b3f07e
--- /dev/null
+++ b/tests/FlickerTests/QuickSwitch/res/anim/show_hide_show_3000ms.xml
@@ -0,0 +1,31 @@
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fillAfter="true">
+
+ <alpha
+ android:fromAlpha="1.0"
+ android:toAlpha="0.0"
+ android:duration="1000" />
+
+ <alpha
+ android:startOffset="2000"
+ android:fromAlpha="1.0"
+ android:toAlpha="1.0"
+ android:duration="1000" />
+</set>
\ No newline at end of file
diff --git a/tests/FlickerTests/manifests/AndroidManifestOther.xml b/tests/FlickerTests/QuickSwitch/res/xml/network_security_config.xml
similarity index 63%
copy from tests/FlickerTests/manifests/AndroidManifestOther.xml
copy to tests/FlickerTests/QuickSwitch/res/xml/network_security_config.xml
index 47749b8..4bd9ca0 100644
--- a/tests/FlickerTests/manifests/AndroidManifestOther.xml
+++ b/tests/FlickerTests/QuickSwitch/res/xml/network_security_config.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2023 The Android Open Source Project
~
@@ -14,11 +15,8 @@
~ limitations under the License.
-->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.wm.flicker">
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.server.wm.flicker"
- android:label="WindowManager Flicker Tests">
- </instrumentation>
-</manifest>
+<network-security-config>
+ <domain-config cleartextTrafficPermitted="true">
+ <domain includeSubdomains="true">localhost</domain>
+ </domain-config>
+</network-security-config>
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt b/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
rename to tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt b/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
rename to tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt b/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
rename to tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
diff --git a/tests/FlickerTests/trace_config/trace_config.textproto b/tests/FlickerTests/QuickSwitch/trace_config/trace_config.textproto
similarity index 100%
copy from tests/FlickerTests/trace_config/trace_config.textproto
copy to tests/FlickerTests/QuickSwitch/trace_config/trace_config.textproto
diff --git a/tests/FlickerTests/Rotation/Android.bp b/tests/FlickerTests/Rotation/Android.bp
new file mode 100644
index 0000000..8e93b5b
--- /dev/null
+++ b/tests/FlickerTests/Rotation/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2018 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 {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "FlickerTestsRotation",
+ defaults: ["FlickerTestsDefault"],
+ manifest: "AndroidManifest.xml",
+ test_config_template: "AndroidTestTemplate.xml",
+ srcs: ["src/**/*"],
+ static_libs: ["FlickerTestsBase"],
+}
diff --git a/tests/FlickerTests/manifests/AndroidManifest.xml b/tests/FlickerTests/Rotation/AndroidManifest.xml
similarity index 91%
copy from tests/FlickerTests/manifests/AndroidManifest.xml
copy to tests/FlickerTests/Rotation/AndroidManifest.xml
index 6bc7cbe..6bbb1f6 100644
--- a/tests/FlickerTests/manifests/AndroidManifest.xml
+++ b/tests/FlickerTests/Rotation/AndroidManifest.xml
@@ -17,7 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
- package="com.android.server.wm.flicker">
+ package="com.android.server.wm.flicker.rotation">
<uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/>
<!-- Read and write traces from external storage -->
@@ -59,4 +59,9 @@
android:authorities="${applicationId}.androidx-startup"
tools:node="remove" />
</application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.server.wm.flicker.rotation"
+ android:label="WindowManager Flicker Tests">
+ </instrumentation>
</manifest>
diff --git a/tests/FlickerTests/AndroidTestTemplate.xml b/tests/FlickerTests/Rotation/AndroidTestTemplate.xml
similarity index 86%
copy from tests/FlickerTests/AndroidTestTemplate.xml
copy to tests/FlickerTests/Rotation/AndroidTestTemplate.xml
index ed71531..b5ea739 100644
--- a/tests/FlickerTests/AndroidTestTemplate.xml
+++ b/tests/FlickerTests/Rotation/AndroidTestTemplate.xml
@@ -83,21 +83,7 @@
<metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
<option name="pull-pattern-keys" value="perfetto_file_path"/>
<option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.close/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.ime/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.launch/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.quickswitch/files"/>
- <option name="directory-keys"
value="/data/user/0/com.android.server.wm.flicker.rotation/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.notification/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.service/files"/>
<option name="collect-on-run-ended-only" value="true"/>
<option name="clean-up" value="true"/>
</metrics_collector>
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/OWNERS b/tests/FlickerTests/Rotation/OWNERS
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/rotation/OWNERS
rename to tests/FlickerTests/Rotation/OWNERS
diff --git a/tests/FlickerTests/Rotation/res/anim/show_hide_show_3000ms.xml b/tests/FlickerTests/Rotation/res/anim/show_hide_show_3000ms.xml
new file mode 100644
index 0000000..7b3f07e
--- /dev/null
+++ b/tests/FlickerTests/Rotation/res/anim/show_hide_show_3000ms.xml
@@ -0,0 +1,31 @@
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fillAfter="true">
+
+ <alpha
+ android:fromAlpha="1.0"
+ android:toAlpha="0.0"
+ android:duration="1000" />
+
+ <alpha
+ android:startOffset="2000"
+ android:fromAlpha="1.0"
+ android:toAlpha="1.0"
+ android:duration="1000" />
+</set>
\ No newline at end of file
diff --git a/tests/FlickerTests/manifests/AndroidManifestOther.xml b/tests/FlickerTests/Rotation/res/xml/network_security_config.xml
similarity index 63%
copy from tests/FlickerTests/manifests/AndroidManifestOther.xml
copy to tests/FlickerTests/Rotation/res/xml/network_security_config.xml
index 47749b8..4bd9ca0 100644
--- a/tests/FlickerTests/manifests/AndroidManifestOther.xml
+++ b/tests/FlickerTests/Rotation/res/xml/network_security_config.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2023 The Android Open Source Project
~
@@ -14,11 +15,8 @@
~ limitations under the License.
-->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.wm.flicker">
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.server.wm.flicker"
- android:label="WindowManager Flicker Tests">
- </instrumentation>
-</manifest>
+<network-security-config>
+ <domain-config cleartextTrafficPermitted="true">
+ <domain includeSubdomains="true">localhost</domain>
+ </domain-config>
+</network-security-config>
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
rename to tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt b/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
rename to tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
rename to tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
diff --git a/tests/FlickerTests/trace_config/trace_config.textproto b/tests/FlickerTests/Rotation/trace_config/trace_config.textproto
similarity index 100%
copy from tests/FlickerTests/trace_config/trace_config.textproto
copy to tests/FlickerTests/Rotation/trace_config/trace_config.textproto
diff --git a/tests/FlickerTests/manifests/AndroidManifestAppClose.xml b/tests/FlickerTests/manifests/AndroidManifestAppClose.xml
deleted file mode 100644
index 4cdcb90..0000000
--- a/tests/FlickerTests/manifests/AndroidManifestAppClose.xml
+++ /dev/null
@@ -1,24 +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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.wm.flicker.close">
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.server.wm.flicker.close"
- android:label="WindowManager Flicker Tests">
- </instrumentation>
-</manifest>
diff --git a/tests/FlickerTests/manifests/AndroidManifestAppLaunch.xml b/tests/FlickerTests/manifests/AndroidManifestAppLaunch.xml
deleted file mode 100644
index 659a745..0000000
--- a/tests/FlickerTests/manifests/AndroidManifestAppLaunch.xml
+++ /dev/null
@@ -1,24 +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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.wm.flicker.launch">
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.server.wm.flicker.launch"
- android:label="WindowManager Flicker Tests">
- </instrumentation>
-</manifest>
diff --git a/tests/FlickerTests/manifests/AndroidManifestIme.xml b/tests/FlickerTests/manifests/AndroidManifestIme.xml
deleted file mode 100644
index abd03af..0000000
--- a/tests/FlickerTests/manifests/AndroidManifestIme.xml
+++ /dev/null
@@ -1,24 +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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.wm.flicker.ime">
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.server.wm.flicker.ime"
- android:label="WindowManager Flicker Tests">
- </instrumentation>
-</manifest>
diff --git a/tests/FlickerTests/manifests/AndroidManifestNotification.xml b/tests/FlickerTests/manifests/AndroidManifestNotification.xml
deleted file mode 100644
index ad33dee..0000000
--- a/tests/FlickerTests/manifests/AndroidManifestNotification.xml
+++ /dev/null
@@ -1,24 +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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.wm.flicker.close">
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.server.wm.flicker.notification"
- android:label="WindowManager Flicker Tests">
- </instrumentation>
-</manifest>
diff --git a/tests/FlickerTests/manifests/AndroidManifestQuickswitch.xml b/tests/FlickerTests/manifests/AndroidManifestQuickswitch.xml
deleted file mode 100644
index 203035d..0000000
--- a/tests/FlickerTests/manifests/AndroidManifestQuickswitch.xml
+++ /dev/null
@@ -1,24 +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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.wm.flicker.quickswitch">
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.server.wm.flicker.quickswitch"
- android:label="WindowManager Flicker Tests">
- </instrumentation>
-</manifest>
diff --git a/tests/FlickerTests/manifests/AndroidManifestRotation.xml b/tests/FlickerTests/manifests/AndroidManifestRotation.xml
deleted file mode 100644
index 2852cf2..0000000
--- a/tests/FlickerTests/manifests/AndroidManifestRotation.xml
+++ /dev/null
@@ -1,24 +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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.wm.flicker.rotation">
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.server.wm.flicker.rotation"
- android:label="WindowManager Flicker Tests">
- </instrumentation>
-</manifest>
diff --git a/tests/FlickerTests/manifests/AndroidManifestService.xml b/tests/FlickerTests/manifests/AndroidManifestService.xml
deleted file mode 100644
index 3a7bc509..0000000
--- a/tests/FlickerTests/manifests/AndroidManifestService.xml
+++ /dev/null
@@ -1,24 +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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.wm.flicker.service">
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.server.wm.flicker.service"
- android:label="WindowManager Flicker Service Tests">
- </instrumentation>
-</manifest>
diff --git a/tests/FlickerTests/test-apps/app-helpers/Android.bp b/tests/FlickerTests/test-apps/app-helpers/Android.bp
new file mode 100644
index 0000000..fc4d71c
--- /dev/null
+++ b/tests/FlickerTests/test-apps/app-helpers/Android.bp
@@ -0,0 +1,42 @@
+//
+// Copyright (C) 2018 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 {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+java_library {
+ name: "wm-flicker-common-app-helpers",
+ platform_apis: true,
+ optimize: {
+ enabled: false,
+ },
+ srcs: ["src/**/*"],
+ static_libs: [
+ "flickertestapplib",
+ "flickerlib",
+ "flickerlib-apphelpers",
+ "flickerlib-helpers",
+ "truth",
+ "app-helpers-core",
+ "wm-flicker-window-extensions",
+ ],
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/AppPairsHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/AppPairsHelper.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/AppPairsHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/AppPairsHelper.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/AssistantAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/AssistantAppHelper.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/AssistantAppHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/AssistantAppHelper.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FixedOrientationAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/FixedOrientationAppHelper.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FixedOrientationAppHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/FixedOrientationAppHelper.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GestureHelper.java b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/GestureHelper.java
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GestureHelper.java
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/GestureHelper.java
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeEditorPopupDialogAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeEditorPopupDialogAppHelper.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeEditorPopupDialogAppHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeEditorPopupDialogAppHelper.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeShownOnAppStartHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeShownOnAppStartHelper.kt
similarity index 98%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeShownOnAppStartHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeShownOnAppStartHelper.kt
index e106f65..d3cee64 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeShownOnAppStartHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeShownOnAppStartHelper.kt
@@ -121,7 +121,7 @@
else -> null
}
if (matcher != null && matcher.find()) {
- return matcher.group(1).equals("VISIBLE")
+ return matcher.group(1) == "VISIBLE"
}
}
return false
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeStateInitializeHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeStateInitializeHelper.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeStateInitializeHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeStateInitializeHelper.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/LaunchBubbleHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LaunchBubbleHelper.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/LaunchBubbleHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LaunchBubbleHelper.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MultiWindowUtils.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/MultiWindowUtils.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MultiWindowUtils.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/MultiWindowUtils.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NotificationAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NotificationAppHelper.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NotificationAppHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NotificationAppHelper.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
similarity index 98%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
index da51eff..73cc2f2 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
@@ -250,11 +250,12 @@
launchedAppComponentMatcherOverride,
action,
stringExtras,
- waitConditionsBuilder = wmHelper
- .StateSyncBuilder()
- .add(ConditionsFactory.isWMStateComplete())
- .withAppTransitionIdle()
- .add(ConditionsFactory.hasPipWindow())
+ waitConditionsBuilder =
+ wmHelper
+ .StateSyncBuilder()
+ .add(ConditionsFactory.isWMStateComplete())
+ .withAppTransitionIdle()
+ .add(ConditionsFactory.hasPipWindow())
)
wmHelper
@@ -265,8 +266,7 @@
}
/** Expand the PIP window back to full screen via intent and wait until the app is visible */
- fun exitPipToFullScreenViaIntent(wmHelper: WindowManagerStateHelper) =
- launchViaIntent(wmHelper)
+ fun exitPipToFullScreenViaIntent(wmHelper: WindowManagerStateHelper) = launchViaIntent(wmHelper)
fun changeAspectRatio() {
val intent = Intent("com.android.wm.shell.flicker.testapp.ASPECT_RATIO")
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ShowWhenLockedAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ShowWhenLockedAppHelper.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ShowWhenLockedAppHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ShowWhenLockedAppHelper.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TransferSplashscreenAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/TransferSplashscreenAppHelper.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TransferSplashscreenAppHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/TransferSplashscreenAppHelper.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
diff --git a/tools/fonts/update_font_metadata.py b/tools/fonts/update_font_metadata.py
index c07a98a..04a5528 100755
--- a/tools/fonts/update_font_metadata.py
+++ b/tools/fonts/update_font_metadata.py
@@ -19,7 +19,7 @@
args_parser.add_argument('--revision', help='Updated font revision. Use + to update revision based on the current revision')
args = args_parser.parse_args()
- font = ttLib.TTFont(args.input)
+ font = ttLib.TTFont(args.input, recalcTimestamp=False)
update_font_revision(font, args.revision)
font.save(args.output)