Merge "Round up to the nearest page size when registering native memory with the VM." into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index edb119e..6f8a189 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -438,10 +438,23 @@
name: "android.companion.virtualdevice.flags-aconfig",
package: "android.companion.virtualdevice.flags",
container: "system",
+ exportable: true,
srcs: ["core/java/android/companion/virtual/flags/*.aconfig"],
}
java_aconfig_library {
+ name: "android.companion.virtualdevice.flags-aconfig-java-export",
+ aconfig_declarations: "android.companion.virtualdevice.flags-aconfig",
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+ mode: "exported",
+ min_sdk_version: "30",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.permission",
+ ],
+}
+
+java_aconfig_library {
name: "android.companion.virtual.flags-aconfig-java",
aconfig_declarations: "android.companion.virtual.flags-aconfig",
defaults: ["framework-minus-apex-aconfig-java-defaults"],
diff --git a/apct-tests/perftests/protolog/src/com/android/internal/protolog/ProtoLogPerfTest.java b/apct-tests/perftests/protolog/src/com/android/internal/protolog/ProtoLogPerfTest.java
index 92dd9be..f4759b8 100644
--- a/apct-tests/perftests/protolog/src/com/android/internal/protolog/ProtoLogPerfTest.java
+++ b/apct-tests/perftests/protolog/src/com/android/internal/protolog/ProtoLogPerfTest.java
@@ -15,43 +15,54 @@
*/
package com.android.internal.protolog;
-import android.perftests.utils.BenchmarkState;
-import android.perftests.utils.PerfStatusReporter;
+import android.app.Activity;
+import android.os.Bundle;
+import android.perftests.utils.Stats;
+
+import androidx.test.InstrumentationRegistry;
import com.android.internal.protolog.common.IProtoLogGroup;
import com.android.internal.protolog.common.LogLevel;
import org.junit.Before;
import org.junit.BeforeClass;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
-import java.util.Arrays;
+import java.util.ArrayList;
import java.util.Collection;
@RunWith(Parameterized.class)
public class ProtoLogPerfTest {
- @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
-
- @Parameters(name="logToProto_{0}_logToLogcat_{1}")
- public static Collection<Object[]> params() {
- return Arrays.asList(new Object[][] {
- { true, true },
- { true, false },
- { false, true },
- { false, false }
- });
- }
-
private final boolean mLogToProto;
private final boolean mLogToLogcat;
- public ProtoLogPerfTest(boolean logToProto, boolean logToLogcat) {
- mLogToProto = logToProto;
- mLogToLogcat = logToLogcat;
+ /**
+ * Generates the parameters used for this test class
+ */
+ @Parameters(name = "LOG_TO_{0}")
+ public static Collection<Object[]> params() {
+ var params = new ArrayList<Object[]>();
+
+ for (LogTo logTo : LogTo.values()) {
+ params.add(new Object[] { logTo });
+ }
+
+ return params;
+ }
+
+ public ProtoLogPerfTest(LogTo logTo) {
+ mLogToProto = switch (logTo) {
+ case ALL, PROTO_ONLY -> true;
+ case LOGCAT_ONLY, NONE -> false;
+ };
+
+ mLogToLogcat = switch (logTo) {
+ case ALL, LOGCAT_ONLY -> true;
+ case PROTO_ONLY, NONE -> false;
+ };
}
@BeforeClass
@@ -66,11 +77,11 @@
}
@Test
- public void logProcessedProtoLogMessageWithoutArgs() {
+ public void log_Processed_NoArgs() {
final var protoLog = ProtoLog.getSingleInstance();
+ final var perfMonitor = new PerfMonitor();
- BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- while (state.keepRunning()) {
+ while (perfMonitor.keepRunning()) {
protoLog.log(
LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 123,
0, (Object[]) null);
@@ -78,11 +89,11 @@
}
@Test
- public void logProcessedProtoLogMessageWithArgs() {
+ public void log_Processed_WithArgs() {
final var protoLog = ProtoLog.getSingleInstance();
+ final var perfMonitor = new PerfMonitor();
- BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- while (state.keepRunning()) {
+ while (perfMonitor.keepRunning()) {
protoLog.log(
LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 123,
0b1110101001010100,
@@ -91,18 +102,58 @@
}
@Test
- public void logNonProcessedProtoLogMessageWithNoArgs() {
- BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- while (state.keepRunning()) {
+ public void log_Unprocessed_NoArgs() {
+ final var perfMonitor = new PerfMonitor();
+
+ while (perfMonitor.keepRunning()) {
ProtoLog.d(TestProtoLogGroup.TEST_GROUP, "Test message");
}
}
@Test
- public void logNonProcessedProtoLogMessageWithArgs() {
- BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- while (state.keepRunning()) {
- ProtoLog.d(TestProtoLogGroup.TEST_GROUP, "Test messag %s, %d, %b", "arg1", 2, true);
+ public void log_Unprocessed_WithArgs() {
+ final var perfMonitor = new PerfMonitor();
+
+ while (perfMonitor.keepRunning()) {
+ ProtoLog.d(TestProtoLogGroup.TEST_GROUP, "Test message %s, %d, %b", "arg1", 2, true);
+ }
+ }
+
+ private class PerfMonitor {
+ private int mIteration = 0;
+
+ private static final int WARM_UP_ITERATIONS = 10;
+ private static final int ITERATIONS = 1000;
+
+ private final ArrayList<Long> mResults = new ArrayList<>();
+
+ private long mStartTimeNs;
+
+ public boolean keepRunning() {
+ final long currentTime = System.nanoTime();
+
+ mIteration++;
+
+ if (mIteration > ITERATIONS) {
+ reportResults();
+ return false;
+ }
+
+ if (mIteration > WARM_UP_ITERATIONS) {
+ mResults.add(currentTime - mStartTimeNs);
+ }
+
+ mStartTimeNs = System.nanoTime();
+ return true;
+ }
+
+ public void reportResults() {
+ final var stats = new Stats(mResults);
+
+ Bundle status = new Bundle();
+ status.putLong("protologging_time_mean_ns", (long) stats.getMean());
+ status.putLong("protologging_time_median_ns", (long) stats.getMedian());
+ InstrumentationRegistry.getInstrumentation().sendStatus(Activity.RESULT_OK, status);
}
}
@@ -168,4 +219,11 @@
return ordinal();
}
}
+
+ private enum LogTo {
+ PROTO_ONLY,
+ LOGCAT_ONLY,
+ ALL,
+ NONE,
+ }
}
diff --git a/core/api/current.txt b/core/api/current.txt
index 2565d6f..ed8ab06 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -141,7 +141,7 @@
field public static final String MANAGE_DEVICE_POLICY_APPS_CONTROL = "android.permission.MANAGE_DEVICE_POLICY_APPS_CONTROL";
field public static final String MANAGE_DEVICE_POLICY_APP_RESTRICTIONS = "android.permission.MANAGE_DEVICE_POLICY_APP_RESTRICTIONS";
field public static final String MANAGE_DEVICE_POLICY_APP_USER_DATA = "android.permission.MANAGE_DEVICE_POLICY_APP_USER_DATA";
- field @FlaggedApi("android.app.admin.flags.assist_content_user_restriction_enabled") public static final String MANAGE_DEVICE_POLICY_ASSIST_CONTENT = "android.permission.MANAGE_DEVICE_POLICY_ASSIST_CONTENT";
+ field public static final String MANAGE_DEVICE_POLICY_ASSIST_CONTENT = "android.permission.MANAGE_DEVICE_POLICY_ASSIST_CONTENT";
field public static final String MANAGE_DEVICE_POLICY_AUDIO_OUTPUT = "android.permission.MANAGE_DEVICE_POLICY_AUDIO_OUTPUT";
field public static final String MANAGE_DEVICE_POLICY_AUTOFILL = "android.permission.MANAGE_DEVICE_POLICY_AUTOFILL";
field public static final String MANAGE_DEVICE_POLICY_BACKUP_SERVICE = "android.permission.MANAGE_DEVICE_POLICY_BACKUP_SERVICE";
@@ -169,7 +169,7 @@
field public static final String MANAGE_DEVICE_POLICY_LOCK = "android.permission.MANAGE_DEVICE_POLICY_LOCK";
field public static final String MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS = "android.permission.MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS";
field public static final String MANAGE_DEVICE_POLICY_LOCK_TASK = "android.permission.MANAGE_DEVICE_POLICY_LOCK_TASK";
- field @FlaggedApi("android.app.admin.flags.esim_management_enabled") public static final String MANAGE_DEVICE_POLICY_MANAGED_SUBSCRIPTIONS = "android.permission.MANAGE_DEVICE_POLICY_MANAGED_SUBSCRIPTIONS";
+ field public static final String MANAGE_DEVICE_POLICY_MANAGED_SUBSCRIPTIONS = "android.permission.MANAGE_DEVICE_POLICY_MANAGED_SUBSCRIPTIONS";
field public static final String MANAGE_DEVICE_POLICY_METERED_DATA = "android.permission.MANAGE_DEVICE_POLICY_METERED_DATA";
field public static final String MANAGE_DEVICE_POLICY_MICROPHONE = "android.permission.MANAGE_DEVICE_POLICY_MICROPHONE";
field @FlaggedApi("android.app.admin.flags.dedicated_device_control_api_enabled") public static final String MANAGE_DEVICE_POLICY_MICROPHONE_TOGGLE = "android.permission.MANAGE_DEVICE_POLICY_MICROPHONE_TOGGLE";
@@ -8081,7 +8081,7 @@
method public CharSequence getStartUserSessionMessage(@NonNull android.content.ComponentName);
method @Deprecated public boolean getStorageEncryption(@Nullable android.content.ComponentName);
method public int getStorageEncryptionStatus();
- method @FlaggedApi("android.app.admin.flags.esim_management_enabled") @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_POLICY_MANAGED_SUBSCRIPTIONS) public java.util.Set<java.lang.Integer> getSubscriptionIds();
+ method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_POLICY_MANAGED_SUBSCRIPTIONS) public java.util.Set<java.lang.Integer> getSubscriptionIds();
method @Nullable public android.app.admin.SystemUpdatePolicy getSystemUpdatePolicy();
method @Nullable public android.os.PersistableBundle getTransferOwnershipBundle();
method @Nullable public java.util.List<android.os.PersistableBundle> getTrustAgentConfiguration(@Nullable android.content.ComponentName, @NonNull android.content.ComponentName);
@@ -34116,7 +34116,7 @@
field public static final String DISALLOW_AIRPLANE_MODE = "no_airplane_mode";
field public static final String DISALLOW_AMBIENT_DISPLAY = "no_ambient_display";
field public static final String DISALLOW_APPS_CONTROL = "no_control_apps";
- field @FlaggedApi("android.app.admin.flags.assist_content_user_restriction_enabled") public static final String DISALLOW_ASSIST_CONTENT = "no_assist_content";
+ field public static final String DISALLOW_ASSIST_CONTENT = "no_assist_content";
field public static final String DISALLOW_AUTOFILL = "no_autofill";
field public static final String DISALLOW_BLUETOOTH = "no_bluetooth";
field public static final String DISALLOW_BLUETOOTH_SHARING = "no_bluetooth_sharing";
@@ -34166,7 +34166,7 @@
field public static final String DISALLOW_SHARE_INTO_MANAGED_PROFILE = "no_sharing_into_profile";
field public static final String DISALLOW_SHARE_LOCATION = "no_share_location";
field public static final String DISALLOW_SHARING_ADMIN_CONFIGURED_WIFI = "no_sharing_admin_configured_wifi";
- field @FlaggedApi("android.app.admin.flags.esim_management_enabled") public static final String DISALLOW_SIM_GLOBALLY = "no_sim_globally";
+ field public static final String DISALLOW_SIM_GLOBALLY = "no_sim_globally";
field public static final String DISALLOW_SMS = "no_sms";
field public static final String DISALLOW_SYSTEM_ERROR_DIALOGS = "no_system_error_dialogs";
field @FlaggedApi("com.android.net.thread.platform.flags.thread_user_restriction_enabled") public static final String DISALLOW_THREAD_NETWORK = "no_thread_network";
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 0a35c5a..009d082 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -3138,6 +3138,7 @@
public abstract class DreamOverlayService extends android.app.Service {
ctor public DreamOverlayService();
+ method @FlaggedApi("android.service.dreams.publish_preview_state_to_overlay") public final boolean isDreamInPreviewMode();
method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
method public void onEndDream();
method public abstract void onStartDream(@NonNull android.view.WindowManager.LayoutParams);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 0fc77f0..d31d8f2 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -56,7 +56,6 @@
import static android.app.admin.DeviceAdminInfo.HEADLESS_DEVICE_OWNER_MODE_UNSUPPORTED;
import static android.app.admin.flags.Flags.FLAG_DEVICE_POLICY_SIZE_TRACKING_INTERNAL_BUG_FIX_ENABLED;
import static android.app.admin.flags.Flags.FLAG_DEVICE_THEFT_API_ENABLED;
-import static android.app.admin.flags.Flags.FLAG_ESIM_MANAGEMENT_ENABLED;
import static android.app.admin.flags.Flags.FLAG_DEVICE_POLICY_SIZE_TRACKING_ENABLED;
import static android.app.admin.flags.Flags.FLAG_HEADLESS_DEVICE_OWNER_PROVISIONING_FIX_ENABLED;
import static android.app.admin.flags.Flags.onboardingBugreportV2Enabled;
@@ -17742,7 +17741,6 @@
* @throws SecurityException if the caller is not authorized to call this method.
* @return ids of all managed subscriptions currently downloaded by an admin on the device.
*/
- @FlaggedApi(FLAG_ESIM_MANAGEMENT_ENABLED)
@RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_POLICY_MANAGED_SUBSCRIPTIONS)
@NonNull
public Set<Integer> getSubscriptionIds() {
diff --git a/core/java/android/app/admin/flags/flags.aconfig b/core/java/android/app/admin/flags/flags.aconfig
index f2861fe..29a5048 100644
--- a/core/java/android/app/admin/flags/flags.aconfig
+++ b/core/java/android/app/admin/flags/flags.aconfig
@@ -139,6 +139,7 @@
bug: "293441361"
}
+# Fully rolled out and must not be used.
flag {
name: "assist_content_user_restriction_enabled"
is_exported: true
@@ -165,6 +166,7 @@
bug: "304999634"
}
+# Fully rolled out and must not be used.
flag {
name: "esim_management_enabled"
is_exported: true
diff --git a/core/java/android/companion/virtual/flags/flags.aconfig b/core/java/android/companion/virtual/flags/flags.aconfig
index b4c36e1..22a9ccf 100644
--- a/core/java/android/companion/virtual/flags/flags.aconfig
+++ b/core/java/android/companion/virtual/flags/flags.aconfig
@@ -50,6 +50,7 @@
name: "activity_control_api"
description: "Enable APIs for fine grained activity policy, fallback and callbacks"
bug: "333443509"
+ is_exported: true
}
flag {
diff --git a/core/java/android/hardware/biometrics/AuthenticateOptions.java b/core/java/android/hardware/biometrics/AuthenticateOptions.java
index 7766071..4dc6ea19 100644
--- a/core/java/android/hardware/biometrics/AuthenticateOptions.java
+++ b/core/java/android/hardware/biometrics/AuthenticateOptions.java
@@ -74,4 +74,7 @@
/** The attribution tag, if any. */
@Nullable String getAttributionTag();
+
+ /** If the authentication is requested due to mandatory biometrics being active. */
+ boolean isMandatoryBiometrics();
}
diff --git a/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl b/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl
index 17cd18c..b195225 100644
--- a/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl
@@ -49,7 +49,7 @@
void prepareForAuthentication(boolean requireConfirmation, IBinder token, long operationId,
int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName,
long requestId, int cookie, boolean allowBackgroundAuthentication,
- boolean isForLegacyFingerprintManager);
+ boolean isForLegacyFingerprintManager, boolean isMandatoryBiometrics);
// Starts authentication with the previously prepared client.
void startPreparedClient(int cookie);
diff --git a/core/java/android/hardware/face/FaceAuthenticateOptions.java b/core/java/android/hardware/face/FaceAuthenticateOptions.java
index 518f902a..8babbfa 100644
--- a/core/java/android/hardware/face/FaceAuthenticateOptions.java
+++ b/core/java/android/hardware/face/FaceAuthenticateOptions.java
@@ -120,6 +120,8 @@
}
+ /** If the authentication is requested due to mandatory biometrics being active. */
+ private boolean mIsMandatoryBiometrics;
// Code below generated by codegen v1.0.23.
//
@@ -188,7 +190,8 @@
@AuthenticateReason int authenticateReason,
@PowerManager.WakeReason int wakeReason,
@NonNull String opPackageName,
- @Nullable String attributionTag) {
+ @Nullable String attributionTag,
+ boolean isMandatoryBiometrics) {
this.mUserId = userId;
this.mSensorId = sensorId;
this.mDisplayState = displayState;
@@ -229,6 +232,7 @@
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mOpPackageName);
this.mAttributionTag = attributionTag;
+ this.mIsMandatoryBiometrics = isMandatoryBiometrics;
// onConstructed(); // You can define this method to get a callback
}
@@ -261,7 +265,7 @@
* The reason for this operation when requested by the system (sysui),
* otherwise AUTHENTICATE_REASON_UNKNOWN.
*
- * See packages/SystemUI/src/com/android/systemui/deviceentry/shared/FaceAuthReason.kt
+ * See frameworks/base/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt
* for more details about each reason.
*/
@DataClass.Generated.Member
@@ -299,6 +303,14 @@
}
/**
+ * If the authentication is requested due to mandatory biometrics being active.
+ */
+ @DataClass.Generated.Member
+ public boolean isMandatoryBiometrics() {
+ return mIsMandatoryBiometrics;
+ }
+
+ /**
* The sensor id for this operation.
*/
@DataClass.Generated.Member
@@ -332,6 +344,15 @@
return this;
}
+ /**
+ * If the authentication is requested due to mandatory biometrics being active.
+ */
+ @DataClass.Generated.Member
+ public @NonNull FaceAuthenticateOptions setIsMandatoryBiometrics( boolean value) {
+ mIsMandatoryBiometrics = value;
+ return this;
+ }
+
@Override
@DataClass.Generated.Member
public boolean equals(@Nullable Object o) {
@@ -351,7 +372,8 @@
&& mAuthenticateReason == that.mAuthenticateReason
&& mWakeReason == that.mWakeReason
&& java.util.Objects.equals(mOpPackageName, that.mOpPackageName)
- && java.util.Objects.equals(mAttributionTag, that.mAttributionTag);
+ && java.util.Objects.equals(mAttributionTag, that.mAttributionTag)
+ && mIsMandatoryBiometrics == that.mIsMandatoryBiometrics;
}
@Override
@@ -368,6 +390,7 @@
_hash = 31 * _hash + mWakeReason;
_hash = 31 * _hash + java.util.Objects.hashCode(mOpPackageName);
_hash = 31 * _hash + java.util.Objects.hashCode(mAttributionTag);
+ _hash = 31 * _hash + Boolean.hashCode(mIsMandatoryBiometrics);
return _hash;
}
@@ -377,9 +400,10 @@
// You can override field parcelling by defining methods like:
// void parcelFieldName(Parcel dest, int flags) { ... }
- byte flg = 0;
+ int flg = 0;
+ if (mIsMandatoryBiometrics) flg |= 0x80;
if (mAttributionTag != null) flg |= 0x40;
- dest.writeByte(flg);
+ dest.writeInt(flg);
dest.writeInt(mUserId);
dest.writeInt(mSensorId);
dest.writeInt(mDisplayState);
@@ -400,7 +424,8 @@
// You can override field unparcelling by defining methods like:
// static FieldType unparcelFieldName(Parcel in) { ... }
- byte flg = in.readByte();
+ int flg = in.readInt();
+ boolean isMandatoryBiometrics = (flg & 0x80) != 0;
int userId = in.readInt();
int sensorId = in.readInt();
int displayState = in.readInt();
@@ -449,6 +474,7 @@
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mOpPackageName);
this.mAttributionTag = attributionTag;
+ this.mIsMandatoryBiometrics = isMandatoryBiometrics;
// onConstructed(); // You can define this method to get a callback
}
@@ -481,6 +507,7 @@
private @PowerManager.WakeReason int mWakeReason;
private @NonNull String mOpPackageName;
private @Nullable String mAttributionTag;
+ private boolean mIsMandatoryBiometrics;
private long mBuilderFieldsSet = 0L;
@@ -524,7 +551,7 @@
* The reason for this operation when requested by the system (sysui),
* otherwise AUTHENTICATE_REASON_UNKNOWN.
*
- * See packages/SystemUI/src/com/android/systemui/deviceentry/shared/FaceAuthReason.kt
+ * See frameworks/base/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt
* for more details about each reason.
*/
@DataClass.Generated.Member
@@ -573,10 +600,21 @@
return this;
}
+ /**
+ * If the authentication is requested due to mandatory biometrics being active.
+ */
+ @DataClass.Generated.Member
+ public @NonNull Builder setIsMandatoryBiometrics(boolean value) {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x80;
+ mIsMandatoryBiometrics = value;
+ return this;
+ }
+
/** Builds the instance. This builder should not be touched after calling this! */
public @NonNull FaceAuthenticateOptions build() {
checkNotUsed();
- mBuilderFieldsSet |= 0x80; // Mark builder used
+ mBuilderFieldsSet |= 0x100; // Mark builder used
if ((mBuilderFieldsSet & 0x1) == 0) {
mUserId = defaultUserId();
@@ -606,12 +644,13 @@
mAuthenticateReason,
mWakeReason,
mOpPackageName,
- mAttributionTag);
+ mAttributionTag,
+ mIsMandatoryBiometrics);
return o;
}
private void checkNotUsed() {
- if ((mBuilderFieldsSet & 0x80) != 0) {
+ if ((mBuilderFieldsSet & 0x100) != 0) {
throw new IllegalStateException(
"This Builder should not be reused. Use a new Builder instance instead");
}
@@ -619,10 +658,10 @@
}
@DataClass.Generated(
- time = 1677119626034L,
+ time = 1723436679828L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/hardware/face/FaceAuthenticateOptions.java",
- inputSignatures = "private final int mUserId\nprivate int mSensorId\nprivate final @android.hardware.biometrics.AuthenticateOptions.DisplayState int mDisplayState\npublic static final int AUTHENTICATE_REASON_UNKNOWN\npublic static final int AUTHENTICATE_REASON_STARTED_WAKING_UP\npublic static final int AUTHENTICATE_REASON_PRIMARY_BOUNCER_SHOWN\npublic static final int AUTHENTICATE_REASON_ASSISTANT_VISIBLE\npublic static final int AUTHENTICATE_REASON_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN\npublic static final int AUTHENTICATE_REASON_NOTIFICATION_PANEL_CLICKED\npublic static final int AUTHENTICATE_REASON_OCCLUDING_APP_REQUESTED\npublic static final int AUTHENTICATE_REASON_PICK_UP_GESTURE_TRIGGERED\npublic static final int AUTHENTICATE_REASON_QS_EXPANDED\npublic static final int AUTHENTICATE_REASON_SWIPE_UP_ON_BOUNCER\npublic static final int AUTHENTICATE_REASON_UDFPS_POINTER_DOWN\nprivate final @android.hardware.face.FaceAuthenticateOptions.AuthenticateReason int mAuthenticateReason\nprivate final @android.os.PowerManager.WakeReason int mWakeReason\nprivate @android.annotation.NonNull java.lang.String mOpPackageName\nprivate @android.annotation.Nullable java.lang.String mAttributionTag\nprivate static int defaultUserId()\nprivate static int defaultSensorId()\nprivate static int defaultDisplayState()\nprivate static int defaultAuthenticateReason()\nprivate static int defaultWakeReason()\nprivate static java.lang.String defaultOpPackageName()\nprivate static java.lang.String defaultAttributionTag()\nclass FaceAuthenticateOptions extends java.lang.Object implements [android.hardware.biometrics.AuthenticateOptions, android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=true, genBuilder=true, genSetters=true, genEqualsHashCode=true)")
+ inputSignatures = "private final int mUserId\nprivate int mSensorId\nprivate final @android.hardware.biometrics.AuthenticateOptions.DisplayState int mDisplayState\npublic static final int AUTHENTICATE_REASON_UNKNOWN\npublic static final int AUTHENTICATE_REASON_STARTED_WAKING_UP\npublic static final int AUTHENTICATE_REASON_PRIMARY_BOUNCER_SHOWN\npublic static final int AUTHENTICATE_REASON_ASSISTANT_VISIBLE\npublic static final int AUTHENTICATE_REASON_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN\npublic static final int AUTHENTICATE_REASON_NOTIFICATION_PANEL_CLICKED\npublic static final int AUTHENTICATE_REASON_OCCLUDING_APP_REQUESTED\npublic static final int AUTHENTICATE_REASON_PICK_UP_GESTURE_TRIGGERED\npublic static final int AUTHENTICATE_REASON_QS_EXPANDED\npublic static final int AUTHENTICATE_REASON_SWIPE_UP_ON_BOUNCER\npublic static final int AUTHENTICATE_REASON_UDFPS_POINTER_DOWN\nprivate final @android.hardware.face.FaceAuthenticateOptions.AuthenticateReason int mAuthenticateReason\nprivate final @android.os.PowerManager.WakeReason int mWakeReason\nprivate @android.annotation.NonNull java.lang.String mOpPackageName\nprivate @android.annotation.Nullable java.lang.String mAttributionTag\nprivate boolean mIsMandatoryBiometrics\nprivate static int defaultUserId()\nprivate static int defaultSensorId()\nprivate static int defaultDisplayState()\nprivate static int defaultAuthenticateReason()\nprivate static int defaultWakeReason()\nprivate static java.lang.String defaultOpPackageName()\nprivate static java.lang.String defaultAttributionTag()\nclass FaceAuthenticateOptions extends java.lang.Object implements [android.hardware.biometrics.AuthenticateOptions, android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=true, genBuilder=true, genSetters=true, genEqualsHashCode=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/hardware/fingerprint/FingerprintAuthenticateOptions.java b/core/java/android/hardware/fingerprint/FingerprintAuthenticateOptions.java
index dc66542..ddf1e5b 100644
--- a/core/java/android/hardware/fingerprint/FingerprintAuthenticateOptions.java
+++ b/core/java/android/hardware/fingerprint/FingerprintAuthenticateOptions.java
@@ -97,6 +97,11 @@
return null;
}
+ /**
+ * If the authentication is requested due to mandatory biometrics being active.
+ */
+ private boolean mIsMandatoryBiometrics;
+
// Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
@@ -118,7 +123,8 @@
@AuthenticateOptions.DisplayState int displayState,
@NonNull String opPackageName,
@Nullable String attributionTag,
- @Nullable AuthenticateReason.Vendor vendorReason) {
+ @Nullable AuthenticateReason.Vendor vendorReason,
+ boolean isMandatoryBiometrics) {
this.mUserId = userId;
this.mSensorId = sensorId;
this.mIgnoreEnrollmentState = ignoreEnrollmentState;
@@ -130,6 +136,7 @@
NonNull.class, null, mOpPackageName);
this.mAttributionTag = attributionTag;
this.mVendorReason = vendorReason;
+ this.mIsMandatoryBiometrics = isMandatoryBiometrics;
// onConstructed(); // You can define this method to get a callback
}
@@ -199,6 +206,14 @@
}
/**
+ * If the authentication is requested due to mandatory biometrics being active.
+ */
+ @DataClass.Generated.Member
+ public boolean isMandatoryBiometrics() {
+ return mIsMandatoryBiometrics;
+ }
+
+ /**
* The sensor id for this operation.
*/
@DataClass.Generated.Member
@@ -244,6 +259,15 @@
return this;
}
+ /**
+ * If the authentication is requested due to mandatory biometrics being active.
+ */
+ @DataClass.Generated.Member
+ public @NonNull FingerprintAuthenticateOptions setIsMandatoryBiometrics( boolean value) {
+ mIsMandatoryBiometrics = value;
+ return this;
+ }
+
@Override
@DataClass.Generated.Member
public boolean equals(@Nullable Object o) {
@@ -263,7 +287,8 @@
&& mDisplayState == that.mDisplayState
&& java.util.Objects.equals(mOpPackageName, that.mOpPackageName)
&& java.util.Objects.equals(mAttributionTag, that.mAttributionTag)
- && java.util.Objects.equals(mVendorReason, that.mVendorReason);
+ && java.util.Objects.equals(mVendorReason, that.mVendorReason)
+ && mIsMandatoryBiometrics == that.mIsMandatoryBiometrics;
}
@Override
@@ -280,6 +305,7 @@
_hash = 31 * _hash + java.util.Objects.hashCode(mOpPackageName);
_hash = 31 * _hash + java.util.Objects.hashCode(mAttributionTag);
_hash = 31 * _hash + java.util.Objects.hashCode(mVendorReason);
+ _hash = 31 * _hash + Boolean.hashCode(mIsMandatoryBiometrics);
return _hash;
}
@@ -289,11 +315,12 @@
// You can override field parcelling by defining methods like:
// void parcelFieldName(Parcel dest, int flags) { ... }
- byte flg = 0;
+ int flg = 0;
if (mIgnoreEnrollmentState) flg |= 0x4;
+ if (mIsMandatoryBiometrics) flg |= 0x80;
if (mAttributionTag != null) flg |= 0x20;
if (mVendorReason != null) flg |= 0x40;
- dest.writeByte(flg);
+ dest.writeInt(flg);
dest.writeInt(mUserId);
dest.writeInt(mSensorId);
dest.writeInt(mDisplayState);
@@ -313,8 +340,9 @@
// You can override field unparcelling by defining methods like:
// static FieldType unparcelFieldName(Parcel in) { ... }
- byte flg = in.readByte();
+ int flg = in.readInt();
boolean ignoreEnrollmentState = (flg & 0x4) != 0;
+ boolean isMandatoryBiometrics = (flg & 0x80) != 0;
int userId = in.readInt();
int sensorId = in.readInt();
int displayState = in.readInt();
@@ -333,6 +361,7 @@
NonNull.class, null, mOpPackageName);
this.mAttributionTag = attributionTag;
this.mVendorReason = vendorReason;
+ this.mIsMandatoryBiometrics = isMandatoryBiometrics;
// onConstructed(); // You can define this method to get a callback
}
@@ -365,6 +394,7 @@
private @NonNull String mOpPackageName;
private @Nullable String mAttributionTag;
private @Nullable AuthenticateReason.Vendor mVendorReason;
+ private boolean mIsMandatoryBiometrics;
private long mBuilderFieldsSet = 0L;
@@ -456,10 +486,21 @@
return this;
}
+ /**
+ * If the authentication is requested due to mandatory biometrics being active.
+ */
+ @DataClass.Generated.Member
+ public @NonNull Builder setIsMandatoryBiometrics(boolean value) {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x80;
+ mIsMandatoryBiometrics = value;
+ return this;
+ }
+
/** Builds the instance. This builder should not be touched after calling this! */
public @NonNull FingerprintAuthenticateOptions build() {
checkNotUsed();
- mBuilderFieldsSet |= 0x80; // Mark builder used
+ mBuilderFieldsSet |= 0x100; // Mark builder used
if ((mBuilderFieldsSet & 0x1) == 0) {
mUserId = defaultUserId();
@@ -489,12 +530,13 @@
mDisplayState,
mOpPackageName,
mAttributionTag,
- mVendorReason);
+ mVendorReason,
+ mIsMandatoryBiometrics);
return o;
}
private void checkNotUsed() {
- if ((mBuilderFieldsSet & 0x80) != 0) {
+ if ((mBuilderFieldsSet & 0x100) != 0) {
throw new IllegalStateException(
"This Builder should not be reused. Use a new Builder instance instead");
}
@@ -502,10 +544,10 @@
}
@DataClass.Generated(
- time = 1689703591032L,
+ time = 1723436831455L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/hardware/fingerprint/FingerprintAuthenticateOptions.java",
- inputSignatures = "private final int mUserId\nprivate int mSensorId\nprivate final boolean mIgnoreEnrollmentState\nprivate final @android.hardware.biometrics.AuthenticateOptions.DisplayState int mDisplayState\nprivate @android.annotation.NonNull java.lang.String mOpPackageName\nprivate @android.annotation.Nullable java.lang.String mAttributionTag\nprivate @android.annotation.Nullable android.hardware.biometrics.common.AuthenticateReason.Vendor mVendorReason\nprivate static int defaultUserId()\nprivate static int defaultSensorId()\nprivate static boolean defaultIgnoreEnrollmentState()\nprivate static int defaultDisplayState()\nprivate static java.lang.String defaultOpPackageName()\nprivate static java.lang.String defaultAttributionTag()\nprivate static android.hardware.biometrics.common.AuthenticateReason.Vendor defaultVendorReason()\nclass FingerprintAuthenticateOptions extends java.lang.Object implements [android.hardware.biometrics.AuthenticateOptions, android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=true, genBuilder=true, genSetters=true, genEqualsHashCode=true)")
+ inputSignatures = "private final int mUserId\nprivate int mSensorId\nprivate final boolean mIgnoreEnrollmentState\nprivate final @android.hardware.biometrics.AuthenticateOptions.DisplayState int mDisplayState\nprivate @android.annotation.NonNull java.lang.String mOpPackageName\nprivate @android.annotation.Nullable java.lang.String mAttributionTag\nprivate @android.annotation.Nullable android.hardware.biometrics.common.AuthenticateReason.Vendor mVendorReason\nprivate boolean mIsMandatoryBiometrics\nprivate static int defaultUserId()\nprivate static int defaultSensorId()\nprivate static boolean defaultIgnoreEnrollmentState()\nprivate static int defaultDisplayState()\nprivate static java.lang.String defaultOpPackageName()\nprivate static java.lang.String defaultAttributionTag()\nprivate static android.hardware.biometrics.common.AuthenticateReason.Vendor defaultVendorReason()\nclass FingerprintAuthenticateOptions extends java.lang.Object implements [android.hardware.biometrics.AuthenticateOptions, android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=true, genBuilder=true, genSetters=true, genEqualsHashCode=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 536eca6..f1ec0e4e 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1978,7 +1978,6 @@
* @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
* @see #getUserRestrictions()
*/
- @FlaggedApi(android.app.admin.flags.Flags.FLAG_ESIM_MANAGEMENT_ENABLED)
public static final String DISALLOW_SIM_GLOBALLY =
"no_sim_globally";
@@ -1999,7 +1998,6 @@
* @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
* @see #getUserRestrictions()
*/
- @FlaggedApi(android.app.admin.flags.Flags.FLAG_ASSIST_CONTENT_USER_RESTRICTION_ENABLED)
public static final String DISALLOW_ASSIST_CONTENT = "no_assist_content";
/**
diff --git a/core/java/android/service/dreams/DreamOverlayService.java b/core/java/android/service/dreams/DreamOverlayService.java
index fc6af7b..711c414 100644
--- a/core/java/android/service/dreams/DreamOverlayService.java
+++ b/core/java/android/service/dreams/DreamOverlayService.java
@@ -58,6 +58,7 @@
private static class OverlayClient extends IDreamOverlayClient.Stub {
private final WeakReference<DreamOverlayService> mService;
private boolean mShowComplications;
+ private boolean mIsPreview;
private ComponentName mDreamComponent;
IDreamOverlayCallback mDreamOverlayCallback;
@@ -75,9 +76,11 @@
@Override
public void startDream(WindowManager.LayoutParams params, IDreamOverlayCallback callback,
- String dreamComponent, boolean shouldShowComplications) throws RemoteException {
+ String dreamComponent, boolean isPreview, boolean shouldShowComplications)
+ throws RemoteException {
mDreamComponent = ComponentName.unflattenFromString(dreamComponent);
mShowComplications = shouldShowComplications;
+ mIsPreview = isPreview;
mDreamOverlayCallback = callback;
applyToDream(dreamOverlayService -> dreamOverlayService.startDream(this, params));
}
@@ -124,6 +127,10 @@
return mShowComplications;
}
+ private boolean isDreamInPreviewMode() {
+ return mIsPreview;
+ }
+
private ComponentName getComponent() {
return mDreamComponent;
}
@@ -303,7 +310,6 @@
*
* @hide
*/
- @FlaggedApi(Flags.FLAG_DREAM_WAKE_REDIRECT)
public void onWakeRequested() {
}
@@ -320,6 +326,19 @@
}
/**
+ * Returns whether dream is in preview mode.
+ */
+ @FlaggedApi(Flags.FLAG_PUBLISH_PREVIEW_STATE_TO_OVERLAY)
+ public final boolean isDreamInPreviewMode() {
+ if (mCurrentClient == null) {
+ throw new IllegalStateException(
+ "requested if preview when no dream active");
+ }
+
+ return mCurrentClient.isDreamInPreviewMode();
+ }
+
+ /**
* Returns the active dream component.
* @hide
*/
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index c3585e3..ce31e1e 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -1701,6 +1701,7 @@
try {
overlay.startDream(mWindow.getAttributes(), mOverlayCallback,
mDreamComponent.flattenToString(),
+ mPreviewMode,
mShouldShowComplications);
} catch (RemoteException e) {
Log.e(mTag, "could not send window attributes:" + e);
diff --git a/core/java/android/service/dreams/IDreamOverlayClient.aidl b/core/java/android/service/dreams/IDreamOverlayClient.aidl
index 0eb15a0..e9df402 100644
--- a/core/java/android/service/dreams/IDreamOverlayClient.aidl
+++ b/core/java/android/service/dreams/IDreamOverlayClient.aidl
@@ -31,11 +31,12 @@
* @param callback The {@link IDreamOverlayCallback} for requesting actions such as exiting the
* dream.
* @param dreamComponent The component name of the dream service requesting overlay.
+ * @param isPreview Whether the dream is in preview mode.
* @param shouldShowComplications Whether the dream overlay should show complications, e.g. clock
* and weather.
*/
void startDream(in LayoutParams params, in IDreamOverlayCallback callback,
- in String dreamComponent, in boolean shouldShowComplications);
+ in String dreamComponent, in boolean isPreview, in boolean shouldShowComplications);
/** Called when the dream is waking, to do any exit animations */
void wakeUp();
diff --git a/core/java/android/service/dreams/flags.aconfig b/core/java/android/service/dreams/flags.aconfig
index 83e0adf..72f2de8 100644
--- a/core/java/android/service/dreams/flags.aconfig
+++ b/core/java/android/service/dreams/flags.aconfig
@@ -57,3 +57,13 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "publish_preview_state_to_overlay"
+ namespace: "systemui"
+ description: "send preview information from dream to overlay"
+ bug: "333734282"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/core/java/android/window/flags/wallpaper_manager.aconfig b/core/java/android/window/flags/wallpaper_manager.aconfig
index 8c6721a..efacc34 100644
--- a/core/java/android/window/flags/wallpaper_manager.aconfig
+++ b/core/java/android/window/flags/wallpaper_manager.aconfig
@@ -49,3 +49,13 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "avoid_rebinding_intentionally_disconnected_wallpaper"
+ namespace: "systemui"
+ description: "Prevents rebinding with intentionally disconnected wallpaper services."
+ bug: "332871851"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig
index 67fc270..a786fc2 100644
--- a/core/java/android/window/flags/windowing_frontend.aconfig
+++ b/core/java/android/window/flags/windowing_frontend.aconfig
@@ -246,3 +246,14 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "always_capture_activity_snapshot"
+ namespace: "windowing_frontend"
+ description: "Always capture activity snapshot regardless predictive back status"
+ bug: "362183912"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/protolog/ProtoLogDataSource.java b/core/java/com/android/internal/protolog/ProtoLogDataSource.java
index 5c06b87..ef6bece 100644
--- a/core/java/com/android/internal/protolog/ProtoLogDataSource.java
+++ b/core/java/com/android/internal/protolog/ProtoLogDataSource.java
@@ -195,7 +195,7 @@
int defaultLogFromLevelInt = configStream.readInt(DEFAULT_LOG_FROM_LEVEL);
if (defaultLogFromLevelInt < defaultLogFromLevel.ordinal()) {
defaultLogFromLevel =
- logLevelFromInt(configStream.readInt(DEFAULT_LOG_FROM_LEVEL));
+ logLevelFromInt(defaultLogFromLevelInt);
}
break;
case (int) TRACING_MODE:
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 2068bd7..46b4695 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -466,10 +466,25 @@
public:
sp<JavaBBinder> get(JNIEnv* env, jobject obj)
{
- AutoMutex _l(mLock);
- sp<JavaBBinder> b = mBinder.promote();
- if (b == NULL) {
- b = new JavaBBinder(env, obj);
+ sp<JavaBBinder> b;
+ {
+ AutoMutex _l(mLock);
+ // must take lock to promote because we set the same wp<>
+ // on another thread.
+ b = mBinder.promote();
+ }
+
+ if (b) return b;
+
+ // b/360067751: constructor may trigger GC, so call outside lock
+ b = new JavaBBinder(env, obj);
+
+ {
+ AutoMutex _l(mLock);
+ // if it was constructed on another thread in the meantime,
+ // return that. 'b' will just get destructed.
+ if (sp<JavaBBinder> b2 = mBinder.promote(); b2) return b2;
+
if (mVintf) {
::android::internal::Stability::markVintf(b.get());
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 91c3370..17ff2eb 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -843,6 +843,7 @@
<protected-broadcast android:name="android.app.action.CONSOLIDATED_NOTIFICATION_POLICY_CHANGED" />
<protected-broadcast android:name="android.intent.action.MAIN_USER_LOCKSCREEN_KNOWLEDGE_FACTOR_CHANGED" />
<protected-broadcast android:name="com.android.uwb.uwbcountrycode.GEOCODE_RETRY" />
+ <protected-broadcast android:name="android.telephony.action.ACTION_SATELLITE_SUBSCRIBER_ID_LIST_CHANGED" />
<!-- ====================================================================== -->
<!-- RUNTIME PERMISSIONS -->
@@ -3765,7 +3766,6 @@
privileged app such as the Assistant app.
<p>Protection level: internal|role
<p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
- @FlaggedApi("android.app.admin.flags.assist_content_user_restriction_enabled")
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_ASSIST_CONTENT"
android:protectionLevel="internal|role" />
@@ -4026,7 +4026,6 @@
APIs protected by this permission on users different to the calling user.
<p>Protection level: internal|role
<p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
- @FlaggedApi("android.app.admin.flags.esim_management_enabled")
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_MANAGED_SUBSCRIPTIONS"
android:protectionLevel="internal|role" />
diff --git a/core/res/res/drawable/ic_zen_priority_modes.xml b/core/res/res/drawable/ic_zen_priority_modes.xml
new file mode 100644
index 0000000..98de27b
--- /dev/null
+++ b/core/res/res/drawable/ic_zen_priority_modes.xml
@@ -0,0 +1,25 @@
+<!--
+Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="960"
+ android:viewportHeight="960"
+ android:tint="?android:attr/colorControlNormal">
+ <path
+ android:pathData="M160,480v-80h320v80L160,480ZM480,880q-80,0 -153.5,-29.5T196,764l56,-56q47,44 106,68t122,24q133,0 226.5,-93.5T800,480q0,-133 -93.5,-226.5T480,160v-80q83,0 155.5,31.5t127,86q54.5,54.5 86,127T880,480q0,82 -31.5,155t-86,127.5q-54.5,54.5 -127,86T480,880Z"
+ android:fillColor="@android:color/white"/>
+</vector>
diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml
index a7240ff..69437b4 100644
--- a/core/res/res/values/config_telephony.xml
+++ b/core/res/res/values/config_telephony.xml
@@ -440,10 +440,6 @@
<string name="config_satellite_carrier_roaming_esos_provisioned_class" translatable="false"></string>
<java-symbol type="string" name="config_satellite_carrier_roaming_esos_provisioned_class" />
- <!-- Telephony satellite gateway intent for handling carrier roaming to satellite is using ESOS messaging. -->
- <string name="config_satellite_carrier_roaming_esos_provisioned_intent_action" translatable="false"></string>
- <java-symbol type="string" name="config_satellite_carrier_roaming_esos_provisioned_intent_action" />
-
<!-- The time duration in minutes to wait before retry validating a possible change
in satellite allowed region. The default value is 10 minutes. -->
<integer name="config_satellite_delay_minutes_before_retry_validating_possible_change_in_allowed_region">10</integer>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index bbe661e..74922ac 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -5566,6 +5566,7 @@
<java-symbol type="string" name="recs_notification_channel_label"/>
<!-- Priority Modes icons -->
+ <java-symbol type="drawable" name="ic_zen_priority_modes" />
<java-symbol type="drawable" name="ic_zen_mode_type_bedtime" />
<java-symbol type="drawable" name="ic_zen_mode_type_driving" />
<java-symbol type="drawable" name="ic_zen_mode_type_immersive" />
diff --git a/data/keyboards/Vendor_0957_Product_0033.idc b/data/keyboards/Vendor_0957_Product_0033.idc
new file mode 100644
index 0000000..7dfbe2c
--- /dev/null
+++ b/data/keyboards/Vendor_0957_Product_0033.idc
@@ -0,0 +1,23 @@
+# Copyright 2024 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Input Device Configuration file for Google Reference RCU Remote.
+# PID 0033 is for new G20 with start button.
+
+# Basic Parameters
+keyboard.layout = Vendor_0957_Product_0031
+# The reason why we set is follow https://docs.partner.android.com/tv/build/gtv/boot-resume
+keyboard.doNotWakeByDefault = 1
+audio.mic = 1
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/BackupHelper.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/BackupHelper.java
index 69a68c8..0726624 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/BackupHelper.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/BackupHelper.java
@@ -24,6 +24,7 @@
import androidx.annotation.NonNull;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -80,9 +81,14 @@
}
if (DEBUG) Log.d(TAG, "Start to back up " + taskContainers);
+ final List<ParcelableTaskContainerData> parcelableTaskContainerDataList = new ArrayList<>(
+ taskContainers.size());
+ for (TaskContainer taskContainer : taskContainers) {
+ parcelableTaskContainerDataList.add(taskContainer.getParcelableData());
+ }
final Bundle state = new Bundle();
- state.setClassLoader(TaskContainer.class.getClassLoader());
- state.putParcelableList(KEY_TASK_CONTAINERS, taskContainers);
+ state.setClassLoader(ParcelableTaskContainerData.class.getClassLoader());
+ state.putParcelableList(KEY_TASK_CONTAINERS, parcelableTaskContainerDataList);
mController.setSavedState(state);
}
@@ -91,10 +97,12 @@
return;
}
- final List<TaskContainer> taskContainers = savedState.getParcelableArrayList(
- KEY_TASK_CONTAINERS, TaskContainer.class);
- for (TaskContainer taskContainer : taskContainers) {
- if (DEBUG) Log.d(TAG, "restore task " + taskContainer.getTaskId());
+ final List<ParcelableTaskContainerData> parcelableTaskContainerDataList =
+ savedState.getParcelableArrayList(KEY_TASK_CONTAINERS,
+ ParcelableTaskContainerData.class);
+ for (ParcelableTaskContainerData data : parcelableTaskContainerDataList) {
+ final TaskContainer taskContainer = new TaskContainer(data, mController);
+ if (DEBUG) Log.d(TAG, "Restoring task " + taskContainer.getTaskId());
// TODO(b/289875940): implement the TaskContainer restoration.
}
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/ParcelableSplitContainerData.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/ParcelableSplitContainerData.java
new file mode 100644
index 0000000..817cfce
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/ParcelableSplitContainerData.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.extensions.embedding;
+
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+/**
+ * This class holds the Parcelable data of a {@link SplitContainer}.
+ */
+class ParcelableSplitContainerData implements Parcelable {
+
+ /**
+ * A reference to the target {@link SplitContainer} that owns the data. This will not be
+ * parcelled and will be {@code null} when the data is created from a parcel.
+ */
+ @Nullable
+ final SplitContainer mSplitContainer;
+
+ @NonNull
+ final IBinder mToken;
+
+ @NonNull
+ private final IBinder mPrimaryContainerToken;
+
+ @NonNull
+ private final IBinder mSecondaryContainerToken;
+
+ // TODO(b/289875940): making this as non-null once the tag can be auto-generated from the rule.
+ @Nullable
+ final String mSplitRuleTag;
+
+ /**
+ * Whether the selection of which container is primary can be changed at runtime. Runtime
+ * updates is currently possible only for {@link SplitPinContainer}
+ *
+ * @see SplitPinContainer
+ */
+ final boolean mIsPrimaryContainerMutable;
+
+ ParcelableSplitContainerData(@NonNull SplitContainer splitContainer, @NonNull IBinder token,
+ @NonNull IBinder primaryContainerToken, @NonNull IBinder secondaryContainerToken,
+ @Nullable String splitRuleTag, boolean isPrimaryContainerMutable) {
+ mSplitContainer = splitContainer;
+ mToken = token;
+ mPrimaryContainerToken = primaryContainerToken;
+ mSecondaryContainerToken = secondaryContainerToken;
+ mSplitRuleTag = splitRuleTag;
+ mIsPrimaryContainerMutable = isPrimaryContainerMutable;
+ }
+
+ private ParcelableSplitContainerData(Parcel in) {
+ mSplitContainer = null;
+ mToken = in.readStrongBinder();
+ mPrimaryContainerToken = in.readStrongBinder();
+ mSecondaryContainerToken = in.readStrongBinder();
+ mSplitRuleTag = in.readString();
+ mIsPrimaryContainerMutable = in.readBoolean();
+ }
+
+ public static final Creator<ParcelableSplitContainerData> CREATOR = new Creator<>() {
+ @Override
+ public ParcelableSplitContainerData createFromParcel(Parcel in) {
+ return new ParcelableSplitContainerData(in);
+ }
+
+ @Override
+ public ParcelableSplitContainerData[] newArray(int size) {
+ return new ParcelableSplitContainerData[size];
+ }
+ };
+
+ @NonNull
+ private IBinder getPrimaryContainerToken() {
+ return mSplitContainer != null ? mSplitContainer.getPrimaryContainer().getToken()
+ : mPrimaryContainerToken;
+ }
+
+ @NonNull
+ private IBinder getSecondaryContainerToken() {
+ return mSplitContainer != null ? mSplitContainer.getSecondaryContainer().getToken()
+ : mSecondaryContainerToken;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeStrongBinder(mToken);
+ dest.writeStrongBinder(getPrimaryContainerToken());
+ dest.writeStrongBinder(getSecondaryContainerToken());
+ dest.writeString(mSplitRuleTag);
+ dest.writeBoolean(mIsPrimaryContainerMutable);
+ }
+}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/ParcelableTaskContainerData.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/ParcelableTaskContainerData.java
new file mode 100644
index 0000000..7377d00
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/ParcelableTaskContainerData.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.extensions.embedding;
+
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class holds the Parcelable data of a {@link TaskContainer}.
+ */
+class ParcelableTaskContainerData implements Parcelable {
+
+ /**
+ * A reference to the target {@link TaskContainer} that owns the data. This will not be
+ * parcelled and will be {@code null} when the data is created from a parcel.
+ */
+ @Nullable
+ final TaskContainer mTaskContainer;
+
+ /**
+ * The unique task id.
+ */
+ final int mTaskId;
+
+ /**
+ * The parcelable data of the active TaskFragmentContainers in this Task.
+ * Note that this will only be populated before parcelling, and will not be copied when
+ * making a new instance copy.
+ */
+ @NonNull
+ private final List<ParcelableTaskFragmentContainerData>
+ mParcelableTaskFragmentContainerDataList = new ArrayList<>();
+
+ /**
+ * The parcelable data of the SplitContainers in this Task.
+ * Note that this will only be populated before parcelling, and will not be copied when
+ * making a new instance copy.
+ */
+ @NonNull
+ private final List<ParcelableSplitContainerData> mParcelableSplitContainerDataList =
+ new ArrayList<>();
+
+ ParcelableTaskContainerData(int taskId, @NonNull TaskContainer taskContainer) {
+ if (taskId == INVALID_TASK_ID) {
+ throw new IllegalArgumentException("Invalid Task id");
+ }
+
+ mTaskId = taskId;
+ mTaskContainer = taskContainer;
+ }
+
+ ParcelableTaskContainerData(@NonNull ParcelableTaskContainerData data,
+ @NonNull TaskContainer taskContainer) {
+ mTaskId = data.mTaskId;
+ mTaskContainer = taskContainer;
+ }
+
+ private ParcelableTaskContainerData(Parcel in) {
+ mTaskId = in.readInt();
+ mTaskContainer = null;
+ in.readParcelableList(mParcelableTaskFragmentContainerDataList,
+ ParcelableTaskFragmentContainerData.class.getClassLoader(),
+ ParcelableTaskFragmentContainerData.class);
+ in.readParcelableList(mParcelableSplitContainerDataList,
+ ParcelableSplitContainerData.class.getClassLoader(),
+ ParcelableSplitContainerData.class);
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mTaskId);
+ dest.writeParcelableList(getParcelableTaskFragmentContainerDataList(), flags);
+ dest.writeParcelableList(getParcelableSplitContainerDataList(), flags);
+ }
+
+ @NonNull
+ List<? extends ParcelableTaskFragmentContainerData>
+ getParcelableTaskFragmentContainerDataList() {
+ return mTaskContainer != null ? mTaskContainer.getParcelableTaskFragmentContainerDataList()
+ : mParcelableTaskFragmentContainerDataList;
+ }
+
+ @NonNull
+ List<? extends ParcelableSplitContainerData> getParcelableSplitContainerDataList() {
+ return mTaskContainer != null ? mTaskContainer.getParcelableSplitContainerDataList()
+ : mParcelableSplitContainerDataList;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Creator<ParcelableTaskContainerData> CREATOR = new Creator<>() {
+ @Override
+ public ParcelableTaskContainerData createFromParcel(Parcel in) {
+ return new ParcelableTaskContainerData(in);
+ }
+
+ @Override
+ public ParcelableTaskContainerData[] newArray(int size) {
+ return new ParcelableTaskContainerData[size];
+ }
+ };
+}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/ParcelableTaskFragmentContainerData.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/ParcelableTaskFragmentContainerData.java
new file mode 100644
index 0000000..a79a89a
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/ParcelableTaskFragmentContainerData.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.extensions.embedding;
+
+import android.app.Activity;
+import android.graphics.Rect;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+/**
+ * This class holds the Parcelable data of a {@link TaskFragmentContainer}.
+ */
+class ParcelableTaskFragmentContainerData implements Parcelable {
+
+ /**
+ * Client-created token that uniquely identifies the task fragment container instance.
+ */
+ @NonNull
+ final IBinder mToken;
+
+ /**
+ * The tag specified in launch options. {@code null} if this taskFragment container is not an
+ * overlay container.
+ */
+ @Nullable
+ final String mOverlayTag;
+
+ /**
+ * The associated {@link Activity#getActivityToken()} of the overlay container.
+ * Must be {@code null} for non-overlay container.
+ * <p>
+ * If an overlay container is associated with an activity, this overlay container will be
+ * dismissed when the associated activity is destroyed. If the overlay container is visible,
+ * activity will be launched on top of the overlay container and expanded to fill the parent
+ * container.
+ */
+ @Nullable
+ final IBinder mAssociatedActivityToken;
+
+ /**
+ * Bounds that were requested last via {@link android.window.WindowContainerTransaction}.
+ */
+ @NonNull
+ final Rect mLastRequestedBounds;
+
+ ParcelableTaskFragmentContainerData(@NonNull IBinder token, @Nullable String overlayTag,
+ @Nullable IBinder associatedActivityToken) {
+ mToken = token;
+ mOverlayTag = overlayTag;
+ mAssociatedActivityToken = associatedActivityToken;
+ mLastRequestedBounds = new Rect();
+ }
+
+ private ParcelableTaskFragmentContainerData(Parcel in) {
+ mToken = in.readStrongBinder();
+ mOverlayTag = in.readString();
+ mAssociatedActivityToken = in.readStrongBinder();
+ mLastRequestedBounds = in.readTypedObject(Rect.CREATOR);
+ }
+
+ public static final Creator<ParcelableTaskFragmentContainerData> CREATOR = new Creator<>() {
+ @Override
+ public ParcelableTaskFragmentContainerData createFromParcel(Parcel in) {
+ return new ParcelableTaskFragmentContainerData(in);
+ }
+
+ @Override
+ public ParcelableTaskFragmentContainerData[] newArray(int size) {
+ return new ParcelableTaskFragmentContainerData[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeStrongBinder(mToken);
+ dest.writeString(mOverlayTag);
+ dest.writeStrongBinder(mAssociatedActivityToken);
+ dest.writeTypedObject(mLastRequestedBounds, flags);
+ }
+
+}
+
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java
index 39cface..6d436ec 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java
@@ -33,6 +33,8 @@
*/
class SplitContainer {
@NonNull
+ private final ParcelableSplitContainerData mParcelableData;
+ @NonNull
private TaskFragmentContainer mPrimaryContainer;
@NonNull
private final TaskFragmentContainer mSecondaryContainer;
@@ -44,16 +46,6 @@
/** @see SplitContainer#getDefaultSplitAttributes() */
@NonNull
private SplitAttributes mDefaultSplitAttributes;
- @NonNull
- private final IBinder mToken;
-
- /**
- * Whether the selection of which container is primary can be changed at runtime. Runtime
- * updates is currently possible only for {@link SplitPinContainer}
- *
- * @see SplitPinContainer
- */
- private final boolean mIsPrimaryContainerMutable;
SplitContainer(@NonNull TaskFragmentContainer primaryContainer,
@NonNull Activity primaryActivity,
@@ -69,13 +61,14 @@
@NonNull TaskFragmentContainer secondaryContainer,
@NonNull SplitRule splitRule,
@NonNull SplitAttributes splitAttributes, boolean isPrimaryContainerMutable) {
+ mParcelableData = new ParcelableSplitContainerData(this, new Binder("SplitContainer"),
+ primaryContainer.getToken(), secondaryContainer.getToken(), splitRule.getTag(),
+ isPrimaryContainerMutable);
mPrimaryContainer = primaryContainer;
mSecondaryContainer = secondaryContainer;
mSplitRule = splitRule;
mDefaultSplitAttributes = splitRule.getDefaultSplitAttributes();
mCurrentSplitAttributes = splitAttributes;
- mToken = new Binder("SplitContainer");
- mIsPrimaryContainerMutable = isPrimaryContainerMutable;
if (shouldFinishPrimaryWithSecondary(splitRule)) {
if (mPrimaryContainer.getRunningActivityCount() == 1
@@ -94,7 +87,7 @@
}
void setPrimaryContainer(@NonNull TaskFragmentContainer primaryContainer) {
- if (!mIsPrimaryContainerMutable) {
+ if (!mParcelableData.mIsPrimaryContainerMutable) {
throw new IllegalStateException("Cannot update primary TaskFragmentContainer");
}
mPrimaryContainer = primaryContainer;
@@ -150,7 +143,12 @@
@NonNull
IBinder getToken() {
- return mToken;
+ return mParcelableData.mToken;
+ }
+
+ @NonNull
+ ParcelableSplitContainerData getParcelableData() {
+ return mParcelableData;
}
/**
@@ -201,7 +199,7 @@
return null;
}
return new SplitInfo(primaryActivityStack, secondaryActivityStack,
- mCurrentSplitAttributes, SplitInfo.Token.createFromBinder(mToken));
+ mCurrentSplitAttributes, SplitInfo.Token.createFromBinder(mParcelableData.mToken));
}
static boolean shouldFinishPrimaryWithSecondary(@NonNull SplitRule splitRule) {
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
index fb8efc4..5637320 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
@@ -169,7 +169,7 @@
mController = controller;
final Bundle outSavedState = new Bundle();
if (Flags.aeBackStackRestore()) {
- outSavedState.setClassLoader(TaskContainer.class.getClassLoader());
+ outSavedState.setClassLoader(ParcelableTaskContainerData.class.getClassLoader());
registerOrganizer(false /* isSystemOrganizer */, outSavedState);
} else {
registerOrganizer();
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
index 5795e8d..82dfda5 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
@@ -16,7 +16,6 @@
package androidx.window.extensions.embedding;
-import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
@@ -32,8 +31,6 @@
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.IBinder;
-import android.os.Parcel;
-import android.os.Parcelable;
import android.util.ArraySet;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -57,11 +54,12 @@
import java.util.Set;
/** Represents TaskFragments and split pairs below a Task. */
-class TaskContainer implements Parcelable {
+class TaskContainer {
private static final String TAG = TaskContainer.class.getSimpleName();
- /** The unique task id. */
- private final int mTaskId;
+ /** Parcelable data of this TaskContainer. */
+ @NonNull
+ private final ParcelableTaskContainerData mParcelableTaskContainerData;
/** Active TaskFragments in this Task. */
@NonNull
@@ -130,11 +128,9 @@
* @param splitController The {@link SplitController}.
*/
TaskContainer(int taskId, @NonNull Activity activityInTask,
- @Nullable SplitController splitController) {
- if (taskId == INVALID_TASK_ID) {
- throw new IllegalArgumentException("Invalid Task id");
- }
- mTaskId = taskId;
+ @NonNull SplitController splitController) {
+ mParcelableTaskContainerData = new ParcelableTaskContainerData(taskId, this);
+
final TaskProperties taskProperties = TaskProperties
.getTaskPropertiesFromActivity(activityInTask);
mInfo = new TaskFragmentParentInfo(
@@ -148,8 +144,44 @@
mSplitController = splitController;
}
+ /** This is only used when restoring it from a {@link ParcelableTaskContainerData}. */
+ TaskContainer(@NonNull ParcelableTaskContainerData data,
+ @NonNull SplitController splitController) {
+ mParcelableTaskContainerData = new ParcelableTaskContainerData(data, this);
+ mSplitController = splitController;
+ for (ParcelableTaskFragmentContainerData tfData :
+ data.getParcelableTaskFragmentContainerDataList()) {
+ final TaskFragmentContainer container =
+ new TaskFragmentContainer(tfData, splitController, this);
+ mContainers.add(container);
+ }
+ }
+
+ @NonNull
+ ParcelableTaskContainerData getParcelableData() {
+ return mParcelableTaskContainerData;
+ }
+
+ @NonNull
+ List<ParcelableTaskFragmentContainerData> getParcelableTaskFragmentContainerDataList() {
+ final List<ParcelableTaskFragmentContainerData> data = new ArrayList<>(mContainers.size());
+ for (TaskFragmentContainer container : mContainers) {
+ data.add(container.getParcelableData());
+ }
+ return data;
+ }
+
+ @NonNull
+ List<ParcelableSplitContainerData> getParcelableSplitContainerDataList() {
+ final List<ParcelableSplitContainerData> data = new ArrayList<>(mSplitContainers.size());
+ for (SplitContainer splitContainer : mSplitContainers) {
+ data.add(splitContainer.getParcelableData());
+ }
+ return data;
+ }
+
int getTaskId() {
- return mTaskId;
+ return mParcelableTaskContainerData.mTaskId;
}
int getDisplayId() {
@@ -680,34 +712,6 @@
return activityStacks;
}
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mTaskId);
- // TODO(b/289875940)
- }
-
- protected TaskContainer(Parcel in) {
- mTaskId = in.readInt();
- // TODO(b/289875940)
- }
-
- public static final Creator<TaskContainer> CREATOR = new Creator<>() {
- @Override
- public TaskContainer createFromParcel(Parcel in) {
- return new TaskContainer(in);
- }
-
- @Override
- public TaskContainer[] newArray(int size) {
- return new TaskContainer[size];
- }
- };
-
/** A wrapper class which contains the information of {@link TaskContainer} */
static final class TaskProperties {
private final int mDisplayId;
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
index dc6506b..dc1d983 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
@@ -53,15 +53,13 @@
class TaskFragmentContainer {
private static final int APPEAR_EMPTY_TIMEOUT_MS = 3000;
+ /** Parcelable data of this TaskFragmentContainer. */
+ @NonNull
+ private final ParcelableTaskFragmentContainerData mParcelableData;
+
@NonNull
private final SplitController mController;
- /**
- * Client-created token that uniquely identifies the task fragment container instance.
- */
- @NonNull
- private final IBinder mToken;
-
/** Parent leaf Task. */
@NonNull
private final TaskContainer mTaskContainer;
@@ -103,9 +101,6 @@
*/
private final List<IBinder> mActivitiesToFinishOnExit = new ArrayList<>();
- @Nullable
- private final String mOverlayTag;
-
/**
* The launch options that was used to create this container. Must not {@link Bundle#isEmpty()}
* for {@link #isOverlay()} container.
@@ -113,29 +108,13 @@
@NonNull
private final Bundle mLaunchOptions = new Bundle();
- /**
- * The associated {@link Activity#getActivityToken()} of the overlay container.
- * Must be {@code null} for non-overlay container.
- * <p>
- * If an overlay container is associated with an activity, this overlay container will be
- * dismissed when the associated activity is destroyed. If the overlay container is visible,
- * activity will be launched on top of the overlay container and expanded to fill the parent
- * container.
- */
- @Nullable
- private final IBinder mAssociatedActivityToken;
-
/** Indicates whether the container was cleaned up after the last activity was removed. */
private boolean mIsFinished;
/**
- * Bounds that were requested last via {@link android.window.WindowContainerTransaction}.
- */
- private final Rect mLastRequestedBounds = new Rect();
-
- /**
* Windowing mode that was requested last via {@link android.window.WindowContainerTransaction}.
*/
+ // TODO(b/289875940): review this and other field that might need to be moved in the base class.
@WindowingMode
private int mLastRequestedWindowingMode = WINDOWING_MODE_UNDEFINED;
@@ -208,17 +187,17 @@
@NonNull SplitController controller,
@Nullable TaskFragmentContainer pairedPrimaryContainer, @Nullable String overlayTag,
@Nullable Bundle launchOptions, @Nullable Activity associatedActivity) {
+ mParcelableData = new ParcelableTaskFragmentContainerData(
+ new Binder("TaskFragmentContainer"), overlayTag,
+ associatedActivity != null ? associatedActivity.getActivityToken() : null);
+
if ((pendingAppearedActivity == null && pendingAppearedIntent == null)
|| (pendingAppearedActivity != null && pendingAppearedIntent != null)) {
throw new IllegalArgumentException(
"One and only one of pending activity and intent must be non-null");
}
mController = controller;
- mToken = new Binder("TaskFragmentContainer");
mTaskContainer = taskContainer;
- mOverlayTag = overlayTag;
- mAssociatedActivityToken = associatedActivity != null
- ? associatedActivity.getActivityToken() : null;
if (launchOptions != null) {
mLaunchOptions.putAll(launchOptions);
@@ -259,18 +238,26 @@
if (overlayTag != null && pendingAppearedIntent != null
&& associatedActivity != null && !associatedActivity.isFinishing()) {
final IBinder associatedActivityToken = associatedActivity.getActivityToken();
- final OverlayContainerRestoreParams params = new OverlayContainerRestoreParams(mToken,
- launchOptions, pendingAppearedIntent);
+ final OverlayContainerRestoreParams params = new OverlayContainerRestoreParams(
+ mParcelableData.mToken, launchOptions, pendingAppearedIntent);
mController.mOverlayRestoreParams.put(associatedActivityToken, params);
}
}
+ /** This is only used when restoring it from a {@link ParcelableTaskFragmentContainerData}. */
+ TaskFragmentContainer(@NonNull ParcelableTaskFragmentContainerData data,
+ @NonNull SplitController splitController, @NonNull TaskContainer taskContainer) {
+ mParcelableData = data;
+ mController = splitController;
+ mTaskContainer = taskContainer;
+ }
+
/**
* Returns the client-created token that uniquely identifies this container.
*/
@NonNull
IBinder getTaskFragmentToken() {
- return mToken;
+ return mParcelableData.mToken;
}
/** List of non-finishing activities that belong to this container and live in this process. */
@@ -389,7 +376,8 @@
return null;
}
return new ActivityStack(activities, isEmpty(),
- ActivityStack.Token.createFromBinder(mToken), mOverlayTag);
+ ActivityStack.Token.createFromBinder(mParcelableData.mToken),
+ mParcelableData.mOverlayTag);
}
/** Adds the activity that will be reparented to this container. */
@@ -413,7 +401,7 @@
final ActivityThread.ActivityClientRecord record = ActivityThread
.currentActivityThread().getActivityClient(activityToken);
if (record != null) {
- record.mTaskFragmentToken = mToken;
+ record.mTaskFragmentToken = mParcelableData.mToken;
}
}
@@ -469,7 +457,7 @@
if (!isOverlayWithActivityAssociation()) {
return;
}
- if (mAssociatedActivityToken == activityToken) {
+ if (mParcelableData.mAssociatedActivityToken == activityToken) {
// If the associated activity is destroyed, also finish this overlay container.
mController.mPresenter.cleanupContainer(wct, this, false /* shouldFinishDependent */);
}
@@ -776,8 +764,8 @@
* @see WindowContainerTransaction#setRelativeBounds
*/
boolean areLastRequestedBoundsEqual(@Nullable Rect relBounds) {
- return (relBounds == null && mLastRequestedBounds.isEmpty())
- || mLastRequestedBounds.equals(relBounds);
+ return (relBounds == null && mParcelableData.mLastRequestedBounds.isEmpty())
+ || mParcelableData.mLastRequestedBounds.equals(relBounds);
}
/**
@@ -787,14 +775,14 @@
*/
void setLastRequestedBounds(@Nullable Rect relBounds) {
if (relBounds == null) {
- mLastRequestedBounds.setEmpty();
+ mParcelableData.mLastRequestedBounds.setEmpty();
} else {
- mLastRequestedBounds.set(relBounds);
+ mParcelableData.mLastRequestedBounds.set(relBounds);
}
}
@NonNull Rect getLastRequestedBounds() {
- return mLastRequestedBounds;
+ return mParcelableData.mLastRequestedBounds;
}
/**
@@ -965,6 +953,16 @@
return mTaskContainer.getTaskId();
}
+ @NonNull
+ IBinder getToken() {
+ return mParcelableData.mToken;
+ }
+
+ @NonNull
+ ParcelableTaskFragmentContainerData getParcelableData() {
+ return mParcelableData;
+ }
+
/** Gets the parent Task. */
@NonNull
TaskContainer getTaskContainer() {
@@ -1011,7 +1009,7 @@
/** Returns whether this taskFragment container is an overlay container. */
boolean isOverlay() {
- return mOverlayTag != null;
+ return mParcelableData.mOverlayTag != null;
}
/**
@@ -1020,7 +1018,7 @@
*/
@Nullable
String getOverlayTag() {
- return mOverlayTag;
+ return mParcelableData.mOverlayTag;
}
/**
@@ -1045,7 +1043,7 @@
*/
@Nullable
IBinder getAssociatedActivityToken() {
- return mAssociatedActivityToken;
+ return mParcelableData.mAssociatedActivityToken;
}
/**
@@ -1053,11 +1051,11 @@
* a non-fill-parent overlay without activity association.
*/
boolean isAlwaysOnTopOverlay() {
- return isOverlay() && mAssociatedActivityToken == null;
+ return isOverlay() && mParcelableData.mAssociatedActivityToken == null;
}
boolean isOverlayWithActivityAssociation() {
- return isOverlay() && mAssociatedActivityToken != null;
+ return isOverlay() && mParcelableData.mAssociatedActivityToken != null;
}
@Override
@@ -1074,13 +1072,13 @@
private String toString(boolean includeContainersToFinishOnExit) {
return "TaskFragmentContainer{"
+ " parentTaskId=" + getTaskId()
- + " token=" + mToken
+ + " token=" + mParcelableData.mToken
+ " topNonFinishingActivity=" + getTopNonFinishingActivity()
+ " runningActivityCount=" + getRunningActivityCount()
+ " isFinished=" + mIsFinished
- + " overlayTag=" + mOverlayTag
- + " associatedActivityToken=" + mAssociatedActivityToken
- + " lastRequestedBounds=" + mLastRequestedBounds
+ + " overlayTag=" + mParcelableData.mOverlayTag
+ + " associatedActivityToken=" + mParcelableData.mAssociatedActivityToken
+ + " lastRequestedBounds=" + mParcelableData.mLastRequestedBounds
+ " pendingAppearedActivities=" + mPendingAppearedActivities
+ (includeContainersToFinishOnExit ? " containersToFinishOnExit="
+ containersToFinishOnExitToString() : "")
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellCoroutinesModule.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellCoroutinesModule.kt
index 423fe57..cc47dbb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellCoroutinesModule.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellCoroutinesModule.kt
@@ -61,20 +61,20 @@
@WMSingleton
@ShellMainThread
fun provideApplicationScope(
- @ShellMainThread applicationDispatcher: CoroutineDispatcher,
+ @ShellMainThread applicationDispatcher: MainCoroutineDispatcher,
): CoroutineScope = CoroutineScope(applicationDispatcher)
@Provides
@WMSingleton
@ShellBackgroundThread
fun provideBackgroundCoroutineScope(
- @ShellBackgroundThread backgroundDispatcher: CoroutineDispatcher,
+ @ShellBackgroundThread backgroundDispatcher: MainCoroutineDispatcher,
): CoroutineScope = CoroutineScope(backgroundDispatcher)
@Provides
@WMSingleton
@ShellBackgroundThread
fun provideBackgroundCoroutineContext(
- @ShellBackgroundThread backgroundDispatcher: CoroutineDispatcher
+ @ShellBackgroundThread backgroundDispatcher: MainCoroutineDispatcher
): CoroutineContext = backgroundDispatcher + SupervisorJob()
}
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt
index 90b9798..cbd4a52 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt
@@ -181,6 +181,13 @@
super.taskBarWindowIsAlwaysVisible()
}
+ // Overridden to remove @Postsubmit annotation
+ @Test
+ @FlakyTest(bugId = 294993100)
+ override fun pipLayerHasCorrectCornersAtEnd() {
+ // No rounded corners as we go back to fullscreen in new orientation.
+ }
+
companion object {
/**
* Creates the test configurations.
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt
index ed2a0a7..578a9b5 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt
@@ -147,6 +147,12 @@
@Test
override fun entireScreenCovered() = super.entireScreenCovered()
+ @Postsubmit
+ @Test
+ override fun pipLayerHasCorrectCornersAtEnd() {
+ flicker.assertLayersEnd { hasNoRoundedCorners(pipApp) }
+ }
+
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ClosePipTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ClosePipTransition.kt
index 8cb81b4..f57335c 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ClosePipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ClosePipTransition.kt
@@ -70,6 +70,11 @@
}
}
+ @Test
+ override fun pipLayerHasCorrectCornersAtEnd() {
+ // PiP might have completely faded out by this point, so corner radii not applicable.
+ }
+
companion object {
/**
* Creates the test configurations.
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ExitPipToAppTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ExitPipToAppTransition.kt
index 0742cf9..ce84eb6 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ExitPipToAppTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ExitPipToAppTransition.kt
@@ -16,6 +16,7 @@
package com.android.wm.shell.flicker.pip.common
+import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.tools.Rotation
import android.tools.flicker.legacy.LegacyFlickerTest
@@ -123,6 +124,12 @@
}
}
+ @Postsubmit
+ @Test
+ override fun pipLayerHasCorrectCornersAtEnd() {
+ flicker.assertLayersEnd { hasNoRoundedCorners(pipApp) }
+ }
+
/** {@inheritDoc} */
@Presubmit @Test override fun entireScreenCovered() = super.entireScreenCovered()
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt
index 99c1ad2..bc2bfdb 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt
@@ -18,6 +18,7 @@
import android.app.Instrumentation
import android.content.Intent
+import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.tools.Rotation
import android.tools.flicker.legacy.FlickerBuilder
@@ -105,4 +106,10 @@
.doesNotContain(false)
}
}
+
+ @Postsubmit
+ @Test
+ open fun pipLayerHasCorrectCornersAtEnd() {
+ flicker.assertLayersEnd { hasRoundedCorners(pipApp) }
+ }
}
diff --git a/packages/SettingsLib/res/drawable/audio_sharing_rounded_bg.xml b/packages/SettingsLib/res/drawable/audio_sharing_rounded_bg.xml
new file mode 100644
index 0000000..35517ea
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/audio_sharing_rounded_bg.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:shape="rectangle">
+ <solid android:color="?androidprv:attr/colorAccentPrimary" />
+ <corners android:radius="12dp" />
+</shape>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/drawable/audio_sharing_rounded_bg_ripple.xml b/packages/SettingsLib/res/drawable/audio_sharing_rounded_bg_ripple.xml
new file mode 100644
index 0000000..18696c6
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/audio_sharing_rounded_bg_ripple.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:attr/colorControlHighlight">
+ <item android:drawable="@drawable/audio_sharing_rounded_bg"/>
+</ripple>
\ No newline at end of file
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
index 055afed..0ffb763 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
@@ -1,5 +1,6 @@
package com.android.settingslib.bluetooth;
+import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.UNKNOWN_VALUE_PLACEHOLDER;
import static com.android.settingslib.widget.AdaptiveOutlineDrawable.ICON_TYPE_ADVANCED;
import android.annotation.SuppressLint;
@@ -704,12 +705,50 @@
return !sourceList.isEmpty() && sourceList.stream().anyMatch(BluetoothUtils::isConnected);
}
+ /**
+ * Check if {@link BluetoothDevice} has a active local broadcast source.
+ *
+ * @param device The bluetooth device to check.
+ * @param localBtManager The BT manager to provide BT functions.
+ * @return Whether the device has a active local broadcast source.
+ */
+ @WorkerThread
+ public static boolean hasActiveLocalBroadcastSourceForBtDevice(
+ @Nullable BluetoothDevice device, @Nullable LocalBluetoothManager localBtManager) {
+ LocalBluetoothLeBroadcastAssistant assistant =
+ localBtManager == null
+ ? null
+ : localBtManager.getProfileManager().getLeAudioBroadcastAssistantProfile();
+ LocalBluetoothLeBroadcast broadcast =
+ localBtManager == null
+ ? null
+ : localBtManager.getProfileManager().getLeAudioBroadcastProfile();
+ if (device == null || assistant == null || broadcast == null) {
+ Log.d(TAG, "Skip check hasActiveLocalBroadcastSourceForBtDevice due to arg is null");
+ return false;
+ }
+ List<BluetoothLeBroadcastReceiveState> sourceList = assistant.getAllSources(device);
+ int broadcastId = broadcast.getLatestBroadcastId();
+ return !sourceList.isEmpty()
+ && broadcastId != UNKNOWN_VALUE_PLACEHOLDER
+ && sourceList.stream()
+ .anyMatch(
+ source -> isSourceMatched(source, broadcastId));
+ }
+
/** Checks the connectivity status based on the provided broadcast receive state. */
@WorkerThread
public static boolean isConnected(BluetoothLeBroadcastReceiveState state) {
return state.getBisSyncState().stream().anyMatch(bitmap -> bitmap != 0);
}
+ /** Checks if the broadcast id is matched based on the provided broadcast receive state. */
+ @WorkerThread
+ public static boolean isSourceMatched(
+ @Nullable BluetoothLeBroadcastReceiveState state, int broadcastId) {
+ return state != null && state.getBroadcastId() == broadcastId;
+ }
+
/**
* Checks if the Bluetooth device is an available hearing device, which means: 1) currently
* connected 2) is Hearing Aid 3) connected profile match hearing aid related profiles (e.g.
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
index 26905b1..6f2567b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
@@ -101,7 +101,7 @@
private static final int DEFAULT_CODE_MIN = 1000;
// Order of this profile in device profiles list
private static final int ORDINAL = 1;
- private static final int UNKNOWN_VALUE_PLACEHOLDER = -1;
+ static final int UNKNOWN_VALUE_PLACEHOLDER = -1;
private static final Uri[] SETTINGS_URIS =
new Uri[] {
Settings.Secure.getUriFor(Settings.Secure.BLUETOOTH_LE_BROADCAST_NAME),
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java
index 3a7b0c7..a0e764a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java
@@ -16,6 +16,7 @@
package com.android.settingslib.bluetooth;
import static com.android.settingslib.bluetooth.BluetoothUtils.isAvailableAudioSharingMediaBluetoothDevice;
+import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.UNKNOWN_VALUE_PLACEHOLDER;
import static com.android.settingslib.flags.Flags.FLAG_ENABLE_DETERMINING_ADVANCED_DETAILS_HEADER_WITH_METADATA;
import static com.google.common.truth.Truth.assertThat;
@@ -96,6 +97,7 @@
+ "</HEARABLE_CONTROL_SLICE_WITH_WIDTH>";
private static final String TEST_EXCLUSIVE_MANAGER_PACKAGE = "com.test.manager";
private static final String TEST_EXCLUSIVE_MANAGER_COMPONENT = "com.test.manager/.component";
+ private static final int TEST_BROADCAST_ID = 25;
@Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
@@ -671,6 +673,34 @@
}
@Test
+ public void testHasActiveLocalBroadcastSourceForBtDevice_hasActiveLocalSource() {
+ when(mBroadcast.getLatestBroadcastId()).thenReturn(TEST_BROADCAST_ID);
+ when(mLeBroadcastReceiveState.getBroadcastId()).thenReturn(TEST_BROADCAST_ID);
+ List<BluetoothLeBroadcastReceiveState> sourceList = new ArrayList<>();
+ sourceList.add(mLeBroadcastReceiveState);
+ when(mAssistant.getAllSources(mBluetoothDevice)).thenReturn(sourceList);
+
+ assertThat(
+ BluetoothUtils.hasActiveLocalBroadcastSourceForBtDevice(
+ mBluetoothDevice, mLocalBluetoothManager))
+ .isTrue();
+ }
+
+ @Test
+ public void testHasActiveLocalBroadcastSourceForBtDevice_noActiveLocalSource() {
+ when(mLeBroadcastReceiveState.getBroadcastId()).thenReturn(UNKNOWN_VALUE_PLACEHOLDER);
+ List<BluetoothLeBroadcastReceiveState> sourceList = new ArrayList<>();
+ sourceList.add(mLeBroadcastReceiveState);
+ when(mAssistant.getAllSources(mBluetoothDevice)).thenReturn(sourceList);
+
+ assertThat(
+ BluetoothUtils.hasActiveLocalBroadcastSourceForBtDevice(
+ mBluetoothDevice, mLocalBluetoothManager))
+ .isFalse();
+ }
+
+
+ @Test
public void isAvailableHearingDevice_isConnectedHearingAid_returnTure() {
when(mCachedBluetoothDevice.isConnectedHearingAidDevice()).thenReturn(true);
when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index c1bb55c..d26a906 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -949,36 +949,37 @@
strict_mode: false,
}
-// Disable for now. TODO(b/356666754) Re-enable it
-// android_ravenwood_test {
-// name: "SystemUiRavenTests",
-// srcs: [
-// ":SystemUI-tests-utils",
-// ":SystemUI-tests-multivalent",
-// // TODO(b/294256649): pivot to using {.aapt.jar} and re-enable
-// // use_resource_processor: true when better supported by soong
-// ":SystemUIRobo-stub{.aapt.srcjar}",
-// ],
-// static_libs: [
-// "SystemUI-core",
-// "SystemUI-res",
-// "SystemUI-tests-base",
-// "androidx.test.uiautomator_uiautomator",
-// "androidx.core_core-animation-testing",
-// "androidx.test.ext.junit",
-// "kosmos",
-// "mockito-kotlin-nodeps",
-// ],
-// libs: [
-// "android.test.runner",
-// "android.test.base",
-// "android.test.mock",
-// ],
-// auto_gen_config: true,
-// plugins: [
-// "dagger2-compiler",
-// ],
-// }
+android_ravenwood_test {
+ name: "SystemUiRavenTests",
+ srcs: [
+ ":SystemUI-tests-utils",
+ ":SystemUI-tests-multivalent",
+ // TODO(b/294256649): pivot to using {.aapt.jar} and re-enable
+ // use_resource_processor: true when better supported by soong
+ ":SystemUIRobo-stub{.aapt.srcjar}",
+ ],
+ static_libs: [
+ "SystemUI-core",
+ "SystemUI-res",
+ "SystemUI-tests-base",
+ "androidx.test.uiautomator_uiautomator",
+ "androidx.core_core-animation-testing",
+ "androidx.test.ext.junit",
+ "kosmos",
+ "kotlin-test",
+ "mockito-kotlin-nodeps",
+ "androidx.compose.runtime_runtime",
+ ],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ "android.test.mock",
+ ],
+ auto_gen_config: true,
+ plugins: [
+ "dagger2-compiler",
+ ],
+}
// Opt-out config for optimizing the SystemUI target using R8.
// Disabled via `export SYSTEMUI_OPTIMIZE_JAVA=false`, or explicitly in Make via
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 8a1d81b..df4b51a 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -139,13 +139,6 @@
}
flag {
- name: "notifications_heads_up_refactor"
- namespace: "systemui"
- description: "Use HeadsUpInteractor to feed HUN updates to the NSSL."
- bug: "325936094"
-}
-
-flag {
name: "notification_transparent_header_fix"
namespace: "systemui"
description: "fix the transparent group header issue for async header inflation."
@@ -391,6 +384,13 @@
}
flag {
+ name: "status_bar_ron_chips"
+ namespace: "systemui"
+ description: "Show rich ongoing notifications as chips in the status bar"
+ bug: "361346412"
+}
+
+flag {
name: "compose_bouncer"
namespace: "systemui"
description: "Use the new compose bouncer in SystemUI"
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
index b0590e0..be6a0f9 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
@@ -567,16 +567,8 @@
// Do nothing if there is no new live content
val indexOfFirstUpdatedContent =
newLiveContentKeys.indexOfFirst { !prevLiveContentKeys.contains(it) }
- if (indexOfFirstUpdatedContent < 0) {
- return@LaunchedEffect
- }
-
- // Scroll if the live content is not visible
- val lastVisibleItemIndex = gridState.layoutInfo.visibleItemsInfo.lastOrNull()?.index
- if (lastVisibleItemIndex != null && indexOfFirstUpdatedContent > lastVisibleItemIndex) {
- // Launching with a scope to prevent the job from being canceled in the case of a
- // recomposition during scrolling
- coroutineScope.launch { gridState.animateScrollToItem(indexOfFirstUpdatedContent) }
+ if (indexOfFirstUpdatedContent in 0 until gridState.firstVisibleItemIndex) {
+ gridState.scrollToItem(indexOfFirstUpdatedContent)
}
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
index 1921624..671b012 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
@@ -98,7 +98,7 @@
else -> QSSceneAdapter.State.CLOSED
}
}
- is TransitionState.Transition.ChangeCurrentScene ->
+ is TransitionState.Transition.ChangeScene ->
with(transitionState) {
when {
isSplitShade -> UnsquishingQS(squishiness)
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
index abe079a..e15bc12 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
@@ -28,7 +28,7 @@
layoutState: MutableSceneTransitionLayoutStateImpl,
target: SceneKey,
transitionKey: TransitionKey?,
-): TransitionState.Transition.ChangeCurrentScene? {
+): TransitionState.Transition.ChangeScene? {
val transitionState = layoutState.transitionState
if (transitionState.currentScene == target) {
// This can happen in 3 different situations, for which there isn't anything else to do:
@@ -55,7 +55,7 @@
replacedTransition = null,
)
}
- is TransitionState.Transition.ChangeCurrentScene -> {
+ is TransitionState.Transition.ChangeScene -> {
val isInitiatedByUserInput = transitionState.isInitiatedByUserInput
// A transition is currently running: first check whether `transition.toScene` or
@@ -139,7 +139,7 @@
reversed: Boolean = false,
fromScene: SceneKey = layoutState.transitionState.currentScene,
chain: Boolean = true,
-): TransitionState.Transition.ChangeCurrentScene {
+): TransitionState.Transition.ChangeScene {
val oneOffAnimation = OneOffAnimation()
val targetProgress = if (reversed) 0f else 1f
val transition =
@@ -184,7 +184,7 @@
override val isInitiatedByUserInput: Boolean,
replacedTransition: TransitionState.Transition?,
private val oneOffAnimation: OneOffAnimation,
-) : TransitionState.Transition.ChangeCurrentScene(fromScene, toScene, replacedTransition) {
+) : TransitionState.Transition.ChangeScene(fromScene, toScene, replacedTransition) {
override val progress: Float
get() = oneOffAnimation.progress
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
index 71ff8a8..37e4daa 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
@@ -109,7 +109,7 @@
// Only intercept the current transition if one of the 2 swipes results is also a transition
// between the same pair of contents.
val swipes = computeSwipes(startedPosition, pointersDown = 1)
- val fromContent = swipeAnimation.currentContent
+ val fromContent = layoutImpl.content(swipeAnimation.currentContent)
val (upOrLeft, downOrRight) = swipes.computeSwipesResults(fromContent)
val currentScene = layoutImpl.state.currentScene
val contentTransition = swipeAnimation.contentTransition
@@ -145,7 +145,9 @@
// We need to recompute the swipe results since this is a new gesture, and the
// fromScene.userActions may have changed.
val swipes = oldDragController.swipes
- swipes.updateSwipesResults(fromContent = oldSwipeAnimation.fromContent)
+ swipes.updateSwipesResults(
+ fromContent = layoutImpl.content(oldSwipeAnimation.fromContent)
+ )
// A new gesture should always create a new SwipeAnimation. This way there cannot be
// different gestures controlling the same transition.
@@ -155,8 +157,10 @@
val swipes = computeSwipes(startedPosition, pointersDown)
val fromContent = layoutImpl.contentForUserActions()
+
+ swipes.updateSwipesResults(fromContent)
val result =
- swipes.findUserActionResult(fromContent, overSlop, updateSwipesResults = true)
+ swipes.findUserActionResult(overSlop)
// As we were unable to locate a valid target scene, the initial SwipeAnimation
// cannot be defined. Consequently, a simple NoOp Controller will be returned.
?: return NoOpDragController
@@ -188,7 +192,13 @@
else -> error("Unknown result $result ($upOrLeftResult $downOrRightResult)")
}
- return createSwipeAnimation(layoutImpl, result, isUpOrLeft, orientation)
+ return createSwipeAnimation(
+ layoutImpl,
+ layoutImpl.coroutineScope,
+ result,
+ isUpOrLeft,
+ orientation
+ )
}
private fun computeSwipes(startedPosition: Offset?, pointersDown: Int): Swipes {
@@ -291,7 +301,7 @@
return onDrag(delta, swipeAnimation)
}
- private fun <T : Content> onDrag(delta: Float, swipeAnimation: SwipeAnimation<T>): Float {
+ private fun <T : ContentKey> onDrag(delta: Float, swipeAnimation: SwipeAnimation<T>): Float {
if (delta == 0f || !isDrivingTransition || swipeAnimation.isFinishing) {
return 0f
}
@@ -304,12 +314,12 @@
fun hasReachedToSceneUpOrLeft() =
distance < 0 &&
desiredOffset <= distance &&
- swipes.upOrLeftResult?.toContent(layoutState.currentScene) == toContent.key
+ swipes.upOrLeftResult?.toContent(layoutState.currentScene) == toContent
fun hasReachedToSceneDownOrRight() =
distance > 0 &&
desiredOffset >= distance &&
- swipes.downOrRightResult?.toContent(layoutState.currentScene) == toContent.key
+ swipes.downOrRightResult?.toContent(layoutState.currentScene) == toContent
// Considering accelerated swipe: Change fromContent in the case where the user quickly
// swiped multiple times in the same direction to accelerate the transition from A => B then
@@ -321,7 +331,7 @@
swipeAnimation.currentContent == toContent &&
(hasReachedToSceneUpOrLeft() || hasReachedToSceneDownOrRight())
- val fromContent: Content
+ val fromContent: ContentKey
val currentTransitionOffset: Float
val newOffset: Float
val consumedDelta: Float
@@ -357,12 +367,10 @@
swipeAnimation.dragOffset = currentTransitionOffset
- val result =
- swipes.findUserActionResult(
- fromContent = fromContent,
- directionOffset = newOffset,
- updateSwipesResults = hasReachedToContent
- )
+ if (hasReachedToContent) {
+ swipes.updateSwipesResults(draggableHandler.layoutImpl.content(fromContent))
+ }
+ val result = swipes.findUserActionResult(directionOffset = newOffset)
if (result == null) {
onStop(velocity = delta, canChangeContent = true)
@@ -371,7 +379,7 @@
val needNewTransition =
hasReachedToContent ||
- result.toContent(layoutState.currentScene) != swipeAnimation.toContent.key ||
+ result.toContent(layoutState.currentScene) != swipeAnimation.toContent ||
result.transitionKey != swipeAnimation.contentTransition.key
if (needNewTransition) {
@@ -390,7 +398,7 @@
return onStop(velocity, canChangeContent, swipeAnimation)
}
- private fun <T : Content> onStop(
+ private fun <T : ContentKey> onStop(
velocity: Float,
canChangeContent: Boolean,
@@ -407,7 +415,6 @@
fun animateTo(targetContent: T) {
swipeAnimation.animateOffset(
- coroutineScope = draggableHandler.coroutineScope,
initialVelocity = velocity,
targetContent = targetContent,
)
@@ -518,6 +525,14 @@
return upOrLeftResult to downOrRightResult
}
+ /**
+ * Update the swipes results.
+ *
+ * Usually we don't want to update them while doing a drag, because this could change the target
+ * content (jump cutting) to a different content, when some system state changed the targets the
+ * background. However, an update is needed any time we calculate the targets for a new
+ * fromContent.
+ */
fun updateSwipesResults(fromContent: Content) {
val (upOrLeftResult, downOrRightResult) = computeSwipesResults(fromContent)
@@ -526,31 +541,17 @@
}
/**
- * Returns the [UserActionResult] from [fromContent] in the direction of [directionOffset].
+ * Returns the [UserActionResult] in the direction of [directionOffset].
*
- * @param fromContent the content from which we look for the target
* @param directionOffset signed float that indicates the direction. Positive is down or right
* negative is up or left.
- * @param updateSwipesResults whether the swipe results should be updated to the current values
- * held in the user actions map. Usually we don't want to update them while doing a drag,
- * because this could change the target content (jump cutting) to a different content, when
- * some system state changed the targets the background. However, an update is needed any time
- * we calculate the targets for a new fromContent.
* @return null when there are no targets in either direction. If one direction is null and you
* drag into the null direction this function will return the opposite direction, assuming
* that the users intention is to start the drag into the other direction eventually. If
* [directionOffset] is 0f and both direction are available, it will default to
* [upOrLeftResult].
*/
- fun findUserActionResult(
- fromContent: Content,
- directionOffset: Float,
- updateSwipesResults: Boolean,
- ): UserActionResult? {
- if (updateSwipesResults) {
- updateSwipesResults(fromContent)
- }
-
+ fun findUserActionResult(directionOffset: Float): UserActionResult? {
return when {
upOrLeftResult == null && downOrRightResult == null -> null
(directionOffset < 0f && upOrLeftResult != null) || downOrRightResult == null ->
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/InterruptionHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/InterruptionHandler.kt
index 6181cfb..cb18c67 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/InterruptionHandler.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/InterruptionHandler.kt
@@ -37,7 +37,7 @@
* @see InterruptionResult
*/
fun onInterruption(
- interrupted: TransitionState.Transition.ChangeCurrentScene,
+ interrupted: TransitionState.Transition.ChangeScene,
newTargetScene: SceneKey,
): InterruptionResult?
}
@@ -76,7 +76,7 @@
*/
object DefaultInterruptionHandler : InterruptionHandler {
override fun onInterruption(
- interrupted: TransitionState.Transition.ChangeCurrentScene,
+ interrupted: TransitionState.Transition.ChangeScene,
newTargetScene: SceneKey,
): InterruptionResult {
return InterruptionResult(
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt
index a82ee4c..3a7c2bf 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt
@@ -43,7 +43,7 @@
fun currentScene(): Flow<SceneKey> {
return when (this) {
is Idle -> flowOf(currentScene)
- is Transition.ChangeCurrentScene -> currentScene
+ is Transition.ChangeScene -> currentScene
is Transition.ShowOrHideOverlay -> flowOf(currentScene)
is Transition.ReplaceOverlay -> flowOf(currentScene)
}
@@ -94,7 +94,7 @@
.trimMargin()
/** A transition animating between [fromScene] and [toScene]. */
- class ChangeCurrentScene(
+ class ChangeScene(
override val fromScene: SceneKey,
override val toScene: SceneKey,
val currentScene: Flow<SceneKey>,
@@ -174,8 +174,8 @@
previewProgress: Flow<Float> = flowOf(0f),
isInPreviewStage: Flow<Boolean> = flowOf(false),
currentOverlays: Flow<Set<OverlayKey>> = flowOf(emptySet()),
- ): ChangeCurrentScene {
- return ChangeCurrentScene(
+ ): ChangeScene {
+ return ChangeScene(
fromScene,
toScene,
currentScene,
@@ -210,8 +210,8 @@
return snapshotFlow {
when (val state = transitionState) {
is TransitionState.Idle -> ObservableTransitionState.Idle(state.currentScene)
- is TransitionState.Transition.ChangeCurrentScene -> {
- ObservableTransitionState.Transition.ChangeCurrentScene(
+ is TransitionState.Transition.ChangeScene -> {
+ ObservableTransitionState.Transition.ChangeScene(
fromScene = state.fromScene,
toScene = state.toScene,
currentScene = snapshotFlow { state.currentScene },
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PredictiveBackHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PredictiveBackHandler.kt
index e7e6b2a..be4fea1 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PredictiveBackHandler.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PredictiveBackHandler.kt
@@ -18,120 +18,75 @@
import androidx.activity.BackEventCompat
import androidx.activity.compose.PredictiveBackHandler
-import androidx.compose.animation.core.Animatable
-import androidx.compose.animation.core.AnimationVector1D
+import androidx.compose.animation.core.spring
+import androidx.compose.foundation.gestures.Orientation
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableFloatStateOf
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.setValue
-import com.android.compose.animation.scene.content.state.TransitionState
import kotlin.coroutines.cancellation.CancellationException
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.CoroutineStart
-import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
-import kotlinx.coroutines.launch
@Composable
internal fun PredictiveBackHandler(
- state: MutableSceneTransitionLayoutStateImpl,
- coroutineScope: CoroutineScope,
- targetSceneForBack: SceneKey? = null,
+ layoutImpl: SceneTransitionLayoutImpl,
+ result: UserActionResult?,
) {
PredictiveBackHandler(
- enabled = targetSceneForBack != null,
+ enabled = result != null,
) { progress: Flow<BackEventCompat> ->
- val fromScene = state.transitionState.currentScene
- if (targetSceneForBack == null || targetSceneForBack == fromScene) {
+ if (result == null) {
// Note: We have to collect progress otherwise PredictiveBackHandler will throw.
progress.first()
return@PredictiveBackHandler
}
- val transition =
- PredictiveBackTransition(state, coroutineScope, fromScene, toScene = targetSceneForBack)
- state.startTransition(transition)
- try {
- progress.collect { backEvent -> transition.dragProgress = backEvent.progress }
+ val animation =
+ createSwipeAnimation(
+ layoutImpl,
+ layoutImpl.coroutineScope,
+ result,
+ isUpOrLeft = false,
+ // Note that the orientation does not matter here given that it's only used to
+ // compute the distance. In our case the distance is always 1f.
+ orientation = Orientation.Horizontal,
+ distance = 1f,
+ )
- // Back gesture successful.
- transition.animateTo(targetSceneForBack)
- } catch (e: CancellationException) {
- // Back gesture cancelled.
- transition.animateTo(fromScene)
- }
+ animate(layoutImpl, animation, progress)
}
}
-private class PredictiveBackTransition(
- val state: MutableSceneTransitionLayoutStateImpl,
- val coroutineScope: CoroutineScope,
- fromScene: SceneKey,
- toScene: SceneKey,
-) : TransitionState.Transition.ChangeCurrentScene(fromScene, toScene) {
- override var currentScene by mutableStateOf(fromScene)
- private set
-
- /** The animated progress once the gesture was committed or cancelled. */
- private var progressAnimatable by mutableStateOf<Animatable<Float, AnimationVector1D>?>(null)
- var dragProgress: Float by mutableFloatStateOf(0f)
-
- override val previewProgress: Float
- get() = dragProgress
-
- override val previewProgressVelocity: Float
- get() = 0f // Currently, velocity is not exposed by predictive back API
-
- override val isInPreviewStage: Boolean
- get() = previewTransformationSpec != null && currentScene == fromScene
-
- override val progress: Float
- get() = progressAnimatable?.value ?: previewTransformationSpec?.let { 0f } ?: dragProgress
-
- override val progressVelocity: Float
- get() = progressAnimatable?.velocity ?: 0f
-
- override val isInitiatedByUserInput: Boolean
- get() = true
-
- override val isUserInputOngoing: Boolean
- get() = progressAnimatable == null
-
- private var animationJob: Job? = null
-
- override fun finish(): Job = animateTo(currentScene)
-
- fun animateTo(scene: SceneKey): Job {
- check(scene == fromScene || scene == toScene)
- animationJob?.let {
- return it
+private suspend fun <T : ContentKey> animate(
+ layoutImpl: SceneTransitionLayoutImpl,
+ animation: SwipeAnimation<T>,
+ progress: Flow<BackEventCompat>,
+) {
+ fun animateOffset(targetContent: T) {
+ if (
+ layoutImpl.state.transitionState != animation.contentTransition || animation.isFinishing
+ ) {
+ return
}
- if (scene != currentScene && state.transitionState == this && state.canChangeScene(scene)) {
- currentScene = scene
- }
+ animation.animateOffset(
+ initialVelocity = 0f,
+ targetContent = targetContent,
- val targetProgress =
- when (currentScene) {
- fromScene -> 0f
- toScene -> 1f
- else -> error("scene $currentScene should be either $fromScene or $toScene")
- }
- val startProgress = if (previewTransformationSpec != null) 0f else dragProgress
- val animatable = Animatable(startProgress).also { progressAnimatable = it }
+ // TODO(b/350705972): Allow to customize or reuse the same customization endpoints as
+ // the normal swipe transitions. We can't just reuse them here because other swipe
+ // transitions animate pixels while this transition animates progress, so the visibility
+ // thresholds will be completely different.
+ spec = spring(),
+ )
+ }
- // Important: We start atomically to make sure that we start the coroutine even if it is
- // cancelled right after it is launched, so that finishTransition() is correctly called.
- return coroutineScope
- .launch(start = CoroutineStart.ATOMIC) {
- try {
- animatable.animateTo(targetProgress)
- } finally {
- state.finishTransition(this@PredictiveBackTransition)
- }
- }
- .also { animationJob = it }
+ layoutImpl.state.startTransition(animation.contentTransition)
+ try {
+ progress.collect { backEvent -> animation.dragOffset = backEvent.progress }
+
+ // Back gesture successful.
+ animateOffset(animation.toContent)
+ } catch (e: CancellationException) {
+ // Back gesture cancelled.
+ animateOffset(animation.fromContent)
}
}
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 258be81..b33b4f6 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
@@ -353,19 +353,8 @@
@Composable
private fun BackHandler() {
- val targetSceneForBack =
- when (val result = contentForUserActions().userActions[Back.Resolved]) {
- null -> null
- is UserActionResult.ChangeScene -> result.toScene
- is UserActionResult.ShowOverlay,
- is UserActionResult.HideOverlay,
- is UserActionResult.ReplaceByOverlay -> {
- // TODO(b/353679003): Support overlay transitions when going back
- null
- }
- }
-
- PredictiveBackHandler(state, coroutineScope, targetSceneForBack)
+ val result = contentForUserActions().userActions[Back.Resolved]
+ PredictiveBackHandler(layoutImpl = this, result = result)
}
@Composable
@@ -389,7 +378,7 @@
// Compose the new scene we are going to first.
transitions.fastForEachReversed { transition ->
when (transition) {
- is TransitionState.Transition.ChangeCurrentScene -> {
+ is TransitionState.Transition.ChangeScene -> {
maybeAdd(transition.toScene)
maybeAdd(transition.fromScene)
}
@@ -439,7 +428,7 @@
transitions.fastForEach { transition ->
when (transition) {
- is TransitionState.Transition.ChangeCurrentScene -> {}
+ is TransitionState.Transition.ChangeScene -> {}
is TransitionState.Transition.ShowOrHideOverlay ->
maybeAdd(transition.overlay)
is TransitionState.Transition.ReplaceOverlay -> {
@@ -495,7 +484,7 @@
val width: Int
val height: Int
val transition =
- layoutImpl.state.currentTransition as? TransitionState.Transition.ChangeCurrentScene
+ layoutImpl.state.currentTransition as? TransitionState.Transition.ChangeScene
if (transition == null) {
width = placeable.width
height = placeable.height
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
index 47065c7..f3128f1 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
@@ -299,7 +299,7 @@
targetScene: SceneKey,
coroutineScope: CoroutineScope,
transitionKey: TransitionKey?,
- ): TransitionState.Transition.ChangeCurrentScene? {
+ ): TransitionState.Transition.ChangeScene? {
checkThread()
return coroutineScope.animateToScene(
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt
index 8ca90f1..57ff597 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt
@@ -18,15 +18,13 @@
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.AnimationVector1D
+import androidx.compose.animation.core.SpringSpec
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.unit.IntSize
-import com.android.compose.animation.scene.content.Content
-import com.android.compose.animation.scene.content.Overlay
-import com.android.compose.animation.scene.content.Scene
import com.android.compose.animation.scene.content.state.TransitionState
import com.android.compose.animation.scene.content.state.TransitionState.HasOverscrollProperties.Companion.DistanceUnspecified
import kotlin.math.absoluteValue
@@ -36,29 +34,96 @@
import kotlinx.coroutines.launch
internal fun createSwipeAnimation(
- layoutImpl: SceneTransitionLayoutImpl,
+ layoutState: MutableSceneTransitionLayoutStateImpl,
+ animationScope: CoroutineScope,
result: UserActionResult,
isUpOrLeft: Boolean,
orientation: Orientation,
+ distance: Float,
): SwipeAnimation<*> {
- fun <T : Content> swipeAnimation(fromContent: T, toContent: T): SwipeAnimation<T> {
+ return createSwipeAnimation(
+ layoutState,
+ animationScope,
+ result,
+ isUpOrLeft,
+ orientation,
+ distance = { distance },
+ contentForUserActions = {
+ error("Computing contentForUserActions requires a SceneTransitionLayoutImpl")
+ },
+ )
+}
+
+internal fun createSwipeAnimation(
+ layoutImpl: SceneTransitionLayoutImpl,
+ animationScope: CoroutineScope,
+ result: UserActionResult,
+ isUpOrLeft: Boolean,
+ orientation: Orientation,
+ distance: Float = DistanceUnspecified
+): SwipeAnimation<*> {
+ var lastDistance = distance
+
+ fun distance(animation: SwipeAnimation<*>): Float {
+ if (lastDistance != DistanceUnspecified) {
+ return lastDistance
+ }
+
+ val absoluteDistance =
+ with(animation.contentTransition.transformationSpec.distance ?: DefaultSwipeDistance) {
+ layoutImpl.userActionDistanceScope.absoluteDistance(
+ layoutImpl.content(animation.fromContent).targetSize,
+ orientation,
+ )
+ }
+
+ if (absoluteDistance <= 0f) {
+ return DistanceUnspecified
+ }
+
+ val distance = if (isUpOrLeft) -absoluteDistance else absoluteDistance
+ lastDistance = distance
+ return distance
+ }
+
+ return createSwipeAnimation(
+ layoutImpl.state,
+ animationScope,
+ result,
+ isUpOrLeft,
+ orientation,
+ distance = ::distance,
+ contentForUserActions = { layoutImpl.contentForUserActions().key },
+ )
+}
+
+private fun createSwipeAnimation(
+ layoutState: MutableSceneTransitionLayoutStateImpl,
+ animationScope: CoroutineScope,
+ result: UserActionResult,
+ isUpOrLeft: Boolean,
+ orientation: Orientation,
+ distance: (SwipeAnimation<*>) -> Float,
+ contentForUserActions: () -> ContentKey,
+): SwipeAnimation<*> {
+ fun <T : ContentKey> swipeAnimation(fromContent: T, toContent: T): SwipeAnimation<T> {
return SwipeAnimation(
- layoutImpl = layoutImpl,
+ layoutState = layoutState,
+ animationScope = animationScope,
fromContent = fromContent,
toContent = toContent,
- userActionDistanceScope = layoutImpl.userActionDistanceScope,
orientation = orientation,
isUpOrLeft = isUpOrLeft,
requiresFullDistanceSwipe = result.requiresFullDistanceSwipe,
+ distance = distance,
)
}
- val layoutState = layoutImpl.state
return when (result) {
is UserActionResult.ChangeScene -> {
- val fromScene = layoutImpl.scene(layoutState.currentScene)
- val toScene = layoutImpl.scene(result.toScene)
- ChangeCurrentSceneSwipeTransition(
+ val fromScene = layoutState.currentScene
+ val toScene = result.toScene
+ ChangeSceneSwipeTransition(
layoutState = layoutState,
swipeAnimation = swipeAnimation(fromContent = fromScene, toContent = toScene),
key = result.transitionKey,
@@ -67,12 +132,12 @@
.swipeAnimation
}
is UserActionResult.ShowOverlay -> {
- val fromScene = layoutImpl.scene(layoutState.currentScene)
- val overlay = layoutImpl.overlay(result.overlay)
+ val fromScene = layoutState.currentScene
+ val overlay = result.overlay
ShowOrHideOverlaySwipeTransition(
layoutState = layoutState,
- _fromOrToScene = fromScene,
- _overlay = overlay,
+ fromOrToScene = fromScene,
+ overlay = overlay,
swipeAnimation = swipeAnimation(fromContent = fromScene, toContent = overlay),
key = result.transitionKey,
replacedTransition = null,
@@ -80,12 +145,12 @@
.swipeAnimation
}
is UserActionResult.HideOverlay -> {
- val toScene = layoutImpl.scene(layoutState.currentScene)
- val overlay = layoutImpl.overlay(result.overlay)
+ val toScene = layoutState.currentScene
+ val overlay = result.overlay
ShowOrHideOverlaySwipeTransition(
layoutState = layoutState,
- _fromOrToScene = toScene,
- _overlay = overlay,
+ fromOrToScene = toScene,
+ overlay = overlay,
swipeAnimation = swipeAnimation(fromContent = overlay, toContent = toScene),
key = result.transitionKey,
replacedTransition = null,
@@ -93,8 +158,14 @@
.swipeAnimation
}
is UserActionResult.ReplaceByOverlay -> {
- val fromOverlay = layoutImpl.contentForUserActions() as Overlay
- val toOverlay = layoutImpl.overlay(result.overlay)
+ val fromOverlay =
+ when (val contentForUserActions = contentForUserActions()) {
+ is SceneKey ->
+ error("ReplaceByOverlay can only be called when an overlay is shown")
+ is OverlayKey -> contentForUserActions
+ }
+
+ val toOverlay = result.overlay
ReplaceOverlaySwipeTransition(
layoutState = layoutState,
swipeAnimation =
@@ -109,9 +180,8 @@
internal fun createSwipeAnimation(old: SwipeAnimation<*>): SwipeAnimation<*> {
return when (val transition = old.contentTransition) {
- is TransitionState.Transition.ChangeCurrentScene -> {
- ChangeCurrentSceneSwipeTransition(transition as ChangeCurrentSceneSwipeTransition)
- .swipeAnimation
+ is TransitionState.Transition.ChangeScene -> {
+ ChangeSceneSwipeTransition(transition as ChangeSceneSwipeTransition).swipeAnimation
}
is TransitionState.Transition.ShowOrHideOverlay -> {
ShowOrHideOverlaySwipeTransition(transition as ShowOrHideOverlaySwipeTransition)
@@ -125,15 +195,15 @@
}
/** A helper class that contains the main logic for swipe transitions. */
-internal class SwipeAnimation<T : Content>(
- val layoutImpl: SceneTransitionLayoutImpl,
+internal class SwipeAnimation<T : ContentKey>(
+ val layoutState: MutableSceneTransitionLayoutStateImpl,
+ val animationScope: CoroutineScope,
val fromContent: T,
val toContent: T,
- private val userActionDistanceScope: UserActionDistanceScope,
override val orientation: Orientation,
override val isUpOrLeft: Boolean,
val requiresFullDistanceSwipe: Boolean,
- private var lastDistance: Float = DistanceUnspecified,
+ private val distance: (SwipeAnimation<T>) -> Float,
currentContent: T = fromContent,
dragOffset: Float = 0f,
) : TransitionState.HasOverscrollProperties {
@@ -147,7 +217,13 @@
// Important: If we are going to return early because distance is equal to 0, we should
// still make sure we read the offset before returning so that the calling code still
// subscribes to the offset value.
- val offset = offsetAnimation?.animatable?.value ?: dragOffset
+ val animatable = offsetAnimation?.animatable
+ val offset =
+ when {
+ animatable != null -> animatable.value
+ contentTransition.previewTransformationSpec != null -> 0f
+ else -> dragOffset
+ }
return computeProgress(offset)
}
@@ -172,6 +248,15 @@
return velocityInDistanceUnit / distance.absoluteValue
}
+ val previewProgress: Float
+ get() = computeProgress(dragOffset)
+
+ val previewProgressVelocity: Float
+ get() = 0f
+
+ val isInPreviewStage: Boolean
+ get() = contentTransition.previewTransformationSpec != null && currentContent == fromContent
+
override var bouncingContent: ContentKey? = null
/** The current offset caused by the drag gesture. */
@@ -183,17 +268,8 @@
val isUserInputOngoing: Boolean
get() = offsetAnimation == null
- override val overscrollScope: OverscrollScope =
- object : OverscrollScope {
- override val density: Float
- get() = layoutImpl.density.density
-
- override val fontScale: Float
- get() = layoutImpl.density.fontScale
-
- override val absoluteDistance: Float
- get() = distance().absoluteValue
- }
+ override val absoluteDistance: Float
+ get() = distance().absoluteValue
/** Whether [finish] was called on this animation. */
var isFinishing = false
@@ -202,14 +278,14 @@
constructor(
other: SwipeAnimation<T>
) : this(
- layoutImpl = other.layoutImpl,
+ layoutState = other.layoutState,
+ animationScope = other.animationScope,
fromContent = other.fromContent,
toContent = other.toContent,
- userActionDistanceScope = other.userActionDistanceScope,
orientation = other.orientation,
isUpOrLeft = other.isUpOrLeft,
requiresFullDistanceSwipe = other.requiresFullDistanceSwipe,
- lastDistance = other.lastDistance,
+ distance = other.distance,
currentContent = other.currentContent,
dragOffset = other.dragOffset,
)
@@ -222,27 +298,7 @@
* transition when the distance depends on the size or position of an element that is composed
* in the content we are going to.
*/
- fun distance(): Float {
- if (lastDistance != DistanceUnspecified) {
- return lastDistance
- }
-
- val absoluteDistance =
- with(contentTransition.transformationSpec.distance ?: DefaultSwipeDistance) {
- userActionDistanceScope.absoluteDistance(
- fromContent.targetSize,
- orientation,
- )
- }
-
- if (absoluteDistance <= 0f) {
- return DistanceUnspecified
- }
-
- val distance = if (isUpOrLeft) -absoluteDistance else absoluteDistance
- lastDistance = distance
- return distance
- }
+ fun distance(): Float = distance(this)
/** Ends any previous [offsetAnimation] and runs the new [animation]. */
private fun startOffsetAnimation(animation: () -> OffsetAnimation): OffsetAnimation {
@@ -262,10 +318,9 @@
}
fun animateOffset(
- // TODO(b/317063114) The CoroutineScope should be removed.
- coroutineScope: CoroutineScope,
initialVelocity: Float,
targetContent: T,
+ spec: SpringSpec<Float>? = null,
): OffsetAnimation {
val initialProgress = progress
// Skip the animation if we have already reached the target content and the overscroll does
@@ -304,12 +359,14 @@
}
return startOffsetAnimation {
- val animatable = Animatable(dragOffset, OffsetVisibilityThreshold)
+ val startProgress =
+ if (contentTransition.previewTransformationSpec != null) 0f else dragOffset
+ val animatable = Animatable(startProgress, OffsetVisibilityThreshold)
val isTargetGreater = targetOffset > animatable.value
val startedWhenOvercrollingTargetContent =
if (targetContent == fromContent) initialProgress < 0f else initialProgress > 1f
val job =
- coroutineScope
+ animationScope
// Important: We start atomically to make sure that we start the coroutine even
// if it is cancelled right after it is launched, so that snapToContent() is
// correctly called. Otherwise, this transition will never be stopped and we
@@ -325,8 +382,9 @@
try {
val swipeSpec =
- contentTransition.transformationSpec.swipeSpec
- ?: layoutImpl.state.transitions.defaultSwipeSpec
+ spec
+ ?: contentTransition.transformationSpec.swipeSpec
+ ?: layoutState.transitions.defaultSwipeSpec
animatable.animateTo(
targetValue = targetOffset,
animationSpec = swipeSpec,
@@ -349,7 +407,7 @@
}
if (isBouncing) {
- bouncingContent = targetContent.key
+ bouncingContent = targetContent
// Immediately stop this transition if we are bouncing on a
// content that does not bounce.
@@ -368,20 +426,19 @@
}
}
- private fun canChangeContent(targetContent: Content): Boolean {
- val layoutState = layoutImpl.state
+ private fun canChangeContent(targetContent: ContentKey): Boolean {
return when (val transition = contentTransition) {
- is TransitionState.Transition.ChangeCurrentScene ->
- layoutState.canChangeScene(targetContent.key as SceneKey)
+ is TransitionState.Transition.ChangeScene ->
+ layoutState.canChangeScene(targetContent as SceneKey)
is TransitionState.Transition.ShowOrHideOverlay -> {
- if (targetContent.key == transition.overlay) {
+ if (targetContent == transition.overlay) {
layoutState.canShowOverlay(transition.overlay)
} else {
layoutState.canHideOverlay(transition.overlay)
}
}
is TransitionState.Transition.ReplaceOverlay -> {
- val to = targetContent.key as OverlayKey
+ val to = targetContent as OverlayKey
val from =
if (to == transition.toOverlay) transition.fromOverlay else transition.toOverlay
layoutState.canReplaceOverlay(from, to)
@@ -392,7 +449,7 @@
private fun snapToContent(content: T) {
cancelOffsetAnimation()
check(currentContent == content)
- layoutImpl.state.finishTransition(contentTransition)
+ layoutState.finishTransition(contentTransition)
}
fun finish(): Job {
@@ -405,12 +462,7 @@
}
// Animate to the current content.
- val animation =
- animateOffset(
- coroutineScope = layoutImpl.coroutineScope,
- initialVelocity = 0f,
- targetContent = currentContent,
- )
+ val animation = animateOffset(initialVelocity = 0f, targetContent = currentContent)
check(offsetAnimation == animation)
return animation.job
}
@@ -436,21 +488,21 @@
}
}
-private class ChangeCurrentSceneSwipeTransition(
+private class ChangeSceneSwipeTransition(
val layoutState: MutableSceneTransitionLayoutStateImpl,
- val swipeAnimation: SwipeAnimation<Scene>,
+ val swipeAnimation: SwipeAnimation<SceneKey>,
override val key: TransitionKey?,
- replacedTransition: ChangeCurrentSceneSwipeTransition?,
+ replacedTransition: ChangeSceneSwipeTransition?,
) :
- TransitionState.Transition.ChangeCurrentScene(
- swipeAnimation.fromContent.key,
- swipeAnimation.toContent.key,
+ TransitionState.Transition.ChangeScene(
+ swipeAnimation.fromContent,
+ swipeAnimation.toContent,
replacedTransition,
),
TransitionState.HasOverscrollProperties by swipeAnimation {
constructor(
- other: ChangeCurrentSceneSwipeTransition
+ other: ChangeSceneSwipeTransition
) : this(
layoutState = other.layoutState,
swipeAnimation = SwipeAnimation(other.swipeAnimation),
@@ -463,7 +515,7 @@
}
override val currentScene: SceneKey
- get() = swipeAnimation.currentContent.key
+ get() = swipeAnimation.currentContent
override val progress: Float
get() = swipeAnimation.progress
@@ -471,6 +523,15 @@
override val progressVelocity: Float
get() = swipeAnimation.progressVelocity
+ override val previewProgress: Float
+ get() = swipeAnimation.previewProgress
+
+ override val previewProgressVelocity: Float
+ get() = swipeAnimation.previewProgressVelocity
+
+ override val isInPreviewStage: Boolean
+ get() = swipeAnimation.isInPreviewStage
+
override val isInitiatedByUserInput: Boolean = true
override val isUserInputOngoing: Boolean
@@ -481,17 +542,17 @@
private class ShowOrHideOverlaySwipeTransition(
val layoutState: MutableSceneTransitionLayoutStateImpl,
- val swipeAnimation: SwipeAnimation<Content>,
- val _overlay: Overlay,
- val _fromOrToScene: Scene,
+ val swipeAnimation: SwipeAnimation<ContentKey>,
+ overlay: OverlayKey,
+ fromOrToScene: SceneKey,
override val key: TransitionKey?,
replacedTransition: ShowOrHideOverlaySwipeTransition?,
) :
TransitionState.Transition.ShowOrHideOverlay(
- _overlay.key,
- _fromOrToScene.key,
- swipeAnimation.fromContent.key,
- swipeAnimation.toContent.key,
+ overlay,
+ fromOrToScene,
+ swipeAnimation.fromContent,
+ swipeAnimation.toContent,
replacedTransition,
),
TransitionState.HasOverscrollProperties by swipeAnimation {
@@ -500,8 +561,8 @@
) : this(
layoutState = other.layoutState,
swipeAnimation = SwipeAnimation(other.swipeAnimation),
- _overlay = other._overlay,
- _fromOrToScene = other._fromOrToScene,
+ overlay = other.overlay,
+ fromOrToScene = other.fromOrToScene,
key = other.key,
replacedTransition = other,
)
@@ -511,7 +572,7 @@
}
override val isEffectivelyShown: Boolean
- get() = swipeAnimation.currentContent == _overlay
+ get() = swipeAnimation.currentContent == overlay
override val progress: Float
get() = swipeAnimation.progress
@@ -519,6 +580,15 @@
override val progressVelocity: Float
get() = swipeAnimation.progressVelocity
+ override val previewProgress: Float
+ get() = swipeAnimation.previewProgress
+
+ override val previewProgressVelocity: Float
+ get() = swipeAnimation.previewProgressVelocity
+
+ override val isInPreviewStage: Boolean
+ get() = swipeAnimation.isInPreviewStage
+
override val isInitiatedByUserInput: Boolean = true
override val isUserInputOngoing: Boolean
@@ -529,13 +599,13 @@
private class ReplaceOverlaySwipeTransition(
val layoutState: MutableSceneTransitionLayoutStateImpl,
- val swipeAnimation: SwipeAnimation<Overlay>,
+ val swipeAnimation: SwipeAnimation<OverlayKey>,
override val key: TransitionKey?,
replacedTransition: ReplaceOverlaySwipeTransition?,
) :
TransitionState.Transition.ReplaceOverlay(
- swipeAnimation.fromContent.key,
- swipeAnimation.toContent.key,
+ swipeAnimation.fromContent,
+ swipeAnimation.toContent,
replacedTransition,
),
TransitionState.HasOverscrollProperties by swipeAnimation {
@@ -553,7 +623,7 @@
}
override val effectivelyShownOverlay: OverlayKey
- get() = swipeAnimation.currentContent.key
+ get() = swipeAnimation.currentContent
override val progress: Float
get() = swipeAnimation.progress
@@ -561,6 +631,15 @@
override val progressVelocity: Float
get() = swipeAnimation.progressVelocity
+ override val previewProgress: Float
+ get() = swipeAnimation.previewProgress
+
+ override val previewProgressVelocity: Float
+ get() = swipeAnimation.previewProgressVelocity
+
+ override val isInPreviewStage: Boolean
+ get() = swipeAnimation.isInPreviewStage
+
override val isInitiatedByUserInput: Boolean = true
override val isUserInputOngoing: Boolean
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt
index fdb019f..0cd8c1a 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt
@@ -26,7 +26,6 @@
import com.android.compose.animation.scene.ContentKey
import com.android.compose.animation.scene.MutableSceneTransitionLayoutState
import com.android.compose.animation.scene.OverlayKey
-import com.android.compose.animation.scene.OverscrollScope
import com.android.compose.animation.scene.OverscrollSpecImpl
import com.android.compose.animation.scene.ProgressVisibilityThreshold
import com.android.compose.animation.scene.SceneKey
@@ -75,7 +74,7 @@
val replacedTransition: Transition? = null,
) : TransitionState {
/** A transition animating between [fromScene] and [toScene]. */
- abstract class ChangeCurrentScene(
+ abstract class ChangeScene(
/** The scene this transition is starting from. Can't be the same as toScene */
val fromScene: SceneKey,
@@ -386,10 +385,10 @@
val orientation: Orientation
/**
- * Scope which can be used in the Overscroll DSL to define a transformation based on the
- * distance between [Transition.fromContent] and [Transition.toContent].
+ * Return the absolute distance between fromScene and toScene, if available, otherwise
+ * [DistanceUnspecified].
*/
- val overscrollScope: OverscrollScope
+ val absoluteDistance: Float
/**
* The content (scene or overlay) around which the transition is currently bouncing. When
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Translate.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Translate.kt
index 59bca50..8f84586 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Translate.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Translate.kt
@@ -17,6 +17,7 @@
package com.android.compose.animation.scene.transformation
import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.android.compose.animation.scene.ContentKey
@@ -53,6 +54,8 @@
val x: OverscrollScope.() -> Float = { 0f },
val y: OverscrollScope.() -> Float = { 0f },
) : PropertyTransformation<Offset> {
+ private val cachedOverscrollScope = CachedOverscrollScope()
+
override fun transform(
layoutImpl: SceneTransitionLayoutImpl,
content: ContentKey,
@@ -65,10 +68,47 @@
// OverscrollSpec only when the transition implements HasOverscrollProperties, we can assume
// that this method was invoked after performing this check.
val overscrollProperties = transition as TransitionState.HasOverscrollProperties
+ val overscrollScope =
+ cachedOverscrollScope.getFromCacheOrCompute(layoutImpl.density, overscrollProperties)
return Offset(
- x = value.x + overscrollProperties.overscrollScope.x(),
- y = value.y + overscrollProperties.overscrollScope.y(),
+ x = value.x + overscrollScope.x(),
+ y = value.y + overscrollScope.y(),
)
}
}
+
+/**
+ * A helper class to cache a [OverscrollScope] given a [Density] and
+ * [TransitionState.HasOverscrollProperties]. This helps avoid recreating a scope every frame
+ * whenever an overscroll transition is computed.
+ */
+private class CachedOverscrollScope() {
+ private var previousScope: OverscrollScope? = null
+ private var previousDensity: Density? = null
+ private var previousOverscrollProperties: TransitionState.HasOverscrollProperties? = null
+
+ fun getFromCacheOrCompute(
+ density: Density,
+ overscrollProperties: TransitionState.HasOverscrollProperties,
+ ): OverscrollScope {
+ if (
+ previousScope == null ||
+ density != previousDensity ||
+ previousOverscrollProperties != overscrollProperties
+ ) {
+ val scope =
+ object : OverscrollScope, Density by density {
+ override val absoluteDistance: Float
+ get() = overscrollProperties.absoluteDistance
+ }
+
+ previousScope = scope
+ previousDensity = density
+ previousOverscrollProperties = overscrollProperties
+ return scope
+ }
+
+ return checkNotNull(previousScope)
+ }
+}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transition/link/LinkedTransition.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transition/link/LinkedTransition.kt
index 59ddb13..564d4b3 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transition/link/LinkedTransition.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transition/link/LinkedTransition.kt
@@ -27,7 +27,7 @@
fromScene: SceneKey,
toScene: SceneKey,
override val key: TransitionKey? = null,
-) : TransitionState.Transition.ChangeCurrentScene(fromScene, toScene) {
+) : TransitionState.Transition.ChangeScene(fromScene, toScene) {
override val currentScene: SceneKey
get() {
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/InterruptionHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/InterruptionHandlerTest.kt
index f4e60a2..3f6bd2c 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/InterruptionHandlerTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/InterruptionHandlerTest.kt
@@ -69,7 +69,7 @@
interruptionHandler =
object : InterruptionHandler {
override fun onInterruption(
- interrupted: TransitionState.Transition.ChangeCurrentScene,
+ interrupted: TransitionState.Transition.ChangeScene,
newTargetScene: SceneKey
): InterruptionResult {
return InterruptionResult(
@@ -104,7 +104,7 @@
interruptionHandler =
object : InterruptionHandler {
override fun onInterruption(
- interrupted: TransitionState.Transition.ChangeCurrentScene,
+ interrupted: TransitionState.Transition.ChangeScene,
newTargetScene: SceneKey
): InterruptionResult {
return InterruptionResult(
@@ -198,7 +198,7 @@
companion object {
val FromToCurrentTriple =
Correspondence.transforming(
- { transition: TransitionState.Transition.ChangeCurrentScene? ->
+ { transition: TransitionState.Transition.ChangeScene? ->
Triple(transition?.fromScene, transition?.toScene, transition?.currentScene)
},
"(from, to, current) triple"
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt
index a549d03..e4879d9 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt
@@ -163,7 +163,7 @@
fromContentZIndex: Float,
toContentZIndex: Float
): ContentKey {
- transition as TransitionState.Transition.ChangeCurrentScene
+ transition as TransitionState.Transition.ChangeScene
assertThat(transition).hasFromScene(SceneA)
assertThat(transition).hasToScene(SceneB)
assertThat(fromContentZIndex).isEqualTo(0)
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/PredictiveBackHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/PredictiveBackHandlerTest.kt
index 00c7588..c5b6cdf 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/PredictiveBackHandlerTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/PredictiveBackHandlerTest.kt
@@ -20,10 +20,16 @@
import androidx.activity.ComponentActivity
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.size
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.hasTestTag
import androidx.compose.ui.test.junit4.createAndroidComposeRule
+import androidx.compose.ui.unit.dp
import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.compose.animation.scene.TestOverlays.OverlayA
+import com.android.compose.animation.scene.TestOverlays.OverlayB
import com.android.compose.animation.scene.TestScenes.SceneA
import com.android.compose.animation.scene.TestScenes.SceneB
import com.android.compose.animation.scene.TestScenes.SceneC
@@ -198,6 +204,42 @@
assertThat(canChangeSceneCalled).isFalse()
}
+ @Test
+ fun backDismissesOverlayWithHighestZIndexByDefault() {
+ val state =
+ rule.runOnUiThread {
+ MutableSceneTransitionLayoutState(
+ SceneA,
+ initialOverlays = setOf(OverlayA, OverlayB)
+ )
+ }
+
+ rule.setContent {
+ SceneTransitionLayout(state, Modifier.size(200.dp)) {
+ scene(SceneA) { Box(Modifier.fillMaxSize()) }
+ overlay(OverlayA) { Box(Modifier.fillMaxSize()) }
+ overlay(OverlayB) { Box(Modifier.fillMaxSize()) }
+ }
+ }
+
+ // Initial state.
+ rule.onNode(hasTestTag(SceneA.testTag)).assertIsDisplayed()
+ rule.onNode(hasTestTag(OverlayA.testTag)).assertIsDisplayed()
+ rule.onNode(hasTestTag(OverlayB.testTag)).assertIsDisplayed()
+
+ // Press back. This should hide overlay B because it has a higher zIndex than overlay A.
+ rule.runOnUiThread { rule.activity.onBackPressedDispatcher.onBackPressed() }
+ rule.onNode(hasTestTag(SceneA.testTag)).assertIsDisplayed()
+ rule.onNode(hasTestTag(OverlayA.testTag)).assertIsDisplayed()
+ rule.onNode(hasTestTag(OverlayB.testTag)).assertDoesNotExist()
+
+ // Press back again. This should hide overlay A.
+ rule.runOnUiThread { rule.activity.onBackPressedDispatcher.onBackPressed() }
+ rule.onNode(hasTestTag(SceneA.testTag)).assertIsDisplayed()
+ rule.onNode(hasTestTag(OverlayA.testTag)).assertDoesNotExist()
+ rule.onNode(hasTestTag(OverlayB.testTag)).assertDoesNotExist()
+ }
+
private fun backEvent(progress: Float = 0f): BackEventCompat {
return BackEventCompat(
touchX = 0f,
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/Transition.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/Transition.kt
index 1f7fe37..467031a 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/Transition.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/Transition.kt
@@ -42,9 +42,9 @@
orientation: Orientation = Orientation.Horizontal,
onFinish: ((TransitionState.Transition) -> Job)? = null,
replacedTransition: TransitionState.Transition? = null,
-): TransitionState.Transition.ChangeCurrentScene {
+): TransitionState.Transition.ChangeScene {
return object :
- TransitionState.Transition.ChangeCurrentScene(from, to, replacedTransition),
+ TransitionState.Transition.ChangeScene(from, to, replacedTransition),
TransitionState.HasOverscrollProperties {
override val currentScene: SceneKey
get() = current()
@@ -69,12 +69,7 @@
override val isUpOrLeft: Boolean = isUpOrLeft
override val bouncingContent: ContentKey? = bouncingContent
override val orientation: Orientation = orientation
- override val overscrollScope: OverscrollScope =
- object : OverscrollScope {
- override val density: Float = 1f
- override val fontScale: Float = 1f
- override val absoluteDistance = 0f
- }
+ override val absoluteDistance = 0f
override fun finish(): Job {
val onFinish =
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/subjects/TransitionStateSubject.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/subjects/TransitionStateSubject.kt
index 3fb5708..44e0ba5 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/subjects/TransitionStateSubject.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/subjects/TransitionStateSubject.kt
@@ -32,8 +32,8 @@
return Truth.assertAbout(TransitionStateSubject.transitionStates()).that(state)
}
-/** Assert on a [TransitionState.Transition.ChangeCurrentScene]. */
-fun assertThat(transition: TransitionState.Transition.ChangeCurrentScene): SceneTransitionSubject {
+/** Assert on a [TransitionState.Transition.ChangeScene]. */
+fun assertThat(transition: TransitionState.Transition.ChangeScene): SceneTransitionSubject {
return Truth.assertAbout(SceneTransitionSubject.sceneTransitions()).that(transition)
}
@@ -74,14 +74,14 @@
return actual as TransitionState.Idle
}
- fun isSceneTransition(): TransitionState.Transition.ChangeCurrentScene {
- if (actual !is TransitionState.Transition.ChangeCurrentScene) {
+ fun isSceneTransition(): TransitionState.Transition.ChangeScene {
+ if (actual !is TransitionState.Transition.ChangeScene) {
failWithActual(
simpleFact("expected to be TransitionState.Transition.ChangeCurrentScene")
)
}
- return actual as TransitionState.Transition.ChangeCurrentScene
+ return actual as TransitionState.Transition.ChangeScene
}
fun isShowOrHideOverlayTransition(): TransitionState.Transition.ShowOrHideOverlay {
@@ -183,8 +183,8 @@
class SceneTransitionSubject
private constructor(
metadata: FailureMetadata,
- actual: TransitionState.Transition.ChangeCurrentScene,
-) : BaseTransitionSubject<TransitionState.Transition.ChangeCurrentScene>(metadata, actual) {
+ actual: TransitionState.Transition.ChangeScene,
+) : BaseTransitionSubject<TransitionState.Transition.ChangeScene>(metadata, actual) {
fun hasFromScene(sceneKey: SceneKey) {
check("fromScene").that(actual.fromScene).isEqualTo(sceneKey)
}
@@ -195,7 +195,7 @@
companion object {
fun sceneTransitions() =
- Factory { metadata, actual: TransitionState.Transition.ChangeCurrentScene ->
+ Factory { metadata, actual: TransitionState.Transition.ChangeScene ->
SceneTransitionSubject(metadata, actual)
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalDreamStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalDreamStartableTest.kt
index 76920e4..3b0057d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalDreamStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalDreamStartableTest.kt
@@ -81,6 +81,7 @@
@Test
fun startDreamWhenTransitioningToHub() =
testScope.runTest {
+ keyguardRepository.setKeyguardShowing(true)
keyguardRepository.setDreaming(false)
powerRepository.setScreenPowerState(ScreenPowerState.SCREEN_ON)
whenever(dreamManager.canStartDreaming(/* isScreenOn= */ true)).thenReturn(true)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
index 1d03ced..99fcbb8 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
@@ -352,7 +352,7 @@
smartspaceRepository.setTimers(targets)
- val smartspaceContent by collectLastValue(underTest.getOngoingContent(true))
+ val smartspaceContent by collectLastValue(underTest.ongoingContent)
assertThat(smartspaceContent?.size).isEqualTo(totalTargets)
for (index in 0 until totalTargets) {
assertThat(smartspaceContent?.get(index)?.size).isEqualTo(expectedSizes[index])
@@ -368,7 +368,7 @@
// Media is playing.
mediaRepository.mediaActive()
- val umoContent by collectLastValue(underTest.getOngoingContent(true))
+ val umoContent by collectLastValue(underTest.ongoingContent)
assertThat(umoContent?.size).isEqualTo(1)
assertThat(umoContent?.get(0)).isInstanceOf(CommunalContentModel.Umo::class.java)
@@ -376,20 +376,6 @@
}
@Test
- fun umo_mediaPlaying_doNotShowUmo() =
- testScope.run {
- // Tutorial completed.
- tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
-
- // Media is playing.
- mediaRepository.mediaActive()
-
- val umoContent by collectLastValue(underTest.getOngoingContent(false))
-
- assertThat(umoContent?.size).isEqualTo(0)
- }
-
- @Test
fun ongoing_shouldOrderAndSizeByTimestamp() =
testScope.runTest {
// Keyguard showing, and tutorial completed.
@@ -412,7 +398,7 @@
val timer3 = smartspaceTimer("timer3", timestamp = 4L)
smartspaceRepository.setTimers(listOf(timer1, timer2, timer3))
- val ongoingContent by collectLastValue(underTest.getOngoingContent(true))
+ val ongoingContent by collectLastValue(underTest.ongoingContent)
assertThat(ongoingContent?.size).isEqualTo(4)
assertThat(ongoingContent?.get(0)?.key)
.isEqualTo(CommunalContentModel.KEY.smartspace("timer3"))
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
index f6f5bc0..780d357 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
@@ -97,6 +97,7 @@
import org.mockito.Mockito
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.atLeastOnce
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.never
@@ -757,7 +758,7 @@
// updateViewVisibility is called when the flow is collected.
assertThat(communalContent).isNotNull()
- verify(mediaHost).updateViewVisibility()
+ verify(mediaHost, atLeastOnce()).updateViewVisibility()
}
@Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt
index eda9039..d21a827 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt
@@ -15,6 +15,7 @@
*/
package com.android.systemui.dreams
+import android.app.WindowConfiguration
import android.content.ComponentName
import android.content.Intent
import android.os.RemoteException
@@ -65,6 +66,8 @@
import com.android.systemui.keyguard.gesture.domain.gestureInteractor
import com.android.systemui.kosmos.testScope
import com.android.systemui.navigationbar.gestural.domain.GestureInteractor
+import com.android.systemui.navigationbar.gestural.domain.TaskInfo
+import com.android.systemui.navigationbar.gestural.domain.TaskMatcher
import com.android.systemui.testKosmos
import com.android.systemui.touch.TouchInsetManager
import com.android.systemui.util.concurrency.FakeExecutor
@@ -83,13 +86,17 @@
import org.mockito.Mockito
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.isNull
+import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
import org.mockito.kotlin.any
import org.mockito.kotlin.argumentCaptor
import org.mockito.kotlin.eq
+import org.mockito.kotlin.firstValue
import org.mockito.kotlin.mock
import org.mockito.kotlin.spy
+import org.mockito.kotlin.times
+import org.mockito.kotlin.verifyZeroInteractions
import org.mockito.kotlin.whenever
@OptIn(ExperimentalCoroutinesApi::class)
@@ -315,6 +322,7 @@
mWindowParams,
mDreamOverlayCallback,
DREAM_COMPONENT,
+ false /*isPreview*/,
false /*shouldShowComplication*/
)
mMainExecutor.runAllReady()
@@ -332,6 +340,7 @@
mWindowParams,
mDreamOverlayCallback,
DREAM_COMPONENT,
+ false /*isPreview*/,
false /*shouldShowComplication*/
)
mMainExecutor.runAllReady()
@@ -351,6 +360,7 @@
mWindowParams,
mDreamOverlayCallback,
DREAM_COMPONENT,
+ false /*isPreview*/,
false /*shouldShowComplication*/
)
mMainExecutor.runAllReady()
@@ -373,6 +383,7 @@
mWindowParams,
mDreamOverlayCallback,
DREAM_COMPONENT,
+ false /*isPreview*/,
false /*shouldShowComplication*/
)
mMainExecutor.runAllReady()
@@ -391,6 +402,7 @@
mWindowParams,
mDreamOverlayCallback,
DREAM_COMPONENT,
+ false /*isPreview*/,
false /*shouldShowComplication*/
)
mMainExecutor.runAllReady()
@@ -406,6 +418,7 @@
mWindowParams,
mDreamOverlayCallback,
DREAM_COMPONENT,
+ false /*isPreview*/,
true /*shouldShowComplication*/
)
mMainExecutor.runAllReady()
@@ -413,6 +426,47 @@
}
@Test
+ fun testDeferredResetRespondsToAnimationEnd() {
+ val client = client
+
+ // Inform the overlay service of dream starting.
+ client.startDream(
+ mWindowParams,
+ mDreamOverlayCallback,
+ DREAM_COMPONENT,
+ false /*isPreview*/,
+ true /*shouldShowComplication*/
+ )
+ mMainExecutor.runAllReady()
+
+ whenever(mStateController.areExitAnimationsRunning()).thenReturn(true)
+ clearInvocations(mStateController, mTouchMonitor)
+
+ // Starting a dream will cause it to end first.
+ client.startDream(
+ mWindowParams,
+ mDreamOverlayCallback,
+ DREAM_COMPONENT,
+ false /*isPreview*/,
+ true /*shouldShowComplication*/
+ )
+
+ mMainExecutor.runAllReady()
+
+ verifyZeroInteractions(mTouchMonitor)
+
+ val captor = ArgumentCaptor.forClass(DreamOverlayStateController.Callback::class.java)
+ verify(mStateController).addCallback(captor.capture())
+
+ whenever(mStateController.areExitAnimationsRunning()).thenReturn(false)
+
+ captor.firstValue.onStateChanged()
+
+ // Should only be called once since it should be null during the second reset.
+ verify(mTouchMonitor).destroy()
+ }
+
+ @Test
fun testLowLightSetByStartDream() {
val client = client
@@ -421,6 +475,7 @@
mWindowParams,
mDreamOverlayCallback,
LOW_LIGHT_COMPONENT.flattenToString(),
+ false /*isPreview*/,
false /*shouldShowComplication*/
)
mMainExecutor.runAllReady()
@@ -437,6 +492,7 @@
mWindowParams,
mDreamOverlayCallback,
HOME_CONTROL_PANEL_DREAM_COMPONENT.flattenToString(),
+ false /*isPreview*/,
false /*shouldShowComplication*/
)
mMainExecutor.runAllReady()
@@ -453,6 +509,7 @@
mWindowParams,
mDreamOverlayCallback,
LOW_LIGHT_COMPONENT.flattenToString(),
+ false /*isPreview*/,
false /*shouldShowComplication*/
)
mMainExecutor.runAllReady()
@@ -487,6 +544,7 @@
mWindowParams,
mDreamOverlayCallback,
DREAM_COMPONENT,
+ false /*isPreview*/,
false /*shouldShowComplication*/
)
// Immediately end the dream.
@@ -518,6 +576,7 @@
mWindowParams,
mDreamOverlayCallback,
DREAM_COMPONENT,
+ false /*isPreview*/,
false /*shouldShowComplication*/
)
mMainExecutor.runAllReady()
@@ -537,6 +596,7 @@
mWindowParams,
mDreamOverlayCallback,
LOW_LIGHT_COMPONENT.flattenToString(),
+ false /*isPreview*/,
false /*shouldShowComplication*/
)
mMainExecutor.runAllReady()
@@ -588,6 +648,7 @@
mWindowParams,
mDreamOverlayCallback,
DREAM_COMPONENT,
+ false /*isPreview*/,
false /*shouldShowComplication*/
)
mMainExecutor.runAllReady()
@@ -611,6 +672,7 @@
mWindowParams,
mDreamOverlayCallback,
DREAM_COMPONENT,
+ false /*isPreview*/,
false /*shouldShowComplication*/
)
mMainExecutor.runAllReady()
@@ -631,6 +693,7 @@
mWindowParams,
mDreamOverlayCallback,
DREAM_COMPONENT,
+ false /*isPreview*/,
true /*shouldShowComplication*/
)
mMainExecutor.runAllReady()
@@ -660,6 +723,7 @@
mWindowParams,
mDreamOverlayCallback,
DREAM_COMPONENT,
+ false /*isPreview*/,
true /*shouldShowComplication*/
)
mMainExecutor.runAllReady()
@@ -683,6 +747,7 @@
mWindowParams,
mDreamOverlayCallback,
DREAM_COMPONENT,
+ false /*isPreview*/,
false /*shouldShowComplication*/
)
mMainExecutor.runAllReady()
@@ -708,6 +773,7 @@
mWindowParams,
mDreamOverlayCallback,
DREAM_COMPONENT,
+ false /*isPreview*/,
false /*shouldShowComplication*/
)
mMainExecutor.runAllReady()
@@ -733,6 +799,7 @@
mWindowParams,
mDreamOverlayCallback,
DREAM_COMPONENT,
+ false /*isPreview*/,
false /*shouldShowComplication*/
)
// Set communal available, verify that overlay callback is informed.
@@ -761,6 +828,7 @@
mWindowParams,
mDreamOverlayCallback,
DREAM_COMPONENT,
+ false /*isPreview*/,
true /*shouldShowComplication*/
)
mMainExecutor.runAllReady()
@@ -781,6 +849,7 @@
mWindowParams,
mDreamOverlayCallback,
DREAM_COMPONENT,
+ false /*isPreview*/,
true /*shouldShowComplication*/
)
mMainExecutor.runAllReady()
@@ -800,6 +869,7 @@
mWindowParams,
mDreamOverlayCallback,
DREAM_COMPONENT,
+ false /*isPreview*/,
true /*shouldShowComplication*/
)
mMainExecutor.runAllReady()
@@ -823,6 +893,7 @@
mWindowParams,
mDreamOverlayCallback,
DREAM_COMPONENT,
+ false /*isPreview*/,
false /*shouldShowComplication*/
)
mMainExecutor.runAllReady()
@@ -853,6 +924,7 @@
mWindowParams,
mDreamOverlayCallback,
DREAM_COMPONENT,
+ false /*isPreview*/,
false /*shouldShowComplication*/
)
testScope.runCurrent()
@@ -869,6 +941,7 @@
mWindowParams,
mDreamOverlayCallback,
DREAM_COMPONENT,
+ false /*isPreview*/,
false /*shouldShowComplication*/
)
mMainExecutor.runAllReady()
@@ -892,6 +965,7 @@
mWindowParams,
mDreamOverlayCallback,
DREAM_COMPONENT,
+ false /*isPreview*/,
false /*shouldShowComplication*/
)
mMainExecutor.runAllReady()
@@ -923,6 +997,7 @@
mWindowParams,
mDreamOverlayCallback,
DREAM_COMPONENT,
+ false /*isPreview*/,
false /*shouldShowComplication*/
)
mMainExecutor.runAllReady()
@@ -954,6 +1029,7 @@
mWindowParams,
mDreamOverlayCallback,
DREAM_COMPONENT,
+ false /*isPreview*/,
false /*shouldShowComplication*/
)
mMainExecutor.runAllReady()
@@ -989,6 +1065,7 @@
mWindowParams,
mDreamOverlayCallback,
DREAM_COMPONENT,
+ false /*isPreview*/,
false /*shouldShowComplication*/
)
mMainExecutor.runAllReady()
@@ -1015,7 +1092,7 @@
}
@Test
- fun testDreamActivityGesturesBlockedOnStart() {
+ fun testDreamActivityGesturesBlockedWhenDreaming() {
val client = client
// Inform the overlay service of dream starting.
@@ -1023,36 +1100,42 @@
mWindowParams,
mDreamOverlayCallback,
DREAM_COMPONENT,
+ false /*isPreview*/,
false /*shouldShowComplication*/
)
mMainExecutor.runAllReady()
- val captor = argumentCaptor<ComponentName>()
+
+ val matcherCaptor = argumentCaptor<TaskMatcher>()
verify(gestureInteractor)
- .addGestureBlockedActivity(captor.capture(), eq(GestureInteractor.Scope.Global))
- assertThat(captor.firstValue.packageName)
- .isEqualTo(ComponentName.unflattenFromString(DREAM_COMPONENT)?.packageName)
- }
+ .addGestureBlockedMatcher(matcherCaptor.capture(), eq(GestureInteractor.Scope.Global))
+ val matcher = matcherCaptor.firstValue
- @Test
- fun testDreamActivityGesturesUnblockedOnEnd() {
- val client = client
-
- // Inform the overlay service of dream starting.
- client.startDream(
- mWindowParams,
- mDreamOverlayCallback,
- DREAM_COMPONENT,
- false /*shouldShowComplication*/
- )
- mMainExecutor.runAllReady()
+ val dreamTaskInfo = TaskInfo(mock<ComponentName>(), WindowConfiguration.ACTIVITY_TYPE_DREAM)
+ assertThat(matcher.matches(dreamTaskInfo)).isTrue()
client.endDream()
mMainExecutor.runAllReady()
- val captor = argumentCaptor<ComponentName>()
+
verify(gestureInteractor)
- .removeGestureBlockedActivity(captor.capture(), eq(GestureInteractor.Scope.Global))
- assertThat(captor.firstValue.packageName)
- .isEqualTo(ComponentName.unflattenFromString(DREAM_COMPONENT)?.packageName)
+ .removeGestureBlockedMatcher(eq(matcher), eq(GestureInteractor.Scope.Global))
+ }
+
+ @Test
+ fun testDreamActivityGesturesNotBlockedWhenPreview() {
+ val client = client
+
+ // Inform the overlay service of dream starting.
+ client.startDream(
+ mWindowParams,
+ mDreamOverlayCallback,
+ DREAM_COMPONENT,
+ true /*isPreview*/,
+ false /*shouldShowComplication*/
+ )
+ mMainExecutor.runAllReady()
+
+ verify(gestureInteractor, never())
+ .addGestureBlockedMatcher(any(), eq(GestureInteractor.Scope.Global))
}
@Test
@@ -1077,6 +1160,7 @@
mWindowParams,
mDreamOverlayCallback,
DREAM_COMPONENT,
+ false /*isPreview*/,
false /*shouldShowComplication*/
)
mMainExecutor.runAllReady()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/gesture/data/GestureRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/gesture/data/GestureRepositoryTest.kt
index 91d37cf..a764256 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/gesture/data/GestureRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/gesture/data/GestureRepositoryTest.kt
@@ -16,12 +16,14 @@
package com.android.systemui.gesture.data
+import android.app.WindowConfiguration
import android.content.ComponentName
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.navigationbar.gestural.data.respository.GestureRepositoryImpl
+import com.android.systemui.navigationbar.gestural.domain.TaskMatcher
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
@@ -40,14 +42,36 @@
@Test
fun addRemoveComponentToBlock_updatesBlockedComponentSet() =
testScope.runTest {
- val component = mock<ComponentName>()
+ val matcher = TaskMatcher.TopActivityComponent(mock<ComponentName>())
- underTest.addGestureBlockedActivity(component)
- val addedBlockedComponents by collectLastValue(underTest.gestureBlockedActivities)
- assertThat(addedBlockedComponents).contains(component)
+ kotlin.run {
+ underTest.addGestureBlockedMatcher(matcher)
+ val blockedMatchers by collectLastValue(underTest.gestureBlockedMatchers)
+ assertThat(blockedMatchers).contains(matcher)
+ }
- underTest.removeGestureBlockedActivity(component)
- val removedBlockedComponents by collectLastValue(underTest.gestureBlockedActivities)
- assertThat(removedBlockedComponents).isEmpty()
+ kotlin.run {
+ underTest.removeGestureBlockedMatcher(matcher)
+ val blockedMatchers by collectLastValue(underTest.gestureBlockedMatchers)
+ assertThat(blockedMatchers).doesNotContain(matcher)
+ }
+ }
+
+ @Test
+ fun addRemoveActivityTypeToBlock_updatesBlockedActivityTypesSet() =
+ testScope.runTest {
+ val matcher = TaskMatcher.TopActivityType(WindowConfiguration.ACTIVITY_TYPE_STANDARD)
+
+ kotlin.run {
+ underTest.addGestureBlockedMatcher(matcher)
+ val blockedMatchers by collectLastValue(underTest.gestureBlockedMatchers)
+ assertThat(blockedMatchers).contains(matcher)
+ }
+
+ kotlin.run {
+ underTest.removeGestureBlockedMatcher(matcher)
+ val blockedMatchers by collectLastValue(underTest.gestureBlockedMatchers)
+ assertThat(blockedMatchers).doesNotContain(matcher)
+ }
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/gesture/domain/GestureInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/gesture/domain/GestureInteractorTest.kt
index 6395448..0ce0d93 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/gesture/domain/GestureInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/gesture/domain/GestureInteractorTest.kt
@@ -26,6 +26,7 @@
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.navigationbar.gestural.data.gestureRepository
import com.android.systemui.navigationbar.gestural.domain.GestureInteractor
+import com.android.systemui.navigationbar.gestural.domain.TaskMatcher
import com.android.systemui.shared.system.activityManagerWrapper
import com.android.systemui.shared.system.taskStackChangeListeners
import com.android.systemui.testKosmos
@@ -76,13 +77,16 @@
fun addBlockedActivity_testCombination() =
testScope.runTest {
val globalComponent = mock<ComponentName>()
- repository.addGestureBlockedActivity(globalComponent)
+ repository.addGestureBlockedMatcher(TaskMatcher.TopActivityComponent(globalComponent))
val localComponent = mock<ComponentName>()
val blocked by collectLastValue(underTest.topActivityBlocked)
- underTest.addGestureBlockedActivity(localComponent, GestureInteractor.Scope.Local)
+ underTest.addGestureBlockedMatcher(
+ TaskMatcher.TopActivityComponent(localComponent),
+ GestureInteractor.Scope.Local
+ )
assertThat(blocked).isFalse()
@@ -95,7 +99,7 @@
fun initialization_testEmit() =
testScope.runTest {
val globalComponent = mock<ComponentName>()
- repository.addGestureBlockedActivity(globalComponent)
+ repository.addGestureBlockedMatcher(TaskMatcher.TopActivityComponent(globalComponent))
setTopActivity(globalComponent)
val interactor = createInteractor()
@@ -114,10 +118,36 @@
val localComponent = mock<ComponentName>()
- interactor1.addGestureBlockedActivity(localComponent, GestureInteractor.Scope.Local)
+ interactor1.addGestureBlockedMatcher(
+ TaskMatcher.TopActivityComponent(localComponent),
+ GestureInteractor.Scope.Local
+ )
setTopActivity(localComponent)
assertThat(interactor1Blocked).isTrue()
assertThat(interactor2Blocked).isFalse()
}
+
+ @Test
+ fun matchingBlockers_separatelyManaged() =
+ testScope.runTest {
+ val interactor = createInteractor()
+ val interactorBlocked by collectLastValue(interactor.topActivityBlocked)
+
+ val localComponent = mock<ComponentName>()
+
+ val matcher1 = TaskMatcher.TopActivityComponent(localComponent)
+ val matcher2 = TaskMatcher.TopActivityComponent(localComponent)
+
+ interactor.addGestureBlockedMatcher(matcher1, GestureInteractor.Scope.Local)
+ interactor.addGestureBlockedMatcher(matcher2, GestureInteractor.Scope.Local)
+ setTopActivity(localComponent)
+ assertThat(interactorBlocked).isTrue()
+
+ interactor.removeGestureBlockedMatcher(matcher1, GestureInteractor.Scope.Local)
+ assertThat(interactorBlocked).isTrue()
+
+ interactor.removeGestureBlockedMatcher(matcher2, GestureInteractor.Scope.Local)
+ assertThat(interactorBlocked).isFalse()
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/gesture/domain/TaskMatcherTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/gesture/domain/TaskMatcherTest.kt
new file mode 100644
index 0000000..a246270
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/gesture/domain/TaskMatcherTest.kt
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.gesture.domain
+
+import android.app.WindowConfiguration
+import android.content.ComponentName
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.navigationbar.gestural.domain.TaskInfo
+import com.android.systemui.navigationbar.gestural.domain.TaskMatcher
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.mock
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class TaskMatcherTest : SysuiTestCase() {
+ @Test
+ fun activityMatcher_matchesComponentName() {
+ val componentName = ComponentName.unflattenFromString("com.foo/.bar")!!
+ val matcher = TaskMatcher.TopActivityComponent(componentName)
+
+ val taskInfo = TaskInfo(componentName, WindowConfiguration.ACTIVITY_TYPE_STANDARD)
+ assertThat(matcher.matches(taskInfo)).isTrue()
+ }
+
+ @Test
+ fun activityMatcher_doesNotMatchComponentName() {
+ val componentName = ComponentName.unflattenFromString("com.foo/.bar")!!
+ val matcher = TaskMatcher.TopActivityComponent(componentName)
+
+ val taskInfo =
+ TaskInfo(
+ ComponentName.unflattenFromString("com.bar/.baz"),
+ WindowConfiguration.ACTIVITY_TYPE_STANDARD
+ )
+ assertThat(matcher.matches(taskInfo)).isFalse()
+ }
+
+ @Test
+ fun activityMatcher_matchesActivityType() {
+ val activityType = WindowConfiguration.ACTIVITY_TYPE_HOME
+ val matcher = TaskMatcher.TopActivityType(activityType)
+
+ val taskInfo = TaskInfo(mock<ComponentName>(), activityType)
+ assertThat(matcher.matches(taskInfo)).isTrue()
+ }
+
+ @Test
+ fun activityMatcher_doesNotMatchEmptyActivityType() {
+ val activityType = WindowConfiguration.ACTIVITY_TYPE_HOME
+ val matcher = TaskMatcher.TopActivityType(activityType)
+
+ val taskInfo = TaskInfo(null, activityType)
+ assertThat(matcher.matches(taskInfo)).isFalse()
+ }
+
+ @Test
+ fun activityMatcher_doesNotMatchActivityType() {
+ val activityType = WindowConfiguration.ACTIVITY_TYPE_HOME
+ val matcher = TaskMatcher.TopActivityType(activityType)
+
+ val taskInfo = TaskInfo(mock<ComponentName>(), WindowConfiguration.ACTIVITY_TYPE_STANDARD)
+ assertThat(matcher.matches(taskInfo)).isFalse()
+ }
+
+ @Test
+ fun activityMatcher_equivalentMatchersAreNotEqual() {
+ val activityType = WindowConfiguration.ACTIVITY_TYPE_HOME
+ val matcher1 = TaskMatcher.TopActivityType(activityType)
+ val matcher2 = TaskMatcher.TopActivityType(activityType)
+
+ assertThat(matcher1).isNotEqualTo(matcher2)
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt
index 6eb9862..9273dce 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt
@@ -39,12 +39,15 @@
import androidx.test.filters.SmallTest
import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.keyguardOcclusionRepository
import com.android.systemui.keyguard.shared.model.BiometricUnlockMode
import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
+import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.keyguard.util.KeyguardTransitionRepositorySpySubject.Companion.assertThat
@@ -53,6 +56,7 @@
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest
import com.android.systemui.power.domain.interactor.powerInteractor
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.statusbar.domain.interactor.keyguardOcclusionInteractor
import com.android.systemui.testKosmos
import junit.framework.Assert.assertEquals
@@ -166,6 +170,10 @@
@EnableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
fun testTransitionToGone_onWakeUp_ifPowerButtonGestureDetected_fromGone() =
testScope.runTest {
+ val isGone by
+ collectLastValue(
+ kosmos.keyguardTransitionInteractor.isFinishedIn(Scenes.Gone, GONE)
+ )
powerInteractor.setAwakeForTest()
transitionRepository.sendTransitionSteps(
from = KeyguardState.AOD,
@@ -175,7 +183,7 @@
runCurrent()
// Make sure we're GONE.
- assertEquals(KeyguardState.GONE, kosmos.keyguardTransitionInteractor.getFinishedState())
+ assertEquals(true, isGone)
// Get part way to AOD.
powerInteractor.onStartedGoingToSleep(PowerManager.GO_TO_SLEEP_REASON_MIN)
@@ -204,6 +212,10 @@
@EnableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
fun testTransitionToOccluded_onWakeUp_ifPowerButtonGestureDetectedAfterFinishedInAod_fromGone() =
testScope.runTest {
+ val isGone by
+ collectLastValue(
+ kosmos.keyguardTransitionInteractor.isFinishedIn(Scenes.Gone, GONE)
+ )
powerInteractor.setAwakeForTest()
transitionRepository.sendTransitionSteps(
from = KeyguardState.AOD,
@@ -213,7 +225,7 @@
runCurrent()
// Make sure we're GONE.
- assertEquals(KeyguardState.GONE, kosmos.keyguardTransitionInteractor.getFinishedState())
+ assertEquals(true, isGone)
// Get all the way to AOD
powerInteractor.onStartedGoingToSleep(PowerManager.GO_TO_SLEEP_REASON_MIN)
@@ -239,6 +251,10 @@
@EnableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
fun testTransitionToOccluded_onWakeUp_ifPowerButtonGestureDetected_fromLockscreen() =
testScope.runTest {
+ val isLockscreen by
+ collectLastValue(
+ kosmos.keyguardTransitionInteractor.isFinishedIn(Scenes.Lockscreen, LOCKSCREEN)
+ )
powerInteractor.setAwakeForTest()
transitionRepository.sendTransitionSteps(
from = KeyguardState.AOD,
@@ -248,10 +264,7 @@
runCurrent()
// Make sure we're in LOCKSCREEN.
- assertEquals(
- KeyguardState.LOCKSCREEN,
- kosmos.keyguardTransitionInteractor.getFinishedState()
- )
+ assertEquals(true, isLockscreen)
// Get part way to AOD.
powerInteractor.onStartedGoingToSleep(PowerManager.GO_TO_SLEEP_REASON_MIN)
@@ -327,6 +340,10 @@
@DisableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
fun testTransitionToGone_onWakeUp_ifPowerButtonGestureDetectedInAod_fromGone() =
testScope.runTest {
+ val isGone by
+ collectLastValue(
+ kosmos.keyguardTransitionInteractor.isFinishedIn(Scenes.Gone, GONE)
+ )
powerInteractor.setAwakeForTest()
transitionRepository.sendTransitionSteps(
from = KeyguardState.AOD,
@@ -336,7 +353,7 @@
runCurrent()
// Make sure we're GONE.
- assertEquals(KeyguardState.GONE, kosmos.keyguardTransitionInteractor.getFinishedState())
+ assertEquals(true, isGone)
// Start going to AOD on first button push
powerInteractor.onStartedGoingToSleep(PowerManager.GO_TO_SLEEP_REASON_MIN)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorTest.kt
index ee4a0d2d..c18deb1 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorTest.kt
@@ -48,12 +48,15 @@
import com.android.systemui.communal.domain.interactor.setCommunalAvailable
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.communal.shared.model.CommunalTransitionKeys
+import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.keyguardOcclusionRepository
import com.android.systemui.keyguard.shared.model.BiometricUnlockMode
import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
+import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.util.KeyguardTransitionRepositorySpySubject.Companion.assertThat
import com.android.systemui.kosmos.applicationCoroutineScope
@@ -62,6 +65,7 @@
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest
import com.android.systemui.power.domain.interactor.powerInteractor
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.testKosmos
import junit.framework.Assert.assertEquals
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -316,6 +320,10 @@
@EnableFlags(FLAG_KEYGUARD_WM_STATE_REFACTOR)
fun testTransitionToGone_onWakeUp_ifPowerButtonGestureDetected_fromGone() =
testScope.runTest {
+ val isGone by
+ collectLastValue(
+ kosmos.keyguardTransitionInteractor.isFinishedIn(Scenes.Gone, GONE)
+ )
powerInteractor.setAwakeForTest()
transitionRepository.sendTransitionSteps(
from = KeyguardState.DOZING,
@@ -325,7 +333,7 @@
runCurrent()
// Make sure we're GONE.
- assertEquals(KeyguardState.GONE, kosmos.keyguardTransitionInteractor.getFinishedState())
+ assertEquals(true, isGone)
// Get part way to AOD.
powerInteractor.onStartedGoingToSleep(PowerManager.GO_TO_SLEEP_REASON_MIN)
@@ -355,6 +363,10 @@
@Suppress("ktlint:standard:max-line-length")
fun testTransitionToOccluded_onWakeUp_ifPowerButtonGestureDetectedAfterFinishedInAod_fromGone() =
testScope.runTest {
+ val isGone by
+ collectLastValue(
+ kosmos.keyguardTransitionInteractor.isFinishedIn(Scenes.Gone, GONE)
+ )
powerInteractor.setAwakeForTest()
transitionRepository.sendTransitionSteps(
from = KeyguardState.DOZING,
@@ -364,7 +376,7 @@
runCurrent()
// Make sure we're GONE.
- assertEquals(KeyguardState.GONE, kosmos.keyguardTransitionInteractor.getFinishedState())
+ assertEquals(true, isGone)
// Get all the way to AOD
powerInteractor.onStartedGoingToSleep(PowerManager.GO_TO_SLEEP_REASON_MIN)
@@ -390,6 +402,10 @@
@EnableFlags(FLAG_KEYGUARD_WM_STATE_REFACTOR)
fun testTransitionToOccluded_onWakeUp_ifPowerButtonGestureDetected_fromLockscreen() =
testScope.runTest {
+ val isLockscreen by
+ collectLastValue(
+ kosmos.keyguardTransitionInteractor.isFinishedIn(Scenes.Lockscreen, LOCKSCREEN)
+ )
powerInteractor.setAwakeForTest()
transitionRepository.sendTransitionSteps(
from = KeyguardState.DOZING,
@@ -399,10 +415,7 @@
runCurrent()
// Make sure we're in LOCKSCREEN.
- assertEquals(
- KeyguardState.LOCKSCREEN,
- kosmos.keyguardTransitionInteractor.getFinishedState()
- )
+ assertEquals(true, isLockscreen)
// Get part way to AOD.
powerInteractor.onStartedGoingToSleep(PowerManager.GO_TO_SLEEP_REASON_MIN)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
index 6e76cbc..6708ffa 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
@@ -90,52 +90,6 @@
}
@Test
- fun finishedKeyguardStateTests() =
- testScope.runTest {
- val finishedSteps by collectValues(underTest.finishedKeyguardState)
- runCurrent()
- val steps = mutableListOf<TransitionStep>()
-
- steps.add(TransitionStep(AOD, PRIMARY_BOUNCER, 0f, STARTED))
- steps.add(TransitionStep(AOD, PRIMARY_BOUNCER, 0.5f, RUNNING))
- steps.add(TransitionStep(AOD, PRIMARY_BOUNCER, 1f, FINISHED))
- steps.add(TransitionStep(PRIMARY_BOUNCER, AOD, 0f, STARTED))
- steps.add(TransitionStep(PRIMARY_BOUNCER, AOD, 0.9f, RUNNING))
- steps.add(TransitionStep(PRIMARY_BOUNCER, AOD, 1f, FINISHED))
- steps.add(TransitionStep(AOD, GONE, 1f, STARTED))
-
- steps.forEach {
- repository.sendTransitionStep(it)
- runCurrent()
- }
-
- assertThat(finishedSteps).isEqualTo(listOf(LOCKSCREEN, PRIMARY_BOUNCER, AOD))
- }
-
- @Test
- fun startedKeyguardStateTests() =
- testScope.runTest {
- val startedStates by collectValues(underTest.startedKeyguardState)
- runCurrent()
- val steps = mutableListOf<TransitionStep>()
-
- steps.add(TransitionStep(AOD, PRIMARY_BOUNCER, 0f, STARTED))
- steps.add(TransitionStep(AOD, PRIMARY_BOUNCER, 0.5f, RUNNING))
- steps.add(TransitionStep(AOD, PRIMARY_BOUNCER, 1f, FINISHED))
- steps.add(TransitionStep(PRIMARY_BOUNCER, AOD, 0f, STARTED))
- steps.add(TransitionStep(PRIMARY_BOUNCER, AOD, 0.9f, RUNNING))
- steps.add(TransitionStep(PRIMARY_BOUNCER, AOD, 1f, FINISHED))
- steps.add(TransitionStep(AOD, GONE, 1f, STARTED))
-
- steps.forEach {
- repository.sendTransitionStep(it)
- runCurrent()
- }
-
- assertThat(startedStates).isEqualTo(listOf(LOCKSCREEN, PRIMARY_BOUNCER, AOD, GONE))
- }
-
- @Test
fun startedKeyguardTransitionStepTests() =
testScope.runTest {
val startedSteps by collectValues(underTest.startedKeyguardTransitionStep)
@@ -1206,95 +1160,6 @@
}
@Test
- fun finishedKeyguardState_emitsAgainIfCancelledAndReversed() =
- testScope.runTest {
- val finishedStates by collectValues(underTest.finishedKeyguardState)
-
- // We default FINISHED in LOCKSCREEN.
- assertEquals(listOf(LOCKSCREEN), finishedStates)
-
- sendSteps(
- TransitionStep(LOCKSCREEN, AOD, 0f, STARTED),
- TransitionStep(LOCKSCREEN, AOD, 0.5f, RUNNING),
- TransitionStep(LOCKSCREEN, AOD, 1f, FINISHED),
- )
-
- // We're FINISHED in AOD.
- assertEquals(
- listOf(
- LOCKSCREEN,
- AOD,
- ),
- finishedStates
- )
-
- // Transition back to LOCKSCREEN.
- sendSteps(
- TransitionStep(AOD, LOCKSCREEN, 0f, STARTED),
- TransitionStep(AOD, LOCKSCREEN, 0.5f, RUNNING),
- TransitionStep(AOD, LOCKSCREEN, 1f, FINISHED),
- )
-
- // We're FINISHED in LOCKSCREEN.
- assertEquals(
- listOf(
- LOCKSCREEN,
- AOD,
- LOCKSCREEN,
- ),
- finishedStates
- )
-
- sendSteps(
- TransitionStep(LOCKSCREEN, GONE, 0f, STARTED),
- TransitionStep(LOCKSCREEN, GONE, 0.5f, RUNNING),
- )
-
- // We've STARTED a transition to GONE but not yet finished it so we're still FINISHED in
- // LOCKSCREEN.
- assertEquals(
- listOf(
- LOCKSCREEN,
- AOD,
- LOCKSCREEN,
- ),
- finishedStates
- )
-
- sendSteps(
- TransitionStep(LOCKSCREEN, GONE, 0.6f, CANCELED),
- )
-
- // We've CANCELED a transition to GONE, we're still FINISHED in LOCKSCREEN.
- assertEquals(
- listOf(
- LOCKSCREEN,
- AOD,
- LOCKSCREEN,
- ),
- finishedStates
- )
-
- sendSteps(
- TransitionStep(GONE, LOCKSCREEN, 0.6f, STARTED),
- TransitionStep(GONE, LOCKSCREEN, 0.9f, RUNNING),
- TransitionStep(GONE, LOCKSCREEN, 1f, FINISHED),
- )
-
- // Expect another emission of LOCKSCREEN, as we have FINISHED a second transition to
- // LOCKSCREEN after the cancellation.
- assertEquals(
- listOf(
- LOCKSCREEN,
- AOD,
- LOCKSCREEN,
- LOCKSCREEN,
- ),
- finishedStates
- )
- }
-
- @Test
fun testCurrentState() =
testScope.runTest {
val currentStates by collectValues(underTest.currentKeyguardState)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt
index 3e0a1f3..073ed61 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt
@@ -19,18 +19,20 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectValues
import com.android.systemui.keyguard.data.fakeLightRevealScrimRepository
+import com.android.systemui.keyguard.data.repository.DEFAULT_REVEAL_EFFECT
import com.android.systemui.keyguard.data.repository.FakeLightRevealScrimRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.kosmos.testScope
import com.android.systemui.statusbar.LightRevealEffect
import com.android.systemui.statusbar.LightRevealScrim
import com.android.systemui.testKosmos
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
import org.junit.Test
@@ -64,35 +66,45 @@
@Test
fun lightRevealEffect_doesNotChangeDuringKeyguardTransition() =
- runTest(UnconfinedTestDispatcher()) {
- val values = mutableListOf<LightRevealEffect>()
- val job = underTest.lightRevealEffect.onEach(values::add).launchIn(this)
+ kosmos.testScope.runTest {
+ val values by collectValues(underTest.lightRevealEffect)
+ runCurrent()
+ assertEquals(listOf(DEFAULT_REVEAL_EFFECT), values)
fakeLightRevealScrimRepository.setRevealEffect(reveal1)
-
+ runCurrent()
// The reveal effect shouldn't emit anything until a keyguard transition starts.
- assertEquals(values.size, 0)
+ assertEquals(listOf(DEFAULT_REVEAL_EFFECT), values)
// Once it starts, it should emit reveal1.
fakeKeyguardTransitionRepository.sendTransitionStep(
- TransitionStep(transitionState = TransitionState.STARTED)
+ TransitionStep(to = KeyguardState.AOD, transitionState = TransitionState.STARTED)
)
- assertEquals(values, listOf(reveal1))
+ runCurrent()
+ assertEquals(listOf(DEFAULT_REVEAL_EFFECT, reveal1), values)
// Until the next transition starts, reveal2 should not be emitted.
fakeLightRevealScrimRepository.setRevealEffect(reveal2)
+ runCurrent()
fakeKeyguardTransitionRepository.sendTransitionStep(
- TransitionStep(transitionState = TransitionState.RUNNING)
+ TransitionStep(
+ to = KeyguardState.LOCKSCREEN,
+ transitionState = TransitionState.RUNNING
+ )
)
+ runCurrent()
fakeKeyguardTransitionRepository.sendTransitionStep(
- TransitionStep(transitionState = TransitionState.FINISHED)
+ TransitionStep(to = KeyguardState.AOD, transitionState = TransitionState.FINISHED)
)
- assertEquals(values, listOf(reveal1))
+ runCurrent()
+ assertEquals(listOf(DEFAULT_REVEAL_EFFECT, reveal1), values)
fakeKeyguardTransitionRepository.sendTransitionStep(
- TransitionStep(transitionState = TransitionState.STARTED)
+ TransitionStep(
+ to = KeyguardState.LOCKSCREEN,
+ transitionState = TransitionState.STARTED
+ )
)
- assertEquals(values, listOf(reveal1, reveal2))
-
- job.cancel()
+ runCurrent()
+ assertEquals(listOf(DEFAULT_REVEAL_EFFECT, reveal1, reveal2), values)
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
index 4d3909c..f365afb 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
@@ -501,7 +501,7 @@
private fun getCurrentSceneInUi(): SceneKey {
return when (val state = transitionState.value) {
is ObservableTransitionState.Idle -> state.currentScene
- is ObservableTransitionState.Transition.ChangeCurrentScene -> state.fromScene
+ is ObservableTransitionState.Transition.ChangeScene -> state.fromScene
is ObservableTransitionState.Transition.ShowOrHideOverlay -> state.currentScene
is ObservableTransitionState.Transition.ReplaceOverlay -> state.currentScene
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractorTest.kt
index 14134cc..cea8857 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractorTest.kt
@@ -18,11 +18,11 @@
package com.android.systemui.statusbar.notification.domain.interactor
-import android.platform.test.annotations.EnableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFaceAuthRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
@@ -31,7 +31,6 @@
import com.android.systemui.shade.shadeTestUtil
import com.android.systemui.statusbar.notification.data.repository.FakeHeadsUpRowRepository
import com.android.systemui.statusbar.notification.data.repository.notificationsKeyguardViewStateRepository
-import com.android.systemui.statusbar.notification.shared.NotificationsHeadsUpRefactor
import com.android.systemui.statusbar.notification.stack.data.repository.headsUpNotificationRepository
import com.android.systemui.statusbar.notification.stack.domain.interactor.headsUpNotificationInteractor
import com.android.systemui.testKosmos
@@ -44,7 +43,7 @@
@SmallTest
@RunWith(AndroidJUnit4::class)
-@EnableFlags(NotificationsHeadsUpRefactor.FLAG_NAME)
+@EnableSceneContainer
class HeadsUpNotificationInteractorTest : SysuiTestCase() {
private val kosmos =
testKosmos().apply {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt
index f96cf10..840aa92 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt
@@ -26,6 +26,7 @@
import com.android.settingslib.notification.data.repository.updateNotificationPolicy
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.flags.Flags
import com.android.systemui.flags.andSceneContainer
import com.android.systemui.flags.fakeFeatureFlagsClassic
@@ -41,7 +42,6 @@
import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
import com.android.systemui.statusbar.notification.data.repository.setActiveNotifs
import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor
-import com.android.systemui.statusbar.notification.shared.NotificationsHeadsUpRefactor
import com.android.systemui.statusbar.notification.stack.data.repository.headsUpNotificationRepository
import com.android.systemui.statusbar.policy.data.repository.fakeUserSetupRepository
import com.android.systemui.statusbar.policy.data.repository.zenModeRepository
@@ -535,7 +535,7 @@
}
@Test
- @EnableFlags(NotificationsHeadsUpRefactor.FLAG_NAME)
+ @EnableSceneContainer
fun pinnedHeadsUpRows_filtersForPinnedItems() =
testScope.runTest {
val pinnedHeadsUpRows by collectLastValue(underTest.pinnedHeadsUpRows)
@@ -576,7 +576,7 @@
}
@Test
- @EnableFlags(NotificationsHeadsUpRefactor.FLAG_NAME)
+ @EnableSceneContainer
fun hasPinnedHeadsUpRows_true() =
testScope.runTest {
val hasPinnedHeadsUpRow by collectLastValue(underTest.hasPinnedHeadsUpRow)
@@ -591,7 +591,7 @@
}
@Test
- @EnableFlags(NotificationsHeadsUpRefactor.FLAG_NAME)
+ @EnableSceneContainer
fun hasPinnedHeadsUpRows_false() =
testScope.runTest {
val hasPinnedHeadsUpRow by collectLastValue(underTest.hasPinnedHeadsUpRow)
@@ -606,7 +606,7 @@
}
@Test
- @EnableFlags(NotificationsHeadsUpRefactor.FLAG_NAME)
+ @EnableSceneContainer
fun topHeadsUpRow_emptyList_null() =
testScope.runTest {
val topHeadsUpRow by collectLastValue(underTest.topHeadsUpRow)
@@ -618,7 +618,7 @@
}
@Test
- @EnableFlags(NotificationsHeadsUpRefactor.FLAG_NAME)
+ @EnableSceneContainer
fun headsUpAnimationsEnabled_true() =
testScope.runTest {
val animationsEnabled by collectLastValue(underTest.headsUpAnimationsEnabled)
@@ -631,7 +631,7 @@
}
@Test
- @EnableFlags(NotificationsHeadsUpRefactor.FLAG_NAME)
+ @EnableSceneContainer
fun headsUpAnimationsEnabled_keyguardShowing_true() =
testScope.runTest {
val animationsEnabled by collectLastValue(underTest.headsUpAnimationsEnabled)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.kt
index ca106fa..469a7bc 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.kt
@@ -23,6 +23,7 @@
import androidx.test.filters.SmallTest
import com.android.internal.logging.UiEventLogger
import com.android.systemui.dump.DumpManager
+import com.android.systemui.flags.andSceneContainer
import com.android.systemui.kosmos.testScope
import com.android.systemui.log.logcatLogBuffer
import com.android.systemui.plugins.statusbar.StatusBarStateController
@@ -36,7 +37,6 @@
import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun
-import com.android.systemui.statusbar.notification.shared.NotificationsHeadsUpRefactor
import com.android.systemui.statusbar.phone.ConfigurationControllerImpl
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
import com.android.systemui.statusbar.phone.KeyguardBypassController
@@ -469,9 +469,9 @@
@get:Parameters(name = "{0}")
val flags: List<FlagsParameterization>
get() = buildList {
- addAll(FlagsParameterization.allCombinationsOf(NotificationThrottleHun.FLAG_NAME))
addAll(
- FlagsParameterization.allCombinationsOf(NotificationsHeadsUpRefactor.FLAG_NAME)
+ FlagsParameterization.allCombinationsOf(NotificationThrottleHun.FLAG_NAME)
+ .andSceneContainer()
)
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModelTest.kt
index 51a70bd..fe6c741 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModelTest.kt
@@ -28,6 +28,7 @@
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.testScope
+import com.android.systemui.res.R
import com.android.systemui.statusbar.policy.configurationController
import com.android.systemui.statusbar.policy.fakeConfigurationController
import com.android.systemui.testKosmos
@@ -157,6 +158,10 @@
@Test
fun testDumpingState() =
test({
+ testableResources.addOverride(R.bool.volume_panel_is_large_screen, false)
+ testableResources.overrideConfiguration(
+ Configuration().apply { orientation = Configuration.ORIENTATION_PORTRAIT }
+ )
componentByKey =
mapOf(
COMPONENT_1 to mockVolumePanelUiComponentProvider,
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index fd943d0..e6cc6cf 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -740,6 +740,8 @@
<string name="quick_settings_bluetooth_device_connected">Connected</string>
<!-- QuickSettings: Bluetooth dialog device in audio sharing default summary [CHAR LIMIT=50]-->
<string name="quick_settings_bluetooth_device_audio_sharing">Audio Sharing</string>
+ <!-- QuickSettings: Bluetooth dialog device summary for devices that are capable of audio sharing and switching to active[CHAR LIMIT=NONE]-->
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active">Tap to switch or share audio</string>
<!-- QuickSettings: Bluetooth dialog device saved default summary [CHAR LIMIT=NONE]-->
<string name="quick_settings_bluetooth_device_saved">Saved</string>
<!-- QuickSettings: Accessibility label to disconnect a device [CHAR LIMIT=NONE]-->
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
index 64fe78d..7ec977a 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
@@ -218,6 +218,7 @@
@ViewDebug.ExportedProperty(category="recents")
public String title;
@ViewDebug.ExportedProperty(category="recents")
+ @Nullable
public String titleDescription;
@ViewDebug.ExportedProperty(category="recents")
public int colorPrimary;
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogUiEvent.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogUiEvent.kt
index 4a358c0..bdd4c16 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogUiEvent.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogUiEvent.kt
@@ -31,6 +31,8 @@
@UiEvent(doc = "Saved clicked to connect") SAVED_DEVICE_CONNECT(1500),
@UiEvent(doc = "Active device clicked to disconnect") ACTIVE_DEVICE_DISCONNECT(1507),
@UiEvent(doc = "Audio sharing device clicked, do nothing") AUDIO_SHARING_DEVICE_CLICKED(1699),
+ @UiEvent(doc = "Available audio sharing device clicked, do nothing")
+ AVAILABLE_AUDIO_SHARING_DEVICE_CLICKED(1880),
@UiEvent(doc = "Connected other device clicked to disconnect")
CONNECTED_OTHER_DEVICE_DISCONNECT(1508),
@UiEvent(doc = "The auto on toggle is clicked") BLUETOOTH_AUTO_ON_TOGGLE_CLICKED(1617),
@@ -44,8 +46,14 @@
doc = "Not broadcasting, having one connected, another saved LE audio device is clicked"
)
LAUNCH_SETTINGS_NOT_SHARING_SAVED_LE_DEVICE_CLICKED(1719),
+ @Deprecated(
+ "Use case no longer needed",
+ ReplaceWith("LAUNCH_SETTINGS_NOT_SHARING_ACTIVE_LE_DEVICE_CLICKED")
+ )
@UiEvent(doc = "Not broadcasting, one of the two connected LE audio devices is clicked")
- LAUNCH_SETTINGS_NOT_SHARING_CONNECTED_LE_DEVICE_CLICKED(1720);
+ LAUNCH_SETTINGS_NOT_SHARING_CONNECTED_LE_DEVICE_CLICKED(1720),
+ @UiEvent(doc = "Not broadcasting, having two connected, the active LE audio devices is clicked")
+ LAUNCH_SETTINGS_NOT_SHARING_ACTIVE_LE_DEVICE_CLICKED(1881);
override fun getId() = metricId
}
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItem.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItem.kt
index a78130f..2ba4c73 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItem.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItem.kt
@@ -38,6 +38,7 @@
enum class DeviceItemType {
ACTIVE_MEDIA_BLUETOOTH_DEVICE,
AUDIO_SHARING_MEDIA_BLUETOOTH_DEVICE,
+ AVAILABLE_AUDIO_SHARING_MEDIA_BLUETOOTH_DEVICE,
AVAILABLE_MEDIA_BLUETOOTH_DEVICE,
CONNECTED_BLUETOOTH_DEVICE,
SAVED_BLUETOOTH_DEVICE,
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractor.kt
index 9d82e76..f1894d3 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractor.kt
@@ -67,7 +67,7 @@
backgroundDispatcher,
logger
),
- NotSharingClickedConnected(
+ NotSharingClickedActive(
leAudioProfile,
assistantProfile,
backgroundDispatcher,
@@ -106,6 +106,12 @@
DeviceItemType.AUDIO_SHARING_MEDIA_BLUETOOTH_DEVICE -> {
uiEventLogger.log(BluetoothTileDialogUiEvent.AUDIO_SHARING_DEVICE_CLICKED)
}
+ DeviceItemType.AVAILABLE_AUDIO_SHARING_MEDIA_BLUETOOTH_DEVICE -> {
+ // TODO(b/360759048): pop up dialog
+ uiEventLogger.log(
+ BluetoothTileDialogUiEvent.AVAILABLE_AUDIO_SHARING_DEVICE_CLICKED
+ )
+ }
DeviceItemType.AVAILABLE_MEDIA_BLUETOOTH_DEVICE -> {
setActive()
uiEventLogger.log(BluetoothTileDialogUiEvent.CONNECTED_DEVICE_SET_ACTIVE)
@@ -238,14 +244,14 @@
BluetoothTileDialogUiEvent.LAUNCH_SETTINGS_NOT_SHARING_SAVED_LE_DEVICE_CLICKED
}
- private class NotSharingClickedConnected(
+ private class NotSharingClickedActive(
private val leAudioProfile: LeAudioProfile?,
private val assistantProfile: LocalBluetoothLeBroadcastAssistant?,
@Background private val backgroundDispatcher: CoroutineDispatcher,
private val logger: BluetoothTileDialogLogger,
) : LaunchSettingsCriteria {
- // If not broadcasting, having two device connected, clicked on any connected LE audio
- // devices
+ // If not broadcasting, having two device connected, clicked on the active LE audio
+ // device
override suspend fun matched(inAudioSharing: Boolean, deviceItem: DeviceItem): Boolean {
return withContext(backgroundDispatcher) {
val matched =
@@ -259,7 +265,7 @@
logger
)
.size == 2 &&
- deviceItem.isActiveOrConnectedLeAudioSupported
+ deviceItem.isActiveLeAudioSupported
}
} ?: false
@@ -275,7 +281,7 @@
}
override suspend fun getClickUiEvent(deviceItem: DeviceItem) =
- BluetoothTileDialogUiEvent.LAUNCH_SETTINGS_NOT_SHARING_CONNECTED_LE_DEVICE_CLICKED
+ BluetoothTileDialogUiEvent.LAUNCH_SETTINGS_NOT_SHARING_ACTIVE_LE_DEVICE_CLICKED
}
private companion object {
@@ -290,10 +296,8 @@
val DeviceItem.isNotConnectedLeAudioSupported: Boolean
get() = type == DeviceItemType.SAVED_BLUETOOTH_DEVICE && isLeAudioSupported
- val DeviceItem.isActiveOrConnectedLeAudioSupported: Boolean
- get() =
- (type == DeviceItemType.ACTIVE_MEDIA_BLUETOOTH_DEVICE ||
- type == DeviceItemType.AVAILABLE_MEDIA_BLUETOOTH_DEVICE) && isLeAudioSupported
+ val DeviceItem.isActiveLeAudioSupported: Boolean
+ get() = type == DeviceItemType.ACTIVE_MEDIA_BLUETOOTH_DEVICE && isLeAudioSupported
val DeviceItem.isMediaDevice: Boolean
get() =
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactory.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactory.kt
index e846bf7..7280489 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactory.kt
@@ -125,6 +125,37 @@
}
}
+internal class AvailableAudioSharingMediaDeviceItemFactory(
+ private val localBluetoothManager: LocalBluetoothManager?
+) : AvailableMediaDeviceItemFactory() {
+ override fun isFilterMatched(
+ context: Context,
+ cachedDevice: CachedBluetoothDevice,
+ audioManager: AudioManager
+ ): Boolean {
+ return BluetoothUtils.isAudioSharingEnabled() &&
+ super.isFilterMatched(context, cachedDevice, audioManager) &&
+ BluetoothUtils.isAvailableAudioSharingMediaBluetoothDevice(
+ cachedDevice,
+ localBluetoothManager
+ )
+ }
+
+ override fun create(context: Context, cachedDevice: CachedBluetoothDevice): DeviceItem {
+ return createDeviceItem(
+ context,
+ cachedDevice,
+ DeviceItemType.AVAILABLE_AUDIO_SHARING_MEDIA_BLUETOOTH_DEVICE,
+ context.getString(
+ R.string.quick_settings_bluetooth_device_audio_sharing_or_switch_active
+ ),
+ if (cachedDevice.isBusy) backgroundOffBusy else backgroundOff,
+ "",
+ isActive = false
+ )
+ }
+}
+
internal class ActiveHearingDeviceItemFactory : ActiveMediaDeviceItemFactory() {
override fun isFilterMatched(
context: Context,
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractor.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractor.kt
index 9524496..9114eca 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractor.kt
@@ -118,6 +118,7 @@
listOf(
ActiveMediaDeviceItemFactory(),
AudioSharingMediaDeviceItemFactory(localBluetoothManager),
+ AvailableAudioSharingMediaDeviceItemFactory(localBluetoothManager),
AvailableMediaDeviceItemFactory(),
ConnectedDeviceItemFactory(),
SavedDeviceItemFactory()
@@ -127,6 +128,7 @@
listOf(
DeviceItemType.ACTIVE_MEDIA_BLUETOOTH_DEVICE,
DeviceItemType.AUDIO_SHARING_MEDIA_BLUETOOTH_DEVICE,
+ DeviceItemType.AVAILABLE_AUDIO_SHARING_MEDIA_BLUETOOTH_DEVICE,
DeviceItemType.AVAILABLE_MEDIA_BLUETOOTH_DEVICE,
DeviceItemType.CONNECTED_BLUETOOTH_DEVICE,
DeviceItemType.SAVED_BLUETOOTH_DEVICE,
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalDreamStartable.kt b/packages/SystemUI/src/com/android/systemui/communal/CommunalDreamStartable.kt
index 0582cc2..c69cea4 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/CommunalDreamStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalDreamStartable.kt
@@ -32,11 +32,14 @@
import com.android.systemui.keyguard.shared.model.filterState
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf
+import com.android.systemui.util.kotlin.BooleanFlowOperators.not
import com.android.systemui.util.kotlin.Utils.Companion.sampleFilter
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
/**
@@ -54,6 +57,18 @@
private val dreamManager: DreamManager,
@Background private val bgScope: CoroutineScope,
) : CoreStartable {
+ /** Flow that emits when the dream should be started underneath the glanceable hub. */
+ val startDream =
+ allOf(
+ keyguardTransitionInteractor
+ .transitionValue(Scenes.Communal, KeyguardState.GLANCEABLE_HUB)
+ .map { it == 1f },
+ not(keyguardInteractor.isDreaming),
+ // TODO(b/362830856): Remove this workaround.
+ keyguardInteractor.isKeyguardShowing,
+ )
+ .filter { it }
+
@SuppressLint("MissingPermission")
override fun start() {
if (!communalSettingsInteractor.isCommunalFlagEnabled()) {
@@ -72,17 +87,10 @@
// Restart the dream underneath the hub in order to support the ability to swipe
// away the hub to enter the dream.
- keyguardTransitionInteractor
- .transition(
- edge = Edge.create(to = Scenes.Communal),
- edgeWithoutSceneContainer = Edge.create(to = KeyguardState.GLANCEABLE_HUB)
- )
- .filterState(TransitionState.FINISHED)
+ startDream
.sampleFilter(powerInteractor.isAwake) { isAwake ->
- dreamManager.canStartDreaming(isAwake)
+ !glanceableHubAllowKeyguardWhenDreaming() && dreamManager.canStartDreaming(isAwake)
}
- .sampleFilter(keyguardInteractor.isDreaming) { isDreaming -> !isDreaming }
- .filter { !glanceableHubAllowKeyguardWhenDreaming() }
.onEach { dreamManager.startDream() }
.launchIn(bgScope)
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
index 98abbeb..9b96341 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
@@ -510,7 +510,7 @@
* A flow of ongoing content, including smartspace timers and umo, ordered by creation time and
* sized dynamically.
*/
- fun getOngoingContent(mediaHostVisible: Boolean): Flow<List<CommunalContentModel.Ongoing>> =
+ val ongoingContent: Flow<List<CommunalContentModel.Ongoing>> =
combine(smartspaceRepository.timers, mediaRepository.mediaModel) { timers, media ->
val ongoingContent = mutableListOf<CommunalContentModel.Ongoing>()
@@ -526,7 +526,7 @@
)
// Add UMO
- if (mediaHostVisible && media.hasAnyMediaOrRecommendation) {
+ if (media.hasAnyMediaOrRecommendation) {
ongoingContent.add(
CommunalContentModel.Umo(
createdTimestampMillis = media.createdTimestampMillis,
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneTransitionInteractor.kt
index 5bbb46d..e04d309 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneTransitionInteractor.kt
@@ -182,6 +182,7 @@
}
private suspend fun finishCurrentTransition() {
+ if (currentTransitionId == null) return
internalTransitionInteractor.updateTransition(
currentTransitionId!!,
1f,
@@ -224,7 +225,7 @@
collectProgress(transition)
} else if (transition.toScene == CommunalScenes.Communal) {
if (currentToState == KeyguardState.GLANCEABLE_HUB) {
- transitionKtfTo(transitionInteractor.getStartedFromState())
+ transitionKtfTo(transitionInteractor.startedKeyguardTransitionStep.value.from)
}
startTransitionToGlanceableHub()
collectProgress(transition)
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
index 32a8b35..d69ba1b 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
@@ -99,7 +99,7 @@
private val logger = Logger(logBuffer, "CommunalViewModel")
- private val _isMediaHostVisible =
+ private val isMediaHostVisible =
conflatedCallbackFlow {
val callback = { visible: Boolean ->
trySend(visible)
@@ -117,12 +117,26 @@
mediaHost.updateViewVisibility()
emit(mediaHost.visible)
}
+ .distinctUntilChanged()
.onEach { logger.d({ "_isMediaHostVisible: $bool1" }) { bool1 = it } }
.flowOn(mainDispatcher)
/** Communal content saved from the previous emission when the flow is active (not "frozen"). */
private var frozenCommunalContent: List<CommunalContentModel>? = null
+ private val ongoingContent =
+ combine(
+ isMediaHostVisible,
+ communalInteractor.ongoingContent.onEach { mediaHost.updateViewVisibility() }
+ ) { mediaVisible, ongoingContent ->
+ if (mediaVisible) {
+ ongoingContent
+ } else {
+ // Media is not visible, don't show UMO
+ ongoingContent.filterNot { it is CommunalContentModel.Umo }
+ }
+ }
+
@OptIn(ExperimentalCoroutinesApi::class)
private val latestCommunalContent: Flow<List<CommunalContentModel>> =
tutorialInteractor.isTutorialAvailable
@@ -130,8 +144,6 @@
if (isTutorialMode) {
return@flatMapLatest flowOf(communalInteractor.tutorialContent)
}
- val ongoingContent =
- _isMediaHostVisible.flatMapLatest { communalInteractor.getOngoingContent(it) }
combine(
ongoingContent,
communalInteractor.widgetContent,
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
index caf5b01..e3f740e 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
@@ -24,12 +24,11 @@
import static com.android.systemui.dreams.dagger.DreamModule.HOME_CONTROL_PANEL_DREAM_COMPONENT;
import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
+import android.app.WindowConfiguration;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.ActivityInfo;
import android.graphics.drawable.ColorDrawable;
-import android.service.dreams.DreamActivity;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
@@ -65,6 +64,7 @@
import com.android.systemui.dreams.dagger.DreamOverlayComponent;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.navigationbar.gestural.domain.GestureInteractor;
+import com.android.systemui.navigationbar.gestural.domain.TaskMatcher;
import com.android.systemui.shade.ShadeExpansionChangeEvent;
import com.android.systemui.touch.TouchInsetManager;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -89,6 +89,8 @@
LifecycleOwner {
private static final String TAG = "DreamOverlayService";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ private static final TaskMatcher DREAM_TYPE_MATCHER =
+ new TaskMatcher.TopActivityType(WindowConfiguration.ACTIVITY_TYPE_DREAM);
// The Context is used to construct the hosting constraint layout and child overlay views.
private final Context mContext;
@@ -141,10 +143,6 @@
private final TouchInsetManager mTouchInsetManager;
private final LifecycleOwner mLifecycleOwner;
-
-
- private ComponentName mCurrentBlockedGestureDreamActivityComponent;
-
private final ArrayList<Job> mFlows = new ArrayList<>();
/**
@@ -221,16 +219,122 @@
}
};
- private final DreamOverlayStateController.Callback mExitAnimationFinishedCallback =
- new DreamOverlayStateController.Callback() {
- @Override
- public void onStateChanged() {
- if (!mStateController.areExitAnimationsRunning()) {
- mStateController.removeCallback(mExitAnimationFinishedCallback);
- resetCurrentDreamOverlayLocked();
+ /**
+ * {@link ResetHandler} protects resetting {@link DreamOverlayService} by making sure reset
+ * requests are processed before subsequent actions proceed. Requests themselves are also
+ * ordered between each other as well to ensure actions are correctly sequenced.
+ */
+ private final class ResetHandler {
+ @FunctionalInterface
+ interface Callback {
+ void onComplete();
+ }
+
+ private record Info(Callback callback, String source) {}
+
+ private final ArrayList<Info> mPendingCallbacks = new ArrayList<>();
+
+ DreamOverlayStateController.Callback mStateCallback =
+ new DreamOverlayStateController.Callback() {
+ @Override
+ public void onStateChanged() {
+ process(true);
}
+ };
+
+ /**
+ * Called from places where there is no need to wait for the reset to complete. This still
+ * will defer the reset until it is okay to reset and also sequences the request with
+ * others.
+ */
+ public void reset(String source) {
+ reset(()-> {}, source);
+ }
+
+ /**
+ * Invoked to request a reset with a callback that will fire after reset if it is deferred.
+ *
+ * @return {@code true} if the reset happened immediately, {@code false} if it was deferred
+ * and will fire later, invoking the callback.
+ */
+ public boolean reset(Callback callback, String source) {
+ // Always add listener pre-emptively
+ if (mPendingCallbacks.isEmpty()) {
+ mStateController.addCallback(mStateCallback);
+ }
+
+ final Info info = new Info(callback, source);
+ mPendingCallbacks.add(info);
+ process(false);
+
+ boolean processed = !mPendingCallbacks.contains(info);
+
+ if (!processed) {
+ Log.d(TAG, "delayed resetting from: " + source);
+ }
+
+ return processed;
+ }
+
+ private void resetInternal() {
+ // This ensures the container view of the current dream is removed before
+ // the controller is potentially reset.
+ removeContainerViewFromParentLocked();
+
+ if (mStarted && mWindow != null) {
+ try {
+ mWindow.clearContentView();
+ mWindowManager.removeView(mWindow.getDecorView());
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Error removing decor view when resetting overlay", e);
}
- };
+ }
+
+ mStateController.setOverlayActive(false);
+ mStateController.setLowLightActive(false);
+ mStateController.setEntryAnimationsFinished(false);
+
+ if (mDreamOverlayContainerViewController != null) {
+ mDreamOverlayContainerViewController.destroy();
+ mDreamOverlayContainerViewController = null;
+ }
+
+ if (mTouchMonitor != null) {
+ mTouchMonitor.destroy();
+ mTouchMonitor = null;
+ }
+
+ mWindow = null;
+
+ // Always unregister the any set DreamActivity from being blocked from gestures.
+ mGestureInteractor.removeGestureBlockedMatcher(DREAM_TYPE_MATCHER,
+ GestureInteractor.Scope.Global);
+
+ mStarted = false;
+ }
+
+ private boolean canReset() {
+ return !mStateController.areExitAnimationsRunning();
+ }
+
+ private void process(boolean fromDelayedCallback) {
+ while (canReset() && !mPendingCallbacks.isEmpty()) {
+ final Info callbackInfo = mPendingCallbacks.removeFirst();
+ resetInternal();
+ callbackInfo.callback.onComplete();
+
+ if (fromDelayedCallback) {
+ Log.d(TAG, "reset overlay (delayed) for " + callbackInfo.source);
+ }
+ }
+
+ if (mPendingCallbacks.isEmpty()) {
+ mStateController.removeCallback(mStateCallback);
+ }
+ }
+ }
+
+ private final ResetHandler mResetHandler = new ResetHandler();
private final DreamOverlayStateController mStateController;
@@ -344,10 +448,8 @@
mExecutor.execute(() -> {
setLifecycleStateLocked(Lifecycle.State.DESTROYED);
-
- resetCurrentDreamOverlayLocked();
-
mDestroyed = true;
+ mResetHandler.reset("destroying");
});
mDispatcher.onServicePreSuperOnDestroy();
@@ -387,7 +489,10 @@
// Reset the current dream overlay before starting a new one. This can happen
// when two dreams overlap (briefly, for a smoother dream transition) and both
// dreams are bound to the dream overlay service.
- resetCurrentDreamOverlayLocked();
+ if (!mResetHandler.reset(() -> onStartDream(layoutParams),
+ "starting with dream already started")) {
+ return;
+ }
}
mDreamOverlayContainerViewController =
@@ -399,7 +504,7 @@
// If we are not able to add the overlay window, reset the overlay.
if (!addOverlayWindowLocked(layoutParams)) {
- resetCurrentDreamOverlayLocked();
+ mResetHandler.reset("couldn't add window while starting");
return;
}
@@ -420,7 +525,11 @@
mStarted = true;
updateRedirectWakeup();
- updateBlockedGestureDreamActivityComponent();
+
+ if (!isDreamInPreviewMode()) {
+ mGestureInteractor.addGestureBlockedMatcher(DREAM_TYPE_MATCHER,
+ GestureInteractor.Scope.Global);
+ }
}
private void updateRedirectWakeup() {
@@ -431,21 +540,9 @@
redirectWake(mCommunalAvailable && !glanceableHubAllowKeyguardWhenDreaming());
}
- private void updateBlockedGestureDreamActivityComponent() {
- // TODO(b/343815446): We should not be crafting this ActivityInfo ourselves. It should be
- // in a common place, Such as DreamActivity itself.
- final ActivityInfo info = new ActivityInfo();
- info.name = DreamActivity.class.getName();
- info.packageName = getDreamComponent().getPackageName();
- mCurrentBlockedGestureDreamActivityComponent = info.getComponentName();
-
- mGestureInteractor.addGestureBlockedActivity(mCurrentBlockedGestureDreamActivityComponent,
- GestureInteractor.Scope.Global);
- }
-
@Override
public void onEndDream() {
- resetCurrentDreamOverlayLocked();
+ mResetHandler.reset("ending dream");
}
@Override
@@ -576,49 +673,4 @@
Log.w(TAG, "Removing dream overlay container view parent!");
parentView.removeView(containerView);
}
-
- private void resetCurrentDreamOverlayLocked() {
- if (mStateController.areExitAnimationsRunning()) {
- mStateController.addCallback(mExitAnimationFinishedCallback);
- return;
- }
-
- // This ensures the container view of the current dream is removed before
- // the controller is potentially reset.
- removeContainerViewFromParentLocked();
-
- if (mStarted && mWindow != null) {
- try {
- mWindow.clearContentView();
- mWindowManager.removeView(mWindow.getDecorView());
- } catch (IllegalArgumentException e) {
- Log.e(TAG, "Error removing decor view when resetting overlay", e);
- }
- }
-
- mStateController.setOverlayActive(false);
- mStateController.setLowLightActive(false);
- mStateController.setEntryAnimationsFinished(false);
-
- if (mDreamOverlayContainerViewController != null) {
- mDreamOverlayContainerViewController.destroy();
- mDreamOverlayContainerViewController = null;
- }
-
- if (mTouchMonitor != null) {
- mTouchMonitor.destroy();
- mTouchMonitor = null;
- }
-
- mWindow = null;
-
- // Always unregister the any set DreamActivity from being blocked from gestures.
- if (mCurrentBlockedGestureDreamActivityComponent != null) {
- mGestureInteractor.removeGestureBlockedActivity(
- mCurrentBlockedGestureDreamActivityComponent, GestureInteractor.Scope.Global);
- mCurrentBlockedGestureDreamActivityComponent = null;
- }
-
- mStarted = false;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt b/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
index cd0b3f9..6318dc0 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
@@ -41,7 +41,6 @@
import com.android.systemui.statusbar.notification.shared.NotificationAvalancheSuppression
import com.android.systemui.statusbar.notification.shared.NotificationMinimalismPrototype
import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun
-import com.android.systemui.statusbar.notification.shared.NotificationsHeadsUpRefactor
import com.android.systemui.statusbar.notification.shared.PriorityPeopleSection
import javax.inject.Inject
@@ -59,7 +58,6 @@
NotificationAvalancheSuppression.token dependsOn VisualInterruptionRefactor.token
PriorityPeopleSection.token dependsOn SortBySectionTimeFlag.token
NotificationMinimalismPrototype.token dependsOn NotificationThrottleHun.token
- NotificationsHeadsUpRefactor.token dependsOn NotificationThrottleHun.token
// SceneContainer dependencies
SceneContainerFlag.getFlagDependencies().forEach { (alpha, beta) -> alpha dependsOn beta }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
index 6e04133..4cf9ec8 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
@@ -89,7 +89,7 @@
.filterRelevantKeyguardStateAnd { wakefulness -> wakefulness.isAwake() }
.debounce(50L)
.sample(
- startedKeyguardTransitionStep,
+ transitionInteractor.startedKeyguardTransitionStep,
wakeToGoneInteractor.canWakeDirectlyToGone,
)
.collect {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
index 4666430..2434b29 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
@@ -117,7 +117,7 @@
if (SceneContainerFlag.isEnabled) return
scope.launch {
keyguardInteractor.primaryBouncerShowing
- .sample(startedKeyguardTransitionStep, ::Pair)
+ .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
.collect { pair ->
val (isBouncerShowing, lastStartedTransitionStep) = pair
if (
@@ -132,7 +132,7 @@
fun startToLockscreenOrGlanceableHubTransition(openHub: Boolean) {
scope.launch {
if (
- transitionInteractor.startedKeyguardState.replayCache.last() ==
+ transitionInteractor.startedKeyguardTransitionStep.value.to ==
KeyguardState.DREAMING
) {
if (powerInteractor.detailedWakefulness.value.isAwake()) {
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 fc70ea5..228e01e 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
@@ -134,16 +134,12 @@
.filterRelevantKeyguardState()
.sampleCombine(
internalTransitionInteractor.currentTransitionInfoInternal,
- finishedKeyguardState,
+ transitionInteractor.isFinishedIn(KeyguardState.LOCKSCREEN),
keyguardInteractor.isActiveDreamLockscreenHosted,
)
.collect {
- (
- isAbleToDream,
- transitionInfo,
- finishedKeyguardState,
- isActiveDreamLockscreenHosted) ->
- val isOnLockscreen = finishedKeyguardState == KeyguardState.LOCKSCREEN
+ (isAbleToDream, transitionInfo, isOnLockscreen, isActiveDreamLockscreenHosted)
+ ->
val isTransitionInterruptible =
transitionInfo.to == KeyguardState.LOCKSCREEN &&
!invalidFromStates.contains(transitionInfo.from)
@@ -189,7 +185,7 @@
scope.launch("$TAG#listenForLockscreenToPrimaryBouncerDragging") {
shadeRepository.legacyShadeExpansion
.sampleCombine(
- startedKeyguardTransitionStep,
+ transitionInteractor.startedKeyguardTransitionStep,
internalTransitionInteractor.currentTransitionInfoInternal,
keyguardInteractor.statusBarState,
keyguardInteractor.isKeyguardDismissible,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitions.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitions.kt
index f9ab1bb..bde0f56 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitions.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitions.kt
@@ -62,16 +62,16 @@
communalInteractor
.transitionProgressToScene(toScene)
.sample(
- transitionInteractor.startedKeyguardState,
+ transitionInteractor.startedKeyguardTransitionStep,
::Pair,
)
- .collect { (transitionProgress, lastStartedState) ->
+ .collect { (transitionProgress, lastStartedStep) ->
val id = transitionId
if (id == null) {
// No transition started.
if (
transitionProgress is CommunalTransitionProgressModel.Transition &&
- lastStartedState == fromState
+ lastStartedStep.to == fromState
) {
transitionId =
transitionRepository.startTransition(
@@ -84,7 +84,7 @@
)
}
} else {
- if (lastStartedState != toState) {
+ if (lastStartedStep.to != toState) {
return@collect
}
// An existing `id` means a transition is started, and calls to
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTouchHandlingInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTouchHandlingInteractor.kt
index 4a8ada7..505c749d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTouchHandlingInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTouchHandlingInteractor.kt
@@ -48,7 +48,6 @@
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
@@ -74,9 +73,7 @@
val isLongPressHandlingEnabled: StateFlow<Boolean> =
if (isFeatureEnabled()) {
combine(
- transitionInteractor.finishedKeyguardState.map {
- it == KeyguardState.LOCKSCREEN
- },
+ transitionInteractor.isFinishedIn(KeyguardState.LOCKSCREEN),
repository.isQuickSettingsVisible,
) { isFullyTransitionedToLockScreen, isQuickSettingsVisible ->
isFullyTransitionedToLockScreen && !isQuickSettingsVisible
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
index c10bacf..92e2a91 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
@@ -49,7 +49,6 @@
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.buffer
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
@@ -58,7 +57,6 @@
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.flow.stateIn
-import kotlinx.coroutines.flow.transform
import kotlinx.coroutines.launch
/** Encapsulates business-logic related to the keyguard transitions. */
@@ -286,67 +284,10 @@
}
/** The last [TransitionStep] with a [TransitionState] of STARTED */
- val startedKeyguardTransitionStep: Flow<TransitionStep> =
- repository.transitions.filter { step -> step.transitionState == TransitionState.STARTED }
-
- /** The destination state of the last [TransitionState.STARTED] transition. */
- @SuppressLint("SharedFlowCreation")
- val startedKeyguardState: SharedFlow<KeyguardState> =
- startedKeyguardTransitionStep
- .map { step -> step.to }
- .buffer(2, BufferOverflow.DROP_OLDEST)
- .shareIn(scope, SharingStarted.Eagerly, replay = 1)
-
- /** The from state of the last [TransitionState.STARTED] transition. */
- // TODO: is it performant to have several SharedFlows side by side instead of one?
- @SuppressLint("SharedFlowCreation")
- val startedKeyguardFromState: SharedFlow<KeyguardState> =
- startedKeyguardTransitionStep
- .map { step -> step.from }
- .buffer(2, BufferOverflow.DROP_OLDEST)
- .shareIn(scope, SharingStarted.Eagerly, replay = 1)
-
- /**
- * The last [KeyguardState] to which we [TransitionState.FINISHED] a transition.
- *
- * WARNING: This will NOT emit a value if a transition is CANCELED, and will also not emit a
- * value when a subsequent transition is STARTED. It will *only* emit once we have finally
- * FINISHED in a state. This can have unintuitive implications.
- *
- * For example, if we're transitioning from GONE -> DOZING, and that transition is CANCELED in
- * favor of a DOZING -> LOCKSCREEN transition, the FINISHED state is still GONE, and will remain
- * GONE throughout the DOZING -> LOCKSCREEN transition until the DOZING -> LOCKSCREEN transition
- * finishes (at which point we'll be FINISHED in LOCKSCREEN).
- *
- * Since there's no real limit to how many consecutive transitions can be canceled, it's even
- * possible for the FINISHED state to be the same as the STARTED state while still
- * transitioning.
- *
- * For example:
- * 1. We're finished in GONE.
- * 2. The user presses the power button, starting a GONE -> DOZING transition. We're still
- * FINISHED in GONE.
- * 3. The user changes their mind, pressing the power button to wake up; this starts a DOZING ->
- * LOCKSCREEN transition. We're still FINISHED in GONE.
- * 4. The user quickly swipes away the lockscreen prior to DOZING -> LOCKSCREEN finishing; this
- * starts a LOCKSCREEN -> GONE transition. We're still FINISHED in GONE, but we've also
- * STARTED a transition *to* GONE.
- * 5. We'll emit KeyguardState.GONE again once the transition finishes.
- *
- * If you just need to know when we eventually settle into a state, this flow is likely
- * sufficient. However, if you're having issues with state *during* transitions started after
- * one or more canceled transitions, you probably need to use [currentKeyguardState].
- */
- @SuppressLint("SharedFlowCreation")
- val finishedKeyguardState: SharedFlow<KeyguardState> =
+ val startedKeyguardTransitionStep: StateFlow<TransitionStep> =
repository.transitions
- .transform { step ->
- if (step.transitionState == TransitionState.FINISHED) {
- emit(step.to)
- }
- }
- .buffer(2, BufferOverflow.DROP_OLDEST)
- .shareIn(scope, SharingStarted.Eagerly, replay = 1)
+ .filter { step -> step.transitionState == TransitionState.STARTED }
+ .stateIn(scope, SharingStarted.Eagerly, TransitionStep())
/**
* The [KeyguardState] we're currently in.
@@ -412,7 +353,6 @@
it.from
}
}
- .distinctUntilChanged()
.stateIn(scope, SharingStarted.Eagerly, OFF)
val isInTransition =
@@ -509,12 +449,13 @@
fun isFinishedIn(scene: SceneKey, stateWithoutSceneContainer: KeyguardState): Flow<Boolean> {
return if (SceneContainerFlag.isEnabled) {
- sceneInteractor.transitionState
- .map { it.isIdle(scene) || it.isTransitioning(from = scene) }
- .distinctUntilChanged()
- } else {
- isFinishedIn(stateWithoutSceneContainer)
- }
+ sceneInteractor.transitionState.map {
+ it.isIdle(scene) || it.isTransitioning(from = scene)
+ }
+ } else {
+ isFinishedIn(stateWithoutSceneContainer)
+ }
+ .distinctUntilChanged()
}
/** Whether we've FINISHED a transition to a state */
@@ -527,13 +468,11 @@
return currentKeyguardState.replayCache.last()
}
- fun getStartedFromState(): KeyguardState {
- return startedKeyguardFromState.replayCache.last()
- }
-
- fun getFinishedState(): KeyguardState {
- return finishedKeyguardState.replayCache.last()
- }
+ private val finishedKeyguardState: StateFlow<KeyguardState> =
+ repository.transitions
+ .filter { it.transitionState == TransitionState.FINISHED }
+ .map { it.to }
+ .stateIn(scope, SharingStarted.Eagerly, OFF)
companion object {
private val TAG = KeyguardTransitionInteractor::class.simpleName
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StatusBarDisableFlagsInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StatusBarDisableFlagsInteractor.kt
index 47818cb..e00e33d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StatusBarDisableFlagsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StatusBarDisableFlagsInteractor.kt
@@ -45,6 +45,7 @@
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@@ -76,7 +77,7 @@
private val disableFlagsForUserId =
combine(
selectedUserInteractor.selectedUser,
- keyguardTransitionInteractor.startedKeyguardState,
+ keyguardTransitionInteractor.startedKeyguardTransitionStep.map { it.to },
deviceConfigInteractor.property(
namespace = DeviceConfig.NAMESPACE_SYSTEMUI,
name = SystemUiDeviceConfigFlags.NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SwipeToDismissInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SwipeToDismissInteractor.kt
index 906d586..e404f27 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SwipeToDismissInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SwipeToDismissInteractor.kt
@@ -22,12 +22,12 @@
import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.shade.data.repository.ShadeRepository
import com.android.systemui.util.kotlin.Utils.Companion.sample
+import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
-import javax.inject.Inject
/**
* Handles logic around the swipe to dismiss gesture, where the user swipes up on the dismissable
@@ -53,15 +53,15 @@
val dismissFling =
shadeRepository.currentFling
.sample(
- transitionInteractor.startedKeyguardState,
+ transitionInteractor.startedKeyguardTransitionStep,
keyguardInteractor.isKeyguardDismissible,
keyguardInteractor.statusBarState,
)
- .filter { (flingInfo, startedState, keyguardDismissable, statusBarState) ->
+ .filter { (flingInfo, startedStep, keyguardDismissable, statusBarState) ->
flingInfo != null &&
- !flingInfo.expand &&
- statusBarState != StatusBarState.SHADE_LOCKED &&
- startedState == KeyguardState.LOCKSCREEN &&
+ !flingInfo.expand &&
+ statusBarState != StatusBarState.SHADE_LOCKED &&
+ startedStep.to == KeyguardState.LOCKSCREEN &&
keyguardDismissable
}
.map { (flingInfo, _) -> flingInfo }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt
index 950eafa..ba12e93 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt
@@ -32,7 +32,6 @@
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filter
-import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
@@ -62,17 +61,6 @@
abstract fun start()
- /* Use background dispatcher for all [KeyguardTransitionInteractor] flows. Necessary because
- * the [sample] utility internally runs a collect on the Unconfined dispatcher, resulting
- * in continuations on the main thread. We don't want that for classes that inherit from this.
- */
- val startedKeyguardTransitionStep =
- transitionInteractor.startedKeyguardTransitionStep.flowOn(bgDispatcher)
- // The following are MutableSharedFlows, and do not require flowOn
- val startedKeyguardState = transitionInteractor.startedKeyguardState
- val finishedKeyguardState = transitionInteractor.finishedKeyguardState
- val currentKeyguardState = transitionInteractor.currentKeyguardState
-
suspend fun startTransitionTo(
toState: KeyguardState,
animator: ValueAnimator? = getDefaultAnimatorForTransitionsToState(toState),
@@ -92,17 +80,6 @@
" $fromState. This should never happen - check currentTransitionInfoInternal" +
" or use filterRelevantKeyguardState before starting transitions."
)
-
- if (fromState == transitionInteractor.finishedKeyguardState.replayCache.last()) {
- Log.e(
- name,
- "This transition would not have been ignored prior to ag/26681239, since we " +
- "are FINISHED in $fromState (but have since started another transition). " +
- "If ignoring this transition has caused a regression, fix it by ensuring " +
- "that transitions are exclusively started from the most recently started " +
- "state."
- )
- }
return null
}
@@ -207,7 +184,7 @@
powerInteractor.isAsleep
.filter { isAsleep -> isAsleep }
.filterRelevantKeyguardState()
- .sample(startedKeyguardTransitionStep)
+ .sample(transitionInteractor.startedKeyguardTransitionStep)
.map(modeOnCanceledFromStartedStep)
.collect { modeOnCanceled ->
startTransitionTo(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt
index 25b2b7c..ac87400 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt
@@ -63,10 +63,13 @@
) {
private val defaultSurfaceBehindVisibility =
combine(
- transitionInteractor.finishedKeyguardState,
+ transitionInteractor.isFinishedIn(
+ scene = Scenes.Gone,
+ stateWithoutSceneContainer = KeyguardState.GONE
+ ),
wakeToGoneInteractor.canWakeDirectlyToGone,
- ) { finishedState, canWakeDirectlyToGone ->
- isSurfaceVisible(finishedState) || canWakeDirectlyToGone
+ ) { isOnGone, canWakeDirectlyToGone ->
+ isOnGone || canWakeDirectlyToGone
}
/**
@@ -196,18 +199,20 @@
edge = Edge.create(to = Scenes.Gone),
edgeWithoutSceneContainer = Edge.create(to = KeyguardState.GONE)
),
- transitionInteractor.finishedKeyguardState,
+ transitionInteractor.isFinishedIn(
+ scene = Scenes.Gone,
+ stateWithoutSceneContainer = KeyguardState.GONE
+ ),
surfaceBehindInteractor.isAnimatingSurface,
notificationLaunchAnimationInteractor.isLaunchAnimationRunning,
- ) { isInTransitionToGone, finishedState, isAnimatingSurface, notifLaunchRunning ->
+ ) { isInTransitionToGone, isOnGone, isAnimatingSurface, notifLaunchRunning ->
// Using the animation if we're animating it directly, or if the
// ActivityLaunchAnimator is in the process of animating it.
val animationsRunning = isAnimatingSurface || notifLaunchRunning
// We may still be animating the surface after the keyguard is fully GONE, since
// some animations (like the translation spring) are not tied directly to the
// transition step amount.
- isInTransitionToGone ||
- (finishedState == KeyguardState.GONE && animationsRunning)
+ isInTransitionToGone || (isOnGone && animationsRunning)
}
.distinctUntilChanged()
}
@@ -248,7 +253,7 @@
// transition. Same for waking directly to gone, due to the lockscreen being
// disabled or because the device was woken back up before the lock timeout
// duration elapsed.
- KeyguardState.lockscreenVisibleInState(KeyguardState.GONE)
+ false
} else if (canWakeDirectlyToGone) {
// Never show the lockscreen if we can wake directly to GONE. This means
// that the lock timeout has not yet elapsed, or the keyguard is disabled.
@@ -274,8 +279,7 @@
// *not* play the going away animation or related animations.
false
} else {
- // Otherwise, use the visibility of the current state.
- KeyguardState.lockscreenVisibleInState(currentState)
+ currentState != KeyguardState.GONE
}
}
.distinctUntilChanged()
@@ -302,10 +306,4 @@
!BiometricUnlockMode.isWakeAndUnlock(biometricUnlockState.mode)
}
.distinctUntilChanged()
-
- companion object {
- fun isSurfaceVisible(state: KeyguardState): Boolean {
- return !KeyguardState.lockscreenVisibleInState(state)
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractor.kt
index b850095..ffd7812 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractor.kt
@@ -116,7 +116,7 @@
} else {
val targetState =
if (idle.currentScene == Scenes.Lockscreen) {
- transitionInteractor.getStartedFromState()
+ transitionInteractor.startedKeyguardTransitionStep.value.from
} else {
UNDEFINED
}
@@ -155,7 +155,7 @@
val currentToState =
internalTransitionInteractor.currentTransitionInfoInternal.value.to
if (currentToState == UNDEFINED) {
- transitionKtfTo(transitionInteractor.getStartedFromState())
+ transitionKtfTo(transitionInteractor.startedKeyguardTransitionStep.value.from)
}
}
startTransitionFromLockscreen()
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt
index 24db3c2..080ddfd 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt
@@ -156,12 +156,6 @@
companion object {
- /** Whether the lockscreen is visible when we're FINISHED in the given state. */
- fun lockscreenVisibleInState(state: KeyguardState): Boolean {
- // TODO(b/349784682): Transform deprecated states for Flexiglass
- return state != GONE
- }
-
/**
* Whether the device is awake ([PowerInteractor.isAwake]) when we're FINISHED in the given
* keyguard state.
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt
index 06b76b3..87c32a5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt
@@ -53,10 +53,10 @@
) {
private val isShowingAodOrDozing: Flow<Boolean> =
combine(
- transitionInteractor.startedKeyguardState,
+ transitionInteractor.startedKeyguardTransitionStep,
transitionInteractor.transitionValue(KeyguardState.DOZING),
- ) { startedKeyguardState, dozingTransitionValue ->
- startedKeyguardState == KeyguardState.AOD || dozingTransitionValue == 1f
+ ) { startedKeyguardStep, dozingTransitionValue ->
+ startedKeyguardStep.to == KeyguardState.AOD || dozingTransitionValue == 1f
}
private fun getColor(usingBackgroundProtection: Boolean): Int {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
index 5ce1b5e..d3bb4f5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
@@ -83,8 +83,8 @@
private val intEvaluator = IntEvaluator()
private val floatEvaluator = FloatEvaluator()
private val showingAlternateBouncer: Flow<Boolean> =
- transitionInteractor.startedKeyguardState.map { keyguardState ->
- keyguardState == KeyguardState.ALTERNATE_BOUNCER
+ transitionInteractor.startedKeyguardTransitionStep.map { keyguardStep ->
+ keyguardStep.to == KeyguardState.ALTERNATE_BOUNCER
}
private val qsProgress: Flow<Float> = shadeInteractor.qsExpansion.onStart { emit(0f) }
private val shadeExpansion: Flow<Float> = shadeInteractor.shadeExpansion.onStart { emit(0f) }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModel.kt
index c885c9a..fe4ebfe 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModel.kt
@@ -85,9 +85,7 @@
private val previewMode = MutableStateFlow(PreviewMode())
private val showingLockscreen: Flow<Boolean> =
- transitionInteractor.finishedKeyguardState.map { keyguardState ->
- keyguardState == KeyguardState.LOCKSCREEN
- }
+ transitionInteractor.isFinishedIn(KeyguardState.LOCKSCREEN)
/** The only time the expansion is important is while lockscreen is actively displayed */
private val shadeExpansionAlpha =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
index a96869d..ebdcaa0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
@@ -132,8 +132,8 @@
val burnInModel = _burnInModel.asStateFlow()
val burnInLayerVisibility: Flow<Int> =
- keyguardTransitionInteractor.startedKeyguardState
- .filter { it == AOD || it == LOCKSCREEN }
+ keyguardTransitionInteractor.startedKeyguardTransitionStep
+ .filter { it.to == AOD || it.to == LOCKSCREEN }
.map { VISIBLE }
val goneToAodTransition =
@@ -333,16 +333,17 @@
.transitionValue(LOCKSCREEN)
.map { it > 0f }
.onStart { emit(false) },
- keyguardTransitionInteractor.finishedKeyguardState.map {
- KeyguardState.lockscreenVisibleInState(it)
- },
+ keyguardTransitionInteractor.isFinishedIn(
+ scene = Scenes.Gone,
+ stateWithoutSceneContainer = GONE
+ ),
deviceEntryInteractor.isBypassEnabled,
areNotifsFullyHiddenAnimated(),
isPulseExpandingAnimated(),
) { flows ->
val goneToAodTransitionRunning = flows[0] as Boolean
val isOnLockscreen = flows[1] as Boolean
- val onKeyguard = flows[2] as Boolean
+ val isOnGone = flows[2] as Boolean
val isBypassEnabled = flows[3] as Boolean
val notifsFullyHidden = flows[4] as AnimatedValue<Boolean>
val pulseExpanding = flows[5] as AnimatedValue<Boolean>
@@ -352,8 +353,7 @@
// animation is playing, in which case we want them to be visible if we're
// animating in the AOD UI and will be switching to KEYGUARD shortly.
goneToAodTransitionRunning ||
- (!onKeyguard &&
- !screenOffAnimationController.shouldShowAodIconsWhenShade()) ->
+ (isOnGone && !screenOffAnimationController.shouldShowAodIconsWhenShade()) ->
AnimatedValue.NotAnimating(false)
else ->
zip(notifsFullyHidden, pulseExpanding) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/ShadeDependentFlows.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/ShadeDependentFlows.kt
index e45d537..708b408 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/ShadeDependentFlows.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/ShadeDependentFlows.kt
@@ -34,7 +34,9 @@
) {
/** When the last keyguard state transition started, was the shade fully expanded? */
private val lastStartedTransitionHadShadeFullyExpanded: Flow<Boolean> =
- transitionInteractor.startedKeyguardState.sample(shadeInteractor.isAnyFullyExpanded)
+ transitionInteractor.startedKeyguardTransitionStep.sample(
+ shadeInteractor.isAnyFullyExpanded
+ )
/**
* Decide which flow to use depending on the shade expansion state at the start of the last
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt
index f5a7966..bf9ef8c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt
@@ -49,7 +49,6 @@
import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.Edge
-import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
import com.android.systemui.keyguard.shared.model.TransitionState
@@ -105,12 +104,14 @@
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
+import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@@ -332,6 +333,11 @@
private val controllerById = mutableMapOf<String, MediaViewController>()
private val commonViewModels = mutableListOf<MediaCommonViewModel>()
+ private val isOnGone =
+ keyguardTransitionInteractor
+ .isFinishedIn(Scenes.Gone, GONE)
+ .stateIn(applicationScope, SharingStarted.Eagerly, true)
+
init {
dumpManager.registerDumpable(TAG, this)
mediaFrame = inflateMediaCarousel()
@@ -913,9 +919,7 @@
if (SceneContainerFlag.isEnabled) {
!deviceEntryInteractor.isDeviceEntered.value
} else {
- KeyguardState.lockscreenVisibleInState(
- keyguardTransitionInteractor.getFinishedState()
- )
+ !isOnGone.value
}
return !allowMediaPlayerOnLockScreen && isOnLockscreen
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index 0f82e02..6bd880d 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -78,6 +78,7 @@
import com.android.systemui.model.SysUiState;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.navigationbar.gestural.domain.GestureInteractor;
+import com.android.systemui.navigationbar.gestural.domain.TaskMatcher;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.NavigationEdgeBackPlugin;
import com.android.systemui.plugins.PluginListener;
@@ -474,9 +475,14 @@
} else {
String[] gestureBlockingActivities = resources.getStringArray(resId);
for (String gestureBlockingActivity : gestureBlockingActivities) {
- mGestureInteractor.addGestureBlockedActivity(
- ComponentName.unflattenFromString(gestureBlockingActivity),
- GestureInteractor.Scope.Local);
+ final ComponentName component =
+ ComponentName.unflattenFromString(gestureBlockingActivity);
+
+ if (component != null) {
+ mGestureInteractor.addGestureBlockedMatcher(
+ new TaskMatcher.TopActivityComponent(component),
+ GestureInteractor.Scope.Local);
+ }
}
}
} catch (NameNotFoundException e) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/data/respository/GestureRepository.kt b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/data/respository/GestureRepository.kt
index 8f35343..c1f238a 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/data/respository/GestureRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/data/respository/GestureRepository.kt
@@ -16,10 +16,9 @@
package com.android.systemui.navigationbar.gestural.data.respository
-import android.content.ComponentName
-import android.util.ArraySet
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.navigationbar.gestural.domain.TaskMatcher
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.MutableStateFlow
@@ -28,36 +27,43 @@
/** A repository for storing gesture related information */
interface GestureRepository {
- /** A {@link StateFlow} tracking activities currently blocked from gestures. */
- val gestureBlockedActivities: StateFlow<Set<ComponentName>>
+ /** A {@link StateFlow} tracking matchers that can block gestures. */
+ val gestureBlockedMatchers: StateFlow<Set<TaskMatcher>>
- /** Adds an activity to be blocked from gestures. */
- suspend fun addGestureBlockedActivity(activity: ComponentName)
+ /** Adds a matcher to determine whether a gesture should be blocked. */
+ suspend fun addGestureBlockedMatcher(matcher: TaskMatcher)
- /** Removes an activity from being blocked from gestures. */
- suspend fun removeGestureBlockedActivity(activity: ComponentName)
+ /** Removes a matcher from blocking from gestures. */
+ suspend fun removeGestureBlockedMatcher(matcher: TaskMatcher)
}
@SysUISingleton
class GestureRepositoryImpl
@Inject
constructor(@Main private val mainDispatcher: CoroutineDispatcher) : GestureRepository {
- private val _gestureBlockedActivities = MutableStateFlow<Set<ComponentName>>(ArraySet())
+ private val _gestureBlockedMatchers = MutableStateFlow<Set<TaskMatcher>>(emptySet())
- override val gestureBlockedActivities: StateFlow<Set<ComponentName>>
- get() = _gestureBlockedActivities
+ override val gestureBlockedMatchers: StateFlow<Set<TaskMatcher>>
+ get() = _gestureBlockedMatchers
- override suspend fun addGestureBlockedActivity(activity: ComponentName) =
+ override suspend fun addGestureBlockedMatcher(matcher: TaskMatcher) =
withContext(mainDispatcher) {
- _gestureBlockedActivities.emit(
- _gestureBlockedActivities.value.toMutableSet().apply { add(activity) }
- )
+ val existingMatchers = _gestureBlockedMatchers.value
+ if (existingMatchers.contains(matcher)) {
+ return@withContext
+ }
+
+ _gestureBlockedMatchers.value = existingMatchers.toMutableSet().apply { add(matcher) }
}
- override suspend fun removeGestureBlockedActivity(activity: ComponentName) =
+ override suspend fun removeGestureBlockedMatcher(matcher: TaskMatcher) =
withContext(mainDispatcher) {
- _gestureBlockedActivities.emit(
- _gestureBlockedActivities.value.toMutableSet().apply { remove(activity) }
- )
+ val existingMatchers = _gestureBlockedMatchers.value
+ if (!existingMatchers.contains(matcher)) {
+ return@withContext
+ }
+
+ _gestureBlockedMatchers.value =
+ existingMatchers.toMutableSet().apply { remove(matcher) }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/domain/GestureInteractor.kt b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/domain/GestureInteractor.kt
index 6182878..96386e5 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/domain/GestureInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/domain/GestureInteractor.kt
@@ -16,7 +16,6 @@
package com.android.systemui.navigationbar.gestural.domain
-import android.content.ComponentName
import com.android.app.tracing.coroutines.flow.flowOn
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
@@ -25,7 +24,6 @@
import com.android.systemui.shared.system.ActivityManagerWrapper
import com.android.systemui.shared.system.TaskStackChangeListener
import com.android.systemui.shared.system.TaskStackChangeListeners
-import com.android.systemui.util.kotlin.combine
import com.android.systemui.util.kotlin.emitOnStart
import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
import javax.inject.Inject
@@ -60,7 +58,7 @@
Global
}
- private val _localGestureBlockedActivities = MutableStateFlow<Set<ComponentName>>(setOf())
+ private val _localGestureBlockedMatchers = MutableStateFlow<Set<TaskMatcher>>(setOf())
private val _topActivity =
conflatedCallbackFlow {
@@ -79,53 +77,47 @@
.mapLatest { getTopActivity() }
.distinctUntilChanged()
- private suspend fun getTopActivity(): ComponentName? =
+ private suspend fun getTopActivity(): TaskInfo? =
withContext(backgroundCoroutineContext) {
- val runningTask = activityManagerWrapper.runningTask
- runningTask?.topActivity
+ activityManagerWrapper.runningTask?.let { TaskInfo(it.topActivity, it.activityType) }
}
val topActivityBlocked =
combine(
_topActivity,
- gestureRepository.gestureBlockedActivities,
- _localGestureBlockedActivities.asStateFlow()
- ) { activity, global, local ->
- activity != null && (global + local).contains(activity)
+ gestureRepository.gestureBlockedMatchers,
+ _localGestureBlockedMatchers.asStateFlow()
+ ) { runningTask, global, local ->
+ runningTask != null && (global + local).any { it.matches(runningTask) }
}
- /**
- * Adds an {@link Activity} to be blocked based on component when the topmost, focused {@link
- * Activity}.
- */
- fun addGestureBlockedActivity(activity: ComponentName, gestureScope: Scope) {
+ /** Adds an [TaskMatcher] to decide whether gestures should be blocked. */
+ fun addGestureBlockedMatcher(matcher: TaskMatcher, gestureScope: Scope) {
scope.launch {
when (gestureScope) {
Scope.Local -> {
- _localGestureBlockedActivities.emit(
- _localGestureBlockedActivities.value.toMutableSet().apply { add(activity) }
+ _localGestureBlockedMatchers.emit(
+ _localGestureBlockedMatchers.value.toMutableSet().apply { add(matcher) }
)
}
Scope.Global -> {
- gestureRepository.addGestureBlockedActivity(activity)
+ gestureRepository.addGestureBlockedMatcher(matcher)
}
}
}
}
- /** Removes an {@link Activity} from being blocked from gestures. */
- fun removeGestureBlockedActivity(activity: ComponentName, gestureScope: Scope) {
+ /** Removes a gesture from deciding whether gestures should be blocked */
+ fun removeGestureBlockedMatcher(matcher: TaskMatcher, gestureScope: Scope) {
scope.launch {
when (gestureScope) {
Scope.Local -> {
- _localGestureBlockedActivities.emit(
- _localGestureBlockedActivities.value.toMutableSet().apply {
- remove(activity)
- }
+ _localGestureBlockedMatchers.emit(
+ _localGestureBlockedMatchers.value.toMutableSet().apply { remove(matcher) }
)
}
Scope.Global -> {
- gestureRepository.removeGestureBlockedActivity(activity)
+ gestureRepository.removeGestureBlockedMatcher(matcher)
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/domain/TaskMatcher.kt b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/domain/TaskMatcher.kt
new file mode 100644
index 0000000..d62b2c0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/domain/TaskMatcher.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.navigationbar.gestural.domain
+
+import android.content.ComponentName
+
+/**
+ * A simple data class for capturing details around a task. Implements equality to ensure changes
+ * can be identified between emitted values.
+ */
+data class TaskInfo(val topActivity: ComponentName?, val topActivityType: Int) {
+ override fun equals(other: Any?): Boolean {
+ return other is TaskInfo &&
+ other.topActivityType == topActivityType &&
+ other.topActivity == topActivity
+ }
+}
+
+/**
+ * [TaskMatcher] provides a way to identify a task based on particular attributes, such as the top
+ * activity type or component name.
+ */
+sealed interface TaskMatcher {
+ fun matches(info: TaskInfo): Boolean
+
+ class TopActivityType(private val type: Int) : TaskMatcher {
+ override fun matches(info: TaskInfo): Boolean {
+ return info.topActivity != null && info.topActivityType == type
+ }
+ }
+
+ class TopActivityComponent(private val component: ComponentName) : TaskMatcher {
+ override fun matches(info: TaskInfo): Boolean {
+ return component == info.topActivity
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractor.kt
index ea61bd3..04620d6 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractor.kt
@@ -118,7 +118,7 @@
get() =
when (this) {
is ObservableTransitionState.Idle -> currentScene.canBeOccluded
- is ObservableTransitionState.Transition.ChangeCurrentScene ->
+ is ObservableTransitionState.Transition.ChangeScene ->
fromScene.canBeOccluded && toScene.canBeOccluded
is ObservableTransitionState.Transition.ReplaceOverlay,
is ObservableTransitionState.Transition.ShowOrHideOverlay ->
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
index bdb148a..a2142b6 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
@@ -131,7 +131,7 @@
.map { state ->
when (state) {
is ObservableTransitionState.Idle -> null
- is ObservableTransitionState.Transition.ChangeCurrentScene -> state.toScene
+ is ObservableTransitionState.Transition.ChangeScene -> state.toScene
is ObservableTransitionState.Transition.ShowOrHideOverlay,
is ObservableTransitionState.Transition.ReplaceOverlay ->
TODO("b/359173565: Handle overlay transitions")
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/ScrimStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/ScrimStartable.kt
index ec743ba..d1629c7 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/ScrimStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/ScrimStartable.kt
@@ -112,7 +112,7 @@
// It
// happens only when unlocking or when dismissing a dismissible lockscreen.
val isTransitioningAwayFromKeyguard =
- transitionState is ObservableTransitionState.Transition.ChangeCurrentScene &&
+ transitionState is ObservableTransitionState.Transition.ChangeScene &&
transitionState.fromScene.isKeyguard() &&
transitionState.toScene == Scenes.Gone
@@ -120,7 +120,7 @@
val isCurrentSceneShade = currentScene.isShade()
// This is true when moving into one of the shade scenes when a non-shade scene.
val isTransitioningToShade =
- transitionState is ObservableTransitionState.Transition.ChangeCurrentScene &&
+ transitionState is ObservableTransitionState.Transition.ChangeScene &&
!transitionState.fromScene.isShade() &&
transitionState.toScene.isShade()
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlag.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlag.kt
index 6c63c97..751448f 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlag.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlag.kt
@@ -27,7 +27,7 @@
import com.android.systemui.keyguard.KeyguardWmStateRefactor
import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.keyguard.shared.ComposeLockscreen
-import com.android.systemui.statusbar.notification.shared.NotificationsHeadsUpRefactor
+import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun
import com.android.systemui.statusbar.phone.PredictiveBackSysUiFlag
/** Helper for reading or using the scene container flag state. */
@@ -43,7 +43,7 @@
KeyguardBottomAreaRefactor.isEnabled &&
KeyguardWmStateRefactor.isEnabled &&
MigrateClocksToBlueprint.isEnabled &&
- NotificationsHeadsUpRefactor.isEnabled &&
+ NotificationThrottleHun.isEnabled &&
PredictiveBackSysUiFlag.isEnabled &&
DeviceEntryUdfpsRefactor.isEnabled
@@ -59,7 +59,7 @@
KeyguardBottomAreaRefactor.token,
KeyguardWmStateRefactor.token,
MigrateClocksToBlueprint.token,
- NotificationsHeadsUpRefactor.token,
+ NotificationThrottleHun.token,
PredictiveBackSysUiFlag.token,
DeviceEntryUdfpsRefactor.token,
// NOTE: Changes should also be made in isEnabled and @EnableSceneContainer
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index c023b83..31813b2 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -191,12 +191,10 @@
import com.android.systemui.statusbar.notification.ViewGroupFadeHelper;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor;
-import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationInteractor;
import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
-import com.android.systemui.statusbar.notification.shared.NotificationsHeadsUpRefactor;
import com.android.systemui.statusbar.notification.stack.AmbientState;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
@@ -439,7 +437,6 @@
private boolean mExpandingFromHeadsUp;
private boolean mCollapsedOnDown;
private boolean mClosingWithAlphaFadeOut;
- private boolean mHeadsUpVisible;
private boolean mHeadsUpAnimatingAway;
private final FalsingManager mFalsingManager;
private final FalsingCollector mFalsingCollector;
@@ -610,7 +607,6 @@
private final PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel;
private final SharedNotificationContainerInteractor mSharedNotificationContainerInteractor;
private final ActiveNotificationsInteractor mActiveNotificationsInteractor;
- private final HeadsUpNotificationInteractor mHeadsUpNotificationInteractor;
private final KeyguardTransitionInteractor mKeyguardTransitionInteractor;
private final KeyguardInteractor mKeyguardInteractor;
private final PowerInteractor mPowerInteractor;
@@ -776,7 +772,6 @@
ActivityStarter activityStarter,
SharedNotificationContainerInteractor sharedNotificationContainerInteractor,
ActiveNotificationsInteractor activeNotificationsInteractor,
- HeadsUpNotificationInteractor headsUpNotificationInteractor,
ShadeAnimationInteractor shadeAnimationInteractor,
KeyguardViewConfigurator keyguardViewConfigurator,
DeviceEntryFaceAuthInteractor deviceEntryFaceAuthInteractor,
@@ -811,7 +806,6 @@
mKeyguardTransitionInteractor = keyguardTransitionInteractor;
mSharedNotificationContainerInteractor = sharedNotificationContainerInteractor;
mActiveNotificationsInteractor = activeNotificationsInteractor;
- mHeadsUpNotificationInteractor = headsUpNotificationInteractor;
mKeyguardInteractor = keyguardInteractor;
mPowerInteractor = powerInteractor;
mKeyguardViewConfigurator = keyguardViewConfigurator;
@@ -1222,11 +1216,6 @@
}
},
mMainDispatcher);
-
- if (NotificationsHeadsUpRefactor.isEnabled()) {
- collectFlow(mView, mHeadsUpNotificationInteractor.isHeadsUpOrAnimatingAway(),
- setHeadsUpVisible(), mMainDispatcher);
- }
}
@VisibleForTesting
@@ -3077,21 +3066,7 @@
mPanelAlphaEndAction = r;
}
- private Consumer<Boolean> setHeadsUpVisible() {
- return (Boolean isHeadsUpVisible) -> {
- mHeadsUpVisible = isHeadsUpVisible;
-
- if (isHeadsUpVisible) {
- updateNotificationTranslucency();
- }
- updateExpansionAndVisibility();
- updateGestureExclusionRect();
- mKeyguardStatusBarViewController.updateForHeadsUp();
- };
- }
-
private void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
- NotificationsHeadsUpRefactor.assertInLegacyMode();
mHeadsUpAnimatingAway = headsUpAnimatingAway;
mNotificationStackScrollLayoutController.setHeadsUpAnimatingAway(headsUpAnimatingAway);
updateVisibility();
@@ -3107,16 +3082,13 @@
}
private boolean shouldPanelBeVisible() {
- boolean headsUpVisible = NotificationsHeadsUpRefactor.isEnabled() ? mHeadsUpVisible
- : (mHeadsUpAnimatingAway || mHeadsUpPinnedMode);
+ boolean headsUpVisible = mHeadsUpAnimatingAway || mHeadsUpPinnedMode;
return headsUpVisible || isExpanded() || mBouncerShowing;
}
private void setHeadsUpManager(HeadsUpManager headsUpManager) {
mHeadsUpManager = headsUpManager;
- if (!NotificationsHeadsUpRefactor.isEnabled()) {
- mHeadsUpManager.addListener(mOnHeadsUpChangedListener);
- }
+ mHeadsUpManager.addListener(mOnHeadsUpChangedListener);
mHeadsUpTouchHelper = new HeadsUpTouchHelper(
headsUpManager,
mStatusBarService,
@@ -3204,8 +3176,7 @@
}
private boolean isPanelVisibleBecauseOfHeadsUp() {
- boolean headsUpVisible = NotificationsHeadsUpRefactor.isEnabled() ? mHeadsUpVisible
- : (mHeadsUpManager.hasPinnedHeadsUp() || mHeadsUpAnimatingAway);
+ boolean headsUpVisible = mHeadsUpManager.hasPinnedHeadsUp() || mHeadsUpAnimatingAway;
return headsUpVisible && mBarState == StatusBarState.SHADE;
}
@@ -3521,7 +3492,6 @@
ipw.print("mExpandingFromHeadsUp="); ipw.println(mExpandingFromHeadsUp);
ipw.print("mCollapsedOnDown="); ipw.println(mCollapsedOnDown);
ipw.print("mClosingWithAlphaFadeOut="); ipw.println(mClosingWithAlphaFadeOut);
- ipw.print("mHeadsUpVisible="); ipw.println(mHeadsUpVisible);
ipw.print("mHeadsUpAnimatingAway="); ipw.println(mHeadsUpAnimatingAway);
ipw.print("mShowIconsWhenExpanded="); ipw.println(mShowIconsWhenExpanded);
ipw.print("mIndicationBottomPadding="); ipw.println(mIndicationBottomPadding);
@@ -4446,8 +4416,6 @@
private final class ShadeHeadsUpChangedListener implements OnHeadsUpChangedListener {
@Override
public void onHeadsUpPinnedModeChanged(final boolean inPinnedMode) {
- NotificationsHeadsUpRefactor.assertInLegacyMode();
-
if (inPinnedMode) {
mHeadsUpExistenceChangedRunnable.run();
updateNotificationTranslucency();
@@ -4464,8 +4432,6 @@
@Override
public void onHeadsUpPinned(NotificationEntry entry) {
- NotificationsHeadsUpRefactor.assertInLegacyMode();
-
if (!isKeyguardShowing()) {
mNotificationStackScrollLayoutController.generateHeadsUpAnimation(entry, true);
}
@@ -4473,8 +4439,6 @@
@Override
public void onHeadsUpUnPinned(NotificationEntry entry) {
- NotificationsHeadsUpRefactor.assertInLegacyMode();
-
// When we're unpinning the notification via active edge they remain heads-upped,
// we need to make sure that an animation happens in this case, otherwise the
// notification
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImpl.kt
index 7d67121..e276f88 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImpl.kt
@@ -64,7 +64,7 @@
0f
}
)
- is ObservableTransitionState.Transition.ChangeCurrentScene ->
+ is ObservableTransitionState.Transition.ChangeScene ->
when {
state.fromScene == Scenes.Gone ->
if (state.toScene.isExpandable()) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/NotificationShadeWindowModel.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/NotificationShadeWindowModel.kt
index f270e82..9c4bf1f 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/NotificationShadeWindowModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/NotificationShadeWindowModel.kt
@@ -26,6 +26,7 @@
import com.android.systemui.util.kotlin.BooleanFlowOperators.any
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
/** Models UI state for the shade window. */
@SysUISingleton
@@ -42,9 +43,11 @@
val isKeyguardOccluded: Flow<Boolean> =
listOf(
// Finished in state...
- keyguardTransitionInteractor.isFinishedIn(OCCLUDED),
- keyguardTransitionInteractor.isFinishedIn(DREAMING),
- keyguardTransitionInteractor.isFinishedIn(Scenes.Communal, GLANCEABLE_HUB),
+ keyguardTransitionInteractor.transitionValue(OCCLUDED).map { it == 1f },
+ keyguardTransitionInteractor.transitionValue(DREAMING).map { it == 1f },
+ keyguardTransitionInteractor.transitionValue(Scenes.Communal, GLANCEABLE_HUB).map {
+ it == 1f
+ },
// ... or transitions between those states
keyguardTransitionInteractor.isInTransition(Edge.create(OCCLUDED, DREAMING)),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/StatusBarChipsModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/StatusBarChipsModule.kt
index 173ff37..be733d4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/StatusBarChipsModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/StatusBarChipsModule.kt
@@ -16,14 +16,24 @@
package com.android.systemui.statusbar.chips
+import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogBufferFactory
+import com.android.systemui.statusbar.chips.ron.demo.ui.viewmodel.DemoRonChipViewModel
+import dagger.Binds
import dagger.Module
import dagger.Provides
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
@Module
abstract class StatusBarChipsModule {
+ @Binds
+ @IntoMap
+ @ClassKey(DemoRonChipViewModel::class)
+ abstract fun binds(impl: DemoRonChipViewModel): CoreStartable
+
companion object {
@Provides
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt
index 18ea0b4..e825258 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt
@@ -69,7 +69,7 @@
state.notificationIconView
)
} else {
- OngoingActivityChipModel.ChipIcon.Basic(phoneIcon)
+ OngoingActivityChipModel.ChipIcon.SingleColorIcon(phoneIcon)
}
// This block mimics OngoingCallController#updateChip.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModel.kt
index cf4e707..d4ad6ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModel.kt
@@ -190,7 +190,7 @@
): OngoingActivityChipModel.Shown {
return OngoingActivityChipModel.Shown.Timer(
icon =
- OngoingActivityChipModel.ChipIcon.Basic(
+ OngoingActivityChipModel.ChipIcon.SingleColorIcon(
Icon.Resource(
CAST_TO_OTHER_DEVICE_ICON,
// This string is "Casting screen"
@@ -215,7 +215,7 @@
private fun createIconOnlyCastChip(deviceName: String?): OngoingActivityChipModel.Shown {
return OngoingActivityChipModel.Shown.IconOnly(
icon =
- OngoingActivityChipModel.ChipIcon.Basic(
+ OngoingActivityChipModel.ChipIcon.SingleColorIcon(
Icon.Resource(
CAST_TO_OTHER_DEVICE_ICON,
// This string is just "Casting"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ron/demo/ui/viewmodel/DemoRonChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ron/demo/ui/viewmodel/DemoRonChipViewModel.kt
new file mode 100644
index 0000000..84ccaec
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ron/demo/ui/viewmodel/DemoRonChipViewModel.kt
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.chips.ron.demo.ui.viewmodel
+
+import android.content.pm.PackageManager
+import android.content.pm.PackageManager.NameNotFoundException
+import android.graphics.drawable.Drawable
+import com.android.systemui.CoreStartable
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.chips.ron.shared.StatusBarRonChips
+import com.android.systemui.statusbar.chips.ui.model.ColorsModel
+import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
+import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipViewModel
+import com.android.systemui.statusbar.commandline.CommandRegistry
+import com.android.systemui.statusbar.commandline.ParseableCommand
+import com.android.systemui.statusbar.commandline.Type
+import com.android.systemui.util.time.SystemClock
+import java.io.PrintWriter
+import javax.inject.Inject
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+/**
+ * A view model that will emit demo RON chips (rich ongoing notification chips) from [chip] based on
+ * adb commands sent by the user.
+ *
+ * Example adb commands:
+ *
+ * To show a chip with the SysUI icon and custom text:
+ * ```
+ * adb shell cmd statusbar demo-ron -p com.android.systemui -t 10min
+ * ```
+ *
+ * To hide the chip:
+ * ```
+ * adb shell cmd statusbar demo-ron --hide
+ * ```
+ *
+ * See [DemoRonCommand] for more information on the adb command spec.
+ */
+@SysUISingleton
+class DemoRonChipViewModel
+@Inject
+constructor(
+ private val commandRegistry: CommandRegistry,
+ private val packageManager: PackageManager,
+ private val systemClock: SystemClock,
+) : OngoingActivityChipViewModel, CoreStartable {
+ override fun start() {
+ commandRegistry.registerCommand("demo-ron") { DemoRonCommand() }
+ }
+
+ private val _chip =
+ MutableStateFlow<OngoingActivityChipModel>(OngoingActivityChipModel.Hidden())
+ override val chip: StateFlow<OngoingActivityChipModel> = _chip.asStateFlow()
+
+ private inner class DemoRonCommand : ParseableCommand("demo-ron") {
+ private val packageName: String? by
+ param(
+ longName = "packageName",
+ shortName = "p",
+ description = "The package name for the demo RON app",
+ valueParser = Type.String,
+ )
+
+ private val text: String? by
+ param(
+ longName = "text",
+ shortName = "t",
+ description = "Text to display in the chip",
+ valueParser = Type.String,
+ )
+
+ private val hide by
+ flag(
+ longName = "hide",
+ description = "Hides any existing demo RON chip",
+ )
+
+ override fun execute(pw: PrintWriter) {
+ if (!StatusBarRonChips.isEnabled) {
+ pw.println(
+ "Error: com.android.systemui.status_bar_ron_chips must be enabled " +
+ "before using this demo feature"
+ )
+ return
+ }
+
+ if (hide) {
+ _chip.value = OngoingActivityChipModel.Hidden()
+ return
+ }
+
+ val currentPackageName = packageName
+ if (currentPackageName == null) {
+ pw.println("--packageName (or -p) must be included")
+ return
+ }
+
+ val appIcon = getAppIcon(currentPackageName)
+ if (appIcon == null) {
+ pw.println("Package $currentPackageName could not be found")
+ return
+ }
+
+ val currentText = text
+ if (currentText != null) {
+ _chip.value =
+ OngoingActivityChipModel.Shown.Text(
+ icon = appIcon,
+ // TODO(b/361346412): Include a demo with a custom color theme.
+ colors = ColorsModel.Themed,
+ text = currentText,
+ )
+ } else {
+ _chip.value =
+ OngoingActivityChipModel.Shown.Timer(
+ icon = appIcon,
+ // TODO(b/361346412): Include a demo with a custom color theme.
+ colors = ColorsModel.Themed,
+ startTimeMs = systemClock.elapsedRealtime(),
+ onClickListener = null,
+ )
+ }
+ }
+
+ private fun getAppIcon(packageName: String): OngoingActivityChipModel.ChipIcon? {
+ lateinit var iconDrawable: Drawable
+ try {
+ // Note: For the real implementation, we should check if applicationInfo exists
+ // before fetching the icon, so that we either don't show the chip or show a good
+ // backup icon in case the app info can't be found for some reason.
+ iconDrawable = packageManager.getApplicationIcon(packageName)
+ } catch (e: NameNotFoundException) {
+ return null
+ }
+ return OngoingActivityChipModel.ChipIcon.FullColorAppIcon(
+ Icon.Loaded(drawable = iconDrawable, contentDescription = null),
+ )
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationsHeadsUpRefactor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ron/shared/StatusBarRonChips.kt
similarity index 72%
rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationsHeadsUpRefactor.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/chips/ron/shared/StatusBarRonChips.kt
index 62641fe..4ef1909 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationsHeadsUpRefactor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ron/shared/StatusBarRonChips.kt
@@ -14,17 +14,17 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.notification.shared
+package com.android.systemui.statusbar.chips.ron.shared
import com.android.systemui.Flags
import com.android.systemui.flags.FlagToken
import com.android.systemui.flags.RefactorFlagUtils
-/** Helper for reading or using the notifications heads up refactor flag state. */
+/** Helper for reading or using the status bar RON chips flag state. */
@Suppress("NOTHING_TO_INLINE")
-object NotificationsHeadsUpRefactor {
+object StatusBarRonChips {
/** The aconfig flag name */
- const val FLAG_NAME = Flags.FLAG_NOTIFICATIONS_HEADS_UP_REFACTOR
+ const val FLAG_NAME = Flags.FLAG_STATUS_BAR_RON_CHIPS
/** A token used for dependency declaration */
val token: FlagToken
@@ -33,7 +33,7 @@
/** Is the refactor enabled */
@JvmStatic
inline val isEnabled
- get() = Flags.notificationsHeadsUpRefactor()
+ get() = Flags.statusBarRonChips()
/**
* Called to ensure code is only run when the flag is enabled. This protects users from the
@@ -46,6 +46,14 @@
/**
* Called to ensure code is only run when the flag is disabled. This will throw an exception if
+ * the flag is not enabled to ensure that the refactor author catches issues in testing.
+ * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
+ */
+ @JvmStatic
+ inline fun assertInNewMode() = RefactorFlagUtils.assertInNewMode(isEnabled, FLAG_NAME)
+
+ /**
+ * Called to ensure code is only run when the flag is disabled. This will throw an exception if
* the flag is enabled to ensure that the refactor author catches issues in testing.
*/
@JvmStatic
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModel.kt
index 9e6cacb..eb73521 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModel.kt
@@ -80,7 +80,7 @@
is ScreenRecordChipModel.Recording -> {
OngoingActivityChipModel.Shown.Timer(
icon =
- OngoingActivityChipModel.ChipIcon.Basic(
+ OngoingActivityChipModel.ChipIcon.SingleColorIcon(
Icon.Resource(
ICON,
ContentDescription.Resource(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModel.kt
index 7897f93..d99a916 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModel.kt
@@ -110,7 +110,7 @@
): OngoingActivityChipModel.Shown {
return OngoingActivityChipModel.Shown.Timer(
icon =
- OngoingActivityChipModel.ChipIcon.Basic(
+ OngoingActivityChipModel.ChipIcon.SingleColorIcon(
Icon.Resource(
SHARE_TO_APP_ICON,
ContentDescription.Resource(R.string.share_to_app_chip_accessibility_label),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt
index 26a2f91..62622a8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt
@@ -89,6 +89,16 @@
) : Shown(icon = null, colors, onClickListener = null) {
override val logName = "Shown.Countdown"
}
+
+ /** This chip shows the specified [text] in the chip. */
+ data class Text(
+ override val icon: ChipIcon,
+ override val colors: ColorsModel,
+ // TODO(b/361346412): Enforce a max length requirement?
+ val text: String,
+ ) : Shown(icon, colors, onClickListener = null) {
+ override val logName = "Shown.Text"
+ }
}
/** Represents an icon to show on the chip. */
@@ -106,7 +116,13 @@
}
}
- /** The icon is a basic resource or drawable icon that System UI created internally. */
- data class Basic(val impl: Icon) : ChipIcon
+ /**
+ * This icon is a single color and it came from basic resource or drawable icon that System
+ * UI created internally.
+ */
+ data class SingleColorIcon(val impl: Icon) : ChipIcon
+
+ /** This icon is an app icon in full color (so it should not get tinted in any way). */
+ data class FullColorAppIcon(val impl: Icon) : ChipIcon
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt
index b0d897d..04c4516 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt
@@ -23,6 +23,8 @@
import com.android.systemui.statusbar.chips.StatusBarChipsLog
import com.android.systemui.statusbar.chips.call.ui.viewmodel.CallChipViewModel
import com.android.systemui.statusbar.chips.casttootherdevice.ui.viewmodel.CastToOtherDeviceChipViewModel
+import com.android.systemui.statusbar.chips.ron.demo.ui.viewmodel.DemoRonChipViewModel
+import com.android.systemui.statusbar.chips.ron.shared.StatusBarRonChips
import com.android.systemui.statusbar.chips.screenrecord.ui.viewmodel.ScreenRecordChipViewModel
import com.android.systemui.statusbar.chips.sharetoapp.ui.viewmodel.ShareToAppChipViewModel
import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
@@ -51,6 +53,7 @@
shareToAppChipViewModel: ShareToAppChipViewModel,
castToOtherDeviceChipViewModel: CastToOtherDeviceChipViewModel,
callChipViewModel: CallChipViewModel,
+ demoRonChipViewModel: DemoRonChipViewModel,
@StatusBarChipsLog private val logger: LogBuffer,
) {
private enum class ChipType {
@@ -58,6 +61,8 @@
ShareToApp,
CastToOtherDevice,
Call,
+ /** A demo of a RON chip (rich ongoing notification chip), used just for testing. */
+ DemoRon,
}
/** Model that helps us internally track the various chip states from each of the types. */
@@ -78,6 +83,7 @@
val shareToApp: OngoingActivityChipModel.Hidden,
val castToOtherDevice: OngoingActivityChipModel.Hidden,
val call: OngoingActivityChipModel.Hidden,
+ val demoRon: OngoingActivityChipModel.Hidden,
) : InternalChipModel
}
@@ -87,7 +93,8 @@
shareToAppChipViewModel.chip,
castToOtherDeviceChipViewModel.chip,
callChipViewModel.chip,
- ) { screenRecord, shareToApp, castToOtherDevice, call ->
+ demoRonChipViewModel.chip,
+ ) { screenRecord, shareToApp, castToOtherDevice, call, demoRon ->
logger.log(
TAG,
LogLevel.INFO,
@@ -98,7 +105,15 @@
},
{ "Chips: ScreenRecord=$str1 > ShareToApp=$str2 > CastToOther=$str3..." },
)
- logger.log(TAG, LogLevel.INFO, { str1 = call.logName }, { "... > Call=$str1" })
+ logger.log(
+ TAG,
+ LogLevel.INFO,
+ {
+ str1 = call.logName
+ str2 = demoRon.logName
+ },
+ { "... > Call=$str1 > DemoRon=$str2" }
+ )
// This `when` statement shows the priority order of the chips.
when {
// Screen recording also activates the media projection APIs, so whenever the
@@ -113,17 +128,23 @@
InternalChipModel.Shown(ChipType.CastToOtherDevice, castToOtherDevice)
call is OngoingActivityChipModel.Shown ->
InternalChipModel.Shown(ChipType.Call, call)
+ demoRon is OngoingActivityChipModel.Shown -> {
+ StatusBarRonChips.assertInNewMode()
+ InternalChipModel.Shown(ChipType.DemoRon, demoRon)
+ }
else -> {
// We should only get here if all chip types are hidden
check(screenRecord is OngoingActivityChipModel.Hidden)
check(shareToApp is OngoingActivityChipModel.Hidden)
check(castToOtherDevice is OngoingActivityChipModel.Hidden)
check(call is OngoingActivityChipModel.Hidden)
+ check(demoRon is OngoingActivityChipModel.Hidden)
InternalChipModel.Hidden(
screenRecord = screenRecord,
shareToApp = shareToApp,
castToOtherDevice = castToOtherDevice,
call = call,
+ demoRon = demoRon,
)
}
}
@@ -154,6 +175,7 @@
ChipType.ShareToApp -> new.shareToApp
ChipType.CastToOtherDevice -> new.castToOtherDevice
ChipType.Call -> new.call
+ ChipType.DemoRon -> new.demoRon
}
} else if (new is InternalChipModel.Shown) {
// If we have a chip to show, always show it.
@@ -179,6 +201,7 @@
shareToApp = OngoingActivityChipModel.Hidden(),
castToOtherDevice = OngoingActivityChipModel.Hidden(),
call = OngoingActivityChipModel.Hidden(),
+ demoRon = OngoingActivityChipModel.Hidden(),
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractor.kt
index 74ec7ed..aa203d7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractor.kt
@@ -21,11 +21,11 @@
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.statusbar.notification.data.repository.HeadsUpRepository
import com.android.systemui.statusbar.notification.data.repository.HeadsUpRowRepository
import com.android.systemui.statusbar.notification.shared.HeadsUpRowKey
-import com.android.systemui.statusbar.notification.shared.NotificationsHeadsUpRefactor
import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
@@ -58,7 +58,7 @@
/** Set of currently pinned top-level heads up rows to be displayed. */
val pinnedHeadsUpRows: Flow<Set<HeadsUpRowKey>> by lazy {
- if (NotificationsHeadsUpRefactor.isUnexpectedlyInLegacyMode()) {
+ if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) {
flowOf(emptySet())
} else {
headsUpRepository.activeHeadsUpRows.flatMapLatest { repositories ->
@@ -80,7 +80,7 @@
/** Are there any pinned heads up rows to display? */
val hasPinnedRows: Flow<Boolean> by lazy {
- if (NotificationsHeadsUpRefactor.isUnexpectedlyInLegacyMode()) {
+ if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) {
flowOf(false)
} else {
headsUpRepository.activeHeadsUpRows.flatMapLatest { rows ->
@@ -95,7 +95,7 @@
}
val isHeadsUpOrAnimatingAway: Flow<Boolean> by lazy {
- if (NotificationsHeadsUpRefactor.isUnexpectedlyInLegacyMode()) {
+ if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) {
flowOf(false)
} else {
combine(hasPinnedRows, headsUpRepository.isHeadsUpAnimatingAway) {
@@ -123,7 +123,7 @@
}
val showHeadsUpStatusBar: Flow<Boolean> by lazy {
- if (NotificationsHeadsUpRefactor.isUnexpectedlyInLegacyMode()) {
+ if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) {
flowOf(false)
} else {
combine(hasPinnedRows, canShowHeadsUp) { hasPinnedRows, canShowHeadsUp ->
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 77c26cb..1f767aa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -114,7 +114,6 @@
import com.android.systemui.statusbar.notification.row.StackScrollerDecorView;
import com.android.systemui.statusbar.notification.shared.NotificationHeadsUpCycling;
import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun;
-import com.android.systemui.statusbar.notification.shared.NotificationsHeadsUpRefactor;
import com.android.systemui.statusbar.notification.shared.NotificationsImprovedHunAnimation;
import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor;
import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimBounds;
@@ -4304,7 +4303,7 @@
// Resetting headsUpAnimatingAway on Shade expansion avoids delays caused by
// waiting for all child animations to finish.
// TODO(b/328390331) Do we need to reset this on QS expanded as well?
- if (NotificationsHeadsUpRefactor.isEnabled()) {
+ if (SceneContainerFlag.isEnabled()) {
setHeadsUpAnimatingAway(false);
}
} else {
@@ -4415,7 +4414,7 @@
void onChildAnimationFinished() {
setAnimationRunning(false);
- if (NotificationsHeadsUpRefactor.isEnabled()) {
+ if (SceneContainerFlag.isEnabled()) {
setHeadsUpAnimatingAway(false);
}
requestChildrenUpdate();
@@ -4961,7 +4960,7 @@
}
public void generateHeadsUpAnimation(NotificationEntry entry, boolean isHeadsUp) {
- NotificationsHeadsUpRefactor.assertInLegacyMode();
+ SceneContainerFlag.assertInLegacyMode();
ExpandableNotificationRow row = entry.getHeadsUpAnimationView();
generateHeadsUpAnimation(row, isHeadsUp);
}
@@ -5004,7 +5003,7 @@
mNeedsAnimation = true;
if (!mIsExpanded && !mWillExpand && !isHeadsUp) {
row.setHeadsUpAnimatingAway(true);
- if (NotificationsHeadsUpRefactor.isEnabled()) {
+ if (SceneContainerFlag.isEnabled()) {
setHeadsUpAnimatingAway(true);
}
}
@@ -5198,7 +5197,7 @@
updateClipping();
}
- /** TODO(b/328390331) make this private, when {@link NotificationsHeadsUpRefactor} is removed */
+ /** TODO(b/328390331) make this private, when {@link SceneContainerFlag} is removed */
public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
if (mHeadsUpAnimatingAway != headsUpAnimatingAway) {
mHeadsUpAnimatingAway = headsUpAnimatingAway;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 4e73529..08d3e9f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -127,7 +127,6 @@
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.row.NotificationSnooze;
import com.android.systemui.statusbar.notification.shared.GroupHunAnimationFix;
-import com.android.systemui.statusbar.notification.shared.NotificationsHeadsUpRefactor;
import com.android.systemui.statusbar.notification.stack.ui.viewbinder.NotificationListViewBinder;
import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
import com.android.systemui.statusbar.phone.HeadsUpNotificationViewControllerEmptyImpl;
@@ -686,13 +685,13 @@
new OnHeadsUpChangedListener() {
@Override
public void onHeadsUpPinnedModeChanged(boolean inPinnedMode) {
- NotificationsHeadsUpRefactor.assertInLegacyMode();
+ SceneContainerFlag.assertInLegacyMode();
mView.setInHeadsUpPinnedMode(inPinnedMode);
}
@Override
public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
- NotificationsHeadsUpRefactor.assertInLegacyMode();
+ SceneContainerFlag.assertInLegacyMode();
NotificationEntry topEntry = mHeadsUpManager.getTopEntry();
mView.setTopHeadsUpRow(topEntry != null ? topEntry.getRow() : null);
generateHeadsUpAnimation(entry, isHeadsUp);
@@ -880,7 +879,7 @@
});
}
- if (!NotificationsHeadsUpRefactor.isEnabled()) {
+ if (!SceneContainerFlag.isEnabled()) {
mHeadsUpManager.addListener(mOnHeadsUpChangedListener);
}
mHeadsUpManager.setAnimationStateHandler(mView::setHeadsUpGoingAwayAnimationsAllowed);
@@ -1508,7 +1507,7 @@
}
public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
- NotificationsHeadsUpRefactor.assertInLegacyMode();
+ SceneContainerFlag.assertInLegacyMode();
mView.setHeadsUpAnimatingAway(headsUpAnimatingAway);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
index 5572f8e..d770b20 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
@@ -27,6 +27,7 @@
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.res.R
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.statusbar.NotificationShelf
import com.android.systemui.statusbar.notification.NotificationActivityStarter
import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController
@@ -36,7 +37,6 @@
import com.android.systemui.statusbar.notification.footer.ui.viewbinder.FooterViewBinder
import com.android.systemui.statusbar.notification.footer.ui.viewmodel.FooterViewModel
import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerShelfViewBinder
-import com.android.systemui.statusbar.notification.shared.NotificationsHeadsUpRefactor
import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor
import com.android.systemui.statusbar.notification.shelf.ui.viewbinder.NotificationShelfViewBinder
import com.android.systemui.statusbar.notification.stack.DisplaySwitchNotificationsHiderTracker
@@ -93,7 +93,7 @@
view.repeatWhenAttached {
lifecycleScope.launch {
- if (NotificationsHeadsUpRefactor.isEnabled) {
+ if (SceneContainerFlag.isEnabled) {
launch { hunBinder.bindHeadsUpNotifications(view) }
}
launch { bindShelf(shelf) }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt
index 5fba615..e55492e6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt
@@ -18,6 +18,7 @@
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dump.DumpManager
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.statusbar.domain.interactor.RemoteInputInteractor
import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor
@@ -26,7 +27,6 @@
import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor
import com.android.systemui.statusbar.notification.footer.ui.viewmodel.FooterViewModel
import com.android.systemui.statusbar.notification.shared.HeadsUpRowKey
-import com.android.systemui.statusbar.notification.shared.NotificationsHeadsUpRefactor
import com.android.systemui.statusbar.notification.shelf.ui.viewmodel.NotificationShelfViewModel
import com.android.systemui.statusbar.notification.stack.domain.interactor.NotificationStackInteractor
import com.android.systemui.statusbar.policy.domain.interactor.UserSetupInteractor
@@ -256,7 +256,7 @@
}
val topHeadsUpRow: Flow<HeadsUpRowKey?> by lazy {
- if (NotificationsHeadsUpRefactor.isUnexpectedlyInLegacyMode()) {
+ if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) {
flowOf(null)
} else {
headsUpNotificationInteractor.topHeadsUpRow.dumpWhileCollecting("topHeadsUpRow")
@@ -264,7 +264,7 @@
}
val pinnedHeadsUpRows: Flow<Set<HeadsUpRowKey>> by lazy {
- if (NotificationsHeadsUpRefactor.isUnexpectedlyInLegacyMode()) {
+ if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) {
flowOf(emptySet())
} else {
headsUpNotificationInteractor.pinnedHeadsUpRows.dumpWhileCollecting("pinnedHeadsUpRows")
@@ -272,7 +272,7 @@
}
val headsUpAnimationsEnabled: Flow<Boolean> by lazy {
- if (NotificationsHeadsUpRefactor.isUnexpectedlyInLegacyMode()) {
+ if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) {
flowOf(false)
} else {
flowOf(true).dumpWhileCollecting("headsUpAnimationsEnabled")
@@ -280,7 +280,7 @@
}
val hasPinnedHeadsUpRow: Flow<Boolean> by lazy {
- if (NotificationsHeadsUpRefactor.isUnexpectedlyInLegacyMode()) {
+ if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) {
flowOf(false)
} else {
headsUpNotificationInteractor.hasPinnedRows.dumpWhileCollecting("hasPinnedHeadsUpRow")
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
index b7f6633..3e42413 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
@@ -19,7 +19,7 @@
import com.android.compose.animation.scene.ObservableTransitionState.Idle
import com.android.compose.animation.scene.ObservableTransitionState.Transition
-import com.android.compose.animation.scene.ObservableTransitionState.Transition.ChangeCurrentScene
+import com.android.compose.animation.scene.ObservableTransitionState.Transition.ChangeScene
import com.android.compose.animation.scene.SceneKey
import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
@@ -77,7 +77,7 @@
}
}
- private fun fullyExpandedDuringSceneChange(change: ChangeCurrentScene): Boolean {
+ private fun fullyExpandedDuringSceneChange(change: ChangeScene): Boolean {
// The lockscreen stack is visible during all transitions away from the lockscreen, so keep
// the stack expanded until those transitions finish.
return (expandedInScene(change.fromScene) && expandedInScene(change.toScene)) ||
@@ -85,7 +85,7 @@
}
private fun expandFractionDuringSceneChange(
- change: ChangeCurrentScene,
+ change: ChangeScene,
shadeExpansion: Float,
qsExpansion: Float,
): Float {
@@ -118,7 +118,7 @@
) { shadeExpansion, _, qsExpansion, transitionState, _ ->
when (transitionState) {
is Idle -> if (expandedInScene(transitionState.currentScene)) 1f else 0f
- is ChangeCurrentScene ->
+ is ChangeScene ->
expandFractionDuringSceneChange(
transitionState,
shadeExpansion,
@@ -248,7 +248,7 @@
}
}
-private fun ChangeCurrentScene.isBetween(
+private fun ChangeScene.isBetween(
a: (SceneKey) -> Boolean,
- b: (SceneKey) -> Boolean
+ b: (SceneKey) -> Boolean,
): Boolean = (a(fromScene) && b(toScene)) || (b(fromScene) && a(toScene))
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index 0ea28a7..1efad3b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -47,7 +47,6 @@
import com.android.systemui.statusbar.notification.data.repository.HeadsUpRowRepository;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun;
-import com.android.systemui.statusbar.notification.shared.NotificationsHeadsUpRefactor;
import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
import com.android.systemui.statusbar.policy.AnimationStateHandler;
import com.android.systemui.statusbar.policy.AvalancheController;
@@ -284,7 +283,7 @@
private void onShadeOrQsExpanded(Boolean isExpanded) {
if (isExpanded != mIsExpanded) {
mIsExpanded = isExpanded;
- if (!NotificationsHeadsUpRefactor.isEnabled() && isExpanded) {
+ if (!SceneContainerFlag.isEnabled() && isExpanded) {
mHeadsUpAnimatingAway.setValue(false);
}
}
@@ -517,7 +516,7 @@
@Nullable
private HeadsUpEntryPhone getTopHeadsUpEntryPhone() {
- if (NotificationsHeadsUpRefactor.isEnabled()) {
+ if (SceneContainerFlag.isEnabled()) {
return (HeadsUpEntryPhone) mTopHeadsUpRow.getValue();
} else {
return (HeadsUpEntryPhone) getTopHeadsUpEntry();
@@ -711,7 +710,7 @@
}
private NotificationEntry requireEntry() {
- /* check if */ NotificationsHeadsUpRefactor.isUnexpectedlyInLegacyMode();
+ /* check if */ SceneContainerFlag.isUnexpectedlyInLegacyMode();
return Objects.requireNonNull(mEntry);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java
index da5877b..8f2d4f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java
@@ -19,12 +19,12 @@
import com.android.systemui.CoreStartable;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.scene.shared.flag.SceneContainerFlag;
import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.notification.shared.NotificationsHeadsUpRefactor;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
@@ -112,7 +112,7 @@
}
private void setHeadsAnimatingAway(boolean headsUpAnimatingAway) {
- if (!NotificationsHeadsUpRefactor.isEnabled()) {
+ if (!SceneContainerFlag.isEnabled()) {
mHeadsUpManager.setHeadsUpAnimatingAway(headsUpAnimatingAway);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt
index d46aaf4..c24d694 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt
@@ -35,6 +35,7 @@
import com.android.systemui.res.R
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.statusbar.StatusBarIconView
+import com.android.systemui.statusbar.chips.ron.shared.StatusBarRonChips
import com.android.systemui.statusbar.chips.ui.binder.ChipChronometerBinder
import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer
@@ -124,10 +125,6 @@
// Colors
val textColor = chipModel.colors.text(chipContext)
- chipDefaultIconView.imageTintList =
- ColorStateList.valueOf(textColor)
- chipBackgroundView.getCustomIconView()?.imageTintList =
- ColorStateList.valueOf(textColor)
chipTimeView.setTextColor(textColor)
chipTextView.setTextColor(textColor)
(chipBackgroundView.background as GradientDrawable).color =
@@ -173,13 +170,22 @@
// it.
backgroundView.removeView(backgroundView.getCustomIconView())
+ val iconTint = chipModel.colors.text(defaultIconView.context)
+
when (val icon = chipModel.icon) {
null -> {
defaultIconView.visibility = View.GONE
}
- is OngoingActivityChipModel.ChipIcon.Basic -> {
+ is OngoingActivityChipModel.ChipIcon.SingleColorIcon -> {
IconViewBinder.bind(icon.impl, defaultIconView)
defaultIconView.visibility = View.VISIBLE
+ defaultIconView.tintView(iconTint)
+ }
+ is OngoingActivityChipModel.ChipIcon.FullColorAppIcon -> {
+ StatusBarRonChips.assertInNewMode()
+ IconViewBinder.bind(icon.impl, defaultIconView)
+ defaultIconView.visibility = View.VISIBLE
+ defaultIconView.untintView()
}
is OngoingActivityChipModel.ChipIcon.StatusBarView -> {
// Hide the default icon since we'll show this custom icon instead.
@@ -194,6 +200,7 @@
// maybe include the app name.
contentDescription =
context.resources.getString(R.string.ongoing_phone_call_content_description)
+ tintView(iconTint)
}
// 2. If we just reinflated the view, we may need to detach the icon view from the
@@ -219,6 +226,14 @@
return this.findViewById(CUSTOM_ICON_VIEW_ID)
}
+ private fun ImageView.tintView(color: Int) {
+ this.imageTintList = ColorStateList.valueOf(color)
+ }
+
+ private fun ImageView.untintView() {
+ this.imageTintList = null
+ }
+
private fun generateCustomIconLayoutParams(iconView: ImageView): FrameLayout.LayoutParams {
val customIconSize =
iconView.context.resources.getDimensionPixelSize(
@@ -237,10 +252,13 @@
chipTextView.text = chipModel.secondsUntilStarted.toString()
chipTextView.visibility = View.VISIBLE
- // The Chronometer should be stopped to prevent leaks -- see b/192243808 and
- // [Chronometer.start].
- chipTimeView.stop()
- chipTimeView.visibility = View.GONE
+ chipTimeView.hide()
+ }
+ is OngoingActivityChipModel.Shown.Text -> {
+ chipTextView.text = chipModel.text
+ chipTextView.visibility = View.VISIBLE
+
+ chipTimeView.hide()
}
is OngoingActivityChipModel.Shown.Timer -> {
ChipChronometerBinder.bind(chipModel.startTimeMs, chipTimeView)
@@ -250,14 +268,18 @@
}
is OngoingActivityChipModel.Shown.IconOnly -> {
chipTextView.visibility = View.GONE
- // The Chronometer should be stopped to prevent leaks -- see b/192243808 and
- // [Chronometer.start].
- chipTimeView.stop()
- chipTimeView.visibility = View.GONE
+ chipTimeView.hide()
}
}
}
+ private fun ChipChronometer.hide() {
+ // The Chronometer should be stopped to prevent leaks -- see b/192243808 and
+ // [Chronometer.start].
+ this.stop()
+ this.visibility = View.GONE
+ }
+
private fun updateChipPadding(
chipModel: OngoingActivityChipModel.Shown,
backgroundView: View,
@@ -356,6 +378,7 @@
chipView.accessibilityLiveRegion = View.ACCESSIBILITY_LIVE_REGION_ASSERTIVE
}
is OngoingActivityChipModel.Shown.Timer,
+ is OngoingActivityChipModel.Shown.Text,
is OngoingActivityChipModel.Shown.IconOnly -> {
chipView.accessibilityLiveRegion = View.ACCESSIBILITY_LIVE_REGION_NONE
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModel.kt
index 89227cf..fe1d647 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModel.kt
@@ -21,10 +21,10 @@
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.statusbar.domain.interactor.KeyguardStatusBarInteractor
import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationInteractor
-import com.android.systemui.statusbar.notification.shared.NotificationsHeadsUpRefactor
import com.android.systemui.statusbar.policy.BatteryController
import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback
import javax.inject.Inject
@@ -58,7 +58,7 @@
) {
private val showingHeadsUpStatusBar: Flow<Boolean> =
- if (NotificationsHeadsUpRefactor.isEnabled) {
+ if (SceneContainerFlag.isEnabled) {
headsUpNotificationInteractor.showHeadsUpStatusBar
} else {
flowOf(false)
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index c7fc445..9c8ef04 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -89,6 +89,9 @@
import com.google.ux.material.libmonet.dynamiccolor.DynamicColor;
import com.google.ux.material.libmonet.dynamiccolor.MaterialDynamicColors;
+import kotlinx.coroutines.flow.Flow;
+import kotlinx.coroutines.flow.StateFlow;
+
import org.json.JSONException;
import org.json.JSONObject;
@@ -162,6 +165,7 @@
private final WakefulnessLifecycle mWakefulnessLifecycle;
private final JavaAdapter mJavaAdapter;
private final KeyguardTransitionInteractor mKeyguardTransitionInteractor;
+ private final StateFlow<Boolean> mIsKeyguardOnAsleepState;
private final UiModeManager mUiModeManager;
private ColorScheme mDarkColorScheme;
private ColorScheme mLightColorScheme;
@@ -202,8 +206,7 @@
}
boolean currentUser = userId == mUserTracker.getUserId();
boolean isAsleep = themeOverlayControllerWakefulnessDeprecation()
- ? KeyguardState.Companion.deviceIsAsleepInState(
- mKeyguardTransitionInteractor.getFinishedState())
+ ? ThemeOverlayController.this.mIsKeyguardOnAsleepState.getValue()
: mWakefulnessLifecycle.getWakefulness() != WAKEFULNESS_ASLEEP;
if (currentUser && !mAcceptColorEvents && isAsleep) {
@@ -434,6 +437,10 @@
mUiModeManager = uiModeManager;
mActivityManager = activityManager;
dumpManager.registerDumpable(TAG, this);
+
+ Flow<Boolean> isFinishedInAsleepStateFlow = mKeyguardTransitionInteractor
+ .isFinishedInStateWhere(KeyguardState.Companion::deviceIsAsleepInState);
+ mIsKeyguardOnAsleepState = mJavaAdapter.stateInApp(isFinishedInAsleepStateFlow, false);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt
index 055671c..64e056d 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt
@@ -31,7 +31,10 @@
import kotlinx.coroutines.DisposableHandle
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
/** A class allowing Java classes to collect on Kotlin flows. */
@@ -58,6 +61,15 @@
): Job {
return scope.launch { flow.collect { consumer.accept(it) } }
}
+
+ @JvmOverloads
+ fun <T> stateInApp(
+ flow: Flow<T>,
+ initialValue: T,
+ started: SharingStarted = SharingStarted.Eagerly
+ ): StateFlow<T> {
+ return flow.stateIn(scope, started, initialValue)
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index d3e8bd3..28effe9 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -125,7 +125,6 @@
static final ArrayMap<Integer, Integer> STREAMS = new ArrayMap<>();
static {
STREAMS.put(AudioSystem.STREAM_ALARM, R.string.stream_alarm);
- STREAMS.put(AudioSystem.STREAM_BLUETOOTH_SCO, R.string.stream_bluetooth_sco);
STREAMS.put(AudioSystem.STREAM_DTMF, R.string.stream_dtmf);
STREAMS.put(AudioSystem.STREAM_MUSIC, R.string.stream_music);
STREAMS.put(AudioSystem.STREAM_ACCESSIBILITY, R.string.stream_accessibility);
@@ -654,7 +653,6 @@
private static boolean isLogWorthy(int stream) {
switch (stream) {
case AudioSystem.STREAM_ALARM:
- case AudioSystem.STREAM_BLUETOOTH_SCO:
case AudioSystem.STREAM_MUSIC:
case AudioSystem.STREAM_RING:
case AudioSystem.STREAM_SYSTEM:
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index eb91518..7786453 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -704,8 +704,6 @@
addRow(AudioManager.STREAM_VOICE_CALL,
com.android.internal.R.drawable.ic_phone,
com.android.internal.R.drawable.ic_phone, false, false);
- addRow(AudioManager.STREAM_BLUETOOTH_SCO,
- R.drawable.ic_volume_bt_sco, R.drawable.ic_volume_bt_sco, false, false);
addRow(AudioManager.STREAM_SYSTEM, R.drawable.ic_volume_system,
R.drawable.ic_volume_system_mute, false, false);
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/domain/interactor/AudioSlidersInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/domain/interactor/AudioSlidersInteractor.kt
index 0451ce6..4be680e 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/domain/interactor/AudioSlidersInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/domain/interactor/AudioSlidersInteractor.kt
@@ -16,9 +16,7 @@
package com.android.systemui.volume.panel.component.volume.domain.interactor
-import android.media.AudioDeviceInfo
import android.media.AudioManager
-import com.android.settingslib.volume.data.repository.AudioRepository
import com.android.settingslib.volume.domain.interactor.AudioModeInteractor
import com.android.settingslib.volume.shared.model.AudioStream
import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaOutputInteractor
@@ -42,7 +40,6 @@
constructor(
@VolumePanelScope scope: CoroutineScope,
mediaOutputInteractor: MediaOutputInteractor,
- audioRepository: AudioRepository,
audioModeInteractor: AudioModeInteractor,
) {
@@ -50,13 +47,12 @@
combineTransform(
mediaOutputInteractor.activeMediaDeviceSessions,
mediaOutputInteractor.defaultActiveMediaSession.filterData(),
- audioRepository.communicationDevice,
audioModeInteractor.isOngoingCall,
- ) { activeSessions, defaultSession, communicationDevice, isOngoingCall ->
+ ) { activeSessions, defaultSession, isOngoingCall ->
coroutineScope {
val viewModels = buildList {
if (isOngoingCall) {
- addCall(communicationDevice?.type)
+ addStream(AudioManager.STREAM_VOICE_CALL)
}
if (defaultSession?.isTheSameSession(activeSessions.remote) == true) {
@@ -68,7 +64,7 @@
}
if (!isOngoingCall) {
- addCall(communicationDevice?.type)
+ addStream(AudioManager.STREAM_VOICE_CALL)
}
addStream(AudioManager.STREAM_RING)
@@ -80,14 +76,6 @@
}
.stateIn(scope, SharingStarted.Eagerly, emptyList())
- private fun MutableList<SliderType>.addCall(communicationDeviceType: Int?) {
- if (communicationDeviceType == AudioDeviceInfo.TYPE_BLUETOOTH_SCO) {
- addStream(AudioManager.STREAM_BLUETOOTH_SCO)
- } else {
- addStream(AudioManager.STREAM_VOICE_CALL)
- }
- }
-
private fun MutableList<SliderType>.addSession(remoteMediaDeviceSession: MediaDeviceSession?) {
if (remoteMediaDeviceSession?.canAdjustVolume == true) {
add(SliderType.MediaDeviceCast(remoteMediaDeviceSession))
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt
index 521f608..ffb1f11 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt
@@ -66,7 +66,6 @@
mapOf(
AudioStream(AudioManager.STREAM_MUSIC) to R.drawable.ic_music_note,
AudioStream(AudioManager.STREAM_VOICE_CALL) to R.drawable.ic_call,
- AudioStream(AudioManager.STREAM_BLUETOOTH_SCO) to R.drawable.ic_call,
AudioStream(AudioManager.STREAM_RING) to R.drawable.ic_ring_volume,
AudioStream(AudioManager.STREAM_NOTIFICATION) to R.drawable.ic_volume_ringer,
AudioStream(AudioManager.STREAM_ALARM) to R.drawable.ic_volume_alarm,
@@ -75,7 +74,6 @@
mapOf(
AudioStream(AudioManager.STREAM_MUSIC) to R.string.stream_music,
AudioStream(AudioManager.STREAM_VOICE_CALL) to R.string.stream_voice_call,
- AudioStream(AudioManager.STREAM_BLUETOOTH_SCO) to R.string.stream_voice_call,
AudioStream(AudioManager.STREAM_RING) to R.string.stream_ring,
AudioStream(AudioManager.STREAM_NOTIFICATION) to R.string.stream_notification,
AudioStream(AudioManager.STREAM_ALARM) to R.string.stream_alarm,
@@ -91,8 +89,6 @@
VolumePanelUiEvent.VOLUME_PANEL_MUSIC_SLIDER_TOUCHED,
AudioStream(AudioManager.STREAM_VOICE_CALL) to
VolumePanelUiEvent.VOLUME_PANEL_VOICE_CALL_SLIDER_TOUCHED,
- AudioStream(AudioManager.STREAM_BLUETOOTH_SCO) to
- VolumePanelUiEvent.VOLUME_PANEL_VOICE_CALL_SLIDER_TOUCHED,
AudioStream(AudioManager.STREAM_RING) to
VolumePanelUiEvent.VOLUME_PANEL_RING_SLIDER_TOUCHED,
AudioStream(AudioManager.STREAM_NOTIFICATION) to
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorTest.kt
index 74bc928..681ea75 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorTest.kt
@@ -59,6 +59,7 @@
private lateinit var mockitoSession: StaticMockitoSession
private lateinit var activeMediaDeviceItem: DeviceItem
private lateinit var notConnectedDeviceItem: DeviceItem
+ private lateinit var connectedAudioSharingMediaDeviceItem: DeviceItem
private lateinit var connectedMediaDeviceItem: DeviceItem
private lateinit var connectedOtherDeviceItem: DeviceItem
@Mock private lateinit var dialog: SystemUIDialog
@@ -100,6 +101,15 @@
iconWithDescription = null,
background = null
)
+ connectedAudioSharingMediaDeviceItem =
+ DeviceItem(
+ type = DeviceItemType.AVAILABLE_AUDIO_SHARING_MEDIA_BLUETOOTH_DEVICE,
+ cachedBluetoothDevice = cachedBluetoothDevice,
+ deviceName = DEVICE_NAME,
+ connectionSummary = DEVICE_CONNECTION_SUMMARY,
+ iconWithDescription = null,
+ background = null
+ )
connectedOtherDeviceItem =
DeviceItem(
type = DeviceItemType.CONNECTED_BLUETOOTH_DEVICE,
@@ -186,6 +196,21 @@
}
@Test
+ fun testOnClick_connectedAudioSharingMediaDevice_logClick() {
+ with(kosmos) {
+ testScope.runTest {
+ whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
+ actionInteractorImpl.onClick(connectedAudioSharingMediaDeviceItem, dialog)
+ verify(bluetoothTileDialogLogger)
+ .logDeviceClick(
+ cachedBluetoothDevice.address,
+ DeviceItemType.AVAILABLE_AUDIO_SHARING_MEDIA_BLUETOOTH_DEVICE
+ )
+ }
+ }
+ }
+
+ @Test
fun testOnClick_audioSharingDisabled_shouldNotLaunchSettings() {
with(kosmos) {
testScope.runTest {
@@ -415,7 +440,7 @@
}
@Test
- fun testOnClick_hasTwoConnectedLeDevice_clickedConnectedLe_shouldLaunchSettings() {
+ fun testOnClick_hasTwoConnectedLeDevice_clickedActiveLe_shouldLaunchSettings() {
with(kosmos) {
testScope.runTest {
whenever(cachedBluetoothDevice.device).thenReturn(bluetoothDevice)
@@ -438,7 +463,7 @@
if (device == bluetoothDevice) GROUP_ID_1 else GROUP_ID_2
}
- actionInteractorImpl.onClick(connectedMediaDeviceItem, dialog)
+ actionInteractorImpl.onClick(activeMediaDeviceItem, dialog)
verify(activityStarter)
.postStartActivityDismissingKeyguard(
ArgumentMatchers.any(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt
index a27ccc6..ef441c1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt
@@ -17,18 +17,24 @@
package com.android.systemui.bluetooth.qsdialog
import android.bluetooth.BluetoothDevice
-import android.content.pm.ApplicationInfo
-import android.content.pm.PackageManager
+import android.graphics.drawable.Drawable
import android.media.AudioManager
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.testing.TestableLooper
+import android.util.Pair
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
+import com.android.dx.mockito.inline.extended.StaticMockitoSession
+import com.android.settingslib.bluetooth.BluetoothUtils
import com.android.settingslib.bluetooth.CachedBluetoothDevice
+import com.android.settingslib.bluetooth.LocalBluetoothManager
import com.android.settingslib.flags.Flags
import com.android.systemui.SysuiTestCase
+import com.android.systemui.res.R
import com.google.common.truth.Truth.assertThat
+import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@@ -37,6 +43,7 @@
import org.mockito.Mockito.`when`
import org.mockito.junit.MockitoJUnit
import org.mockito.junit.MockitoRule
+import org.mockito.kotlin.any
@SmallTest
@RunWith(AndroidJUnit4::class)
@@ -44,9 +51,11 @@
class DeviceItemFactoryTest : SysuiTestCase() {
@get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
+ private lateinit var mockitoSession: StaticMockitoSession
@Mock private lateinit var cachedDevice: CachedBluetoothDevice
@Mock private lateinit var bluetoothDevice: BluetoothDevice
- @Mock private lateinit var packageManager: PackageManager
+ @Mock private lateinit var localBluetoothManager: LocalBluetoothManager
+ @Mock private lateinit var drawable: Drawable
private val availableMediaDeviceItemFactory = AvailableMediaDeviceItemFactory()
private val connectedDeviceItemFactory = ConnectedDeviceItemFactory()
@@ -56,16 +65,21 @@
@Before
fun setup() {
- `when`(cachedDevice.name).thenReturn(DEVICE_NAME)
- `when`(cachedDevice.address).thenReturn(DEVICE_ADDRESS)
- `when`(cachedDevice.device).thenReturn(bluetoothDevice)
- `when`(cachedDevice.connectionSummary).thenReturn(CONNECTION_SUMMARY)
+ mockitoSession =
+ mockitoSession().initMocks(this).mockStatic(BluetoothUtils::class.java).startMocking()
+ }
- context.setMockPackageManager(packageManager)
+ @After
+ fun tearDown() {
+ mockitoSession.finishMocking()
}
@Test
fun testAvailableMediaDeviceItemFactory_createFromCachedDevice() {
+ `when`(cachedDevice.name).thenReturn(DEVICE_NAME)
+ `when`(cachedDevice.connectionSummary).thenReturn(CONNECTION_SUMMARY)
+ `when`(BluetoothUtils.getBtClassDrawableWithDescription(any(), any()))
+ .thenReturn(Pair.create(drawable, ""))
val deviceItem = availableMediaDeviceItemFactory.create(context, cachedDevice)
assertDeviceItem(deviceItem, DeviceItemType.AVAILABLE_MEDIA_BLUETOOTH_DEVICE)
@@ -73,6 +87,10 @@
@Test
fun testConnectedDeviceItemFactory_createFromCachedDevice() {
+ `when`(cachedDevice.name).thenReturn(DEVICE_NAME)
+ `when`(cachedDevice.connectionSummary).thenReturn(CONNECTION_SUMMARY)
+ `when`(BluetoothUtils.getBtClassDrawableWithDescription(any(), any()))
+ .thenReturn(Pair.create(drawable, ""))
val deviceItem = connectedDeviceItemFactory.create(context, cachedDevice)
assertDeviceItem(deviceItem, DeviceItemType.CONNECTED_BLUETOOTH_DEVICE)
@@ -80,6 +98,10 @@
@Test
fun testSavedDeviceItemFactory_createFromCachedDevice() {
+ `when`(cachedDevice.name).thenReturn(DEVICE_NAME)
+ `when`(cachedDevice.connectionSummary).thenReturn(CONNECTION_SUMMARY)
+ `when`(BluetoothUtils.getBtClassDrawableWithDescription(any(), any()))
+ .thenReturn(Pair.create(drawable, ""))
val deviceItem = savedDeviceItemFactory.create(context, cachedDevice)
assertDeviceItem(deviceItem, DeviceItemType.SAVED_BLUETOOTH_DEVICE)
@@ -87,6 +109,90 @@
}
@Test
+ fun testAvailableAudioSharingMediaDeviceItemFactory_createFromCachedDevice() {
+ `when`(cachedDevice.name).thenReturn(DEVICE_NAME)
+ `when`(BluetoothUtils.getBtClassDrawableWithDescription(any(), any()))
+ .thenReturn(Pair.create(drawable, ""))
+ val deviceItem =
+ AvailableAudioSharingMediaDeviceItemFactory(localBluetoothManager)
+ .create(context, cachedDevice)
+
+ assertThat(deviceItem).isNotNull()
+ assertThat(deviceItem.type)
+ .isEqualTo(DeviceItemType.AVAILABLE_AUDIO_SHARING_MEDIA_BLUETOOTH_DEVICE)
+ assertThat(deviceItem.cachedBluetoothDevice).isEqualTo(cachedDevice)
+ assertThat(deviceItem.deviceName).isEqualTo(DEVICE_NAME)
+ assertThat(deviceItem.isActive).isFalse()
+ assertThat(deviceItem.connectionSummary)
+ .isEqualTo(
+ context.getString(
+ R.string.quick_settings_bluetooth_device_audio_sharing_or_switch_active
+ )
+ )
+ }
+
+ @Test
+ fun testAvailableAudioSharingMediaDeviceItemFactory_isFilterMatched_flagOff_returnsFalse() {
+ // Flags.FLAG_ENABLE_LE_AUDIO_SHARING off or the device doesn't support broadcast
+ // source or assistant.
+ `when`(BluetoothUtils.isAudioSharingEnabled()).thenReturn(false)
+
+ assertThat(
+ AvailableAudioSharingMediaDeviceItemFactory(localBluetoothManager)
+ .isFilterMatched(context, cachedDevice, audioManager)
+ )
+ .isFalse()
+ }
+
+ @Test
+ fun testAvailableAudioSharingMediaDeviceItemFactory_isFilterMatched_isActiveDevice_returnsFalse() {
+ // Flags.FLAG_ENABLE_LE_AUDIO_SHARING on and the device support broadcast source and
+ // assistant.
+ `when`(BluetoothUtils.isAudioSharingEnabled()).thenReturn(true)
+ `when`(BluetoothUtils.isActiveMediaDevice(any())).thenReturn(true)
+
+ assertThat(
+ AvailableAudioSharingMediaDeviceItemFactory(localBluetoothManager)
+ .isFilterMatched(context, cachedDevice, audioManager)
+ )
+ .isFalse()
+ }
+
+ @Test
+ fun testAvailableAudioSharingMediaDeviceItemFactory_isFilterMatched_isNotAvailable_returnsFalse() {
+ // Flags.FLAG_ENABLE_LE_AUDIO_SHARING on and the device support broadcast source and
+ // assistant.
+ `when`(BluetoothUtils.isAudioSharingEnabled()).thenReturn(true)
+ `when`(BluetoothUtils.isActiveMediaDevice(any())).thenReturn(false)
+ `when`(BluetoothUtils.isAvailableMediaBluetoothDevice(any(), any())).thenReturn(true)
+ `when`(BluetoothUtils.isAvailableAudioSharingMediaBluetoothDevice(any(), any()))
+ .thenReturn(false)
+
+ assertThat(
+ AvailableAudioSharingMediaDeviceItemFactory(localBluetoothManager)
+ .isFilterMatched(context, cachedDevice, audioManager)
+ )
+ .isFalse()
+ }
+
+ @Test
+ fun testAvailableAudioSharingMediaDeviceItemFactory_isFilterMatched_returnsTrue() {
+ // Flags.FLAG_ENABLE_LE_AUDIO_SHARING on and the device support broadcast source and
+ // assistant.
+ `when`(BluetoothUtils.isAudioSharingEnabled()).thenReturn(true)
+ `when`(BluetoothUtils.isActiveMediaDevice(any())).thenReturn(false)
+ `when`(BluetoothUtils.isAvailableMediaBluetoothDevice(any(), any())).thenReturn(true)
+ `when`(BluetoothUtils.isAvailableAudioSharingMediaBluetoothDevice(any(), any()))
+ .thenReturn(true)
+
+ assertThat(
+ AvailableAudioSharingMediaDeviceItemFactory(localBluetoothManager)
+ .isFilterMatched(context, cachedDevice, audioManager)
+ )
+ .isTrue()
+ }
+
+ @Test
@DisableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
fun testSavedFactory_isFilterMatched_bondedAndNotConnected_returnsTrue() {
`when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
@@ -110,7 +216,6 @@
@DisableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
fun testSavedFactory_isFilterMatched_notBonded_returnsFalse() {
`when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_NONE)
- `when`(cachedDevice.isConnected).thenReturn(false)
assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
.isFalse()
@@ -119,12 +224,8 @@
@Test
@EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
fun testSavedFactory_isFilterMatched_exclusivelyManaged_returnsFalse() {
- `when`(bluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER))
- .thenReturn(TEST_EXCLUSIVE_MANAGER.toByteArray())
- `when`(packageManager.getApplicationInfo(TEST_EXCLUSIVE_MANAGER, 0))
- .thenReturn(ApplicationInfo())
- `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
- `when`(cachedDevice.isConnected).thenReturn(false)
+ `when`(cachedDevice.device).thenReturn(bluetoothDevice)
+ `when`(BluetoothUtils.isExclusivelyManagedBluetoothDevice(any(), any())).thenReturn(true)
assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
.isFalse()
@@ -132,7 +233,9 @@
@Test
@EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
- fun testSavedFactory_isFilterMatched_noExclusiveManager_returnsTrue() {
+ fun testSavedFactory_isFilterMatched_notExclusiveManaged_returnsTrue() {
+ `when`(cachedDevice.device).thenReturn(bluetoothDevice)
+ `when`(BluetoothUtils.isExclusivelyManagedBluetoothDevice(any(), any())).thenReturn(false)
`when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
`when`(cachedDevice.isConnected).thenReturn(false)
@@ -142,45 +245,9 @@
@Test
@EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
- fun testSavedFactory_isFilterMatched_exclusiveManagerNotEnabled_returnsTrue() {
- `when`(bluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER))
- .thenReturn(TEST_EXCLUSIVE_MANAGER.toByteArray())
- `when`(packageManager.getApplicationInfo(TEST_EXCLUSIVE_MANAGER, 0))
- .thenReturn(ApplicationInfo().also { it.enabled = false })
- `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
- `when`(cachedDevice.isConnected).thenReturn(false)
-
- assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
- .isTrue()
- }
-
- @Test
- @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
- fun testSavedFactory_isFilterMatched_exclusiveManagerNotInstalled_returnsTrue() {
- `when`(bluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER))
- .thenReturn(TEST_EXCLUSIVE_MANAGER.toByteArray())
- `when`(packageManager.getApplicationInfo(TEST_EXCLUSIVE_MANAGER, 0))
- .thenThrow(PackageManager.NameNotFoundException("Test!"))
- `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
- `when`(cachedDevice.isConnected).thenReturn(false)
-
- assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
- .isTrue()
- }
-
- @Test
- @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
- fun testSavedFactory_isFilterMatched_notExclusivelyManaged_notBonded_returnsFalse() {
- `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_NONE)
- `when`(cachedDevice.isConnected).thenReturn(false)
-
- assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
- .isFalse()
- }
-
- @Test
- @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
fun testSavedFactory_isFilterMatched_notExclusivelyManaged_connected_returnsFalse() {
+ `when`(cachedDevice.device).thenReturn(bluetoothDevice)
+ `when`(BluetoothUtils.isExclusivelyManagedBluetoothDevice(any(), any())).thenReturn(false)
`when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
`when`(cachedDevice.isConnected).thenReturn(true)
@@ -191,9 +258,7 @@
@Test
@DisableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
fun testConnectedFactory_isFilterMatched_bondedAndConnected_returnsTrue() {
- `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
- `when`(bluetoothDevice.isConnected).thenReturn(true)
- audioManager.setMode(AudioManager.MODE_NORMAL)
+ `when`(BluetoothUtils.isConnectedBluetoothDevice(any(), any())).thenReturn(true)
assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
.isTrue()
@@ -202,21 +267,6 @@
@Test
@DisableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
fun testConnectedFactory_isFilterMatched_notConnected_returnsFalse() {
- `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
- `when`(bluetoothDevice.isConnected).thenReturn(false)
- audioManager.setMode(AudioManager.MODE_NORMAL)
-
- assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
- .isFalse()
- }
-
- @Test
- @DisableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
- fun testConnectedFactory_isFilterMatched_notBonded_returnsFalse() {
- `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_NONE)
- `when`(bluetoothDevice.isConnected).thenReturn(true)
- audioManager.setMode(AudioManager.MODE_NORMAL)
-
assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
.isFalse()
}
@@ -224,13 +274,8 @@
@Test
@EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
fun testConnectedFactory_isFilterMatched_exclusivelyManaged_returnsFalse() {
- `when`(bluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER))
- .thenReturn(TEST_EXCLUSIVE_MANAGER.toByteArray())
- `when`(packageManager.getApplicationInfo(TEST_EXCLUSIVE_MANAGER, 0))
- .thenReturn(ApplicationInfo())
- `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
- `when`(bluetoothDevice.isConnected).thenReturn(true)
- audioManager.setMode(AudioManager.MODE_NORMAL)
+ `when`(cachedDevice.device).thenReturn(bluetoothDevice)
+ `when`(BluetoothUtils.isExclusivelyManagedBluetoothDevice(any(), any())).thenReturn(true)
assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
.isFalse()
@@ -239,9 +284,9 @@
@Test
@EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
fun testConnectedFactory_isFilterMatched_noExclusiveManager_returnsTrue() {
- `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
- `when`(bluetoothDevice.isConnected).thenReturn(true)
- audioManager.setMode(AudioManager.MODE_NORMAL)
+ `when`(cachedDevice.device).thenReturn(bluetoothDevice)
+ `when`(BluetoothUtils.isExclusivelyManagedBluetoothDevice(any(), any())).thenReturn(false)
+ `when`(BluetoothUtils.isConnectedBluetoothDevice(any(), any())).thenReturn(true)
assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
.isTrue()
@@ -249,51 +294,10 @@
@Test
@EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
- fun testConnectedFactory_isFilterMatched_exclusiveManagerNotEnabled_returnsTrue() {
- `when`(bluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER))
- .thenReturn(TEST_EXCLUSIVE_MANAGER.toByteArray())
- `when`(packageManager.getApplicationInfo(TEST_EXCLUSIVE_MANAGER, 0))
- .thenReturn(ApplicationInfo().also { it.enabled = false })
- `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
- `when`(bluetoothDevice.isConnected).thenReturn(true)
- audioManager.setMode(AudioManager.MODE_NORMAL)
-
- assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
- .isTrue()
- }
-
- @Test
- @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
- fun testConnectedFactory_isFilterMatched_exclusiveManagerNotInstalled_returnsTrue() {
- `when`(bluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER))
- .thenReturn(TEST_EXCLUSIVE_MANAGER.toByteArray())
- `when`(packageManager.getApplicationInfo(TEST_EXCLUSIVE_MANAGER, 0))
- .thenThrow(PackageManager.NameNotFoundException("Test!"))
- `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
- `when`(bluetoothDevice.isConnected).thenReturn(true)
- audioManager.setMode(AudioManager.MODE_NORMAL)
-
- assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
- .isTrue()
- }
-
- @Test
- @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
- fun testConnectedFactory_isFilterMatched_notExclusivelyManaged_notBonded_returnsFalse() {
- `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_NONE)
- `when`(bluetoothDevice.isConnected).thenReturn(true)
- audioManager.setMode(AudioManager.MODE_NORMAL)
-
- assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
- .isFalse()
- }
-
- @Test
- @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
fun testConnectedFactory_isFilterMatched_notExclusivelyManaged_notConnected_returnsFalse() {
- `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
- `when`(bluetoothDevice.isConnected).thenReturn(false)
- audioManager.setMode(AudioManager.MODE_NORMAL)
+ `when`(cachedDevice.device).thenReturn(bluetoothDevice)
+ `when`(BluetoothUtils.isExclusivelyManagedBluetoothDevice(any(), any())).thenReturn(false)
+ `when`(BluetoothUtils.isConnectedBluetoothDevice(any(), any())).thenReturn(false)
assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
.isFalse()
@@ -310,7 +314,5 @@
companion object {
const val DEVICE_NAME = "DeviceName"
const val CONNECTION_SUMMARY = "ConnectionSummary"
- private const val TEST_EXCLUSIVE_MANAGER = "com.test.manager"
- private const val DEVICE_ADDRESS = "04:52:C7:0B:D8:3C"
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt
index 73b9f57..07f7557 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt
@@ -47,8 +47,11 @@
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory
import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
-import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
+import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
+import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
+import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.keyguard.shared.quickaffordance.ActivationState
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancePosition
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancesMetricsLogger
@@ -56,7 +59,10 @@
import com.android.systemui.kosmos.testScope
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.res.R
+import com.android.systemui.scene.data.repository.Idle
+import com.android.systemui.scene.data.repository.setTransition
import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker
import com.android.systemui.shade.domain.interactor.ShadeInteractor
@@ -144,7 +150,6 @@
@Mock
private lateinit var glanceableHubToLockscreenTransitionViewModel:
GlanceableHubToLockscreenTransitionViewModel
- @Mock private lateinit var transitionInteractor: KeyguardTransitionInteractor
private val kosmos = testKosmos()
@@ -163,8 +168,6 @@
// the viewModel does a `map { 1 - it }` on this value, which is why it's different
private val intendedShadeAlphaMutableStateFlow: MutableStateFlow<Float> = MutableStateFlow(0f)
- private val intendedFinishedKeyguardStateFlow = MutableStateFlow(KeyguardState.LOCKSCREEN)
-
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
@@ -256,7 +259,6 @@
intendedAlphaMutableStateFlow.value = 1f
intendedShadeAlphaMutableStateFlow.value = 0f
- intendedFinishedKeyguardStateFlow.value = KeyguardState.LOCKSCREEN
whenever(aodToLockscreenTransitionViewModel.shortcutsAlpha)
.thenReturn(intendedAlphaMutableStateFlow)
whenever(dozingToLockscreenTransitionViewModel.shortcutsAlpha).thenReturn(emptyFlow())
@@ -283,8 +285,6 @@
whenever(glanceableHubToLockscreenTransitionViewModel.shortcutsAlpha)
.thenReturn(emptyFlow())
whenever(shadeInteractor.anyExpansion).thenReturn(intendedShadeAlphaMutableStateFlow)
- whenever(transitionInteractor.finishedKeyguardState)
- .thenReturn(intendedFinishedKeyguardStateFlow)
underTest =
KeyguardQuickAffordancesCombinedViewModel(
@@ -334,7 +334,7 @@
lockscreenToPrimaryBouncerTransitionViewModel,
lockscreenToGlanceableHubTransitionViewModel =
lockscreenToGlanceableHubTransitionViewModel,
- transitionInteractor = transitionInteractor,
+ transitionInteractor = kosmos.keyguardTransitionInteractor,
)
}
@@ -776,7 +776,10 @@
@Test
fun shadeExpansionAlpha_changes_whenOnLockscreen() =
testScope.runTest {
- intendedFinishedKeyguardStateFlow.value = KeyguardState.LOCKSCREEN
+ kosmos.setTransition(
+ sceneTransition = Idle(Scenes.Lockscreen),
+ stateTransition = TransitionStep(from = AOD, to = LOCKSCREEN)
+ )
intendedShadeAlphaMutableStateFlow.value = 0.25f
val underTest = collectLastValue(underTest.transitionAlpha)
assertEquals(0.75f, underTest())
@@ -788,7 +791,10 @@
@Test
fun shadeExpansionAlpha_alwaysZero_whenNotOnLockscreen() =
testScope.runTest {
- intendedFinishedKeyguardStateFlow.value = KeyguardState.GONE
+ kosmos.setTransition(
+ sceneTransition = Idle(Scenes.Gone),
+ stateTransition = TransitionStep(from = AOD, to = GONE)
+ )
intendedShadeAlphaMutableStateFlow.value = 0.5f
val underTest = collectLastValue(underTest.transitionAlpha)
assertEquals(0f, underTest())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index 523d15c..9481e5a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -155,7 +155,6 @@
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinatorLogger;
import com.android.systemui.statusbar.notification.data.repository.NotificationsKeyguardViewStateRepository;
import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor;
-import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationInteractor;
import com.android.systemui.statusbar.notification.domain.interactor.NotificationsKeyguardInteractor;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.stack.AmbientState;
@@ -163,7 +162,6 @@
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator;
-import com.android.systemui.statusbar.notification.stack.data.repository.FakeHeadsUpNotificationRepository;
import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor;
import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
@@ -365,13 +363,6 @@
protected TestScope mTestScope = mKosmos.getTestScope();
protected ShadeInteractor mShadeInteractor;
protected PowerInteractor mPowerInteractor;
- protected FakeHeadsUpNotificationRepository mFakeHeadsUpNotificationRepository =
- new FakeHeadsUpNotificationRepository();
- protected NotificationsKeyguardViewStateRepository mNotificationsKeyguardViewStateRepository =
- new NotificationsKeyguardViewStateRepository();
- protected NotificationsKeyguardInteractor mNotificationsKeyguardInteractor =
- new NotificationsKeyguardInteractor(mNotificationsKeyguardViewStateRepository);
- protected HeadsUpNotificationInteractor mHeadsUpNotificationInteractor;
protected NotificationPanelViewController.TouchHandler mTouchHandler;
protected ConfigurationController mConfigurationController;
protected SysuiStatusBarStateController mStatusBarStateController;
@@ -689,12 +680,6 @@
when(longPressHandlingView.getResources()).thenReturn(longPressHandlingViewRes);
when(longPressHandlingViewRes.getString(anyInt())).thenReturn("");
-
- mHeadsUpNotificationInteractor =
- new HeadsUpNotificationInteractor(mFakeHeadsUpNotificationRepository,
- mDeviceEntryFaceAuthInteractor, mKeyguardTransitionInteractor,
- mNotificationsKeyguardInteractor, mShadeInteractor);
-
mNotificationPanelViewController = new NotificationPanelViewController(
mView,
mMainHandler,
@@ -769,7 +754,6 @@
mActivityStarter,
mSharedNotificationContainerInteractor,
mActiveNotificationsInteractor,
- mHeadsUpNotificationInteractor,
mShadeAnimationInteractor,
mKeyguardViewConfigurator,
mDeviceEntryFaceAuthInteractor,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
index 905cc4c..a7fd160 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
@@ -58,13 +58,13 @@
import androidx.test.filters.SmallTest;
import com.android.systemui.DejankUtils;
+import com.android.systemui.flags.DisableSceneContainer;
import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.power.domain.interactor.PowerInteractor;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.notification.row.ExpandableView.OnHeightChangedListener;
-import com.android.systemui.statusbar.notification.shared.NotificationsHeadsUpRefactor;
import com.android.systemui.statusbar.notification.stack.AmbientState;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
import com.android.systemui.statusbar.phone.KeyguardClockPositionAlgorithm;
@@ -1375,7 +1375,7 @@
}
@Test
- @DisableFlags(NotificationsHeadsUpRefactor.FLAG_NAME)
+ @DisableSceneContainer
public void shadeExpanded_whenHunIsPresent() {
when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true);
assertThat(mNotificationPanelViewController.isExpanded()).isTrue();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerWithCoroutinesTest.kt
index 64eadb7..90655c3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerWithCoroutinesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerWithCoroutinesTest.kt
@@ -19,7 +19,6 @@
package com.android.systemui.shade
import android.platform.test.annotations.DisableFlags
-import android.platform.test.annotations.EnableFlags
import android.testing.TestableLooper
import android.view.HapticFeedbackConstants
import android.view.View
@@ -35,7 +34,6 @@
import com.android.systemui.statusbar.StatusBarState.SHADE
import com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED
import com.android.systemui.statusbar.notification.data.repository.FakeHeadsUpRowRepository
-import com.android.systemui.statusbar.notification.shared.NotificationsHeadsUpRefactor
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
@@ -243,36 +241,4 @@
val bottomAreaAlpha by collectLastValue(mFakeKeyguardRepository.bottomAreaAlpha)
assertThat(bottomAreaAlpha).isEqualTo(1f)
}
-
- @Test
- @EnableFlags(NotificationsHeadsUpRefactor.FLAG_NAME)
- fun shadeExpanded_whenHunIsPresent() = runTest {
- launch(mainDispatcher) {
- givenViewAttached()
-
- // WHEN a pinned heads up is present
- mFakeHeadsUpNotificationRepository.setNotifications(
- FakeHeadsUpRowRepository("key", isPinned = true)
- )
- }
- advanceUntilIdle()
-
- // THEN the panel should be visible
- assertThat(mNotificationPanelViewController.isExpanded).isTrue()
- }
-
- @Test
- @EnableFlags(NotificationsHeadsUpRefactor.FLAG_NAME)
- fun shadeExpanded_whenHunIsAnimatingAway() = runTest {
- launch(mainDispatcher) {
- givenViewAttached()
-
- // WHEN a heads up is animating away
- mFakeHeadsUpNotificationRepository.isHeadsUpAnimatingAway.value = true
- }
- advanceUntilIdle()
-
- // THEN the panel should be visible
- assertThat(mNotificationPanelViewController.isExpanded).isTrue()
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt
index ce79fbd..7bc6d4a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt
@@ -132,10 +132,10 @@
)
assertThat((latest as OngoingActivityChipModel.Shown).icon)
- .isInstanceOf(OngoingActivityChipModel.ChipIcon.Basic::class.java)
+ .isInstanceOf(OngoingActivityChipModel.ChipIcon.SingleColorIcon::class.java)
val icon =
(((latest as OngoingActivityChipModel.Shown).icon)
- as OngoingActivityChipModel.ChipIcon.Basic)
+ as OngoingActivityChipModel.ChipIcon.SingleColorIcon)
.impl as Icon.Resource
assertThat(icon.res).isEqualTo(com.android.internal.R.drawable.ic_phone)
assertThat(icon.contentDescription).isNotNull()
@@ -170,10 +170,10 @@
)
assertThat((latest as OngoingActivityChipModel.Shown).icon)
- .isInstanceOf(OngoingActivityChipModel.ChipIcon.Basic::class.java)
+ .isInstanceOf(OngoingActivityChipModel.ChipIcon.SingleColorIcon::class.java)
val icon =
(((latest as OngoingActivityChipModel.Shown).icon)
- as OngoingActivityChipModel.ChipIcon.Basic)
+ as OngoingActivityChipModel.ChipIcon.SingleColorIcon)
.impl as Icon.Resource
assertThat(icon.res).isEqualTo(com.android.internal.R.drawable.ic_phone)
assertThat(icon.contentDescription).isNotNull()
@@ -206,10 +206,10 @@
repo.setOngoingCallState(inCallModel(startTimeMs = 1000, notificationIcon = null))
assertThat((latest as OngoingActivityChipModel.Shown).icon)
- .isInstanceOf(OngoingActivityChipModel.ChipIcon.Basic::class.java)
+ .isInstanceOf(OngoingActivityChipModel.ChipIcon.SingleColorIcon::class.java)
val icon =
(((latest as OngoingActivityChipModel.Shown).icon)
- as OngoingActivityChipModel.ChipIcon.Basic)
+ as OngoingActivityChipModel.ChipIcon.SingleColorIcon)
.impl as Icon.Resource
assertThat(icon.res).isEqualTo(com.android.internal.R.drawable.ic_phone)
assertThat(icon.contentDescription).isNotNull()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModelTest.kt
index a8d2c5b..77992db 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModelTest.kt
@@ -127,7 +127,7 @@
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown.Timer::class.java)
val icon =
(((latest as OngoingActivityChipModel.Shown).icon)
- as OngoingActivityChipModel.ChipIcon.Basic)
+ as OngoingActivityChipModel.ChipIcon.SingleColorIcon)
.impl as Icon.Resource
assertThat(icon.res).isEqualTo(R.drawable.ic_cast_connected)
assertThat((icon.contentDescription as ContentDescription.Resource).res)
@@ -146,7 +146,7 @@
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown.Timer::class.java)
val icon =
(((latest as OngoingActivityChipModel.Shown).icon)
- as OngoingActivityChipModel.ChipIcon.Basic)
+ as OngoingActivityChipModel.ChipIcon.SingleColorIcon)
.impl as Icon.Resource
assertThat(icon.res).isEqualTo(R.drawable.ic_cast_connected)
assertThat((icon.contentDescription as ContentDescription.Resource).res)
@@ -184,7 +184,7 @@
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown.IconOnly::class.java)
val icon =
(((latest as OngoingActivityChipModel.Shown).icon)
- as OngoingActivityChipModel.ChipIcon.Basic)
+ as OngoingActivityChipModel.ChipIcon.SingleColorIcon)
.impl as Icon.Resource
assertThat(icon.res).isEqualTo(R.drawable.ic_cast_connected)
// This content description is just generic "Casting", not "Casting screen"
@@ -214,7 +214,7 @@
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown.Timer::class.java)
val icon =
(((latest as OngoingActivityChipModel.Shown).icon)
- as OngoingActivityChipModel.ChipIcon.Basic)
+ as OngoingActivityChipModel.ChipIcon.SingleColorIcon)
.impl as Icon.Resource
assertThat(icon.res).isEqualTo(R.drawable.ic_cast_connected)
// MediaProjection == screen casting, so this content description reflects that we're
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ron/demo/ui/viewmodel/DemoRonChipViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ron/demo/ui/viewmodel/DemoRonChipViewModelTest.kt
new file mode 100644
index 0000000..8576893
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ron/demo/ui/viewmodel/DemoRonChipViewModelTest.kt
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.chips.ron.demo.ui.viewmodel
+
+import android.content.packageManager
+import android.graphics.drawable.BitmapDrawable
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import androidx.test.filters.SmallTest
+import com.android.systemui.Flags.FLAG_STATUS_BAR_RON_CHIPS
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
+import com.android.systemui.statusbar.commandline.CommandRegistry
+import com.android.systemui.statusbar.commandline.commandRegistry
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import java.io.PrintWriter
+import java.io.StringWriter
+import kotlin.test.Test
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.mockito.kotlin.any
+import org.mockito.kotlin.whenever
+
+@SmallTest
+class DemoRonChipViewModelTest : SysuiTestCase() {
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+ private val commandRegistry = kosmos.commandRegistry
+ private val pw = PrintWriter(StringWriter())
+
+ private val underTest = kosmos.demoRonChipViewModel
+
+ @Before
+ fun setUp() {
+ underTest.start()
+ whenever(kosmos.packageManager.getApplicationIcon(any<String>()))
+ .thenReturn(BitmapDrawable())
+ }
+
+ @Test
+ @DisableFlags(FLAG_STATUS_BAR_RON_CHIPS)
+ fun chip_flagOff_hidden() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.chip)
+
+ addDemoRonChip()
+
+ assertThat(latest).isInstanceOf(OngoingActivityChipModel.Hidden::class.java)
+ }
+
+ @Test
+ @EnableFlags(FLAG_STATUS_BAR_RON_CHIPS)
+ fun chip_noPackage_hidden() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.chip)
+
+ commandRegistry.onShellCommand(pw, arrayOf("demo-ron"))
+
+ assertThat(latest).isInstanceOf(OngoingActivityChipModel.Hidden::class.java)
+ }
+
+ @Test
+ @EnableFlags(FLAG_STATUS_BAR_RON_CHIPS)
+ fun chip_hasPackage_shown() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.chip)
+
+ commandRegistry.onShellCommand(pw, arrayOf("demo-ron", "-p", "com.android.systemui"))
+
+ assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
+ }
+
+ @Test
+ @EnableFlags(FLAG_STATUS_BAR_RON_CHIPS)
+ fun chip_hasText_shownWithText() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.chip)
+
+ commandRegistry.onShellCommand(
+ pw,
+ arrayOf("demo-ron", "-p", "com.android.systemui", "-t", "test")
+ )
+
+ assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown.Text::class.java)
+ }
+
+ @Test
+ @EnableFlags(FLAG_STATUS_BAR_RON_CHIPS)
+ fun chip_hasHideArg_hidden() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.chip)
+
+ // First, show a chip
+ addDemoRonChip()
+ assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
+
+ // Then, hide the chip
+ commandRegistry.onShellCommand(pw, arrayOf("demo-ron", "--hide"))
+
+ assertThat(latest).isInstanceOf(OngoingActivityChipModel.Hidden::class.java)
+ }
+
+ private fun addDemoRonChip() {
+ Companion.addDemoRonChip(commandRegistry, pw)
+ }
+
+ companion object {
+ fun addDemoRonChip(commandRegistry: CommandRegistry, pw: PrintWriter) {
+ commandRegistry.onShellCommand(pw, arrayOf("demo-ron", "-p", "com.android.systemui"))
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModelTest.kt
index 804eb5c..16101bf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModelTest.kt
@@ -150,7 +150,7 @@
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown.Timer::class.java)
val icon =
(((latest as OngoingActivityChipModel.Shown).icon)
- as OngoingActivityChipModel.ChipIcon.Basic)
+ as OngoingActivityChipModel.ChipIcon.SingleColorIcon)
.impl as Icon.Resource
assertThat(icon.res).isEqualTo(R.drawable.ic_screenrecord)
assertThat(icon.contentDescription).isNotNull()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModelTest.kt
index a2ef599..791a21d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModelTest.kt
@@ -135,7 +135,7 @@
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown.Timer::class.java)
val icon =
(((latest as OngoingActivityChipModel.Shown).icon)
- as OngoingActivityChipModel.ChipIcon.Basic)
+ as OngoingActivityChipModel.ChipIcon.SingleColorIcon)
.impl as Icon.Resource
assertThat(icon.res).isEqualTo(R.drawable.ic_present_to_all)
assertThat(icon.contentDescription).isNotNull()
@@ -152,7 +152,7 @@
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown.Timer::class.java)
val icon =
(((latest as OngoingActivityChipModel.Shown).icon)
- as OngoingActivityChipModel.ChipIcon.Basic)
+ as OngoingActivityChipModel.ChipIcon.SingleColorIcon)
.impl as Icon.Resource
assertThat(icon.res).isEqualTo(R.drawable.ic_present_to_all)
assertThat(icon.contentDescription).isNotNull()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/ChipTransitionHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/ChipTransitionHelperTest.kt
index a724cfaa..4977c548 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/ChipTransitionHelperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/ChipTransitionHelperTest.kt
@@ -154,5 +154,7 @@
}
private fun createIcon(@DrawableRes drawable: Int) =
- OngoingActivityChipModel.ChipIcon.Basic(Icon.Resource(drawable, contentDescription = null))
+ OngoingActivityChipModel.ChipIcon.SingleColorIcon(
+ Icon.Resource(drawable, contentDescription = null)
+ )
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
index 556ec6a..bd5df07 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
@@ -19,9 +19,12 @@
import android.content.DialogInterface
import android.content.packageManager
import android.content.pm.PackageManager
+import android.graphics.drawable.BitmapDrawable
+import android.platform.test.annotations.EnableFlags
import android.view.View
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.systemui.Flags.FLAG_STATUS_BAR_RON_CHIPS
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.coroutines.collectLastValue
@@ -36,8 +39,11 @@
import com.android.systemui.screenrecord.data.repository.screenRecordRepository
import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractorTest.Companion.NORMAL_PACKAGE
import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractorTest.Companion.setUpPackageManagerForMediaProjection
+import com.android.systemui.statusbar.chips.ron.demo.ui.viewmodel.DemoRonChipViewModelTest.Companion.addDemoRonChip
+import com.android.systemui.statusbar.chips.ron.demo.ui.viewmodel.demoRonChipViewModel
import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer
+import com.android.systemui.statusbar.commandline.commandRegistry
import com.android.systemui.statusbar.phone.SystemUIDialog
import com.android.systemui.statusbar.phone.mockSystemUIDialogFactory
import com.android.systemui.statusbar.phone.ongoingcall.data.repository.ongoingCallRepository
@@ -45,6 +51,8 @@
import com.android.systemui.statusbar.phone.ongoingcall.shared.model.inCallModel
import com.android.systemui.util.time.fakeSystemClock
import com.google.common.truth.Truth.assertThat
+import java.io.PrintWriter
+import java.io.StringWriter
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
@@ -68,11 +76,14 @@
private val kosmos = Kosmos().also { it.testCase = this }
private val testScope = kosmos.testScope
private val systemClock = kosmos.fakeSystemClock
+ private val commandRegistry = kosmos.commandRegistry
private val screenRecordState = kosmos.screenRecordRepository.screenRecordState
private val mediaProjectionState = kosmos.fakeMediaProjectionRepository.mediaProjectionState
private val callRepo = kosmos.ongoingCallRepository
+ private val pw = PrintWriter(StringWriter())
+
private val mockSystemUIDialog = mock<SystemUIDialog>()
private val chipBackgroundView = mock<ChipBackgroundContainer>()
private val chipView =
@@ -90,6 +101,9 @@
@Before
fun setUp() {
setUpPackageManagerForMediaProjection(kosmos)
+ kosmos.demoRonChipViewModel.start()
+ whenever(kosmos.packageManager.getApplicationIcon(any<String>()))
+ .thenReturn(BitmapDrawable())
}
@Test
@@ -169,15 +183,24 @@
}
@Test
+ @EnableFlags(FLAG_STATUS_BAR_RON_CHIPS)
fun chip_higherPriorityChipAdded_lowerPriorityChipReplaced() =
testScope.runTest {
- // Start with just the lower priority call chip
- callRepo.setOngoingCallState(inCallModel(startTimeMs = 34))
+ // Start with just the lowest priority chip shown
+ addDemoRonChip(commandRegistry, pw)
+ // And everything else hidden
+ callRepo.setOngoingCallState(OngoingCallModel.NoCall)
mediaProjectionState.value = MediaProjectionState.NotProjecting
screenRecordState.value = ScreenRecordModel.DoingNothing
val latest by collectLastValue(underTest.chip)
+ assertIsDemoRonChip(latest)
+
+ // WHEN the higher priority call chip is added
+ callRepo.setOngoingCallState(inCallModel(startTimeMs = 34))
+
+ // THEN the higher priority call chip is used
assertIsCallChip(latest)
// WHEN the higher priority media projection chip is added
@@ -199,14 +222,15 @@
}
@Test
+ @EnableFlags(FLAG_STATUS_BAR_RON_CHIPS)
fun chip_highestPriorityChipRemoved_showsNextPriorityChip() =
testScope.runTest {
// WHEN all chips are active
screenRecordState.value = ScreenRecordModel.Recording
mediaProjectionState.value =
MediaProjectionState.Projecting.EntireScreen(NORMAL_PACKAGE)
-
callRepo.setOngoingCallState(inCallModel(startTimeMs = 34))
+ addDemoRonChip(commandRegistry, pw)
val latest by collectLastValue(underTest.chip)
@@ -224,6 +248,12 @@
// THEN the lower priority call is used
assertIsCallChip(latest)
+
+ // WHEN the higher priority call is removed
+ callRepo.setOngoingCallState(OngoingCallModel.NoCall)
+
+ // THEN the lower priority demo RON is used
+ assertIsDemoRonChip(latest)
}
/** Regression test for b/347726238. */
@@ -338,7 +368,7 @@
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
val icon =
(((latest as OngoingActivityChipModel.Shown).icon)
- as OngoingActivityChipModel.ChipIcon.Basic)
+ as OngoingActivityChipModel.ChipIcon.SingleColorIcon)
.impl as Icon.Resource
assertThat(icon.res).isEqualTo(R.drawable.ic_screenrecord)
}
@@ -347,7 +377,7 @@
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
val icon =
(((latest as OngoingActivityChipModel.Shown).icon)
- as OngoingActivityChipModel.ChipIcon.Basic)
+ as OngoingActivityChipModel.ChipIcon.SingleColorIcon)
.impl as Icon.Resource
assertThat(icon.res).isEqualTo(R.drawable.ic_present_to_all)
}
@@ -356,9 +386,15 @@
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
val icon =
(((latest as OngoingActivityChipModel.Shown).icon)
- as OngoingActivityChipModel.ChipIcon.Basic)
+ as OngoingActivityChipModel.ChipIcon.SingleColorIcon)
.impl as Icon.Resource
assertThat(icon.res).isEqualTo(com.android.internal.R.drawable.ic_phone)
}
+
+ fun assertIsDemoRonChip(latest: OngoingActivityChipModel?) {
+ assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
+ assertThat((latest as OngoingActivityChipModel.Shown).icon)
+ .isInstanceOf(OngoingActivityChipModel.ChipIcon.FullColorAppIcon::class.java)
+ }
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 1717f4c..8d1228c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -95,7 +95,6 @@
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun;
-import com.android.systemui.statusbar.notification.shared.NotificationsHeadsUpRefactor;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -1206,7 +1205,7 @@
@Test
- @EnableFlags(NotificationsHeadsUpRefactor.FLAG_NAME)
+ @EnableSceneContainer
public void testGenerateHeadsUpDisappearEvent_setsHeadsUpAnimatingAway() {
// GIVEN NSSL is ready for HUN animations
Consumer<Boolean> headsUpAnimatingAwayListener = mock(BooleanConsumer.class);
@@ -1222,7 +1221,7 @@
}
@Test
- @EnableFlags(NotificationsHeadsUpRefactor.FLAG_NAME)
+ @EnableSceneContainer
public void testGenerateHeadsUpDisappearEvent_stackExpanded_headsUpAnimatingAwayNotSet() {
// GIVEN NSSL would be ready for HUN animations, BUT it is expanded
Consumer<Boolean> headsUpAnimatingAwayListener = mock(BooleanConsumer.class);
@@ -1241,7 +1240,7 @@
}
@Test
- @EnableFlags(NotificationsHeadsUpRefactor.FLAG_NAME)
+ @EnableSceneContainer
public void testGenerateHeadsUpDisappearEvent_pendingAppearEvent_headsUpAnimatingAwayNotSet() {
// GIVEN NSSL is ready for HUN animations
Consumer<Boolean> headsUpAnimatingAwayListener = mock(BooleanConsumer.class);
@@ -1259,7 +1258,7 @@
}
@Test
- @EnableFlags(NotificationsHeadsUpRefactor.FLAG_NAME)
+ @EnableSceneContainer
public void testGenerateHeadsUpAppearEvent_headsUpAnimatingAwayNotSet() {
// GIVEN NSSL is ready for HUN animations
Consumer<Boolean> headsUpAnimatingAwayListener = mock(BooleanConsumer.class);
@@ -1295,7 +1294,7 @@
}
@Test
- @EnableFlags(NotificationsHeadsUpRefactor.FLAG_NAME)
+ @EnableSceneContainer
public void testOnChildAnimationsFinished_resetsheadsUpAnimatingAway() {
// GIVEN NSSL is ready for HUN animations
Consumer<Boolean> headsUpAnimatingAwayListener = mock(BooleanConsumer.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt
index 12cfdcf..e396b56 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt
@@ -16,11 +16,11 @@
package com.android.systemui.statusbar.ui.viewmodel
-import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.FlagsParameterization
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.flags.andSceneContainer
import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFaceAuthRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
@@ -33,7 +33,6 @@
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.statusbar.domain.interactor.keyguardStatusBarInteractor
import com.android.systemui.statusbar.notification.data.repository.FakeHeadsUpRowRepository
-import com.android.systemui.statusbar.notification.shared.NotificationsHeadsUpRefactor
import com.android.systemui.statusbar.notification.stack.data.repository.headsUpNotificationRepository
import com.android.systemui.statusbar.notification.stack.domain.interactor.headsUpNotificationInteractor
import com.android.systemui.statusbar.policy.BatteryController
@@ -127,7 +126,7 @@
}
@Test
- @EnableFlags(NotificationsHeadsUpRefactor.FLAG_NAME)
+ @EnableSceneContainer
fun isVisible_headsUpStatusBarShown_false() =
testScope.runTest {
val latest by collectLastValue(underTest.isVisible)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
index caa1779..1e2648b22 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
@@ -257,13 +257,13 @@
private State createShellState() {
State state = new VolumeDialogController.State();
- for (int i = AudioManager.STREAM_VOICE_CALL; i <= AudioManager.STREAM_ACCESSIBILITY; i++) {
+ for (int stream : STREAMS.keySet()) {
VolumeDialogController.StreamState ss = new VolumeDialogController.StreamState();
- ss.name = STREAMS.get(i);
+ ss.name = STREAMS.get(stream);
ss.level = 1;
ss.levelMin = 0;
ss.levelMax = 25;
- state.states.append(i, ss);
+ state.states.append(stream, ss);
}
return state;
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/EnableSceneContainer.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/EnableSceneContainer.kt
index 1107971..c252924 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/EnableSceneContainer.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/EnableSceneContainer.kt
@@ -22,7 +22,7 @@
import com.android.systemui.Flags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR
import com.android.systemui.Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR
import com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT
-import com.android.systemui.Flags.FLAG_NOTIFICATIONS_HEADS_UP_REFACTOR
+import com.android.systemui.Flags.FLAG_NOTIFICATION_AVALANCHE_THROTTLE_HUN
import com.android.systemui.Flags.FLAG_PREDICTIVE_BACK_SYSUI
import com.android.systemui.Flags.FLAG_SCENE_CONTAINER
@@ -35,7 +35,7 @@
FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR,
FLAG_KEYGUARD_WM_STATE_REFACTOR,
FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT,
- FLAG_NOTIFICATIONS_HEADS_UP_REFACTOR,
+ FLAG_NOTIFICATION_AVALANCHE_THROTTLE_HUN,
FLAG_PREDICTIVE_BACK_SYSUI,
FLAG_SCENE_CONTAINER,
FLAG_DEVICE_ENTRY_UDFPS_REFACTOR,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ron/demo/ui/viewmodel/DemoRonChipViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ron/demo/ui/viewmodel/DemoRonChipViewModelKosmos.kt
new file mode 100644
index 0000000..c0d65a0
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ron/demo/ui/viewmodel/DemoRonChipViewModelKosmos.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.chips.ron.demo.ui.viewmodel
+
+import android.content.packageManager
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.statusbar.commandline.commandRegistry
+import com.android.systemui.util.time.fakeSystemClock
+
+val Kosmos.demoRonChipViewModel: DemoRonChipViewModel by
+ Kosmos.Fixture {
+ DemoRonChipViewModel(
+ commandRegistry = commandRegistry,
+ packageManager = packageManager,
+ systemClock = fakeSystemClock,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelKosmos.kt
index 16e288f..5382c1c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelKosmos.kt
@@ -20,6 +20,7 @@
import com.android.systemui.kosmos.testScope
import com.android.systemui.statusbar.chips.call.ui.viewmodel.callChipViewModel
import com.android.systemui.statusbar.chips.casttootherdevice.ui.viewmodel.castToOtherDeviceChipViewModel
+import com.android.systemui.statusbar.chips.ron.demo.ui.viewmodel.demoRonChipViewModel
import com.android.systemui.statusbar.chips.screenrecord.ui.viewmodel.screenRecordChipViewModel
import com.android.systemui.statusbar.chips.sharetoapp.ui.viewmodel.shareToAppChipViewModel
import com.android.systemui.statusbar.chips.statusBarChipsLogger
@@ -32,6 +33,7 @@
shareToAppChipViewModel = shareToAppChipViewModel,
castToOtherDeviceChipViewModel = castToOtherDeviceChipViewModel,
callChipViewModel = callChipViewModel,
+ demoRonChipViewModel = demoRonChipViewModel,
logger = statusBarChipsLogger,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/commandline/CommandRegistryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/commandline/CommandRegistryKosmos.kt
new file mode 100644
index 0000000..14777b4
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/commandline/CommandRegistryKosmos.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.commandline
+
+import android.content.applicationContext
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.commandRegistry: CommandRegistry by
+ Kosmos.Fixture {
+ CommandRegistry(
+ context = applicationContext,
+ // Immediately run anything that comes in
+ mainExecutor = { command -> command.run() },
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/domain/interactor/AudioSlidersInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/domain/interactor/AudioSlidersInteractorKosmos.kt
index 63386d0..dd5bbf3 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/domain/interactor/AudioSlidersInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/domain/interactor/AudioSlidersInteractorKosmos.kt
@@ -18,7 +18,6 @@
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
-import com.android.systemui.volume.data.repository.audioRepository
import com.android.systemui.volume.domain.interactor.audioModeInteractor
import com.android.systemui.volume.mediaOutputInteractor
@@ -27,7 +26,6 @@
AudioSlidersInteractor(
applicationCoroutineScope,
mediaOutputInteractor,
- audioRepository,
audioModeInteractor,
)
}
diff --git a/services/companion/Android.bp b/services/companion/Android.bp
index 2bfdd0a..77650eb 100644
--- a/services/companion/Android.bp
+++ b/services/companion/Android.bp
@@ -28,7 +28,6 @@
],
static_libs: [
"ukey2_jni",
- "virtualdevice_flags_lib",
"virtual_camera_service_aidl-java",
],
lint: {
diff --git a/services/companion/java/com/android/server/companion/virtual/Android.bp b/services/companion/java/com/android/server/companion/virtual/Android.bp
deleted file mode 100644
index 66313e6..0000000
--- a/services/companion/java/com/android/server/companion/virtual/Android.bp
+++ /dev/null
@@ -1,17 +0,0 @@
-package {
- default_team: "trendy_team_xr_framework",
-}
-
-java_aconfig_library {
- name: "virtualdevice_flags_lib",
- aconfig_declarations: "virtualdevice_flags",
-}
-
-aconfig_declarations {
- name: "virtualdevice_flags",
- package: "com.android.server.companion.virtual",
- container: "system",
- srcs: [
- "flags.aconfig",
- ],
-}
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceLog.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceLog.java
index b0bacfd..fed153f 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceLog.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceLog.java
@@ -48,9 +48,6 @@
void logCreated(int deviceId, int ownerUid) {
final long token = Binder.clearCallingIdentity();
try {
- if (!Flags.dumpHistory()) {
- return;
- }
addEntry(new LogEntry(TYPE_CREATED, deviceId, System.currentTimeMillis(), ownerUid));
} finally {
Binder.restoreCallingIdentity(token);
@@ -60,9 +57,6 @@
void logClosed(int deviceId, int ownerUid) {
final long token = Binder.clearCallingIdentity();
try {
- if (!Flags.dumpHistory()) {
- return;
- }
addEntry(new LogEntry(TYPE_CLOSED, deviceId, System.currentTimeMillis(), ownerUid));
} finally {
Binder.restoreCallingIdentity(token);
@@ -79,9 +73,6 @@
void dump(PrintWriter pw) {
final long token = Binder.clearCallingIdentity();
try {
- if (!Flags.dumpHistory()) {
- return;
- }
pw.println("VirtualDevice Log:");
UidToPackageNameCache packageNameCache = new UidToPackageNameCache(
mContext.getPackageManager());
diff --git a/services/companion/java/com/android/server/companion/virtual/flags.aconfig b/services/companion/java/com/android/server/companion/virtual/flags.aconfig
deleted file mode 100644
index 616f5d0..0000000
--- a/services/companion/java/com/android/server/companion/virtual/flags.aconfig
+++ /dev/null
@@ -1,11 +0,0 @@
-# OLD PACKAGE, DO NOT USE: Prefer `flags.aconfig` in core/java/android/companion/virtual
-# (or other custom files) to define your flags
-package: "com.android.server.companion.virtual"
-container: "system"
-
-flag {
- name: "dump_history"
- namespace: "virtual_devices"
- description: "This flag controls if a history of virtual devices is shown in dumpsys virtualdevices"
- bug: "293114719"
-}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index d80b38e..d121535 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -16248,43 +16248,55 @@
boolean closeFd = true;
try {
- synchronized (mProcLock) {
- if (fd == null) {
- throw new IllegalArgumentException("null fd");
- }
- mBinderTransactionTrackingEnabled = false;
+ Objects.requireNonNull(fd);
- PrintWriter pw = new FastPrintWriter(new FileOutputStream(fd.getFileDescriptor()));
- pw.println("Binder transaction traces for all processes.\n");
- mProcessList.forEachLruProcessesLOSP(true, process -> {
+ record ProcessToDump(String processName, IApplicationThread thread) { }
+
+ PrintWriter pw = new FastPrintWriter(new FileOutputStream(fd.getFileDescriptor()));
+ pw.println("Binder transaction traces for all processes.\n");
+ final ArrayList<ProcessToDump> processes = new ArrayList<>();
+ synchronized (mProcLock) {
+ // Since dumping binder transactions is a long-running operation, we can't do it
+ // with mProcLock held. Do the initial verification here, and save the processes
+ // to dump later outside the lock.
+ final ArrayList<ProcessRecord> unverifiedProcesses =
+ new ArrayList<>(mProcessList.getLruProcessesLOSP());
+ for (int i = 0, size = unverifiedProcesses.size(); i < size; i++) {
+ ProcessRecord process = unverifiedProcesses.get(i);
final IApplicationThread thread = process.getThread();
if (!processSanityChecksLPr(process, thread)) {
- return;
+ continue;
}
-
- pw.println("Traces for process: " + process.processName);
- pw.flush();
- try {
- TransferPipe tp = new TransferPipe();
- try {
- thread.stopBinderTrackingAndDump(tp.getWriteFd());
- tp.go(fd.getFileDescriptor());
- } finally {
- tp.kill();
- }
- } catch (IOException e) {
- pw.println("Failure while dumping IPC traces from " + process +
- ". Exception: " + e);
- pw.flush();
- } catch (RemoteException e) {
- pw.println("Got a RemoteException while dumping IPC traces from " +
- process + ". Exception: " + e);
- pw.flush();
- }
- });
- closeFd = false;
- return true;
+ processes.add(new ProcessToDump(process.processName, process.getThread()));
+ }
+ mBinderTransactionTrackingEnabled = false;
}
+ for (int i = 0, size = processes.size(); i < size; i++) {
+ final String processName = processes.get(i).processName();
+ final IApplicationThread thread = processes.get(i).thread();
+
+ pw.println("Traces for process: " + processName);
+ pw.flush();
+ try {
+ TransferPipe tp = new TransferPipe();
+ try {
+ thread.stopBinderTrackingAndDump(tp.getWriteFd());
+ tp.go(fd.getFileDescriptor());
+ } finally {
+ tp.kill();
+ }
+ } catch (IOException e) {
+ pw.println("Failure while dumping IPC traces from " + processName +
+ ". Exception: " + e);
+ pw.flush();
+ } catch (RemoteException e) {
+ pw.println("Got a RemoteException while dumping IPC traces from " +
+ processName + ". Exception: " + e);
+ pw.flush();
+ }
+ }
+ closeFd = false;
+ return true;
} finally {
if (fd != null && closeFd) {
try {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index b738482..168ec05 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -790,8 +790,7 @@
private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
private final Executor mAudioServerLifecycleExecutor;
- private final ConcurrentLinkedQueue<Future> mScheduledPermissionTasks =
- new ConcurrentLinkedQueue();
+ private final List<Future> mScheduledPermissionTasks = new ArrayList();
private IMediaProjectionManager mProjectionService; // to validate projection token
@@ -10600,46 +10599,50 @@
// instanceof to simplify the construction requirements of AudioService for testing: no
// delayed execution during unit tests.
if (mAudioServerLifecycleExecutor instanceof ScheduledExecutorService exec) {
- // We schedule and add from a this callback thread only (serially), so the task order on
- // the serial executor matches the order on the task list. This list should almost
- // always have only two elements, except in cases of serious system contention.
- Runnable task = () -> mScheduledPermissionTasks.add(exec.schedule(() -> {
- try {
- // Clean up completed tasks before us to bound the queue length. Cancel any
- // pending permission refresh tasks, after our own, since we are about to
- // fulfill all of them. We must be the first non-completed task in the
- // queue, since the execution order matches the queue order. Note, this
- // task is the only writer on elements in the queue, and the task is
- // serialized, so
- // => no in-flight cancellation
- // => exists at least one non-completed task (ourselves)
- // => the queue is non-empty (only completed tasks removed)
- final var iter = mScheduledPermissionTasks.iterator();
- while (iter.next().isDone()) {
- iter.remove();
- }
- // iter is on the first element which is not completed (us)
- while (iter.hasNext()) {
- if (!iter.next().cancel(false)) {
- throw new AssertionError(
- "Cancel should be infallible since we" +
- "cancel from the executor");
+ // The order on the task list is an embedding on the scheduling order of the executor,
+ // since we synchronously add the scheduled task to our local queue. This list should
+ // almost always have only two elements, except in cases of serious system contention.
+ Runnable task = () -> {
+ synchronized (mScheduledPermissionTasks) {
+ mScheduledPermissionTasks.add(exec.schedule(() -> {
+ try {
+ // Our goal is to remove all tasks which don't correspond to ourselves
+ // on this queue. Either they are already done (ahead of us), or we
+ // should cancel them (behind us), since their work is redundant after
+ // we fire.
+ // We must be the first non-completed task in the queue, since the
+ // execution order matches the queue order. Note, this task is the only
+ // writer on elements in the queue, and the task is serialized, so
+ // => no in-flight cancellation
+ // => exists at least one non-completed task (ourselves)
+ // => the queue is non-empty (only completed tasks removed)
+ synchronized (mScheduledPermissionTasks) {
+ final var iter = mScheduledPermissionTasks.iterator();
+ while (iter.next().isDone()) {
+ iter.remove();
+ }
+ // iter is on the first element which is not completed (us)
+ while (iter.hasNext()) {
+ if (!iter.next().cancel(false)) {
+ throw new AssertionError(
+ "Cancel should be infallible since we" +
+ "cancel from the executor");
+ }
+ iter.remove();
+ }
}
- iter.remove();
+ mPermissionProvider.onPermissionStateChanged();
+ } catch (Exception e) {
+ // Handle executor routing exceptions to nowhere
+ Thread.getDefaultUncaughtExceptionHandler()
+ .uncaughtException(Thread.currentThread(), e);
}
- mPermissionProvider.onPermissionStateChanged();
- } catch (Exception e) {
- // Handle executor routing exceptions to nowhere
- Thread.getDefaultUncaughtExceptionHandler()
- .uncaughtException(Thread.currentThread(), e);
- }
- },
- UPDATE_DELAY_MS,
- TimeUnit.MILLISECONDS));
+ }, UPDATE_DELAY_MS, TimeUnit.MILLISECONDS));
+ }
+ };
mAudioSystem.listenForSystemPropertyChange(
PermissionManager.CACHE_KEY_PACKAGE_INFO,
task);
- task.run();
} else {
mAudioSystem.listenForSystemPropertyChange(
PermissionManager.CACHE_KEY_PACKAGE_INFO,
@@ -14710,7 +14713,11 @@
@Override
/** @see AudioManager#permissionUpdateBarrier() */
public void permissionUpdateBarrier() {
- for (var x : List.copyOf(mScheduledPermissionTasks)) {
+ List<Future> snapshot;
+ synchronized (mScheduledPermissionTasks) {
+ snapshot = List.copyOf(mScheduledPermissionTasks);
+ }
+ for (var x : snapshot) {
try {
x.get();
} catch (CancellationException e) {
diff --git a/services/core/java/com/android/server/biometrics/AuthSession.java b/services/core/java/com/android/server/biometrics/AuthSession.java
index 276ab03..abfbddc 100644
--- a/services/core/java/com/android/server/biometrics/AuthSession.java
+++ b/services/core/java/com/android/server/biometrics/AuthSession.java
@@ -221,7 +221,8 @@
mFingerprintSensorProperties = fingerprintSensorProperties;
mCancelled = false;
mBiometricFrameworkStatsLogger = logger;
- mOperationContext = new OperationContextExt(true /* isBP */);
+ mOperationContext = new OperationContextExt(true /* isBP */,
+ preAuthInfo.getIsMandatoryBiometricsAuthentication() /* isMandatoryBiometrics */);
mBiometricManager = mContext.getSystemService(BiometricManager.class);
mSfpsSensorIds = mFingerprintSensorProperties.stream().filter(
@@ -285,7 +286,8 @@
sensor.goToStateWaitingForCookie(requireConfirmation, mToken, mOperationId,
mUserId, mSensorReceiver, mOpPackageName, mRequestId, cookie,
mPromptInfo.isAllowBackgroundAuthentication(),
- mPromptInfo.isForLegacyFingerprintManager());
+ mPromptInfo.isForLegacyFingerprintManager(),
+ mOperationContext.getIsMandatoryBiometrics());
}
}
diff --git a/services/core/java/com/android/server/biometrics/BiometricSensor.java b/services/core/java/com/android/server/biometrics/BiometricSensor.java
index 42dd36a..c7532d4 100644
--- a/services/core/java/com/android/server/biometrics/BiometricSensor.java
+++ b/services/core/java/com/android/server/biometrics/BiometricSensor.java
@@ -107,12 +107,13 @@
void goToStateWaitingForCookie(boolean requireConfirmation, IBinder token, long sessionId,
int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName,
long requestId, int cookie, boolean allowBackgroundAuthentication,
- boolean isForLegacyFingerprintManager)
+ boolean isForLegacyFingerprintManager, boolean isMandatoryBiometrics)
throws RemoteException {
mCookie = cookie;
impl.prepareForAuthentication(requireConfirmation, token,
sessionId, userId, sensorReceiver, opPackageName, requestId, mCookie,
- allowBackgroundAuthentication, isForLegacyFingerprintManager);
+ allowBackgroundAuthentication, isForLegacyFingerprintManager,
+ isMandatoryBiometrics);
mSensorState = STATE_WAITING_FOR_COOKIE;
}
diff --git a/services/core/java/com/android/server/biometrics/PreAuthInfo.java b/services/core/java/com/android/server/biometrics/PreAuthInfo.java
index f0da67b..eaf4f81 100644
--- a/services/core/java/com/android/server/biometrics/PreAuthInfo.java
+++ b/services/core/java/com/android/server/biometrics/PreAuthInfo.java
@@ -447,6 +447,12 @@
getInternalStatus().second));
}
+ /** Returns if mandatory biometrics authentication is in effect */
+ boolean getIsMandatoryBiometricsAuthentication() {
+ return mIsMandatoryBiometricsAuthentication;
+ }
+
+
/**
* For the given request, generate the appropriate reason why authentication cannot be started.
* Note that for some errors, modality is intentionally cleared.
diff --git a/services/core/java/com/android/server/biometrics/log/BiometricFrameworkStatsLogger.java b/services/core/java/com/android/server/biometrics/log/BiometricFrameworkStatsLogger.java
index 2c52e3d..f5af5ea 100644
--- a/services/core/java/com/android/server/biometrics/log/BiometricFrameworkStatsLogger.java
+++ b/services/core/java/com/android/server/biometrics/log/BiometricFrameworkStatsLogger.java
@@ -78,6 +78,7 @@
public void authenticate(OperationContextExt operationContext,
int statsModality, int statsAction, int statsClient, boolean isDebug, long latency,
int authState, boolean requireConfirmation, int targetUserId, float ambientLightLux) {
+ Slog.d(TAG, "authenticate logging " + operationContext.getIsMandatoryBiometrics());
FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_AUTHENTICATED,
statsModality,
targetUserId,
@@ -98,7 +99,8 @@
foldType(operationContext.getFoldState()),
operationContext.getOrderAndIncrement(),
toProtoWakeReason(operationContext),
- toProtoWakeReasonDetails(operationContext));
+ toProtoWakeReasonDetails(operationContext),
+ operationContext.getIsMandatoryBiometrics());
}
/** {@see FrameworkStatsLog.BIOMETRIC_AUTHENTICATED}. */
@@ -129,6 +131,7 @@
public void error(OperationContextExt operationContext,
int statsModality, int statsAction, int statsClient, boolean isDebug, long latency,
int error, int vendorCode, int targetUserId) {
+ Slog.d(TAG, "error logging " + operationContext.getIsMandatoryBiometrics());
FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_ERROR_OCCURRED,
statsModality,
targetUserId,
@@ -149,7 +152,8 @@
foldType(operationContext.getFoldState()),
operationContext.getOrderAndIncrement(),
toProtoWakeReason(operationContext),
- toProtoWakeReasonDetails(operationContext));
+ toProtoWakeReasonDetails(operationContext),
+ operationContext.getIsMandatoryBiometrics());
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/biometrics/log/OperationContextExt.java b/services/core/java/com/android/server/biometrics/log/OperationContextExt.java
index da4e515..4df63e2 100644
--- a/services/core/java/com/android/server/biometrics/log/OperationContextExt.java
+++ b/services/core/java/com/android/server/biometrics/log/OperationContextExt.java
@@ -50,21 +50,33 @@
@Surface.Rotation private int mOrientation = Surface.ROTATION_0;
private int mFoldState = IBiometricContextListener.FoldState.UNKNOWN;
private final boolean mIsBP;
+ private final boolean mIsMandatoryBiometrics;
/** Create a context. */
public OperationContextExt(boolean isBP) {
this(new OperationContext(), isBP, BiometricAuthenticator.TYPE_NONE);
}
- public OperationContextExt(boolean isBP, @BiometricAuthenticator.Modality int modality) {
- this(new OperationContext(), isBP, modality);
+ public OperationContextExt(boolean isBP, boolean isMandatoryBiometrics) {
+ this(new OperationContext(), isBP, BiometricAuthenticator.TYPE_NONE, isMandatoryBiometrics);
+ }
+
+ public OperationContextExt(boolean isBP, @BiometricAuthenticator.Modality int modality,
+ boolean isMandatoryBiometrics) {
+ this(new OperationContext(), isBP, modality, isMandatoryBiometrics);
}
/** Create a wrapped context. */
public OperationContextExt(@NonNull OperationContext context, boolean isBP,
@BiometricAuthenticator.Modality int modality) {
+ this(context, isBP, modality, false /* isMandatoryBiometrics */);
+ }
+
+ public OperationContextExt(@NonNull OperationContext context, boolean isBP,
+ @BiometricAuthenticator.Modality int modality, boolean isMandatoryBiometrics) {
mAidlContext = context;
mIsBP = isBP;
+ mIsMandatoryBiometrics = isMandatoryBiometrics;
if (modality == BiometricAuthenticator.TYPE_FINGERPRINT) {
mAidlContext.operationState = OperationState.fingerprintOperationState(
@@ -285,6 +297,11 @@
return mAidlContext.operationState;
}
+ /** If mandatory biometrics is active. */
+ public boolean getIsMandatoryBiometrics() {
+ return mIsMandatoryBiometrics;
+ }
+
/** Update this object with the latest values from the given context. */
OperationContextExt update(@NonNull BiometricContext biometricContext, boolean isCrypto) {
mAidlContext.isAod = biometricContext.isAod();
diff --git a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
index fbd32a6..04522e3 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
@@ -59,9 +59,10 @@
public AcquisitionClient(@NonNull Context context, @NonNull Supplier<T> lazyDaemon,
@NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId,
@NonNull String owner, int cookie, int sensorId, boolean shouldVibrate,
- @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext) {
+ @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext,
+ boolean isMandatoryBiometrics) {
super(context, lazyDaemon, token, listener, userId, owner, cookie, sensorId,
- logger, biometricContext);
+ logger, biometricContext, isMandatoryBiometrics);
mPowerManager = context.getSystemService(PowerManager.class);
mShouldVibrate = shouldVibrate;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
index daaafcb..09386ae28 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@@ -99,7 +99,7 @@
boolean shouldVibrate, int sensorStrength) {
super(context, lazyDaemon, token, listener, options.getUserId(),
options.getOpPackageName(), cookie, options.getSensorId(), shouldVibrate,
- biometricLogger, biometricContext);
+ biometricLogger, biometricContext, options.isMandatoryBiometrics());
mIsStrongBiometric = isStrongBiometric;
mOperationId = operationId;
mRequireConfirmation = requireConfirmation;
diff --git a/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java
index 438367d..32c0bd3 100644
--- a/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java
@@ -60,7 +60,7 @@
@NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext,
int enrollReason) {
super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
- shouldVibrate, logger, biometricContext);
+ shouldVibrate, logger, biometricContext, false /* isMandatoryBiometrics */);
mBiometricUtils = utils;
mHardwareAuthToken = Arrays.copyOf(hardwareAuthToken, hardwareAuthToken.length);
mTimeoutSec = timeoutSec;
diff --git a/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java
index 2adf0cb..b573b56 100644
--- a/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java
@@ -37,7 +37,7 @@
int userId, @NonNull String owner, int sensorId,
@NonNull BiometricLogger biometricLogger, @NonNull BiometricContext biometricContext) {
super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
- biometricLogger, biometricContext);
+ biometricLogger, biometricContext, false /* isMandatoryBiometrics */);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/HalClientMonitor.java b/services/core/java/com/android/server/biometrics/sensors/HalClientMonitor.java
index 0f01510..3bc51a9 100644
--- a/services/core/java/com/android/server/biometrics/sensors/HalClientMonitor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/HalClientMonitor.java
@@ -41,26 +41,29 @@
private final OperationContextExt mOperationContext;
/**
- * @param context system_server context
- * @param lazyDaemon pointer for lazy retrieval of the HAL
- * @param token a unique token for the client
- * @param listener recipient of related events (e.g. authentication)
- * @param userId target user id for operation
- * @param owner name of the client that owns this
- * @param cookie BiometricPrompt authentication cookie (to be moved into a subclass soon)
- * @param sensorId ID of the sensor that the operation should be requested of
- * @param biometricLogger framework stats logger
+ * @param context system_server context
+ * @param lazyDaemon pointer for lazy retrieval of the HAL
+ * @param token a unique token for the client
+ * @param listener recipient of related events (e.g. authentication)
+ * @param userId target user id for operation
+ * @param owner name of the client that owns this
+ * @param cookie BiometricPrompt authentication cookie (to be moved into a subclass
+ * soon)
+ * @param sensorId ID of the sensor that the operation should be requested of
+ * @param biometricLogger framework stats logger
* @param biometricContext system context metadata
*/
public HalClientMonitor(@NonNull Context context, @NonNull Supplier<T> lazyDaemon,
@Nullable IBinder token, @Nullable ClientMonitorCallbackConverter listener, int userId,
@NonNull String owner, int cookie, int sensorId,
- @NonNull BiometricLogger biometricLogger, @NonNull BiometricContext biometricContext) {
+ @NonNull BiometricLogger biometricLogger, @NonNull BiometricContext biometricContext,
+ boolean isMandatoryBiometrics) {
super(context, token, listener, userId, owner, cookie, sensorId,
biometricLogger, biometricContext);
mLazyDaemon = lazyDaemon;
int modality = listener != null ? listener.getModality() : BiometricAuthenticator.TYPE_NONE;
- mOperationContext = new OperationContextExt(isBiometricPrompt(), modality);
+ mOperationContext = new OperationContextExt(isBiometricPrompt(), modality,
+ isMandatoryBiometrics);
}
@Nullable
diff --git a/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java b/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java
index 7bd905b..6c30559 100644
--- a/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java
@@ -143,7 +143,8 @@
@NonNull BiometricUtils<S> utils,
@NonNull Map<Integer, Long> authenticatorIds) {
super(context, lazyDaemon, null /* token */, null /* ClientMonitorCallbackConverter */,
- userId, owner, 0 /* cookie */, sensorId, logger, biometricContext);
+ userId, owner, 0 /* cookie */, sensorId, logger, biometricContext,
+ false /* isMandatoryBiometrics */);
mBiometricUtils = utils;
mAuthenticatorIds = authenticatorIds;
mHasEnrollmentsBeforeStarting = !utils.getBiometricsForUser(context, userId).isEmpty();
diff --git a/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java b/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java
index 81ab26d..2c2c685 100644
--- a/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java
@@ -55,7 +55,8 @@
// Internal enumerate does not need to send results to anyone. Cleanup (enumerate + remove)
// is all done internally.
super(context, lazyDaemon, token, null /* ClientMonitorCallbackConverter */, userId, owner,
- 0 /* cookie */, sensorId, logger, biometricContext);
+ 0 /* cookie */, sensorId, logger, biometricContext,
+ false /* isMandatoryBiometrics */);
mEnrolledList = enrolledList;
mInitialEnrolledSize = mEnrolledList.size();
mUtils = utils;
diff --git a/services/core/java/com/android/server/biometrics/sensors/InvalidationClient.java b/services/core/java/com/android/server/biometrics/sensors/InvalidationClient.java
index d5aa5e2..6c93366 100644
--- a/services/core/java/com/android/server/biometrics/sensors/InvalidationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/InvalidationClient.java
@@ -49,7 +49,7 @@
@NonNull IInvalidationCallback callback) {
super(context, lazyDaemon, null /* token */, null /* listener */, userId,
context.getOpPackageName(), 0 /* cookie */, sensorId,
- logger, biometricContext);
+ logger, biometricContext, false /* isMandatoryBiometrics */);
mAuthenticatorIds = authenticatorIds;
mInvalidationCallback = callback;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java b/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java
index d2ef278..ad5877a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java
@@ -49,7 +49,7 @@
@NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext,
@NonNull Map<Integer, Long> authenticatorIds) {
super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
- logger, biometricContext);
+ logger, biometricContext, false /* isMandatoryBiometrics */);
mBiometricUtils = utils;
mAuthenticatorIds = authenticatorIds;
mHasEnrollmentsBeforeStarting = !utils.getBiometricsForUser(context, userId).isEmpty();
diff --git a/services/core/java/com/android/server/biometrics/sensors/RevokeChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/RevokeChallengeClient.java
index 88f4da2..0c8a2dd 100644
--- a/services/core/java/com/android/server/biometrics/sensors/RevokeChallengeClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/RevokeChallengeClient.java
@@ -32,7 +32,8 @@
@NonNull IBinder token, int userId, @NonNull String owner, int sensorId,
@NonNull BiometricLogger biometricLogger, @NonNull BiometricContext biometricContext) {
super(context, lazyDaemon, token, null /* listener */, userId, owner,
- 0 /* cookie */, sensorId, biometricLogger, biometricContext);
+ 0 /* cookie */, sensorId, biometricLogger, biometricContext,
+ false /* isMandatoryBiometrics */);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/StartUserClient.java b/services/core/java/com/android/server/biometrics/sensors/StartUserClient.java
index 21c9f64..ff694cd 100644
--- a/services/core/java/com/android/server/biometrics/sensors/StartUserClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/StartUserClient.java
@@ -51,7 +51,8 @@
@NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext,
@NonNull UserStartedCallback<U> callback) {
super(context, lazyDaemon, token, null /* listener */, userId, context.getOpPackageName(),
- 0 /* cookie */, sensorId, logger, biometricContext);
+ 0 /* cookie */, sensorId, logger, biometricContext,
+ false /* isMandatoryBiometrics */);
mUserStartedCallback = callback;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/StopUserClient.java b/services/core/java/com/android/server/biometrics/sensors/StopUserClient.java
index e01c4ec..9119bc7 100644
--- a/services/core/java/com/android/server/biometrics/sensors/StopUserClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/StopUserClient.java
@@ -54,7 +54,8 @@
@NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext,
@NonNull UserStoppedCallback callback) {
super(context, lazyDaemon, token, null /* listener */, userId, context.getOpPackageName(),
- 0 /* cookie */, sensorId, logger, biometricContext);
+ 0 /* cookie */, sensorId, logger, biometricContext,
+ false /* isMandatoryBiometrics */);
mUserStoppedCallback = callback;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java
index 2211003..67d7505 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java
@@ -63,13 +63,14 @@
public void prepareForAuthentication(boolean requireConfirmation, IBinder token,
long operationId, int userId, IBiometricSensorReceiver sensorReceiver,
String opPackageName, long requestId, int cookie, boolean allowBackgroundAuthentication,
- boolean isForLegacyFingerprintManager)
+ boolean isForLegacyFingerprintManager, boolean isMandatoryBiometrics)
throws RemoteException {
mFaceService.prepareForAuthentication(requireConfirmation, token, operationId,
sensorReceiver, new FaceAuthenticateOptions.Builder()
.setUserId(userId)
.setSensorId(mSensorId)
.setOpPackageName(opPackageName)
+ .setIsMandatoryBiometrics(isMandatoryBiometrics)
.build(),
requestId, cookie, allowBackgroundAuthentication);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java
index 8b4da31..8eb62eb 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java
@@ -83,7 +83,8 @@
boolean isStrongBiometric, SensorPrivacyManager sensorPrivacyManager) {
super(context, lazyDaemon, token, listener, options.getUserId(),
options.getOpPackageName(), 0 /* cookie */, options.getSensorId(),
- false /* shouldVibrate */, logger, biometricContext);
+ false /* shouldVibrate */, logger, biometricContext,
+ false /* isMandatoryBiometrics */);
setRequestId(requestId);
mAuthenticationStateListeners = authenticationStateListeners;
mIsStrongBiometric = isStrongBiometric;
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetAuthenticatorIdClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetAuthenticatorIdClient.java
index 1f4f612..dbd293c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetAuthenticatorIdClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetAuthenticatorIdClient.java
@@ -42,7 +42,8 @@
@NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext,
Map<Integer, Long> authenticatorIds) {
super(context, lazyDaemon, null /* token */, null /* listener */, userId, opPackageName,
- 0 /* cookie */, sensorId, logger, biometricContext);
+ 0 /* cookie */, sensorId, logger, biometricContext,
+ false /* isMandatoryBiometrics */);
mAuthenticatorIds = authenticatorIds;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetFeatureClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetFeatureClient.java
index c41b706..8d1336f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetFeatureClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetFeatureClient.java
@@ -55,7 +55,7 @@
@NonNull String owner, int sensorId, @NonNull BiometricLogger logger,
@NonNull BiometricContext biometricContext, int feature) {
super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
- logger, biometricContext);
+ logger, biometricContext, false /* isMandatoryBiometrics */);
mUserId = userId;
mFeature = feature;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java
index d02eefa..93bc1f2 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java
@@ -60,7 +60,8 @@
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@Authenticators.Types int biometricStrength) {
super(context, lazyDaemon, null /* token */, null /* listener */, userId, owner,
- 0 /* cookie */, sensorId, logger, biometricContext);
+ 0 /* cookie */, sensorId, logger, biometricContext,
+ false /* isMandatoryBiometrics */);
mHardwareAuthToken = HardwareAuthTokenUtils.toHardwareAuthToken(hardwareAuthToken);
mLockoutTracker = lockoutTracker;
mLockoutResetDispatcher = lockoutResetDispatcher;
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceSetFeatureClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceSetFeatureClient.java
index f6da872..fc73e58 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceSetFeatureClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceSetFeatureClient.java
@@ -52,7 +52,7 @@
@NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext,
int feature, boolean enabled, byte[] hardwareAuthToken) {
super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
- logger, biometricContext);
+ logger, biometricContext, false /* isMandatoryBiometrics */);
mFeature = feature;
mEnabled = enabled;
mHardwareAuthToken = HardwareAuthTokenUtils.toHardwareAuthToken(hardwareAuthToken);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java
index b6fa0c1..d50ab8d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java
@@ -63,13 +63,14 @@
public void prepareForAuthentication(boolean requireConfirmation, IBinder token,
long operationId, int userId, IBiometricSensorReceiver sensorReceiver,
String opPackageName, long requestId, int cookie, boolean allowBackgroundAuthentication,
- boolean isForLegacyFingerprintManager)
+ boolean isForLegacyFingerprintManager, boolean isMandatoryBiometrics)
throws RemoteException {
mFingerprintService.prepareForAuthentication(token, operationId, sensorReceiver,
new FingerprintAuthenticateOptions.Builder()
.setSensorId(mSensorId)
.setUserId(userId)
.setOpPackageName(opPackageName)
+ .setIsMandatoryBiometrics(isMandatoryBiometrics)
.build(),
requestId, cookie, allowBackgroundAuthentication, isForLegacyFingerprintManager);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
index fb48053..a81ab8e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
@@ -71,7 +71,8 @@
boolean isStrongBiometric) {
super(context, lazyDaemon, token, listener, options.getUserId(),
options.getOpPackageName(), 0 /* cookie */, options.getSensorId(),
- true /* shouldVibrate */, biometricLogger, biometricContext);
+ true /* shouldVibrate */, biometricLogger, biometricContext,
+ false /* isMandatoryBiometrics */);
setRequestId(requestId);
mAuthenticationStateListeners = authenticationStateListeners;
mIsStrongBiometric = isStrongBiometric;
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGetAuthenticatorIdClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGetAuthenticatorIdClient.java
index 0353969..f77e116 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGetAuthenticatorIdClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGetAuthenticatorIdClient.java
@@ -42,7 +42,8 @@
@NonNull BiometricLogger biometricLogger, @NonNull BiometricContext biometricContext,
Map<Integer, Long> authenticatorIds) {
super(context, lazyDaemon, null /* token */, null /* listener */, userId, owner,
- 0 /* cookie */, sensorId, biometricLogger, biometricContext);
+ 0 /* cookie */, sensorId, biometricLogger, biometricContext,
+ false /* isMandatoryBiometrics */);
mAuthenticatorIds = authenticatorIds;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java
index 387ae12..81a3d83 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java
@@ -59,7 +59,8 @@
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@Authenticators.Types int biometricStrength) {
super(context, lazyDaemon, null /* token */, null /* listener */, userId, owner,
- 0 /* cookie */, sensorId, biometricLogger, biometricContext);
+ 0 /* cookie */, sensorId, biometricLogger, biometricContext,
+ false /* isMandatoryBiometrics */);
mHardwareAuthToken = hardwareAuthToken == null ? null :
HardwareAuthTokenUtils.toHardwareAuthToken(hardwareAuthToken);
mLockoutCache = lockoutTracker;
diff --git a/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java
index 01d1e378..76b5c4e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java
@@ -60,7 +60,7 @@
public void prepareForAuthentication(boolean requireConfirmation, IBinder token,
long sessionId, int userId, IBiometricSensorReceiver sensorReceiver,
String opPackageName, long requestId, int cookie, boolean allowBackgroundAuthentication,
- boolean isForLegacyFingerprintManager)
+ boolean isForLegacyFingerprintManager, boolean isMandatoryBiometrics)
throws RemoteException {
}
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
index d0b8990..f44b852 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
@@ -142,7 +142,6 @@
ERROR_KEYSTORE_FAILURE,
ERROR_NO_NETWORK,
ERROR_TIMEOUT_EXHAUSTED,
- ERROR_NO_REBOOT_ESCROW_DATA,
})
@Retention(RetentionPolicy.SOURCE)
@interface RebootEscrowErrorCode {
@@ -158,7 +157,6 @@
static final int ERROR_KEYSTORE_FAILURE = 7;
static final int ERROR_NO_NETWORK = 8;
static final int ERROR_TIMEOUT_EXHAUSTED = 9;
- static final int ERROR_NO_REBOOT_ESCROW_DATA = 10;
private @RebootEscrowErrorCode int mLoadEscrowDataErrorCode = ERROR_NONE;
@@ -507,9 +505,6 @@
if (rebootEscrowUsers.isEmpty()) {
Slog.i(TAG, "No reboot escrow data found for users,"
+ " skipping loading escrow data");
- setLoadEscrowDataErrorCode(ERROR_NO_REBOOT_ESCROW_DATA, retryHandler);
- reportMetricOnRestoreComplete(
- /* success= */ false, /* attemptCount= */ 1, retryHandler);
clearMetricsStorage();
return;
}
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 95e5b84..2bc6d53 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -503,26 +503,21 @@
String restriction,
boolean isMainUser,
boolean isProfileOwnerOnOrgOwnedDevice) {
- if (android.app.admin.flags.Flags.esimManagementEnabled()) {
- if (IMMUTABLE_BY_OWNERS.contains(restriction)) {
- return false;
- }
- if (DEVICE_OWNER_ONLY_RESTRICTIONS.contains(restriction)) {
- return false;
- }
- if (!isMainUser && MAIN_USER_ONLY_RESTRICTIONS.contains(restriction)) {
- return false;
- }
- if (!isProfileOwnerOnOrgOwnedDevice
- && PROFILE_OWNER_ORGANIZATION_OWNED_PROFILE_RESTRICTIONS.contains(
- restriction)) {
- return false;
- }
- return true;
+ if (IMMUTABLE_BY_OWNERS.contains(restriction)) {
+ return false;
}
- return !IMMUTABLE_BY_OWNERS.contains(restriction)
- && !DEVICE_OWNER_ONLY_RESTRICTIONS.contains(restriction)
- && !(!isMainUser && MAIN_USER_ONLY_RESTRICTIONS.contains(restriction));
+ if (DEVICE_OWNER_ONLY_RESTRICTIONS.contains(restriction)) {
+ return false;
+ }
+ if (!isMainUser && MAIN_USER_ONLY_RESTRICTIONS.contains(restriction)) {
+ return false;
+ }
+ if (!isProfileOwnerOnOrgOwnedDevice
+ && PROFILE_OWNER_ORGANIZATION_OWNED_PROFILE_RESTRICTIONS.contains(
+ restriction)) {
+ return false;
+ }
+ return true;
}
/**
diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
index b45651d..385561d 100644
--- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
+++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
@@ -15300,15 +15300,6 @@
mHistory.writeHistoryItem(elapsedRealtimeMs, uptimeMs);
}
}
- if (!onBattery &&
- (status == BatteryManager.BATTERY_STATUS_FULL ||
- status == BatteryManager.BATTERY_STATUS_UNKNOWN)) {
- // We don't record history while we are plugged in and fully charged
- // (or when battery is not present). The next time we are
- // unplugged, history will be cleared.
- mHistory.setHistoryRecordingEnabled(DEBUG);
- }
-
mLastLearnedBatteryCapacityUah = chargeFullUah;
if (mMinLearnedBatteryCapacityUah == -1) {
mMinLearnedBatteryCapacityUah = chargeFullUah;
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index ba2594a..f53dda6 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -42,6 +42,7 @@
import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER_LOCK_ORIG;
import static com.android.server.wallpaper.WallpaperUtils.getWallpaperDir;
import static com.android.server.wallpaper.WallpaperUtils.makeWallpaperIdLocked;
+import static com.android.window.flags.Flags.avoidRebindingIntentionallyDisconnectedWallpaper;
import static com.android.window.flags.Flags.multiCrop;
import static com.android.window.flags.Flags.offloadColorExtraction;
@@ -897,6 +898,12 @@
return;
}
+ if (avoidRebindingIntentionallyDisconnectedWallpaper()
+ && mWallpaper.connection == null) {
+ Slog.w(TAG, "Trying to reset an intentionally disconnected wallpaper!");
+ return;
+ }
+
if (!mWallpaper.wallpaperUpdating && mWallpaper.userId == mCurrentUserId) {
Slog.w(TAG, "Wallpaper reconnect timed out for " + mWallpaper.wallpaperComponent
+ ", reverting to built-in wallpaper!");
@@ -1066,6 +1073,13 @@
if (mWallpaper.wallpaperUpdating) {
return;
}
+
+ if (avoidRebindingIntentionallyDisconnectedWallpaper()
+ && mWallpaper.connection == null) {
+ Slog.w(TAG, "Trying to rebind an intentionally disconnected wallpaper!");
+ return;
+ }
+
final ComponentName wpService = mWallpaper.wallpaperComponent;
// The broadcast of package update could be delayed after service disconnected. Try
// to re-bind the service for 10 seconds.
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index c44f838b..3710f7f 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -574,10 +574,15 @@
private void scheduleAnimation(@NonNull AnimationHandler.ScheduleAnimationBuilder builder) {
mPendingAnimation = builder.build();
- mWindowManagerService.mWindowPlacerLocked.requestTraversal();
- if (mShowWallpaper) {
- mWindowManagerService.getDefaultDisplayContentLocked().mWallpaperController
- .adjustWallpaperWindows();
+ if (mAnimationHandler.mOpenAnimAdaptor != null
+ && mAnimationHandler.mOpenAnimAdaptor.mPreparedOpenTransition != null) {
+ startAnimation();
+ } else {
+ mWindowManagerService.mWindowPlacerLocked.requestTraversal();
+ if (mShowWallpaper) {
+ mWindowManagerService.getDefaultDisplayContentLocked().mWallpaperController
+ .adjustWallpaperWindows();
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/SnapshotController.java b/services/core/java/com/android/server/wm/SnapshotController.java
index 0f9c001..52994c7 100644
--- a/services/core/java/com/android/server/wm/SnapshotController.java
+++ b/services/core/java/com/android/server/wm/SnapshotController.java
@@ -31,6 +31,8 @@
import android.view.WindowManager;
import android.window.TaskSnapshot;
+import com.android.window.flags.Flags;
+
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -150,6 +152,9 @@
if (mOpenActivities.isEmpty()) {
return false;
}
+ if (Flags.alwaysCaptureActivitySnapshot()) {
+ return true;
+ }
for (int i = mOpenActivities.size() - 1; i >= 0; --i) {
if (!mOpenActivities.get(i).mOptInOnBackInvoked) {
return false;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index af4a48d..4abbdee 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -13972,11 +13972,9 @@
UserManager.DISALLOW_THREAD_NETWORK,
new String[]{MANAGE_DEVICE_POLICY_THREAD_NETWORK});
}
- if (Flags.assistContentUserRestrictionEnabled()) {
- USER_RESTRICTION_PERMISSIONS.put(
- UserManager.DISALLOW_ASSIST_CONTENT,
- new String[]{MANAGE_DEVICE_POLICY_ASSIST_CONTENT});
- }
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_ASSIST_CONTENT,
+ new String[]{MANAGE_DEVICE_POLICY_ASSIST_CONTENT});
USER_RESTRICTION_PERMISSIONS.put(
UserManager.DISALLOW_ULTRA_WIDEBAND_RADIO, new String[]{MANAGE_DEVICE_POLICY_NEARBY_COMMUNICATION});
USER_RESTRICTION_PERMISSIONS.put(
@@ -19755,16 +19753,14 @@
}
private void transferSubscriptionOwnership(ComponentName admin, ComponentName target) {
- if (Flags.esimManagementEnabled()) {
- SubscriptionManager subscriptionManager = mContext.getSystemService(
- SubscriptionManager.class);
- for (int subId : getSubscriptionIdsInternal(admin.getPackageName()).toArray()) {
- try {
- subscriptionManager.setGroupOwner(subId, target.getPackageName());
- } catch (Exception e) {
- // Shouldn't happen.
- Slogf.e(LOG_TAG, e, "Error setting group owner for subId: " + subId);
- }
+ SubscriptionManager subscriptionManager = mContext.getSystemService(
+ SubscriptionManager.class);
+ for (int subId : getSubscriptionIdsInternal(admin.getPackageName()).toArray()) {
+ try {
+ subscriptionManager.setGroupOwner(subId, target.getPackageName());
+ } catch (Exception e) {
+ // Shouldn't happen.
+ Slogf.e(LOG_TAG, e, "Error setting group owner for subId: " + subId);
}
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
index 19a942c..24ee46f 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
@@ -536,7 +536,6 @@
USER_RESTRICTION_FLAGS.put(
UserManager.DISALLOW_THREAD_NETWORK, POLICY_FLAG_GLOBAL_ONLY_POLICY);
}
- USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_ASSIST_CONTENT, /* flags= */ 0);
for (String key : USER_RESTRICTION_FLAGS.keySet()) {
createAndAddUserRestrictionPolicyDefinition(key, USER_RESTRICTION_FLAGS.get(key));
}
diff --git a/services/tests/dreamservicetests/src/com/android/server/dreams/DreamOverlayServiceTest.java b/services/tests/dreamservicetests/src/com/android/server/dreams/DreamOverlayServiceTest.java
index 698ce13..1abc557 100644
--- a/services/tests/dreamservicetests/src/com/android/server/dreams/DreamOverlayServiceTest.java
+++ b/services/tests/dreamservicetests/src/com/android/server/dreams/DreamOverlayServiceTest.java
@@ -140,7 +140,7 @@
// Start the dream.
client.startDream(mLayoutParams, mOverlayCallback,
- FIRST_DREAM_COMPONENT.flattenToString(), false);
+ FIRST_DREAM_COMPONENT.flattenToString(), false, false);
// The callback should not have run yet.
verify(monitor, never()).onStartDream();
@@ -198,22 +198,24 @@
// Start a dream with the first client and ensure the dream is now active from the
// overlay's perspective.
firstClient.startDream(mLayoutParams, mOverlayCallback,
- FIRST_DREAM_COMPONENT.flattenToString(), false);
+ FIRST_DREAM_COMPONENT.flattenToString(), true, false);
verify(monitor).onStartDream();
assertThat(service.getDreamComponent()).isEqualTo(FIRST_DREAM_COMPONENT);
+ assertThat(service.isDreamInPreviewMode()).isTrue();
Mockito.clearInvocations(monitor);
// Start a dream from the second client and verify that the overlay has both cycled to
// the new dream (ended/started).
secondClient.startDream(mLayoutParams, mOverlayCallback,
- SECOND_DREAM_COMPONENT.flattenToString(), false);
+ SECOND_DREAM_COMPONENT.flattenToString(), false, false);
verify(monitor).onEndDream();
verify(monitor).onStartDream();
assertThat(service.getDreamComponent()).isEqualTo(SECOND_DREAM_COMPONENT);
+ assertThat(service.isDreamInPreviewMode()).isFalse();
Mockito.clearInvocations(monitor);
@@ -248,7 +250,7 @@
// Start the dream.
client.startDream(mLayoutParams, mOverlayCallback,
- FIRST_DREAM_COMPONENT.flattenToString(), false);
+ FIRST_DREAM_COMPONENT.flattenToString(), false, false);
// Make sure redirect state is set on dream.
verify(mOverlayCallback).onRedirectWake(eq(true));
@@ -262,7 +264,7 @@
service.redirectWake(true);
clearInvocations(mOverlayCallback);
client.startDream(mLayoutParams, mOverlayCallback,
- FIRST_DREAM_COMPONENT.flattenToString(), false);
+ FIRST_DREAM_COMPONENT.flattenToString(), false, false);
verify(mOverlayCallback).onRedirectWake(eq(true));
}
diff --git a/services/tests/dreamservicetests/src/com/android/server/dreams/TestDreamEnvironment.java b/services/tests/dreamservicetests/src/com/android/server/dreams/TestDreamEnvironment.java
index 43aa7fe..7c239ef 100644
--- a/services/tests/dreamservicetests/src/com/android/server/dreams/TestDreamEnvironment.java
+++ b/services/tests/dreamservicetests/src/com/android/server/dreams/TestDreamEnvironment.java
@@ -385,7 +385,8 @@
final ArgumentCaptor<IDreamOverlayCallback> overlayCallbackCaptor =
ArgumentCaptor.forClass(IDreamOverlayCallback.class);
verify(mDreamOverlayClient, description("dream client not informed of dream start"))
- .startDream(any(), overlayCallbackCaptor.capture(), any(), anyBoolean());
+ .startDream(any(), overlayCallbackCaptor.capture(), any(), anyBoolean(),
+ anyBoolean());
mDreamOverlayCallback = overlayCallbackCaptor.getValue();
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
index bc2fd73..2f7b8d2 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
@@ -200,7 +200,8 @@
eq(TEST_REQUEST_ID),
eq(sensor.getCookie()),
anyBoolean() /* allowBackgroundAuthentication */,
- anyBoolean() /* isForLegacyFingerprintManager */);
+ anyBoolean() /* isForLegacyFingerprintManager */,
+ eq(false) /* isMandatoryBiometrics */);
}
final int cookie1 = session.mPreAuthInfo.eligibleSensors.get(0).getCookie();
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
index d2961bc..6b8e414 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
@@ -636,7 +636,8 @@
eq(TEST_REQUEST_ID),
cookieCaptor.capture() /* cookie */,
anyBoolean() /* allowBackgroundAuthentication */,
- anyBoolean() /* isForLegacyFingerprintManager */);
+ anyBoolean() /* isForLegacyFingerprintManager */,
+ eq(false) /* isMandatoryBiometrics */);
// onReadyForAuthentication, mAuthSession state OK
mBiometricService.mImpl.onReadyForAuthentication(TEST_REQUEST_ID, cookieCaptor.getValue());
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/AcquisitionClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/AcquisitionClientTest.java
index 4604b31..613cb20 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/AcquisitionClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/AcquisitionClientTest.java
@@ -98,7 +98,8 @@
@NonNull ClientMonitorCallbackConverter callback) {
super(context, lazyDaemon, token, callback, 0 /* userId */, "Test", 0 /* cookie */,
TEST_SENSOR_ID /* sensorId */, true /* shouldVibrate */,
- mock(BiometricLogger.class), mock(BiometricContext.class));
+ mock(BiometricLogger.class), mock(BiometricContext.class),
+ false /* isMandatoryBiometrics */);
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerOperationTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerOperationTest.java
index ffc7811..4f07380 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerOperationTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerOperationTest.java
@@ -62,7 +62,8 @@
extends HalClientMonitor<T> {
public InterruptableMonitor() {
super(null, null, null, null, 0, null, 0, 0,
- mock(BiometricLogger.class), mock(BiometricContext.class));
+ mock(BiometricLogger.class), mock(BiometricContext.class),
+ false /* isMandatoryBiometrics */);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
index 36a7b3d..90c07d4 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
@@ -1051,6 +1051,11 @@
public String getAttributionTag() {
return null;
}
+
+ @Override
+ public boolean isMandatoryBiometrics() {
+ return false;
+ }
}
private static class TestAuthenticationClient
@@ -1176,7 +1181,7 @@
@NonNull Supplier<Object> lazyDaemon, int cookie, int protoEnum) {
super(context, lazyDaemon, token /* token */, null /* listener */, 0 /* userId */, TAG,
cookie, TEST_SENSOR_ID, mock(BiometricLogger.class),
- mock(BiometricContext.class));
+ mock(BiometricContext.class), false /* isMandatoryBiometrics */);
mProtoEnum = protoEnum;
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
index 17b499e..d6f7e21 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
@@ -625,25 +625,10 @@
// pretend reboot happens here
when(mInjected.getBootCount()).thenReturn(1);
- ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
- ArgumentCaptor<Integer> metricsErrorCodeCaptor = ArgumentCaptor.forClass(Integer.class);
- doNothing()
- .when(mInjected)
- .reportMetric(
- metricsSuccessCaptor.capture(),
- metricsErrorCodeCaptor.capture(),
- eq(2) /* Server based */,
- eq(1) /* attempt count */,
- anyInt(),
- eq(0) /* vbmeta status */,
- anyInt());
+
mService.loadRebootEscrowDataIfAvailable(null);
verify(mServiceConnection, never()).unwrap(any(), anyLong());
verify(mCallbacks, never()).onRebootEscrowRestored(anyByte(), any(), anyInt());
- assertFalse(metricsSuccessCaptor.getValue());
- assertEquals(
- Integer.valueOf(RebootEscrowManager.ERROR_NO_REBOOT_ESCROW_DATA),
- metricsErrorCodeCaptor.getValue());
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
index 55c48e0..f0a5f75 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
@@ -36,7 +36,6 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -55,11 +54,6 @@
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
- @Before
- public void setUp() {
- mSetFlagsRule.enableFlags(android.app.admin.flags.Flags.FLAG_ESIM_MANAGEMENT_ENABLED);
- }
-
@Test
public void testNonNull() {
Bundle out = UserRestrictionsUtils.nonNull(null);
@@ -144,7 +138,6 @@
@Test
public void testCanProfileOwnerChange_restrictionRequiresOrgOwnedDevice_orgOwned() {
- mSetFlagsRule.enableFlags(android.app.admin.flags.Flags.FLAG_ESIM_MANAGEMENT_ENABLED);
assertTrue(UserRestrictionsUtils.canProfileOwnerChange(
UserManager.DISALLOW_SIM_GLOBALLY,
false,
@@ -157,7 +150,6 @@
@Test
public void testCanProfileOwnerChange_restrictionRequiresOrgOwnedDevice_notOrgOwned() {
- mSetFlagsRule.enableFlags(android.app.admin.flags.Flags.FLAG_ESIM_MANAGEMENT_ENABLED);
assertFalse(UserRestrictionsUtils.canProfileOwnerChange(
UserManager.DISALLOW_SIM_GLOBALLY,
false,
@@ -169,22 +161,7 @@
}
@Test
- public void
- testCanProfileOwnerChange_disabled_restrictionRequiresOrgOwnedDevice_notOrgOwned() {
- mSetFlagsRule.disableFlags(android.app.admin.flags.Flags.FLAG_ESIM_MANAGEMENT_ENABLED);
- assertTrue(UserRestrictionsUtils.canProfileOwnerChange(
- UserManager.DISALLOW_SIM_GLOBALLY,
- false,
- false));
- assertTrue(UserRestrictionsUtils.canProfileOwnerChange(
- UserManager.DISALLOW_SIM_GLOBALLY,
- true,
- false));
- }
-
- @Test
public void testCanProfileOwnerChange_restrictionNotRequiresOrgOwnedDevice_orgOwned() {
- mSetFlagsRule.enableFlags(android.app.admin.flags.Flags.FLAG_ESIM_MANAGEMENT_ENABLED);
assertTrue(UserRestrictionsUtils.canProfileOwnerChange(
UserManager.DISALLOW_ADJUST_VOLUME,
false,
@@ -197,7 +174,6 @@
@Test
public void testCanProfileOwnerChange_restrictionNotRequiresOrgOwnedDevice_notOrgOwned() {
- mSetFlagsRule.enableFlags(android.app.admin.flags.Flags.FLAG_ESIM_MANAGEMENT_ENABLED);
assertTrue(UserRestrictionsUtils.canProfileOwnerChange(
UserManager.DISALLOW_ADJUST_VOLUME,
false,
diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java
index 6ef953c..c5934a7 100644
--- a/telephony/java/android/telephony/satellite/SatelliteManager.java
+++ b/telephony/java/android/telephony/satellite/SatelliteManager.java
@@ -546,6 +546,16 @@
public static final int EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911 = 2;
/**
+ * This intent will be broadcasted if there are any change to list of subscriber informations.
+ * This intent will be sent only to the app with component defined in
+ * config_satellite_carrier_roaming_esos_provisioned_class and package defined in
+ * config_satellite_gateway_service_package
+ * @hide
+ */
+ public static final String ACTION_SATELLITE_SUBSCRIBER_ID_LIST_CHANGED =
+ "android.telephony.action.ACTION_SATELLITE_SUBSCRIBER_ID_LIST_CHANGED";
+
+ /**
* Request to enable or disable the satellite modem and demo mode.
* If satellite modem and cellular modem cannot work concurrently,
* then this will disable the cellular modem if satellite modem is enabled,