Merge "Use background handler for biometrics DisplayStateRepositoryImpl" into main
diff --git a/core/java/android/content/pm/parsing/ApkLite.java b/core/java/android/content/pm/parsing/ApkLite.java
index 4990a27..74ce62c 100644
--- a/core/java/android/content/pm/parsing/ApkLite.java
+++ b/core/java/android/content/pm/parsing/ApkLite.java
@@ -145,6 +145,11 @@
private final boolean mUpdatableSystem;
/**
+ * Name of the emergency installer for the designated system app.
+ */
+ private final @Nullable String mEmergencyInstaller;
+
+ /**
* Archival install info.
*/
private final @Nullable ArchivedPackageParcel mArchivedPackage;
@@ -159,7 +164,8 @@
String requiredSystemPropertyName, String requiredSystemPropertyValue,
int minSdkVersion, int targetSdkVersion, int rollbackDataPolicy,
Set<String> requiredSplitTypes, Set<String> splitTypes,
- boolean hasDeviceAdminReceiver, boolean isSdkLibrary, boolean updatableSystem) {
+ boolean hasDeviceAdminReceiver, boolean isSdkLibrary, boolean updatableSystem,
+ String emergencyInstaller) {
mPath = path;
mPackageName = packageName;
mSplitName = splitName;
@@ -194,6 +200,7 @@
mHasDeviceAdminReceiver = hasDeviceAdminReceiver;
mIsSdkLibrary = isSdkLibrary;
mUpdatableSystem = updatableSystem;
+ mEmergencyInstaller = emergencyInstaller;
mArchivedPackage = null;
}
@@ -232,6 +239,7 @@
mHasDeviceAdminReceiver = false;
mIsSdkLibrary = false;
mUpdatableSystem = true;
+ mEmergencyInstaller = null;
mArchivedPackage = archivedPackage;
}
@@ -550,6 +558,14 @@
}
/**
+ * Name of the emergency installer for the designated system app.
+ */
+ @DataClass.Generated.Member
+ public @Nullable String getEmergencyInstaller() {
+ return mEmergencyInstaller;
+ }
+
+ /**
* Archival install info.
*/
@DataClass.Generated.Member
@@ -558,10 +574,10 @@
}
@DataClass.Generated(
- time = 1699587291575L,
+ time = 1706896661616L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/content/pm/parsing/ApkLite.java",
- inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.Nullable java.lang.String mSplitName\nprivate final @android.annotation.Nullable java.lang.String mUsesSplitName\nprivate final @android.annotation.Nullable java.lang.String mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mSplitTypes\nprivate final int mVersionCodeMajor\nprivate final int mVersionCode\nprivate final int mRevisionCode\nprivate final int mInstallLocation\nprivate final int mMinSdkVersion\nprivate final int mTargetSdkVersion\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.SigningDetails mSigningDetails\nprivate final boolean mFeatureSplit\nprivate final boolean mIsolatedSplits\nprivate final boolean mSplitRequired\nprivate final boolean mCoreApp\nprivate final boolean mDebuggable\nprivate final boolean mProfileableByShell\nprivate final boolean mMultiArch\nprivate final boolean mUse32bitAbi\nprivate final boolean mExtractNativeLibs\nprivate final boolean mUseEmbeddedDex\nprivate final @android.annotation.Nullable java.lang.String mTargetPackageName\nprivate final boolean mOverlayIsStatic\nprivate final int mOverlayPriority\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyName\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyValue\nprivate final int mRollbackDataPolicy\nprivate final boolean mHasDeviceAdminReceiver\nprivate final boolean mIsSdkLibrary\nprivate final boolean mUpdatableSystem\nprivate final @android.annotation.Nullable android.content.pm.ArchivedPackageParcel mArchivedPackage\npublic long getLongVersionCode()\nprivate boolean hasAnyRequiredSplitTypes()\nclass ApkLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
+ inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.Nullable java.lang.String mSplitName\nprivate final @android.annotation.Nullable java.lang.String mUsesSplitName\nprivate final @android.annotation.Nullable java.lang.String mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mSplitTypes\nprivate final int mVersionCodeMajor\nprivate final int mVersionCode\nprivate final int mRevisionCode\nprivate final int mInstallLocation\nprivate final int mMinSdkVersion\nprivate final int mTargetSdkVersion\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.SigningDetails mSigningDetails\nprivate final boolean mFeatureSplit\nprivate final boolean mIsolatedSplits\nprivate final boolean mSplitRequired\nprivate final boolean mCoreApp\nprivate final boolean mDebuggable\nprivate final boolean mProfileableByShell\nprivate final boolean mMultiArch\nprivate final boolean mUse32bitAbi\nprivate final boolean mExtractNativeLibs\nprivate final boolean mUseEmbeddedDex\nprivate final @android.annotation.Nullable java.lang.String mTargetPackageName\nprivate final boolean mOverlayIsStatic\nprivate final int mOverlayPriority\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyName\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyValue\nprivate final int mRollbackDataPolicy\nprivate final boolean mHasDeviceAdminReceiver\nprivate final boolean mIsSdkLibrary\nprivate final boolean mUpdatableSystem\nprivate final @android.annotation.Nullable java.lang.String mEmergencyInstaller\nprivate final @android.annotation.Nullable android.content.pm.ArchivedPackageParcel mArchivedPackage\npublic long getLongVersionCode()\nprivate boolean hasAnyRequiredSplitTypes()\nclass ApkLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
index 69f9a7d..ffb69c0 100644
--- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
@@ -435,6 +435,7 @@
boolean isSplitRequired = parser.getAttributeBooleanValue(ANDROID_RES_NAMESPACE,
"isSplitRequired", false);
String configForSplit = parser.getAttributeValue(null, "configForSplit");
+ String emergencyInstaller = parser.getAttributeValue(null, "emergencyInstaller");
int targetSdkVersion = DEFAULT_TARGET_SDK_VERSION;
int minSdkVersion = DEFAULT_MIN_SDK_VERSION;
@@ -644,7 +645,7 @@
overlayIsStatic, overlayPriority, requiredSystemPropertyName,
requiredSystemPropertyValue, minSdkVersion, targetSdkVersion,
rollbackDataPolicy, requiredSplitTypes.first, requiredSplitTypes.second,
- hasDeviceAdminReceiver, isSdkLibrary, updatableSystem));
+ hasDeviceAdminReceiver, isSdkLibrary, updatableSystem, emergencyInstaller));
}
private static boolean isDeviceAdminReceiver(
diff --git a/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java b/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java
index 83acc47..d433ca3 100644
--- a/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java
+++ b/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java
@@ -227,6 +227,9 @@
private String requiredAccountType;
@Nullable
@DataClass.ParcelWith(ForInternedString.class)
+ private String mEmergencyInstaller;
+ @Nullable
+ @DataClass.ParcelWith(ForInternedString.class)
private String overlayTarget;
@Nullable
@DataClass.ParcelWith(ForInternedString.class)
@@ -1275,6 +1278,12 @@
return restrictedAccountType;
}
+ @Nullable
+ @Override
+ public String getEmergencyInstaller() {
+ return mEmergencyInstaller;
+ }
+
@Override
public int getRoundIconResourceId() {
return roundIconRes;
@@ -2336,6 +2345,12 @@
}
@Override
+ public PackageImpl setEmergencyInstaller(@Nullable String emergencyInstaller) {
+ this.mEmergencyInstaller = emergencyInstaller;
+ return this;
+ }
+
+ @Override
public PackageImpl setRoundIconResourceId(int value) {
roundIconRes = value;
return this;
@@ -3105,6 +3120,7 @@
dest.writeString(this.mBaseApkPath);
dest.writeString(this.restrictedAccountType);
dest.writeString(this.requiredAccountType);
+ dest.writeString(this.mEmergencyInstaller);
sForInternedString.parcel(this.overlayTarget, dest, flags);
dest.writeString(this.overlayTargetOverlayableName);
dest.writeString(this.overlayCategory);
@@ -3255,6 +3271,7 @@
this.mBaseApkPath = in.readString();
this.restrictedAccountType = in.readString();
this.requiredAccountType = in.readString();
+ this.mEmergencyInstaller = in.readString();
this.overlayTarget = sForInternedString.unparcel(in);
this.overlayTargetOverlayableName = in.readString();
this.overlayCategory = in.readString();
diff --git a/core/java/com/android/internal/pm/parsing/pkg/ParsedPackage.java b/core/java/com/android/internal/pm/parsing/pkg/ParsedPackage.java
index 7ef0b48..66cfb69 100644
--- a/core/java/com/android/internal/pm/parsing/pkg/ParsedPackage.java
+++ b/core/java/com/android/internal/pm/parsing/pkg/ParsedPackage.java
@@ -75,6 +75,11 @@
ParsedPackage setUpdatableSystem(boolean value);
+ /**
+ * Sets a system app that is allowed to update another system app
+ */
+ ParsedPackage setEmergencyInstaller(String emergencyInstaller);
+
ParsedPackage markNotActivitiesAsNotExportedIfSingleUser();
ParsedPackage setOdm(boolean odm);
diff --git a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java
index 6c09b7c..ef106e0 100644
--- a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java
+++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java
@@ -347,6 +347,11 @@
ParsingPackage setUpdatableSystem(boolean value);
+ /**
+ * Sets a system app that is allowed to update another system app
+ */
+ ParsingPackage setEmergencyInstaller(String emergencyInstaller);
+
ParsingPackage setLargeScreensSupported(int supportsLargeScreens);
ParsingPackage setNormalScreensSupported(int supportsNormalScreens);
diff --git a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
index f483597..e0fdbc6 100644
--- a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
@@ -952,6 +952,8 @@
final boolean updatableSystem = parser.getAttributeBooleanValue(null /*namespace*/,
"updatableSystem", true);
+ final String emergencyInstaller = parser.getAttributeValue(null /*namespace*/,
+ "emergencyInstaller");
pkg.setInstallLocation(anInteger(PARSE_DEFAULT_INSTALL_LOCATION,
R.styleable.AndroidManifest_installLocation, sa))
@@ -959,7 +961,8 @@
R.styleable.AndroidManifest_targetSandboxVersion, sa))
/* Set the global "on SD card" flag */
.setExternalStorage((flags & PARSE_EXTERNAL_STORAGE) != 0)
- .setUpdatableSystem(updatableSystem);
+ .setUpdatableSystem(updatableSystem)
+ .setEmergencyInstaller(emergencyInstaller);
boolean foundApp = false;
final int depth = parser.getDepth();
diff --git a/core/java/com/android/server/pm/pkg/AndroidPackage.java b/core/java/com/android/server/pm/pkg/AndroidPackage.java
index adb0c69..096f246 100644
--- a/core/java/com/android/server/pm/pkg/AndroidPackage.java
+++ b/core/java/com/android/server/pm/pkg/AndroidPackage.java
@@ -273,6 +273,13 @@
String getRestrictedAccountType();
/**
+ * @see R.styleable#AndroidManifestApplication_emergencyInstaller
+ * @hide
+ */
+ @Nullable
+ String getEmergencyInstaller();
+
+ /**
* @see ApplicationInfo#roundIconRes
* @see R.styleable#AndroidManifestApplication_roundIcon
*/
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 65c4d9f..d910940 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1608,6 +1608,10 @@
This is a private attribute, used without android: namespace. -->
<attr name="updatableSystem" format="boolean" />
+ <!-- Allows each installer in the system image to designate another app in the system image to
+ update the installer. -->
+ <attr name="emergencyInstaller" format="string" />
+
<!-- Specify the type of foreground service. Multiple types can be specified by ORing the flags
together. -->
<attr name="foregroundServiceType">
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 61d9bce..a8da551 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
@@ -24,6 +24,10 @@
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
+import androidx.compose.ui.util.fastFilter
+import androidx.compose.ui.util.fastForEach
+import com.android.compose.animation.scene.transition.link.LinkedTransition
+import com.android.compose.animation.scene.transition.link.StateLink
import kotlin.math.absoluteValue
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.Channel
@@ -101,8 +105,9 @@
fun MutableSceneTransitionLayoutState(
initialScene: SceneKey,
transitions: SceneTransitions = SceneTransitions.Empty,
+ stateLinks: List<StateLink> = emptyList(),
): MutableSceneTransitionLayoutState {
- return MutableSceneTransitionLayoutStateImpl(initialScene, transitions)
+ return MutableSceneTransitionLayoutStateImpl(initialScene, transitions, stateLinks)
}
/**
@@ -121,9 +126,12 @@
currentScene: SceneKey,
onChangeScene: (SceneKey) -> Unit,
transitions: SceneTransitions = SceneTransitions.Empty,
+ stateLinks: List<StateLink> = emptyList(),
): SceneTransitionLayoutState {
- return remember { HoistedSceneTransitionLayoutScene(currentScene, transitions, onChangeScene) }
- .apply { update(currentScene, onChangeScene, transitions) }
+ return remember {
+ HoistedSceneTransitionLayoutScene(currentScene, transitions, onChangeScene, stateLinks)
+ }
+ .apply { update(currentScene, onChangeScene, transitions, stateLinks) }
}
@Stable
@@ -184,8 +192,10 @@
}
}
-internal abstract class BaseSceneTransitionLayoutState(initialScene: SceneKey) :
- SceneTransitionLayoutState {
+internal abstract class BaseSceneTransitionLayoutState(
+ initialScene: SceneKey,
+ protected var stateLinks: List<StateLink>,
+) : SceneTransitionLayoutState {
override var transitionState: TransitionState by
mutableStateOf(TransitionState.Idle(initialScene))
protected set
@@ -196,6 +206,8 @@
*/
internal var transformationSpec: TransformationSpecImpl = TransformationSpec.Empty
+ private val activeTransitionLinks = mutableMapOf<StateLink, LinkedTransition>()
+
/**
* Called when the [current scene][TransitionState.currentScene] should be changed to [scene].
*
@@ -224,20 +236,71 @@
transitions
.transitionSpec(transition.fromScene, transition.toScene, key = transitionKey)
.transformationSpec()
-
+ cancelActiveTransitionLinks()
+ setupTransitionLinks(transition)
transitionState = transition
}
+ private fun cancelActiveTransitionLinks() {
+ for ((link, linkedTransition) in activeTransitionLinks) {
+ link.target.finishTransition(linkedTransition, linkedTransition.currentScene)
+ }
+ activeTransitionLinks.clear()
+ }
+
+ private fun setupTransitionLinks(transitionState: TransitionState) {
+ if (transitionState !is TransitionState.Transition) return
+ stateLinks.fastForEach { stateLink ->
+ val matchingLinks =
+ stateLink.transitionLinks.fastFilter { it.isMatchingLink(transitionState) }
+ if (matchingLinks.isEmpty()) return@fastForEach
+ if (matchingLinks.size > 1) error("More than one link matched.")
+
+ val targetCurrentScene = stateLink.target.transitionState.currentScene
+ val matchingLink = matchingLinks[0]
+
+ if (!matchingLink.targetIsInValidState(targetCurrentScene)) return@fastForEach
+
+ val linkedTransition =
+ LinkedTransition(
+ originalTransition = transitionState,
+ fromScene = targetCurrentScene,
+ toScene = matchingLink.targetTo,
+ )
+
+ stateLink.target.startTransition(linkedTransition, matchingLink.targetTransitionKey)
+ activeTransitionLinks[stateLink] = linkedTransition
+ }
+ }
+
/**
* Notify that [transition] was finished and that we should settle to [idleScene]. This will do
* nothing if [transition] was interrupted since it was started.
*/
internal fun finishTransition(transition: TransitionState.Transition, idleScene: SceneKey) {
+ resolveActiveTransitionLinks(idleScene)
if (transitionState == transition) {
transitionState = TransitionState.Idle(idleScene)
}
}
+ private fun resolveActiveTransitionLinks(idleScene: SceneKey) {
+ val previousTransition = this.transitionState as? TransitionState.Transition ?: return
+ for ((link, linkedTransition) in activeTransitionLinks) {
+ if (previousTransition.fromScene == idleScene) {
+ // The transition ended by arriving at the fromScene, move link to Idle(fromScene).
+ link.target.finishTransition(linkedTransition, linkedTransition.fromScene)
+ } else if (previousTransition.toScene == idleScene) {
+ // The transition ended by arriving at the toScene, move link to Idle(toScene).
+ link.target.finishTransition(linkedTransition, linkedTransition.toScene)
+ } else {
+ // The transition was interrupted by something else, we reset to initial state.
+ link.target.finishTransition(linkedTransition, linkedTransition.fromScene)
+ }
+ }
+ activeTransitionLinks.clear()
+ }
+
/**
* Check if a transition is in progress. If the progress value is near 0 or 1, immediately snap
* to the closest scene.
@@ -271,7 +334,8 @@
initialScene: SceneKey,
override var transitions: SceneTransitions,
private var changeScene: (SceneKey) -> Unit,
-) : BaseSceneTransitionLayoutState(initialScene) {
+ stateLinks: List<StateLink> = emptyList(),
+) : BaseSceneTransitionLayoutState(initialScene, stateLinks) {
private val targetSceneChannel = Channel<SceneKey>(Channel.CONFLATED)
override fun CoroutineScope.onChangeScene(scene: SceneKey) = changeScene(scene)
@@ -281,10 +345,12 @@
currentScene: SceneKey,
onChangeScene: (SceneKey) -> Unit,
transitions: SceneTransitions,
+ stateLinks: List<StateLink>,
) {
SideEffect {
this.changeScene = onChangeScene
this.transitions = transitions
+ this.stateLinks = stateLinks
targetSceneChannel.trySend(currentScene)
}
@@ -308,7 +374,8 @@
internal class MutableSceneTransitionLayoutStateImpl(
initialScene: SceneKey,
override var transitions: SceneTransitions,
-) : MutableSceneTransitionLayoutState, BaseSceneTransitionLayoutState(initialScene) {
+ stateLinks: List<StateLink> = emptyList(),
+) : MutableSceneTransitionLayoutState, BaseSceneTransitionLayoutState(initialScene, stateLinks) {
override fun setTargetScene(
targetScene: SceneKey,
coroutineScope: CoroutineScope,
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
new file mode 100644
index 0000000..33b57b2
--- /dev/null
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transition/link/LinkedTransition.kt
@@ -0,0 +1,46 @@
+/*
+ * 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.compose.animation.scene.transition.link
+
+import com.android.compose.animation.scene.SceneKey
+import com.android.compose.animation.scene.TransitionState
+
+/** A linked transition which is driven by a [originalTransition]. */
+internal class LinkedTransition(
+ private val originalTransition: TransitionState.Transition,
+ fromScene: SceneKey,
+ toScene: SceneKey,
+) : TransitionState.Transition(fromScene, toScene) {
+
+ override val currentScene: SceneKey
+ get() {
+ return when (originalTransition.currentScene) {
+ originalTransition.fromScene -> fromScene
+ originalTransition.toScene -> toScene
+ else -> error("Original currentScene is neither FromScene nor ToScene")
+ }
+ }
+
+ override val isInitiatedByUserInput: Boolean
+ get() = originalTransition.isInitiatedByUserInput
+
+ override val isUserInputOngoing: Boolean
+ get() = originalTransition.isUserInputOngoing
+
+ override val progress: Float
+ get() = originalTransition.progress
+}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transition/link/StateLink.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transition/link/StateLink.kt
new file mode 100644
index 0000000..6c29946
--- /dev/null
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transition/link/StateLink.kt
@@ -0,0 +1,62 @@
+/*
+ * 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.compose.animation.scene.transition.link
+
+import com.android.compose.animation.scene.BaseSceneTransitionLayoutState
+import com.android.compose.animation.scene.SceneKey
+import com.android.compose.animation.scene.SceneTransitionLayoutState
+import com.android.compose.animation.scene.TransitionKey
+import com.android.compose.animation.scene.TransitionState
+
+/** A link between a source (implicit) and [target] `SceneTransitionLayoutState`. */
+class StateLink(target: SceneTransitionLayoutState, val transitionLinks: List<TransitionLink>) {
+
+ internal val target = target as BaseSceneTransitionLayoutState
+
+ /**
+ * Links two transitions (source and target) together.
+ *
+ * `null` can be passed to indicate that any SceneKey should match. e.g. passing `null`, `null`,
+ * `null`, `SceneA` means that any transition at the source will trigger a transition in the
+ * target to `SceneA` from any current scene.
+ */
+ class TransitionLink(
+ val sourceFrom: SceneKey?,
+ val sourceTo: SceneKey?,
+ val targetFrom: SceneKey?,
+ val targetTo: SceneKey,
+ val targetTransitionKey: TransitionKey? = null,
+ ) {
+ init {
+ if (
+ (sourceFrom != null && sourceFrom == sourceTo) ||
+ (targetFrom != null && targetFrom == targetTo)
+ )
+ error("From and To can't be the same")
+ }
+
+ internal fun isMatchingLink(transition: TransitionState.Transition): Boolean {
+ return (sourceFrom == null || sourceFrom == transition.fromScene) &&
+ (sourceTo == null || sourceTo == transition.toScene)
+ }
+
+ internal fun targetIsInValidState(targetCurrentScene: SceneKey): Boolean {
+ return (targetFrom == null || targetFrom == targetCurrentScene) &&
+ targetTo != targetCurrentScene
+ }
+ }
+}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
index 302fc0b..f81a7f2 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
@@ -18,10 +18,14 @@
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.compose.animation.scene.TestScenes.SceneA
+import com.android.compose.animation.scene.TestScenes.SceneB
+import com.android.compose.animation.scene.TestScenes.SceneC
+import com.android.compose.animation.scene.TestScenes.SceneD
+import com.android.compose.animation.scene.transition.link.StateLink
import com.android.compose.test.runMonotonicClockTest
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.CoroutineStart
-import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
import org.junit.Rule
import org.junit.Test
@@ -31,93 +35,241 @@
class SceneTransitionLayoutStateTest {
@get:Rule val rule = createComposeRule()
+ class TestableTransition(
+ fromScene: SceneKey,
+ toScene: SceneKey,
+ ) : TransitionState.Transition(fromScene, toScene) {
+ override var currentScene: SceneKey = fromScene
+ override var progress: Float = 0.0f
+ override var isInitiatedByUserInput: Boolean = false
+ override var isUserInputOngoing: Boolean = false
+ }
+
@Test
fun isTransitioningTo_idle() {
- val state = MutableSceneTransitionLayoutStateImpl(TestScenes.SceneA, SceneTransitions.Empty)
+ val state = MutableSceneTransitionLayoutStateImpl(SceneA, SceneTransitions.Empty)
assertThat(state.isTransitioning()).isFalse()
- assertThat(state.isTransitioning(from = TestScenes.SceneA)).isFalse()
- assertThat(state.isTransitioning(to = TestScenes.SceneB)).isFalse()
- assertThat(state.isTransitioning(from = TestScenes.SceneA, to = TestScenes.SceneB))
- .isFalse()
+ assertThat(state.isTransitioning(from = SceneA)).isFalse()
+ assertThat(state.isTransitioning(to = SceneB)).isFalse()
+ assertThat(state.isTransitioning(from = SceneA, to = SceneB)).isFalse()
}
@Test
fun isTransitioningTo_transition() {
- val state = MutableSceneTransitionLayoutStateImpl(TestScenes.SceneA, SceneTransitions.Empty)
- state.startTransition(
- transition(from = TestScenes.SceneA, to = TestScenes.SceneB),
- transitionKey = null
- )
+ val state = MutableSceneTransitionLayoutStateImpl(SceneA, SceneTransitions.Empty)
+ state.startTransition(transition(from = SceneA, to = SceneB), transitionKey = null)
assertThat(state.isTransitioning()).isTrue()
- assertThat(state.isTransitioning(from = TestScenes.SceneA)).isTrue()
- assertThat(state.isTransitioning(from = TestScenes.SceneB)).isFalse()
- assertThat(state.isTransitioning(to = TestScenes.SceneB)).isTrue()
- assertThat(state.isTransitioning(to = TestScenes.SceneA)).isFalse()
- assertThat(state.isTransitioning(from = TestScenes.SceneA, to = TestScenes.SceneB)).isTrue()
+ assertThat(state.isTransitioning(from = SceneA)).isTrue()
+ assertThat(state.isTransitioning(from = SceneB)).isFalse()
+ assertThat(state.isTransitioning(to = SceneB)).isTrue()
+ assertThat(state.isTransitioning(to = SceneA)).isFalse()
+ assertThat(state.isTransitioning(from = SceneA, to = SceneB)).isTrue()
}
@Test
fun setTargetScene_idleToSameScene() = runMonotonicClockTest {
- val state = MutableSceneTransitionLayoutState(TestScenes.SceneA)
- assertThat(state.setTargetScene(TestScenes.SceneA, coroutineScope = this)).isNull()
+ val state = MutableSceneTransitionLayoutState(SceneA)
+ assertThat(state.setTargetScene(SceneA, coroutineScope = this)).isNull()
}
@Test
fun setTargetScene_idleToDifferentScene() = runMonotonicClockTest {
- val state = MutableSceneTransitionLayoutState(TestScenes.SceneA)
- val transition = state.setTargetScene(TestScenes.SceneB, coroutineScope = this)
+ val state = MutableSceneTransitionLayoutState(SceneA)
+ val transition = state.setTargetScene(SceneB, coroutineScope = this)
assertThat(transition).isNotNull()
assertThat(state.transitionState).isEqualTo(transition)
testScheduler.advanceUntilIdle()
- assertThat(state.transitionState).isEqualTo(TransitionState.Idle(TestScenes.SceneB))
+ assertThat(state.transitionState).isEqualTo(TransitionState.Idle(SceneB))
}
@Test
fun setTargetScene_transitionToSameScene() = runMonotonicClockTest {
- val state = MutableSceneTransitionLayoutState(TestScenes.SceneA)
- assertThat(state.setTargetScene(TestScenes.SceneB, coroutineScope = this)).isNotNull()
- assertThat(state.setTargetScene(TestScenes.SceneB, coroutineScope = this)).isNull()
+ val state = MutableSceneTransitionLayoutState(SceneA)
+ assertThat(state.setTargetScene(SceneB, coroutineScope = this)).isNotNull()
+ assertThat(state.setTargetScene(SceneB, coroutineScope = this)).isNull()
testScheduler.advanceUntilIdle()
- assertThat(state.transitionState).isEqualTo(TransitionState.Idle(TestScenes.SceneB))
+ assertThat(state.transitionState).isEqualTo(TransitionState.Idle(SceneB))
}
@Test
fun setTargetScene_transitionToDifferentScene() = runMonotonicClockTest {
- val state = MutableSceneTransitionLayoutState(TestScenes.SceneA)
- assertThat(state.setTargetScene(TestScenes.SceneB, coroutineScope = this)).isNotNull()
- assertThat(state.setTargetScene(TestScenes.SceneC, coroutineScope = this)).isNotNull()
+ val state = MutableSceneTransitionLayoutState(SceneA)
+ assertThat(state.setTargetScene(SceneB, coroutineScope = this)).isNotNull()
+ assertThat(state.setTargetScene(SceneC, coroutineScope = this)).isNotNull()
testScheduler.advanceUntilIdle()
- assertThat(state.transitionState).isEqualTo(TransitionState.Idle(TestScenes.SceneC))
+ assertThat(state.transitionState).isEqualTo(TransitionState.Idle(SceneC))
}
@Test
fun setTargetScene_transitionToOriginalScene() = runMonotonicClockTest {
- val state = MutableSceneTransitionLayoutState(TestScenes.SceneA)
- assertThat(state.setTargetScene(TestScenes.SceneB, coroutineScope = this)).isNotNull()
+ val state = MutableSceneTransitionLayoutState(SceneA)
+ assertThat(state.setTargetScene(SceneB, coroutineScope = this)).isNotNull()
// Progress is 0f, so we don't animate at all and directly snap back to A.
- assertThat(state.setTargetScene(TestScenes.SceneA, coroutineScope = this)).isNull()
- assertThat(state.transitionState).isEqualTo(TransitionState.Idle(TestScenes.SceneA))
+ assertThat(state.setTargetScene(SceneA, coroutineScope = this)).isNull()
+ assertThat(state.transitionState).isEqualTo(TransitionState.Idle(SceneA))
}
@Test
fun setTargetScene_coroutineScopeCancelled() = runMonotonicClockTest {
- val state = MutableSceneTransitionLayoutState(TestScenes.SceneA)
+ val state = MutableSceneTransitionLayoutState(SceneA)
lateinit var transition: TransitionState.Transition
val job =
launch(start = CoroutineStart.UNDISPATCHED) {
- transition = state.setTargetScene(TestScenes.SceneB, coroutineScope = this)!!
+ transition = state.setTargetScene(SceneB, coroutineScope = this)!!
}
assertThat(state.transitionState).isEqualTo(transition)
// Cancelling the scope/job still sets the state to Idle(targetScene).
job.cancel()
testScheduler.advanceUntilIdle()
- assertThat(state.transitionState).isEqualTo(TransitionState.Idle(TestScenes.SceneB))
+ assertThat(state.transitionState).isEqualTo(TransitionState.Idle(SceneB))
+ }
+
+ private fun setupLinkedStates(
+ parentInitialScene: SceneKey = SceneC,
+ childInitialScene: SceneKey = SceneA,
+ sourceFrom: SceneKey? = SceneA,
+ sourceTo: SceneKey? = SceneB,
+ targetFrom: SceneKey? = SceneC,
+ targetTo: SceneKey = SceneD
+ ): Pair<BaseSceneTransitionLayoutState, BaseSceneTransitionLayoutState> {
+ val parentState = MutableSceneTransitionLayoutState(parentInitialScene)
+ val link =
+ listOf(
+ StateLink(
+ parentState,
+ listOf(StateLink.TransitionLink(sourceFrom, sourceTo, targetFrom, targetTo))
+ )
+ )
+ val childState = MutableSceneTransitionLayoutState(childInitialScene, stateLinks = link)
+ return Pair(
+ parentState as BaseSceneTransitionLayoutState,
+ childState as BaseSceneTransitionLayoutState
+ )
+ }
+
+ @Test
+ fun linkedTransition_startsLinkAndFinishesLinkInToState() {
+ val (parentState, childState) = setupLinkedStates()
+
+ val childTransition = TestableTransition(SceneA, SceneB)
+
+ childState.startTransition(childTransition, null)
+ assertThat(childState.isTransitioning(SceneA, SceneB)).isTrue()
+ assertThat(parentState.isTransitioning(SceneC, SceneD)).isTrue()
+
+ childState.finishTransition(childTransition, SceneB)
+ assertThat(childState.transitionState).isEqualTo(TransitionState.Idle(SceneB))
+ assertThat(parentState.transitionState).isEqualTo(TransitionState.Idle(SceneD))
+ }
+
+ @Test
+ fun linkedTransition_transitiveLink() {
+ val parentParentState =
+ MutableSceneTransitionLayoutState(SceneB) as BaseSceneTransitionLayoutState
+ val parentLink =
+ listOf(
+ StateLink(
+ parentParentState,
+ listOf(StateLink.TransitionLink(SceneC, SceneD, SceneB, SceneC))
+ )
+ )
+ val parentState =
+ MutableSceneTransitionLayoutState(SceneC, stateLinks = parentLink)
+ as BaseSceneTransitionLayoutState
+ val link =
+ listOf(
+ StateLink(
+ parentState,
+ listOf(StateLink.TransitionLink(SceneA, SceneB, SceneC, SceneD))
+ )
+ )
+ val childState =
+ MutableSceneTransitionLayoutState(SceneA, stateLinks = link)
+ as BaseSceneTransitionLayoutState
+
+ val childTransition = TestableTransition(SceneA, SceneB)
+
+ childState.startTransition(childTransition, null)
+ assertThat(childState.isTransitioning(SceneA, SceneB)).isTrue()
+ assertThat(parentState.isTransitioning(SceneC, SceneD)).isTrue()
+ assertThat(parentParentState.isTransitioning(SceneB, SceneC)).isTrue()
+
+ childState.finishTransition(childTransition, SceneB)
+ assertThat(childState.transitionState).isEqualTo(TransitionState.Idle(SceneB))
+ assertThat(parentState.transitionState).isEqualTo(TransitionState.Idle(SceneD))
+ assertThat(parentParentState.transitionState).isEqualTo(TransitionState.Idle(SceneC))
+ }
+
+ @Test
+ fun linkedTransition_linkProgressIsEqual() {
+ val (parentState, childState) = setupLinkedStates()
+
+ val childTransition = TestableTransition(SceneA, SceneB)
+
+ childState.startTransition(childTransition, null)
+ assertThat(parentState.currentTransition?.progress).isEqualTo(0f)
+
+ childTransition.progress = .5f
+ assertThat(parentState.currentTransition?.progress).isEqualTo(.5f)
+ }
+
+ @Test
+ fun linkedTransition_reverseTransitionIsNotLinked() {
+ val (parentState, childState) = setupLinkedStates()
+
+ val childTransition = TestableTransition(SceneB, SceneA)
+
+ childState.startTransition(childTransition, null)
+ assertThat(childState.isTransitioning(SceneB, SceneA)).isTrue()
+ assertThat(parentState.transitionState).isEqualTo(TransitionState.Idle(SceneC))
+
+ childState.finishTransition(childTransition, SceneB)
+ assertThat(childState.transitionState).isEqualTo(TransitionState.Idle(SceneB))
+ assertThat(parentState.transitionState).isEqualTo(TransitionState.Idle(SceneC))
+ }
+
+ @Test
+ fun linkedTransition_startsLinkAndFinishesLinkInFromState() {
+ val (parentState, childState) = setupLinkedStates()
+
+ val childTransition = TestableTransition(SceneA, SceneB)
+ childState.startTransition(childTransition, null)
+
+ childState.finishTransition(childTransition, SceneA)
+ assertThat(childState.transitionState).isEqualTo(TransitionState.Idle(SceneA))
+ assertThat(parentState.transitionState).isEqualTo(TransitionState.Idle(SceneC))
+ }
+
+ @Test
+ fun linkedTransition_startsLinkAndFinishesLinkInUnknownState() {
+ val (parentState, childState) = setupLinkedStates()
+
+ val childTransition = TestableTransition(SceneA, SceneB)
+ childState.startTransition(childTransition, null)
+
+ childState.finishTransition(childTransition, SceneD)
+ assertThat(childState.transitionState).isEqualTo(TransitionState.Idle(SceneD))
+ assertThat(parentState.transitionState).isEqualTo(TransitionState.Idle(SceneC))
+ }
+
+ @Test
+ fun linkedTransition_startsLinkButLinkedStateIsTakenOver() {
+ val (parentState, childState) = setupLinkedStates()
+
+ val childTransition = TestableTransition(SceneA, SceneB)
+ val parentTransition = TestableTransition(SceneC, SceneA)
+ childState.startTransition(childTransition, null)
+ parentState.startTransition(parentTransition, null)
+
+ childState.finishTransition(childTransition, SceneB)
+ assertThat(childState.transitionState).isEqualTo(TransitionState.Idle(SceneB))
+ assertThat(parentState.transitionState).isEqualTo(parentTransition)
}
@Test
@@ -125,11 +277,11 @@
val transitionkey = TransitionKey(debugName = "foo")
val state =
MutableSceneTransitionLayoutState(
- TestScenes.SceneA,
+ SceneA,
transitions =
transitions {
- from(TestScenes.SceneA, to = TestScenes.SceneB) { fade(TestElements.Foo) }
- from(TestScenes.SceneA, to = TestScenes.SceneB, key = transitionkey) {
+ from(SceneA, to = SceneB) { fade(TestElements.Foo) }
+ from(SceneA, to = SceneB, key = transitionkey) {
fade(TestElements.Foo)
fade(TestElements.Bar)
}
@@ -138,19 +290,19 @@
as MutableSceneTransitionLayoutStateImpl
// Default transition from A to B.
- assertThat(state.setTargetScene(TestScenes.SceneB, coroutineScope = this)).isNotNull()
+ assertThat(state.setTargetScene(SceneB, coroutineScope = this)).isNotNull()
assertThat(state.transformationSpec.transformations).hasSize(1)
// Go back to A.
- state.setTargetScene(TestScenes.SceneA, coroutineScope = this)
+ state.setTargetScene(SceneA, coroutineScope = this)
testScheduler.advanceUntilIdle()
assertThat(state.currentTransition).isNull()
- assertThat(state.transitionState.currentScene).isEqualTo(TestScenes.SceneA)
+ assertThat(state.transitionState.currentScene).isEqualTo(SceneA)
// Specific transition from A to B.
assertThat(
state.setTargetScene(
- TestScenes.SceneB,
+ SceneB,
coroutineScope = this,
transitionKey = transitionkey,
)
@@ -196,4 +348,45 @@
assertThat(state.isTransitioning()).isFalse()
assertThat(state.transitionState).isEqualTo(TransitionState.Idle(TestScenes.SceneB))
}
+
+ @Test
+ fun linkedTransition_fuzzyLinksAreMatchedAndStarted() {
+ val (parentState, childState) = setupLinkedStates(SceneC, SceneA, null, null, null, SceneD)
+ val childTransition = TestableTransition(SceneA, SceneB)
+
+ childState.startTransition(childTransition, null)
+ assertThat(childState.isTransitioning(SceneA, SceneB)).isTrue()
+ assertThat(parentState.isTransitioning(SceneC, SceneD)).isTrue()
+
+ childState.finishTransition(childTransition, SceneB)
+ assertThat(childState.transitionState).isEqualTo(TransitionState.Idle(SceneB))
+ assertThat(parentState.transitionState).isEqualTo(TransitionState.Idle(SceneD))
+ }
+
+ @Test
+ fun linkedTransition_fuzzyLinksAreMatchedAndResetToProperPreviousScene() {
+ val (parentState, childState) =
+ setupLinkedStates(SceneC, SceneA, SceneA, null, null, SceneD)
+
+ val childTransition = TestableTransition(SceneA, SceneB)
+
+ childState.startTransition(childTransition, null)
+ assertThat(childState.isTransitioning(SceneA, SceneB)).isTrue()
+ assertThat(parentState.isTransitioning(SceneC, SceneD)).isTrue()
+
+ childState.finishTransition(childTransition, SceneA)
+ assertThat(childState.transitionState).isEqualTo(TransitionState.Idle(SceneA))
+ assertThat(parentState.transitionState).isEqualTo(TransitionState.Idle(SceneC))
+ }
+
+ @Test
+ fun linkedTransition_fuzzyLinksAreNotMatched() {
+ val (parentState, childState) =
+ setupLinkedStates(SceneC, SceneA, SceneB, null, SceneC, SceneD)
+ val childTransition = TestableTransition(SceneA, SceneB)
+
+ childState.startTransition(childTransition, null)
+ assertThat(childState.isTransitioning(SceneA, SceneB)).isTrue()
+ assertThat(parentState.isTransitioning(SceneC, SceneD)).isFalse()
+ }
}
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/settings/data/repository/SecureSettingsRepository.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/settings/data/repository/SecureSettingsRepository.kt
index 754d5dc..2a87452 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/settings/data/repository/SecureSettingsRepository.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/settings/data/repository/SecureSettingsRepository.kt
@@ -27,7 +27,11 @@
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.withContext
-/** Defines interface for classes that can provide access to data from [Settings.Secure]. */
+/**
+ * Defines interface for classes that can provide access to data from [Settings.Secure].
+ * This repository doesn't guarantee to provide value across different users. For that
+ * see: [UserAwareSecureSettingsRepository]
+ */
interface SecureSettingsRepository {
/** Returns a [Flow] tracking the value of a setting as an [Int]. */
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 51012a4..cc31754 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -174,7 +174,7 @@
<dimen name="status_bar_clock_size">14sp</dimen>
<!-- The starting padding for the clock in the status bar. -->
- <dimen name="status_bar_clock_starting_padding">7dp</dimen>
+ <dimen name="status_bar_clock_starting_padding">4dp</dimen>
<!-- The end padding for the clock in the status bar. -->
<dimen name="status_bar_clock_end_padding">0dp</dimen>
@@ -395,7 +395,7 @@
<dimen name="status_bar_icon_horizontal_margin">0sp</dimen>
<!-- the padding on the start of the statusbar -->
- <dimen name="status_bar_padding_start">8dp</dimen>
+ <dimen name="status_bar_padding_start">4dp</dimen>
<!-- the padding on the end of the statusbar -->
<dimen name="status_bar_padding_end">4dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/data/repository/StickyKeysRepository.kt b/packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/data/repository/StickyKeysRepository.kt
index ec29bd6..89cdd25 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/data/repository/StickyKeysRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/data/repository/StickyKeysRepository.kt
@@ -32,19 +32,13 @@
import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.CTRL
import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.META
import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.SHIFT
-import com.android.systemui.user.data.repository.UserRepository
-import com.android.systemui.util.settings.SecureSettings
-import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
+import com.android.systemui.util.settings.repository.UserAwareSecureSettingsRepository
import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.flow.onStart
import javax.inject.Inject
interface StickyKeysRepository {
@@ -53,14 +47,12 @@
}
@SysUISingleton
-@OptIn(ExperimentalCoroutinesApi::class)
class StickyKeysRepositoryImpl
@Inject
constructor(
private val inputManager: InputManager,
@Background private val backgroundDispatcher: CoroutineDispatcher,
- private val secureSettings: SecureSettings,
- userRepository: UserRepository,
+ secureSettingsRepository: UserAwareSecureSettingsRepository,
private val stickyKeysLogger: StickyKeysLogger,
) : StickyKeysRepository {
@@ -78,25 +70,10 @@
.flowOn(backgroundDispatcher)
override val settingEnabled: Flow<Boolean> =
- userRepository.selectedUserInfo
- .flatMapLatest { stickyKeySettingObserver(it.id) }
- .flowOn(backgroundDispatcher)
-
- private fun stickyKeySettingObserver(userId: Int): Flow<Boolean> {
- return secureSettings
- .observerFlow(userId, SETTING_KEY)
- .onStart { emit(Unit) }
- .map { isSettingEnabledForCurrentUser(userId) }
- .distinctUntilChanged()
+ secureSettingsRepository
+ .boolSettingForActiveUser(SETTING_KEY, defaultValue = false)
.onEach { stickyKeysLogger.logNewSettingValue(it) }
- }
-
- private fun isSettingEnabledForCurrentUser(userId: Int) =
- secureSettings.getIntForUser(
- /* name= */ SETTING_KEY,
- /* default= */ 0,
- /* userHandle= */ userId
- ) != 0
+ .flowOn(backgroundDispatcher)
private fun toStickyKeysMap(state: StickyModifierState): LinkedHashMap<ModifierKey, Locked> {
val keys = linkedMapOf<ModifierKey, Locked>()
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 8fa33ee7..5606d43 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
@@ -21,18 +21,18 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.keyguard.KeyguardWmStateRefactor
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel.Companion.isWakeAndUnlock
import com.android.systemui.keyguard.shared.model.DozeStateModel
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled
-import com.android.systemui.util.kotlin.Utils.Companion.toTriple
+import com.android.systemui.util.kotlin.Utils.Companion.sample
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
@SysUISingleton
@@ -85,15 +85,16 @@
keyguardInteractor
.dozeTransitionTo(DozeStateModel.FINISH)
.sample(
- combine(
- startedKeyguardTransitionStep,
- keyguardInteractor.isKeyguardOccluded,
- ::Pair
- ),
- ::toTriple
+ startedKeyguardTransitionStep,
+ keyguardInteractor.isKeyguardOccluded,
+ keyguardInteractor.biometricUnlockState,
)
- .collect { (_, lastStartedStep, occluded) ->
- if (lastStartedStep.to == KeyguardState.AOD && !occluded) {
+ .collect { (_, lastStartedStep, occluded, biometricUnlockState) ->
+ if (
+ lastStartedStep.to == KeyguardState.AOD &&
+ !occluded &&
+ !isWakeAndUnlock(biometricUnlockState)
+ ) {
val modeOnCanceled =
if (lastStartedStep.from == KeyguardState.LOCKSCREEN) {
TransitionModeOnCanceled.REVERSE
@@ -126,15 +127,29 @@
}
private fun listenForAodToGone() {
+ if (KeyguardWmStateRefactor.isEnabled) {
+ return
+ }
+
scope.launch {
keyguardInteractor.biometricUnlockState.sample(finishedKeyguardState, ::Pair).collect {
(biometricUnlockState, keyguardState) ->
+ KeyguardWmStateRefactor.assertInLegacyMode()
if (keyguardState == KeyguardState.AOD && isWakeAndUnlock(biometricUnlockState)) {
startTransitionTo(KeyguardState.GONE)
}
}
}
}
+
+ /**
+ * Dismisses AOD and transitions to GONE. This is called whenever authentication occurs while on
+ * AOD.
+ */
+ fun dismissAod() {
+ scope.launch { startTransitionTo(KeyguardState.GONE) }
+ }
+
override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator {
return ValueAnimator().apply {
interpolator = Interpolators.LINEAR
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
index 7477624..6b85a63 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
@@ -68,11 +68,11 @@
scope.launch {
keyguardInteractor.isKeyguardShowing
.sample(
- startedKeyguardTransitionStep,
+ currentKeyguardState,
communalInteractor.isIdleOnCommunal,
)
- .collect { (isKeyguardShowing, lastStartedStep, isIdleOnCommunal) ->
- if (isKeyguardShowing && lastStartedStep.to == KeyguardState.GONE) {
+ .collect { (isKeyguardShowing, currentState, isIdleOnCommunal) ->
+ if (isKeyguardShowing && currentState == KeyguardState.GONE) {
val to =
if (isIdleOnCommunal) {
KeyguardState.GLANCEABLE_HUB
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractor.kt
index 8784723..c496a6e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractor.kt
@@ -22,6 +22,7 @@
import com.android.systemui.keyguard.domain.interactor.WindowManagerLockscreenVisibilityInteractor.Companion.isSurfaceVisible
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.KeyguardSurfaceBehindModel
+import com.android.systemui.statusbar.notification.domain.interactor.NotificationLaunchAnimationInteractor
import com.android.systemui.util.kotlin.toPx
import dagger.Lazy
import javax.inject.Inject
@@ -44,6 +45,7 @@
transitionInteractor: KeyguardTransitionInteractor,
inWindowLauncherUnlockAnimationInteractor: Lazy<InWindowLauncherUnlockAnimationInteractor>,
swipeToDismissInteractor: SwipeToDismissInteractor,
+ notificationLaunchInteractor: NotificationLaunchAnimationInteractor,
) {
/**
* The view params to use for the surface. These params describe the alpha/translation values to
@@ -53,10 +55,20 @@
combine(
transitionInteractor.startedKeyguardTransitionStep,
transitionInteractor.currentKeyguardState,
- ) { startedStep, currentState ->
+ notificationLaunchInteractor.isLaunchAnimationRunning,
+ ) { startedStep, currentState, notifAnimationRunning ->
// If we're in transition to GONE, special unlock animation params apply.
if (startedStep.to == KeyguardState.GONE && currentState != KeyguardState.GONE) {
- if (inWindowLauncherUnlockAnimationInteractor.get().isLauncherUnderneath()) {
+ if (notifAnimationRunning) {
+ // If the notification launch animation is running, leave the alpha at 0f.
+ // The ActivityLaunchAnimator will morph it from the notification at the
+ // appropriate time.
+ return@combine KeyguardSurfaceBehindModel(
+ alpha = 0f,
+ )
+ } else if (
+ inWindowLauncherUnlockAnimationInteractor.get().isLauncherUnderneath()
+ ) {
// The Launcher icons have their own translation/alpha animations during the
// in-window animation. We'll just make the surface visible and let Launcher
// do its thing.
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 b43ab5e..310f13d 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
@@ -60,6 +60,7 @@
private val fromLockscreenTransitionInteractor: dagger.Lazy<FromLockscreenTransitionInteractor>,
private val fromPrimaryBouncerTransitionInteractor:
dagger.Lazy<FromPrimaryBouncerTransitionInteractor>,
+ private val fromAodTransitionInteractor: dagger.Lazy<FromAodTransitionInteractor>,
) {
private val TAG = this::class.simpleName
@@ -346,6 +347,7 @@
when (val startedState = startedKeyguardState.replayCache.last()) {
LOCKSCREEN -> fromLockscreenTransitionInteractor.get().dismissKeyguard()
PRIMARY_BOUNCER -> fromPrimaryBouncerTransitionInteractor.get().dismissPrimaryBouncer()
+ AOD -> fromAodTransitionInteractor.get().dismissAod()
else ->
Log.e(
"KeyguardTransitionInteractor",
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt
index 19d00cf..c7f262a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt
@@ -42,7 +42,7 @@
private val lightRevealScrimRepository: LightRevealScrimRepository,
@Application private val scope: CoroutineScope,
private val scrimLogger: ScrimLogger,
- powerInteractor: PowerInteractor,
+ private val powerInteractor: PowerInteractor,
) {
init {
@@ -83,11 +83,13 @@
// (invisible) jank. However, we need to still pass through 1f and 0f to ensure that the
// correct end states are respected even if the screen turned off (or was still off)
// when the animation finished
- powerInteractor.screenPowerState.value != ScreenPowerState.SCREEN_OFF ||
- it == 1f ||
- it == 0f
+ screenIsShowingContent() || it == 1f || it == 0f
}
+ private fun screenIsShowingContent() =
+ powerInteractor.screenPowerState.value != ScreenPowerState.SCREEN_OFF &&
+ powerInteractor.screenPowerState.value != ScreenPowerState.SCREEN_TURNING_ON
+
companion object {
/**
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 5c2df45..3ccbdba 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
@@ -60,6 +60,7 @@
// 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,
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 49af664..b81793e 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
@@ -19,6 +19,8 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.statusbar.notification.domain.interactor.NotificationLaunchAnimationInteractor
+import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
@@ -26,7 +28,6 @@
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
-import javax.inject.Inject
@SysUISingleton
class WindowManagerLockscreenVisibilityInteractor
@@ -37,6 +38,7 @@
surfaceBehindInteractor: KeyguardSurfaceBehindInteractor,
fromLockscreenInteractor: FromLockscreenTransitionInteractor,
fromBouncerInteractor: FromPrimaryBouncerTransitionInteractor,
+ notificationLaunchAnimationInteractor: NotificationLaunchAnimationInteractor,
) {
private val defaultSurfaceBehindVisibility =
transitionInteractor.finishedKeyguardState.map(::isSurfaceVisible)
@@ -72,8 +74,7 @@
*/
@OptIn(ExperimentalCoroutinesApi::class)
val surfaceBehindVisibility: Flow<Boolean> =
- transitionInteractor
- .isInTransitionToAnyState
+ transitionInteractor.isInTransitionToAnyState
.flatMapLatest { isInTransition ->
if (!isInTransition) {
defaultSurfaceBehindVisibility
@@ -99,12 +100,16 @@
combine(
transitionInteractor.isInTransitionToState(KeyguardState.GONE),
transitionInteractor.finishedKeyguardState,
- surfaceBehindInteractor.isAnimatingSurface
- ) { isInTransitionToGone, finishedState, isAnimatingSurface ->
+ surfaceBehindInteractor.isAnimatingSurface,
+ notificationLaunchAnimationInteractor.isLaunchAnimationRunning,
+ ) { isInTransitionToGone, finishedState, 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 && isAnimatingSurface)
+ isInTransitionToGone || (finishedState == KeyguardState.GONE && animationsRunning)
}
.distinctUntilChanged()
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java
index be1fa2b..e9af295 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java
@@ -30,11 +30,11 @@
import com.android.internal.logging.UiEventLogger;
import com.android.settingslib.RestrictedLockUtils;
import com.android.systemui.Gefingerpoken;
-import com.android.systemui.res.R;
import com.android.systemui.classifier.Classifier;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.haptics.slider.SeekableSliderEventProducer;
import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
import com.android.systemui.util.ViewController;
@@ -236,7 +236,7 @@
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
mTracking = true;
- mUiEventLogger.log(BrightnessSliderEvent.SLIDER_STARTED_TRACKING_TOUCH);
+ mUiEventLogger.log(BrightnessSliderEvent.BRIGHTNESS_SLIDER_STARTED_TRACKING_TOUCH);
if (mListener != null) {
mListener.onChanged(mTracking, getValue(), false);
SeekableSliderEventProducer eventProducer =
@@ -255,7 +255,7 @@
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
mTracking = false;
- mUiEventLogger.log(BrightnessSliderEvent.SLIDER_STOPPED_TRACKING_TOUCH);
+ mUiEventLogger.log(BrightnessSliderEvent.BRIGHTNESS_SLIDER_STOPPED_TRACKING_TOUCH);
if (mListener != null) {
mListener.onChanged(mTracking, getValue(), true);
SeekableSliderEventProducer eventProducer =
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderEvent.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderEvent.java
index 3a30880..a8641bf 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderEvent.java
@@ -21,10 +21,10 @@
public enum BrightnessSliderEvent implements UiEventLogger.UiEventEnum {
- @UiEvent(doc = "slider started to track touch")
- SLIDER_STARTED_TRACKING_TOUCH(1472),
- @UiEvent(doc = "slider stopped tracking touch")
- SLIDER_STOPPED_TRACKING_TOUCH(1473);
+ @UiEvent(doc = "brightness slider started to track touch")
+ BRIGHTNESS_SLIDER_STARTED_TRACKING_TOUCH(1472),
+ @UiEvent(doc = "brightness slider stopped tracking touch")
+ BRIGHTNESS_SLIDER_STOPPED_TRACKING_TOUCH(1473);
private final int mId;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 69282ae..3ad60d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -1442,10 +1442,6 @@
hideAlternateBouncer(false);
executeAfterKeyguardGoneAction();
}
-
- if (KeyguardWmStateRefactor.isEnabled()) {
- mKeyguardTransitionInteractor.startDismissKeyguardTransition();
- }
}
/** Display security message to relevant KeyguardMessageArea. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java
index 3741f14..c0e36b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java
@@ -91,7 +91,9 @@
@StatusBarFragmentScope
@Named(OPERATOR_NAME_VIEW)
static View provideOperatorNameView(@RootView PhoneStatusBarView view) {
- return ((ViewStub) view.findViewById(R.id.operator_name_stub)).inflate();
+ View operatorName = ((ViewStub) view.findViewById(R.id.operator_name_stub)).inflate();
+ operatorName.setVisibility(View.GONE);
+ return operatorName;
}
/** */
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsUtilModule.java b/packages/SystemUI/src/com/android/systemui/util/settings/SettingsUtilModule.java
index f36c335e..d509b2d 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsUtilModule.java
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/SettingsUtilModule.java
@@ -16,6 +16,9 @@
package com.android.systemui.util.settings;
+import com.android.systemui.util.settings.repository.UserAwareSecureSettingsRepository;
+import com.android.systemui.util.settings.repository.UserAwareSecureSettingsRepositoryImpl;
+
import dagger.Binds;
import dagger.Module;
@@ -36,4 +39,9 @@
/** Bind GlobalSettingsImpl to GlobalSettings. */
@Binds
GlobalSettings bindsGlobalSettings(GlobalSettingsImpl impl);
+
+ /** Bind UserAwareSecureSettingsRepositoryImpl to UserAwareSecureSettingsRepository. */
+ @Binds
+ UserAwareSecureSettingsRepository bindsUserAwareSecureSettingsRepository(
+ UserAwareSecureSettingsRepositoryImpl impl);
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/repository/UserAwareSecureSettingsRepository.kt b/packages/SystemUI/src/com/android/systemui/util/settings/repository/UserAwareSecureSettingsRepository.kt
new file mode 100644
index 0000000..d3e5080
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/repository/UserAwareSecureSettingsRepository.kt
@@ -0,0 +1,70 @@
+/*
+ * 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.util.settings.repository
+
+import android.provider.Settings
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.user.data.repository.UserRepository
+import com.android.systemui.util.settings.SecureSettings
+import com.android.systemui.util.settings.SettingsProxy
+import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onStart
+import javax.inject.Inject
+
+/**
+ * Repository for observing values of [Settings.Secure] for the currently active user. That means
+ * when user is switched and the new user has different value, flow will emit new value.
+ */
+interface UserAwareSecureSettingsRepository {
+
+ /**
+ * Emits boolean value of the setting for active user. Also emits starting value when
+ * subscribed.
+ * See: [SettingsProxy.getBool].
+ */
+ fun boolSettingForActiveUser(name: String, defaultValue: Boolean = false): Flow<Boolean>
+}
+
+@SysUISingleton
+@OptIn(ExperimentalCoroutinesApi::class)
+class UserAwareSecureSettingsRepositoryImpl @Inject constructor(
+ private val secureSettings: SecureSettings,
+ private val userRepository: UserRepository,
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
+) : UserAwareSecureSettingsRepository {
+
+ override fun boolSettingForActiveUser(name: String, defaultValue: Boolean): Flow<Boolean> =
+ userRepository.selectedUserInfo
+ .flatMapLatest { userInfo -> settingObserver(name, defaultValue, userInfo.id) }
+ .distinctUntilChanged()
+ .flowOn(backgroundDispatcher)
+
+ private fun settingObserver(name: String, defaultValue: Boolean, userId: Int): Flow<Boolean> {
+ return secureSettings
+ .observerFlow(userId, name)
+ .onStart { emit(Unit) }
+ .map { secureSettings.getBoolForUser(name, defaultValue, userId) }
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/stickykeys/data/repository/StickyKeysRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/stickykeys/data/repository/StickyKeysRepositoryImplTest.kt
deleted file mode 100644
index ed80a86..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/keyboard/stickykeys/data/repository/StickyKeysRepositoryImplTest.kt
+++ /dev/null
@@ -1,98 +0,0 @@
-package com.android.systemui.keyboard.stickykeys.data.repository
-
-import android.content.pm.UserInfo
-import android.hardware.input.InputManager
-import android.provider.Settings.Secure.ACCESSIBILITY_STICKY_KEYS
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.coroutines.collectValues
-import com.android.systemui.keyboard.stickykeys.StickyKeysLogger
-import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.user.data.repository.fakeUserRepository
-import com.android.systemui.util.mockito.mock
-import com.android.systemui.util.settings.FakeSettings
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.StandardTestDispatcher
-import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.runCurrent
-import kotlinx.coroutines.test.runTest
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-@OptIn(ExperimentalCoroutinesApi::class)
-@SmallTest
-@RunWith(JUnit4::class)
-class StickyKeysRepositoryImplTest : SysuiTestCase() {
-
- private val dispatcher = StandardTestDispatcher()
- private val testScope = TestScope(dispatcher)
- private val secureSettings = FakeSettings()
- private val userRepository = Kosmos().fakeUserRepository
- private lateinit var stickyKeysRepository: StickyKeysRepositoryImpl
-
- @Before
- fun setup() {
- stickyKeysRepository = StickyKeysRepositoryImpl(
- mock<InputManager>(),
- dispatcher,
- secureSettings,
- userRepository,
- mock<StickyKeysLogger>()
- )
- userRepository.setUserInfos(USER_INFOS)
- setStickyKeySettingForUser(enabled = true, userInfo = SETTING_ENABLED_USER)
- setStickyKeySettingForUser(enabled = false, userInfo = SETTING_DISABLED_USER)
- }
-
- @Test
- fun settingEnabledEmitsValueForCurrentUser() {
- testScope.runTest {
- userRepository.setSelectedUserInfo(SETTING_ENABLED_USER)
-
- val enabled by collectLastValue(stickyKeysRepository.settingEnabled)
-
- assertThat(enabled).isTrue()
- }
- }
-
- @Test
- fun settingEnabledEmitsNewValueWhenSettingChanges() {
- testScope.runTest {
- userRepository.setSelectedUserInfo(SETTING_ENABLED_USER)
- val enabled by collectValues(stickyKeysRepository.settingEnabled)
- runCurrent()
-
- setStickyKeySettingForUser(enabled = false, userInfo = SETTING_ENABLED_USER)
-
- assertThat(enabled).containsExactly(true, false).inOrder()
- }
- }
-
- @Test
- fun settingEnabledEmitsValueForNewUserWhenUserChanges() {
- testScope.runTest {
- userRepository.setSelectedUserInfo(SETTING_ENABLED_USER)
- val enabled by collectLastValue(stickyKeysRepository.settingEnabled)
- runCurrent()
-
- userRepository.setSelectedUserInfo(SETTING_DISABLED_USER)
-
- assertThat(enabled).isFalse()
- }
- }
-
- private fun setStickyKeySettingForUser(enabled: Boolean, userInfo: UserInfo) {
- val newValue = if (enabled) "1" else "0"
- secureSettings.putStringForUser(ACCESSIBILITY_STICKY_KEYS, newValue, userInfo.id)
- }
-
- private companion object {
- val SETTING_ENABLED_USER = UserInfo(/* id= */ 0, "user1", /* flags= */ 0)
- val SETTING_DISABLED_USER = UserInfo(/* id= */ 1, "user2", /* flags= */ 0)
- val USER_INFOS = listOf(SETTING_ENABLED_USER, SETTING_DISABLED_USER)
- }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/stickykeys/ui/viewmodel/StickyKeysIndicatorViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/stickykeys/ui/viewmodel/StickyKeysIndicatorViewModelTest.kt
index 6eebb6d..d14d72d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyboard/stickykeys/ui/viewmodel/StickyKeysIndicatorViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/stickykeys/ui/viewmodel/StickyKeysIndicatorViewModelTest.kt
@@ -37,6 +37,7 @@
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.settings.FakeSettings
+import com.android.systemui.util.settings.repository.UserAwareSecureSettingsRepositoryImpl
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
@@ -68,11 +69,15 @@
@Before
fun setup() {
+ val settingsRepository = UserAwareSecureSettingsRepositoryImpl(
+ secureSettings,
+ userRepository,
+ dispatcher
+ )
val stickyKeysRepository = StickyKeysRepositoryImpl(
inputManager,
dispatcher,
- secureSettings,
- userRepository,
+ settingsRepository,
mock<StickyKeysLogger>()
)
setStickyKeySetting(enabled = false)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractorTest.kt
new file mode 100644
index 0000000..c174cb8
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractorTest.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.domain.interactor
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+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.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.keyguard.util.KeyguardTransitionRepositorySpySubject.Companion.assertThat
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.reset
+import org.mockito.Mockito.spy
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class FromGoneTransitionInteractorTest : SysuiTestCase() {
+ private val kosmos =
+ testKosmos().apply {
+ fakeKeyguardTransitionRepository = spy(FakeKeyguardTransitionRepository())
+ }
+ private val testScope = kosmos.testScope
+ private val underTest = kosmos.fromGoneTransitionInteractor
+ private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
+
+ @Before
+ fun setUp() {
+ underTest.start()
+ }
+
+ @Test
+ fun testDoesNotTransitionToLockscreen_ifStartedButNotFinishedInGone() =
+ testScope.runTest {
+ keyguardTransitionRepository.sendTransitionSteps(
+ listOf(
+ TransitionStep(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ transitionState = TransitionState.STARTED,
+ ),
+ TransitionStep(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ transitionState = TransitionState.RUNNING,
+ ),
+ ),
+ testScope,
+ )
+ reset(keyguardTransitionRepository)
+ kosmos.fakeKeyguardRepository.setKeyguardShowing(true)
+ runCurrent()
+
+ // We're in the middle of a LOCKSCREEN -> GONE transition.
+ assertThat(keyguardTransitionRepository).noTransitionsStarted()
+ }
+
+ @Test
+ fun testTransitionsToLockscreen_ifFinishedInGone() =
+ testScope.runTest {
+ keyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ testScope,
+ )
+ reset(keyguardTransitionRepository)
+ kosmos.fakeKeyguardRepository.setKeyguardShowing(true)
+ runCurrent()
+
+ // We're in the middle of a LOCKSCREEN -> GONE transition.
+ assertThat(keyguardTransitionRepository)
+ .startedTransition(
+ to = KeyguardState.LOCKSCREEN,
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorTest.kt
index 668fb64..6d8e7aa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorTest.kt
@@ -27,17 +27,15 @@
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
-import com.android.systemui.keyguard.shared.model.TransitionInfo
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 as assertThatRepository
import com.android.systemui.kosmos.testScope
import com.android.systemui.shade.data.repository.FlingInfo
import com.android.systemui.shade.data.repository.fakeShadeRepository
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.withArgCaptor
import com.google.common.truth.Truth.assertThat
-import junit.framework.Assert.assertEquals
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
@@ -132,13 +130,11 @@
)
runCurrent()
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
- .also {
- assertEquals(KeyguardState.LOCKSCREEN, it.from)
- assertEquals(KeyguardState.GONE, it.to)
- }
+ assertThatRepository(transitionRepository)
+ .startedTransition(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ )
}
@Test
@@ -155,6 +151,6 @@
)
runCurrent()
- verify(transitionRepository, never()).startTransition(any())
+ assertThatRepository(transitionRepository).noTransitionsStarted()
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorTest.kt
index f23dd55..3f05bfa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorTest.kt
@@ -28,6 +28,7 @@
import com.android.systemui.keyguard.util.mockTopActivityClassName
import com.android.systemui.kosmos.testScope
import com.android.systemui.shared.system.activityManagerWrapper
+import com.android.systemui.statusbar.notification.domain.interactor.notificationLaunchAnimationInteractor
import com.android.systemui.testKosmos
import com.android.systemui.util.assertValuesMatch
import com.google.common.truth.Truth.assertThat
@@ -192,4 +193,38 @@
)
.inOrder()
}
+
+ @Test
+ fun testSurfaceBehindModel_fromNotificationLaunch() =
+ testScope.runTest {
+ val values by collectValues(underTest.viewParams)
+ runCurrent()
+
+ kosmos.notificationLaunchAnimationInteractor.setIsLaunchAnimationRunning(true)
+ runCurrent()
+
+ transitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ transitionState = TransitionState.STARTED,
+ )
+ )
+ runCurrent()
+
+ transitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ transitionState = TransitionState.RUNNING,
+ value = 0.5f,
+ )
+ )
+ runCurrent()
+
+ values.assertValuesMatch(
+ // We should be at alpha = 0f during the animation.
+ { it == KeyguardSurfaceBehindModel(alpha = 0f) },
+ )
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
index bb61d18..4d57670 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
@@ -37,9 +37,9 @@
import com.android.systemui.keyguard.shared.model.DozeTransitionModel
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.StatusBarState
-import com.android.systemui.keyguard.shared.model.TransitionInfo
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
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest
@@ -51,8 +51,6 @@
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.whenever
-import com.android.systemui.util.mockito.withArgCaptor
-import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.cancelChildren
import kotlinx.coroutines.flow.MutableStateFlow
@@ -254,15 +252,13 @@
bouncerRepository.setPrimaryShow(true)
runCurrent()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
- // THEN a transition to PRIMARY_BOUNCER should occur
- assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.LOCKSCREEN)
- assertThat(info.to).isEqualTo(KeyguardState.PRIMARY_BOUNCER)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ to = KeyguardState.PRIMARY_BOUNCER,
+ from = KeyguardState.LOCKSCREEN,
+ ownerName = "FromLockscreenTransitionInteractor",
+ animatorAssertion = { it.isNotNull() }
+ )
coroutineContext.cancelChildren()
}
@@ -281,15 +277,13 @@
powerInteractor.setAsleepForTest()
runCurrent()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
- // THEN a transition to DOZING should occur
- assertThat(info.ownerName).isEqualTo("FromOccludedTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.OCCLUDED)
- assertThat(info.to).isEqualTo(KeyguardState.DOZING)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ to = KeyguardState.DOZING,
+ from = KeyguardState.OCCLUDED,
+ ownerName = "FromOccludedTransitionInteractor",
+ animatorAssertion = { it.isNotNull() }
+ )
coroutineContext.cancelChildren()
}
@@ -308,15 +302,13 @@
powerInteractor.setAsleepForTest()
runCurrent()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
- // THEN a transition to DOZING should occur
- assertThat(info.ownerName).isEqualTo("FromOccludedTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.OCCLUDED)
- assertThat(info.to).isEqualTo(KeyguardState.AOD)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ to = KeyguardState.AOD,
+ from = KeyguardState.OCCLUDED,
+ ownerName = "FromOccludedTransitionInteractor",
+ animatorAssertion = { it.isNotNull() }
+ )
coroutineContext.cancelChildren()
}
@@ -338,15 +330,13 @@
keyguardRepository.setDreamingWithOverlay(true)
advanceUntilIdle()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
- // THEN a transition to DREAMING should occur
- assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.LOCKSCREEN)
- assertThat(info.to).isEqualTo(KeyguardState.DREAMING)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ to = KeyguardState.DREAMING,
+ from = KeyguardState.LOCKSCREEN,
+ ownerName = "FromLockscreenTransitionInteractor",
+ animatorAssertion = { it.isNotNull() }
+ )
coroutineContext.cancelChildren()
}
@@ -369,15 +359,13 @@
keyguardRepository.setIsActiveDreamLockscreenHosted(true)
advanceUntilIdle()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
- // THEN a transition to DREAMING_LOCKSCREEN_HOSTED should occur
- assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.LOCKSCREEN)
- assertThat(info.to).isEqualTo(KeyguardState.DREAMING_LOCKSCREEN_HOSTED)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ to = KeyguardState.DREAMING_LOCKSCREEN_HOSTED,
+ from = KeyguardState.LOCKSCREEN,
+ ownerName = "FromLockscreenTransitionInteractor",
+ animatorAssertion = { it.isNotNull() }
+ )
coroutineContext.cancelChildren()
}
@@ -396,15 +384,13 @@
powerInteractor.setAsleepForTest()
runCurrent()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
- // THEN a transition to DOZING should occur
- assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.LOCKSCREEN)
- assertThat(info.to).isEqualTo(KeyguardState.DOZING)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ to = KeyguardState.DOZING,
+ from = KeyguardState.LOCKSCREEN,
+ ownerName = "FromLockscreenTransitionInteractor",
+ animatorAssertion = { it.isNotNull() }
+ )
coroutineContext.cancelChildren()
}
@@ -423,15 +409,13 @@
powerInteractor.setAsleepForTest()
runCurrent()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
- // THEN a transition to DOZING should occur
- assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.LOCKSCREEN)
- assertThat(info.to).isEqualTo(KeyguardState.AOD)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ to = KeyguardState.AOD,
+ from = KeyguardState.LOCKSCREEN,
+ ownerName = "FromLockscreenTransitionInteractor",
+ animatorAssertion = { it.isNotNull() }
+ )
coroutineContext.cancelChildren()
}
@@ -456,15 +440,13 @@
keyguardRepository.setIsActiveDreamLockscreenHosted(false)
advanceUntilIdle()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
- // THEN a transition to Lockscreen should occur
- assertThat(info.ownerName).isEqualTo("FromDreamingLockscreenHostedTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.DREAMING_LOCKSCREEN_HOSTED)
- assertThat(info.to).isEqualTo(KeyguardState.LOCKSCREEN)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ to = KeyguardState.LOCKSCREEN,
+ from = KeyguardState.DREAMING_LOCKSCREEN_HOSTED,
+ ownerName = "FromDreamingLockscreenHostedTransitionInteractor",
+ animatorAssertion = { it.isNotNull() }
+ )
coroutineContext.cancelChildren()
}
@@ -484,15 +466,13 @@
)
runCurrent()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
- // THEN a transition to Gone should occur
- assertThat(info.ownerName).isEqualTo("FromDreamingLockscreenHostedTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.DREAMING_LOCKSCREEN_HOSTED)
- assertThat(info.to).isEqualTo(KeyguardState.GONE)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ to = KeyguardState.GONE,
+ from = KeyguardState.DREAMING_LOCKSCREEN_HOSTED,
+ ownerName = "FromDreamingLockscreenHostedTransitionInteractor",
+ animatorAssertion = { it.isNotNull() }
+ )
coroutineContext.cancelChildren()
}
@@ -514,15 +494,13 @@
bouncerRepository.setPrimaryShow(true)
runCurrent()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
- // THEN a transition to PRIMARY_BOUNCER should occur
- assertThat(info.ownerName).isEqualTo("FromDreamingLockscreenHostedTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.DREAMING_LOCKSCREEN_HOSTED)
- assertThat(info.to).isEqualTo(KeyguardState.PRIMARY_BOUNCER)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ to = KeyguardState.PRIMARY_BOUNCER,
+ from = KeyguardState.DREAMING_LOCKSCREEN_HOSTED,
+ ownerName = "FromDreamingLockscreenHostedTransitionInteractor",
+ animatorAssertion = { it.isNotNull() }
+ )
coroutineContext.cancelChildren()
}
@@ -547,15 +525,13 @@
)
runCurrent()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
- // THEN a transition to DOZING should occur
- assertThat(info.ownerName).isEqualTo("FromDreamingLockscreenHostedTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.DREAMING_LOCKSCREEN_HOSTED)
- assertThat(info.to).isEqualTo(KeyguardState.DOZING)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ to = KeyguardState.DOZING,
+ from = KeyguardState.DREAMING_LOCKSCREEN_HOSTED,
+ ownerName = "FromDreamingLockscreenHostedTransitionInteractor",
+ animatorAssertion = { it.isNotNull() }
+ )
coroutineContext.cancelChildren()
}
@@ -579,15 +555,13 @@
keyguardRepository.setKeyguardOccluded(true)
runCurrent()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
- // THEN a transition to OCCLUDED should occur
- assertThat(info.ownerName).isEqualTo("FromDreamingLockscreenHostedTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.DREAMING_LOCKSCREEN_HOSTED)
- assertThat(info.to).isEqualTo(KeyguardState.OCCLUDED)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ to = KeyguardState.OCCLUDED,
+ from = KeyguardState.DREAMING_LOCKSCREEN_HOSTED,
+ ownerName = "FromDreamingLockscreenHostedTransitionInteractor",
+ animatorAssertion = { it.isNotNull() }
+ )
coroutineContext.cancelChildren()
}
@@ -603,15 +577,13 @@
powerInteractor.setAwakeForTest()
runCurrent()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
- // THEN a transition to DOZING should occur
- assertThat(info.ownerName).isEqualTo("FromDozingTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.DOZING)
- assertThat(info.to).isEqualTo(KeyguardState.LOCKSCREEN)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ to = KeyguardState.LOCKSCREEN,
+ from = KeyguardState.DOZING,
+ ownerName = "FromDozingTransitionInteractor",
+ animatorAssertion = { it.isNotNull() }
+ )
coroutineContext.cancelChildren()
}
@@ -667,15 +639,13 @@
keyguardRepository.setBiometricUnlockState(BiometricUnlockModel.WAKE_AND_UNLOCK)
runCurrent()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
- // THEN a transition to DOZING should occur
- assertThat(info.ownerName).isEqualTo("FromDozingTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.DOZING)
- assertThat(info.to).isEqualTo(KeyguardState.GONE)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ to = KeyguardState.GONE,
+ from = KeyguardState.DOZING,
+ ownerName = "FromDozingTransitionInteractor",
+ animatorAssertion = { it.isNotNull() }
+ )
coroutineContext.cancelChildren()
}
@@ -699,15 +669,13 @@
powerInteractor.setAwakeForTest()
runCurrent()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
- // THEN a transition to DOZING should occur
- assertThat(info.ownerName).isEqualTo(FromDozingTransitionInteractor::class.simpleName)
- assertThat(info.from).isEqualTo(KeyguardState.DOZING)
- assertThat(info.to).isEqualTo(KeyguardState.GLANCEABLE_HUB)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ to = KeyguardState.GLANCEABLE_HUB,
+ from = KeyguardState.DOZING,
+ ownerName = FromDozingTransitionInteractor::class.simpleName,
+ animatorAssertion = { it.isNotNull() }
+ )
coroutineContext.cancelChildren()
}
@@ -726,15 +694,13 @@
powerInteractor.setAsleepForTest()
runCurrent()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
- // THEN a transition to DOZING should occur
- assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.GONE)
- assertThat(info.to).isEqualTo(KeyguardState.DOZING)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ to = KeyguardState.DOZING,
+ from = KeyguardState.GONE,
+ ownerName = "FromGoneTransitionInteractor",
+ animatorAssertion = { it.isNotNull() }
+ )
coroutineContext.cancelChildren()
}
@@ -753,15 +719,13 @@
powerInteractor.setAsleepForTest()
runCurrent()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
- // THEN a transition to AOD should occur
- assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.GONE)
- assertThat(info.to).isEqualTo(KeyguardState.AOD)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ to = KeyguardState.AOD,
+ from = KeyguardState.GONE,
+ ownerName = "FromGoneTransitionInteractor",
+ animatorAssertion = { it.isNotNull() }
+ )
coroutineContext.cancelChildren()
}
@@ -776,15 +740,13 @@
keyguardRepository.setKeyguardShowing(true)
runCurrent()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
- // THEN a transition to AOD should occur
- assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.GONE)
- assertThat(info.to).isEqualTo(KeyguardState.LOCKSCREEN)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ to = KeyguardState.LOCKSCREEN,
+ from = KeyguardState.GONE,
+ ownerName = "FromGoneTransitionInteractor",
+ animatorAssertion = { it.isNotNull() }
+ )
coroutineContext.cancelChildren()
}
@@ -806,15 +768,13 @@
keyguardRepository.setDreamingWithOverlay(true)
advanceUntilIdle()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
- // THEN a transition to DREAMING should occur
- assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.GONE)
- assertThat(info.to).isEqualTo(KeyguardState.DREAMING)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ to = KeyguardState.DREAMING,
+ from = KeyguardState.GONE,
+ ownerName = "FromGoneTransitionInteractor",
+ animatorAssertion = { it.isNotNull() }
+ )
coroutineContext.cancelChildren()
}
@@ -837,15 +797,13 @@
keyguardRepository.setIsActiveDreamLockscreenHosted(true)
advanceUntilIdle()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
- // THEN a transition to DREAMING_LOCKSCREEN_HOSTED should occur
- assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.GONE)
- assertThat(info.to).isEqualTo(KeyguardState.DREAMING_LOCKSCREEN_HOSTED)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ to = KeyguardState.DREAMING_LOCKSCREEN_HOSTED,
+ from = KeyguardState.GONE,
+ ownerName = "FromGoneTransitionInteractor",
+ animatorAssertion = { it.isNotNull() }
+ )
coroutineContext.cancelChildren()
}
@@ -868,15 +826,13 @@
keyguardRepository.setKeyguardShowing(true)
runCurrent()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
- // THEN a transition to DOZING should occur
- assertThat(info.ownerName).isEqualTo(FromGoneTransitionInteractor::class.simpleName)
- assertThat(info.from).isEqualTo(KeyguardState.GONE)
- assertThat(info.to).isEqualTo(KeyguardState.GLANCEABLE_HUB)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ to = KeyguardState.GLANCEABLE_HUB,
+ from = KeyguardState.GONE,
+ ownerName = FromGoneTransitionInteractor::class.simpleName,
+ animatorAssertion = { it.isNotNull() }
+ )
coroutineContext.cancelChildren()
}
@@ -894,15 +850,13 @@
bouncerRepository.setPrimaryShow(true)
runCurrent()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
- // THEN a transition to PRIMARY_BOUNCER should occur
- assertThat(info.ownerName).isEqualTo("FromAlternateBouncerTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.ALTERNATE_BOUNCER)
- assertThat(info.to).isEqualTo(KeyguardState.PRIMARY_BOUNCER)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ to = KeyguardState.PRIMARY_BOUNCER,
+ from = KeyguardState.ALTERNATE_BOUNCER,
+ ownerName = "FromAlternateBouncerTransitionInteractor",
+ animatorAssertion = { it.isNotNull() }
+ )
coroutineContext.cancelChildren()
}
@@ -926,15 +880,13 @@
bouncerRepository.setAlternateVisible(false)
advanceUntilIdle()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
- // THEN a transition to AOD should occur
- assertThat(info.ownerName).isEqualTo("FromAlternateBouncerTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.ALTERNATE_BOUNCER)
- assertThat(info.to).isEqualTo(KeyguardState.AOD)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ to = KeyguardState.AOD,
+ from = KeyguardState.ALTERNATE_BOUNCER,
+ ownerName = "FromAlternateBouncerTransitionInteractor",
+ animatorAssertion = { it.isNotNull() }
+ )
coroutineContext.cancelChildren()
}
@@ -959,15 +911,13 @@
bouncerRepository.setAlternateVisible(false)
advanceUntilIdle()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
- // THEN a transition to DOZING should occur
- assertThat(info.ownerName).isEqualTo("FromAlternateBouncerTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.ALTERNATE_BOUNCER)
- assertThat(info.to).isEqualTo(KeyguardState.DOZING)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ to = KeyguardState.DOZING,
+ from = KeyguardState.ALTERNATE_BOUNCER,
+ ownerName = "FromAlternateBouncerTransitionInteractor",
+ animatorAssertion = { it.isNotNull() }
+ )
coroutineContext.cancelChildren()
}
@@ -989,15 +939,13 @@
bouncerRepository.setAlternateVisible(false)
advanceUntilIdle()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
- // THEN a transition to LOCKSCREEN should occur
- assertThat(info.ownerName).isEqualTo("FromAlternateBouncerTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.ALTERNATE_BOUNCER)
- assertThat(info.to).isEqualTo(KeyguardState.LOCKSCREEN)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ ownerName = "FromAlternateBouncerTransitionInteractor",
+ from = KeyguardState.ALTERNATE_BOUNCER,
+ to = KeyguardState.LOCKSCREEN,
+ animatorAssertion = { it.isNotNull() },
+ )
coroutineContext.cancelChildren()
}
@@ -1027,16 +975,14 @@
bouncerRepository.setAlternateVisible(false)
advanceUntilIdle()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
// THEN a transition to LOCKSCREEN should occur
- assertThat(info.ownerName)
- .isEqualTo(FromAlternateBouncerTransitionInteractor::class.simpleName)
- assertThat(info.from).isEqualTo(KeyguardState.ALTERNATE_BOUNCER)
- assertThat(info.to).isEqualTo(KeyguardState.GLANCEABLE_HUB)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ ownerName = FromAlternateBouncerTransitionInteractor::class.simpleName,
+ from = KeyguardState.ALTERNATE_BOUNCER,
+ to = KeyguardState.GLANCEABLE_HUB,
+ animatorAssertion = { it.isNotNull() },
+ )
coroutineContext.cancelChildren()
}
@@ -1056,15 +1002,14 @@
bouncerRepository.setPrimaryShow(false)
runCurrent()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
// THEN a transition to AOD should occur
- assertThat(info.ownerName).isEqualTo("FromPrimaryBouncerTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.PRIMARY_BOUNCER)
- assertThat(info.to).isEqualTo(KeyguardState.AOD)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ ownerName = "FromPrimaryBouncerTransitionInteractor",
+ from = KeyguardState.PRIMARY_BOUNCER,
+ to = KeyguardState.AOD,
+ animatorAssertion = { it.isNotNull() },
+ )
coroutineContext.cancelChildren()
}
@@ -1084,15 +1029,14 @@
bouncerRepository.setPrimaryShow(false)
runCurrent()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
// THEN a transition to DOZING should occur
- assertThat(info.ownerName).isEqualTo("FromPrimaryBouncerTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.PRIMARY_BOUNCER)
- assertThat(info.to).isEqualTo(KeyguardState.DOZING)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ ownerName = "FromPrimaryBouncerTransitionInteractor",
+ from = KeyguardState.PRIMARY_BOUNCER,
+ to = KeyguardState.DOZING,
+ animatorAssertion = { it.isNotNull() },
+ )
coroutineContext.cancelChildren()
}
@@ -1108,15 +1052,14 @@
bouncerRepository.setPrimaryShow(false)
runCurrent()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
// THEN a transition to LOCKSCREEN should occur
- assertThat(info.ownerName).isEqualTo("FromPrimaryBouncerTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.PRIMARY_BOUNCER)
- assertThat(info.to).isEqualTo(KeyguardState.LOCKSCREEN)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ ownerName = "FromPrimaryBouncerTransitionInteractor",
+ from = KeyguardState.PRIMARY_BOUNCER,
+ to = KeyguardState.LOCKSCREEN,
+ animatorAssertion = { it.isNotNull() },
+ )
coroutineContext.cancelChildren()
}
@@ -1140,16 +1083,14 @@
bouncerRepository.setPrimaryShow(false)
runCurrent()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
// THEN a transition to LOCKSCREEN should occur
- assertThat(info.ownerName)
- .isEqualTo(FromPrimaryBouncerTransitionInteractor::class.simpleName)
- assertThat(info.from).isEqualTo(KeyguardState.PRIMARY_BOUNCER)
- assertThat(info.to).isEqualTo(KeyguardState.GLANCEABLE_HUB)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ ownerName = FromPrimaryBouncerTransitionInteractor::class.simpleName,
+ from = KeyguardState.PRIMARY_BOUNCER,
+ to = KeyguardState.GLANCEABLE_HUB,
+ animatorAssertion = { it.isNotNull() },
+ )
coroutineContext.cancelChildren()
}
@@ -1171,15 +1112,14 @@
bouncerRepository.setPrimaryShow(false)
runCurrent()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
// THEN a transition back to DREAMING_LOCKSCREEN_HOSTED should occur
- assertThat(info.ownerName).isEqualTo("FromPrimaryBouncerTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.PRIMARY_BOUNCER)
- assertThat(info.to).isEqualTo(KeyguardState.DREAMING_LOCKSCREEN_HOSTED)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ ownerName = "FromPrimaryBouncerTransitionInteractor",
+ from = KeyguardState.PRIMARY_BOUNCER,
+ to = KeyguardState.DREAMING_LOCKSCREEN_HOSTED,
+ animatorAssertion = { it.isNotNull() },
+ )
coroutineContext.cancelChildren()
}
@@ -1202,15 +1142,14 @@
keyguardRepository.setKeyguardOccluded(false)
runCurrent()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
// THEN a transition to GONE should occur
- assertThat(info.ownerName).isEqualTo("FromOccludedTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.OCCLUDED)
- assertThat(info.to).isEqualTo(KeyguardState.GONE)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ ownerName = "FromOccludedTransitionInteractor",
+ from = KeyguardState.OCCLUDED,
+ to = KeyguardState.GONE,
+ animatorAssertion = { it.isNotNull() },
+ )
coroutineContext.cancelChildren()
}
@@ -1231,15 +1170,14 @@
keyguardRepository.setKeyguardOccluded(false)
runCurrent()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
// THEN a transition to LOCKSCREEN should occur
- assertThat(info.ownerName).isEqualTo("FromOccludedTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.OCCLUDED)
- assertThat(info.to).isEqualTo(KeyguardState.LOCKSCREEN)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ ownerName = "FromOccludedTransitionInteractor",
+ from = KeyguardState.OCCLUDED,
+ to = KeyguardState.LOCKSCREEN,
+ animatorAssertion = { it.isNotNull() },
+ )
coroutineContext.cancelChildren()
}
@@ -1268,15 +1206,14 @@
keyguardRepository.setKeyguardOccluded(false)
runCurrent()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
// THEN a transition to GLANCEABLE_HUB should occur
- assertThat(info.ownerName).isEqualTo(FromOccludedTransitionInteractor::class.simpleName)
- assertThat(info.from).isEqualTo(KeyguardState.OCCLUDED)
- assertThat(info.to).isEqualTo(KeyguardState.GLANCEABLE_HUB)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ ownerName = FromOccludedTransitionInteractor::class.simpleName,
+ from = KeyguardState.OCCLUDED,
+ to = KeyguardState.GLANCEABLE_HUB,
+ animatorAssertion = { it.isNotNull() },
+ )
coroutineContext.cancelChildren()
}
@@ -1293,15 +1230,14 @@
bouncerRepository.setAlternateVisible(true)
runCurrent()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
// THEN a transition to AlternateBouncer should occur
- assertThat(info.ownerName).isEqualTo("FromOccludedTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.OCCLUDED)
- assertThat(info.to).isEqualTo(KeyguardState.ALTERNATE_BOUNCER)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ ownerName = "FromOccludedTransitionInteractor",
+ from = KeyguardState.OCCLUDED,
+ to = KeyguardState.ALTERNATE_BOUNCER,
+ animatorAssertion = { it.isNotNull() },
+ )
coroutineContext.cancelChildren()
}
@@ -1318,15 +1254,14 @@
bouncerRepository.setPrimaryShow(true)
runCurrent()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
// THEN a transition to AlternateBouncer should occur
- assertThat(info.ownerName).isEqualTo("FromOccludedTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.OCCLUDED)
- assertThat(info.to).isEqualTo(KeyguardState.PRIMARY_BOUNCER)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ ownerName = "FromOccludedTransitionInteractor",
+ from = KeyguardState.OCCLUDED,
+ to = KeyguardState.PRIMARY_BOUNCER,
+ animatorAssertion = { it.isNotNull() },
+ )
coroutineContext.cancelChildren()
}
@@ -1344,15 +1279,14 @@
bouncerRepository.setPrimaryShow(false)
runCurrent()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
// THEN a transition to OCCLUDED should occur
- assertThat(info.ownerName).isEqualTo("FromPrimaryBouncerTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.PRIMARY_BOUNCER)
- assertThat(info.to).isEqualTo(KeyguardState.OCCLUDED)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ ownerName = "FromPrimaryBouncerTransitionInteractor",
+ from = KeyguardState.PRIMARY_BOUNCER,
+ to = KeyguardState.OCCLUDED,
+ animatorAssertion = { it.isNotNull() },
+ )
coroutineContext.cancelChildren()
}
@@ -1369,15 +1303,14 @@
powerInteractor.setAwakeForTest()
runCurrent()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
// THEN a transition to OCCLUDED should occur
- assertThat(info.ownerName).isEqualTo("FromDozingTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.DOZING)
- assertThat(info.to).isEqualTo(KeyguardState.OCCLUDED)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ ownerName = "FromDozingTransitionInteractor",
+ from = KeyguardState.DOZING,
+ to = KeyguardState.OCCLUDED,
+ animatorAssertion = { it.isNotNull() },
+ )
coroutineContext.cancelChildren()
}
@@ -1396,15 +1329,14 @@
powerInteractor.setAwakeForTest()
runCurrent()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
// THEN a transition to OCCLUDED should occur
- assertThat(info.ownerName).isEqualTo("FromDreamingTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.DREAMING)
- assertThat(info.to).isEqualTo(KeyguardState.OCCLUDED)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ ownerName = "FromDreamingTransitionInteractor",
+ from = KeyguardState.DREAMING,
+ to = KeyguardState.OCCLUDED,
+ animatorAssertion = { it.isNotNull() },
+ )
coroutineContext.cancelChildren()
}
@@ -1426,15 +1358,14 @@
)
runCurrent()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
// THEN a transition to AOD should occur
- assertThat(info.ownerName).isEqualTo("FromDreamingTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.DREAMING)
- assertThat(info.to).isEqualTo(KeyguardState.AOD)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ ownerName = "FromDreamingTransitionInteractor",
+ from = KeyguardState.DREAMING,
+ to = KeyguardState.AOD,
+ animatorAssertion = { it.isNotNull() },
+ )
coroutineContext.cancelChildren()
}
@@ -1450,15 +1381,14 @@
keyguardRepository.setKeyguardOccluded(true)
runCurrent()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
// THEN a transition to OCCLUDED should occur
- assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.LOCKSCREEN)
- assertThat(info.to).isEqualTo(KeyguardState.OCCLUDED)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ ownerName = "FromLockscreenTransitionInteractor",
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.OCCLUDED,
+ animatorAssertion = { it.isNotNull() },
+ )
coroutineContext.cancelChildren()
}
@@ -1474,15 +1404,14 @@
keyguardRepository.setKeyguardOccluded(true)
runCurrent()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
// THEN a transition to OCCLUDED should occur
- assertThat(info.ownerName).isEqualTo("FromAodTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.AOD)
- assertThat(info.to).isEqualTo(KeyguardState.OCCLUDED)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ ownerName = "FromAodTransitionInteractor",
+ from = KeyguardState.AOD,
+ to = KeyguardState.OCCLUDED,
+ animatorAssertion = { it.isNotNull() },
+ )
coroutineContext.cancelChildren()
}
@@ -1498,15 +1427,14 @@
bouncerRepository.setPrimaryShow(true)
runCurrent()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
// THEN a transition to OCCLUDED should occur
- assertThat(info.ownerName).isEqualTo("FromAodTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.AOD)
- assertThat(info.to).isEqualTo(KeyguardState.PRIMARY_BOUNCER)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ ownerName = "FromAodTransitionInteractor",
+ from = KeyguardState.AOD,
+ to = KeyguardState.PRIMARY_BOUNCER,
+ animatorAssertion = { it.isNotNull() },
+ )
coroutineContext.cancelChildren()
}
@@ -1532,14 +1460,13 @@
runCurrent()
// THEN a transition from LOCKSCREEN => OCCLUDED should occur
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
- assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.LOCKSCREEN)
- assertThat(info.to).isEqualTo(KeyguardState.OCCLUDED)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ ownerName = "FromLockscreenTransitionInteractor",
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.OCCLUDED,
+ animatorAssertion = { it.isNotNull() },
+ )
coroutineContext.cancelChildren()
}
@@ -1559,14 +1486,13 @@
runCurrent()
// THEN a transition from LOCKSCREEN => PRIMARY_BOUNCER should occur
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
- assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.LOCKSCREEN)
- assertThat(info.to).isEqualTo(KeyguardState.PRIMARY_BOUNCER)
- assertThat(info.animator).isNull() // dragging should be manually animated
+ assertThat(transitionRepository)
+ .startedTransition(
+ ownerName = "FromLockscreenTransitionInteractor",
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.PRIMARY_BOUNCER,
+ animatorAssertion = { it.isNull() }, // dragging should be manually animated
+ )
// WHEN the user stops dragging and shade is back to expanded
clearInvocations(transitionRepository)
@@ -1575,14 +1501,13 @@
shadeRepository.setLegacyShadeExpansion(1f)
runCurrent()
- // THEN a transition from PRIMARY_BOUNCER => LOCKSCREEN should occur
- val info2 =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
- assertThat(info2.from).isEqualTo(KeyguardState.PRIMARY_BOUNCER)
- assertThat(info2.to).isEqualTo(KeyguardState.LOCKSCREEN)
- assertThat(info2.animator).isNotNull()
+ // THEN a transition from LOCKSCREEN => PRIMARY_BOUNCER should occur
+ assertThat(transitionRepository)
+ .startedTransition(
+ from = KeyguardState.PRIMARY_BOUNCER,
+ to = KeyguardState.LOCKSCREEN,
+ animatorAssertion = { it.isNotNull() },
+ )
coroutineContext.cancelChildren()
}
@@ -1614,15 +1539,13 @@
runCurrent()
// THEN a transition from LOCKSCREEN => GLANCEABLE_HUB should occur
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
- assertThat(info.ownerName)
- .isEqualTo(FromLockscreenTransitionInteractor::class.simpleName)
- assertThat(info.from).isEqualTo(KeyguardState.LOCKSCREEN)
- assertThat(info.to).isEqualTo(KeyguardState.GLANCEABLE_HUB)
- assertThat(info.animator).isNull() // transition should be manually animated
+ assertThat(transitionRepository)
+ .startedTransition(
+ ownerName = FromLockscreenTransitionInteractor::class.simpleName,
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GLANCEABLE_HUB,
+ animatorAssertion = { it.isNull() }, // transition should be manually animated
+ )
// WHEN the user stops dragging and the glanceable hub opening is cancelled
clearInvocations(transitionRepository)
@@ -1634,14 +1557,13 @@
communalInteractor.setTransitionState(idleTransitionState)
runCurrent()
- // THEN a transition from GLANCEABLE_HUB => LOCKSCREEN should occur
- val info2 =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
- assertThat(info2.from).isEqualTo(KeyguardState.GLANCEABLE_HUB)
- assertThat(info2.to).isEqualTo(KeyguardState.LOCKSCREEN)
- assertThat(info.animator).isNull() // transition should be manually animated
+ // THEN a transition from LOCKSCREEN => GLANCEABLE_HUB should occur
+ assertThat(transitionRepository)
+ .startedTransition(
+ ownerName = FromLockscreenTransitionInteractor::class.simpleName,
+ from = KeyguardState.GLANCEABLE_HUB,
+ to = KeyguardState.LOCKSCREEN,
+ )
coroutineContext.cancelChildren()
}
@@ -1672,16 +1594,13 @@
progress.value = .1f
runCurrent()
- // THEN a transition from GLANCEABLE_HUB => LOCKSCREEN should occur
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
- assertThat(info.ownerName)
- .isEqualTo(FromGlanceableHubTransitionInteractor::class.simpleName)
- assertThat(info.from).isEqualTo(KeyguardState.GLANCEABLE_HUB)
- assertThat(info.to).isEqualTo(KeyguardState.LOCKSCREEN)
- assertThat(info.animator).isNull() // transition should be manually animated
+ assertThat(transitionRepository)
+ .startedTransition(
+ ownerName = FromGlanceableHubTransitionInteractor::class.simpleName,
+ from = KeyguardState.GLANCEABLE_HUB,
+ to = KeyguardState.LOCKSCREEN,
+ animatorAssertion = { it.isNull() }, // transition should be manually animated
+ )
// WHEN the user stops dragging and the glanceable hub closing is cancelled
clearInvocations(transitionRepository)
@@ -1693,14 +1612,11 @@
communalInteractor.setTransitionState(idleTransitionState)
runCurrent()
- // THEN a transition from LOCKSCREEN => GLANCEABLE_HUB should occur
- val info2 =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
- assertThat(info2.from).isEqualTo(KeyguardState.LOCKSCREEN)
- assertThat(info2.to).isEqualTo(KeyguardState.GLANCEABLE_HUB)
- assertThat(info.animator).isNull() // transition should be manually animated
+ assertThat(transitionRepository)
+ .startedTransition(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GLANCEABLE_HUB,
+ )
coroutineContext.cancelChildren()
}
@@ -1715,16 +1631,13 @@
powerInteractor.setAsleepForTest()
runCurrent()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
- // THEN a transition to DOZING should occur
- assertThat(info.ownerName)
- .isEqualTo(FromGlanceableHubTransitionInteractor::class.simpleName)
- assertThat(info.from).isEqualTo(KeyguardState.GLANCEABLE_HUB)
- assertThat(info.to).isEqualTo(KeyguardState.DOZING)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ ownerName = FromGlanceableHubTransitionInteractor::class.simpleName,
+ from = KeyguardState.GLANCEABLE_HUB,
+ to = KeyguardState.DOZING,
+ animatorAssertion = { it.isNotNull() },
+ )
coroutineContext.cancelChildren()
}
@@ -1739,16 +1652,13 @@
bouncerRepository.setPrimaryShow(true)
runCurrent()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
- // THEN a transition to PRIMARY_BOUNCER should occur
- assertThat(info.ownerName)
- .isEqualTo(FromGlanceableHubTransitionInteractor::class.simpleName)
- assertThat(info.from).isEqualTo(KeyguardState.GLANCEABLE_HUB)
- assertThat(info.to).isEqualTo(KeyguardState.PRIMARY_BOUNCER)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ ownerName = FromGlanceableHubTransitionInteractor::class.simpleName,
+ from = KeyguardState.GLANCEABLE_HUB,
+ to = KeyguardState.PRIMARY_BOUNCER,
+ animatorAssertion = { it.isNotNull() },
+ )
coroutineContext.cancelChildren()
}
@@ -1763,16 +1673,13 @@
bouncerRepository.setAlternateVisible(true)
runCurrent()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
- // THEN a transition to PRIMARY_BOUNCER should occur
- assertThat(info.ownerName)
- .isEqualTo(FromGlanceableHubTransitionInteractor::class.simpleName)
- assertThat(info.from).isEqualTo(KeyguardState.GLANCEABLE_HUB)
- assertThat(info.to).isEqualTo(KeyguardState.ALTERNATE_BOUNCER)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ ownerName = FromGlanceableHubTransitionInteractor::class.simpleName,
+ from = KeyguardState.GLANCEABLE_HUB,
+ to = KeyguardState.ALTERNATE_BOUNCER,
+ animatorAssertion = { it.isNotNull() },
+ )
coroutineContext.cancelChildren()
}
@@ -1796,16 +1703,13 @@
keyguardRepository.setKeyguardOccluded(true)
runCurrent()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
- // THEN a transition to OCCLUDED should occur
- assertThat(info.ownerName)
- .isEqualTo(FromGlanceableHubTransitionInteractor::class.simpleName)
- assertThat(info.from).isEqualTo(KeyguardState.GLANCEABLE_HUB)
- assertThat(info.to).isEqualTo(KeyguardState.OCCLUDED)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ ownerName = FromGlanceableHubTransitionInteractor::class.simpleName,
+ from = KeyguardState.GLANCEABLE_HUB,
+ to = KeyguardState.OCCLUDED,
+ animatorAssertion = { it.isNotNull() },
+ )
coroutineContext.cancelChildren()
}
@@ -1820,16 +1724,13 @@
keyguardRepository.setKeyguardGoingAway(true)
runCurrent()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
- // THEN a transition to DOZING should occur
- assertThat(info.ownerName)
- .isEqualTo(FromGlanceableHubTransitionInteractor::class.simpleName)
- assertThat(info.from).isEqualTo(KeyguardState.GLANCEABLE_HUB)
- assertThat(info.to).isEqualTo(KeyguardState.GONE)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ ownerName = FromGlanceableHubTransitionInteractor::class.simpleName,
+ from = KeyguardState.GLANCEABLE_HUB,
+ to = KeyguardState.GONE,
+ animatorAssertion = { it.isNotNull() },
+ )
coroutineContext.cancelChildren()
}
@@ -1851,31 +1752,17 @@
keyguardRepository.setDreamingWithOverlay(true)
advanceUntilIdle()
- val info =
- withArgCaptor<TransitionInfo> {
- verify(transitionRepository).startTransition(capture())
- }
- // THEN a transition to DREAMING should occur
- assertThat(info.ownerName)
- .isEqualTo(FromGlanceableHubTransitionInteractor::class.simpleName)
- assertThat(info.from).isEqualTo(KeyguardState.GLANCEABLE_HUB)
- assertThat(info.to).isEqualTo(KeyguardState.DREAMING)
- assertThat(info.animator).isNotNull()
+ assertThat(transitionRepository)
+ .startedTransition(
+ ownerName = FromGlanceableHubTransitionInteractor::class.simpleName,
+ from = KeyguardState.GLANCEABLE_HUB,
+ to = KeyguardState.DREAMING,
+ animatorAssertion = { it.isNotNull() },
+ )
coroutineContext.cancelChildren()
}
- private fun createKeyguardInteractor(): KeyguardInteractor {
- return KeyguardInteractorFactory.create(
- featureFlags = featureFlags,
- repository = keyguardRepository,
- commandQueue = commandQueue,
- bouncerRepository = bouncerRepository,
- powerInteractor = powerInteractor,
- )
- .keyguardInteractor
- }
-
private suspend fun TestScope.runTransitionAndSetWakefulness(
from: KeyguardState,
to: KeyguardState
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/util/KeyguardTransitionRepositorySpySubject.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/util/KeyguardTransitionRepositorySpySubject.kt
new file mode 100644
index 0000000..655a551
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/util/KeyguardTransitionRepositorySpySubject.kt
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.util
+
+import androidx.core.animation.ValueAnimator
+import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionInfo
+import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.withArgCaptor
+import com.google.common.truth.FailureMetadata
+import com.google.common.truth.Subject
+import com.google.common.truth.Truth
+import com.google.common.truth.Truth.assertAbout
+import junit.framework.Assert.assertEquals
+import kotlin.test.fail
+import org.mockito.Mockito
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+
+/** [Subject] used to make assertions about a [Mockito.spy] KeyguardTransitionRepository. */
+class KeyguardTransitionRepositorySpySubject
+private constructor(
+ failureMetadata: FailureMetadata,
+ private val repository: KeyguardTransitionRepository,
+) : Subject(failureMetadata, repository) {
+
+ /**
+ * Asserts that we started a transition to the given state, optionally checking additional
+ * parameters. If an animator param or assertion is not provided, we will not assert anything
+ * about the animator.
+ */
+ fun startedTransition(
+ ownerName: String? = null,
+ from: KeyguardState? = null,
+ to: KeyguardState,
+ modeOnCanceled: TransitionModeOnCanceled? = null,
+ ) {
+ startedTransition(ownerName, from, to, {}, modeOnCanceled)
+ }
+
+ /**
+ * Asserts that we started a transition to the given state, optionally verifying additional
+ * params.
+ */
+ fun startedTransition(
+ ownerName: String? = null,
+ from: KeyguardState? = null,
+ to: KeyguardState,
+ animator: ValueAnimator?,
+ modeOnCanceled: TransitionModeOnCanceled? = null,
+ ) {
+ startedTransition(ownerName, from, to, { assertEquals(animator, it) }, modeOnCanceled)
+ }
+
+ /**
+ * Asserts that we started a transition to the given state, optionally verifying additional
+ * params.
+ */
+ fun startedTransition(
+ ownerName: String? = null,
+ from: KeyguardState? = null,
+ to: KeyguardState,
+ animatorAssertion: (Subject) -> Unit,
+ modeOnCanceled: TransitionModeOnCanceled? = null,
+ ) {
+ withArgCaptor<TransitionInfo> { verify(repository).startTransition(capture()) }
+ .also { transitionInfo ->
+ assertEquals(to, transitionInfo.to)
+ animatorAssertion.invoke(Truth.assertThat(transitionInfo.animator))
+ from?.let { assertEquals(it, transitionInfo.from) }
+ ownerName?.let { assertEquals(it, transitionInfo.ownerName) }
+ modeOnCanceled?.let { assertEquals(it, transitionInfo.modeOnCanceled) }
+ }
+ }
+
+ /** Verifies that [KeyguardTransitionRepository.startTransition] was never called. */
+ fun noTransitionsStarted() {
+ verify(repository, never()).startTransition(any())
+ }
+
+ companion object {
+ fun assertThat(
+ repository: KeyguardTransitionRepository
+ ): KeyguardTransitionRepositorySpySubject =
+ assertAbout { failureMetadata, repository: KeyguardTransitionRepository ->
+ if (!Mockito.mockingDetails(repository).isSpy) {
+ fail(
+ "Cannot assert on a non-spy KeyguardTransitionRepository. " +
+ "Use Mockito.spy(keyguardTransitionRepository)."
+ )
+ }
+ KeyguardTransitionRepositorySpySubject(failureMetadata, repository)
+ }
+ .that(repository)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessSliderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessSliderControllerTest.kt
index 707a297..d757d71 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessSliderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessSliderControllerTest.kt
@@ -202,7 +202,7 @@
@Test
fun testSeekBarTrackingStarted() {
whenever(brightnessSliderView.value).thenReturn(42)
- val event = BrightnessSliderEvent.SLIDER_STARTED_TRACKING_TOUCH
+ val event = BrightnessSliderEvent.BRIGHTNESS_SLIDER_STARTED_TRACKING_TOUCH
mController.onViewAttached()
mController.setMirrorControllerAndMirror(mirrorController)
@@ -220,7 +220,7 @@
@Test
fun testSeekBarTrackingStopped() {
whenever(brightnessSliderView.value).thenReturn(23)
- val event = BrightnessSliderEvent.SLIDER_STOPPED_TRACKING_TOUCH
+ val event = BrightnessSliderEvent.BRIGHTNESS_SLIDER_STOPPED_TRACKING_TOUCH
mController.onViewAttached()
mController.setMirrorControllerAndMirror(mirrorController)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
index c772ee2..8a22f4c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
@@ -63,7 +63,6 @@
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.data.repository.FakeCommandQueue;
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository;
-import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository;
import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor;
import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
@@ -197,16 +196,8 @@
() -> sceneInteractor);
CommunalInteractor communalInteractor = mKosmos.getCommunalInteractor();
- FakeKeyguardTransitionRepository keyguardTransitionRepository =
- new FakeKeyguardTransitionRepository();
-
KeyguardTransitionInteractor keyguardTransitionInteractor =
- new KeyguardTransitionInteractor(
- mTestScope.getBackgroundScope(),
- keyguardTransitionRepository,
- () -> keyguardInteractor,
- () -> mFromLockscreenTransitionInteractor,
- () -> mFromPrimaryBouncerTransitionInteractor);
+ mKosmos.getKeyguardTransitionInteractor();
mFromLockscreenTransitionInteractor = mKosmos.getFromLockscreenTransitionInteractor();
mFromPrimaryBouncerTransitionInteractor =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
index 72c52ec..f582402 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
@@ -41,7 +41,6 @@
import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository;
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository;
import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor;
-import com.android.systemui.communal.domain.interactor.CommunalInteractor;
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor;
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor;
import com.android.systemui.dump.DumpManager;
@@ -50,7 +49,6 @@
import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.keyguard.data.repository.FakeCommandQueue;
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository;
-import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository;
import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor;
import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
@@ -223,18 +221,9 @@
new ConfigurationInteractor(configurationRepository),
mShadeRepository,
() -> sceneInteractor);
- CommunalInteractor communalInteractor = mKosmos.getCommunalInteractor();
-
- FakeKeyguardTransitionRepository keyguardTransitionRepository =
- new FakeKeyguardTransitionRepository();
KeyguardTransitionInteractor keyguardTransitionInteractor =
- new KeyguardTransitionInteractor(
- mTestScope.getBackgroundScope(),
- keyguardTransitionRepository,
- () -> keyguardInteractor,
- () -> mFromLockscreenTransitionInteractor,
- () -> mFromPrimaryBouncerTransitionInteractor);
+ mKosmos.getKeyguardTransitionInteractor();
mFromLockscreenTransitionInteractor = mKosmos.getFromLockscreenTransitionInteractor();
mFromPrimaryBouncerTransitionInteractor =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
index 8fd9c80..fb105e2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
@@ -35,9 +35,9 @@
import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor
import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.domain.interactor.fromLockscreenTransitionInteractor
import com.android.systemui.keyguard.domain.interactor.fromPrimaryBouncerTransitionInteractor
+import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
import com.android.systemui.plugins.statusbar.StatusBarStateController
@@ -133,14 +133,7 @@
shadeRepository,
{ kosmos.sceneInteractor },
)
- val keyguardTransitionInteractor =
- KeyguardTransitionInteractor(
- testScope.backgroundScope,
- keyguardTransitionRepository,
- { keyguardInteractor },
- { fromLockscreenTransitionInteractor },
- { fromPrimaryBouncerTransitionInteractor }
- )
+ val keyguardTransitionInteractor = kosmos.keyguardTransitionInteractor
fromLockscreenTransitionInteractor = kosmos.fromLockscreenTransitionInteractor
fromPrimaryBouncerTransitionInteractor = kosmos.fromPrimaryBouncerTransitionInteractor
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/settings/repository/UserAwareSecureSettingsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/settings/repository/UserAwareSecureSettingsRepositoryTest.kt
new file mode 100644
index 0000000..913759f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/settings/repository/UserAwareSecureSettingsRepositoryTest.kt
@@ -0,0 +1,108 @@
+/*
+ * 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.util.settings.repository
+
+import android.content.pm.UserInfo
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.user.data.repository.fakeUserRepository
+import com.android.systemui.util.settings.FakeSettings
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class UserAwareSecureSettingsRepositoryTest : SysuiTestCase() {
+
+ private val dispatcher = StandardTestDispatcher()
+ private val testScope = TestScope(dispatcher)
+ private val secureSettings = FakeSettings()
+ private val userRepository = Kosmos().fakeUserRepository
+ private lateinit var repository: UserAwareSecureSettingsRepository
+
+ @Before
+ fun setup() {
+ repository = UserAwareSecureSettingsRepositoryImpl(
+ secureSettings,
+ userRepository,
+ dispatcher,
+ )
+ userRepository.setUserInfos(USER_INFOS)
+ setSettingValueForUser(enabled = true, userInfo = SETTING_ENABLED_USER)
+ setSettingValueForUser(enabled = false, userInfo = SETTING_DISABLED_USER)
+ }
+
+ @Test
+ fun settingEnabledEmitsValueForCurrentUser() {
+ testScope.runTest {
+ userRepository.setSelectedUserInfo(SETTING_ENABLED_USER)
+
+ val enabled by collectLastValue(repository.boolSettingForActiveUser(SETTING_NAME))
+
+ assertThat(enabled).isTrue()
+ }
+ }
+
+ @Test
+ fun settingEnabledEmitsNewValueWhenSettingChanges() {
+ testScope.runTest {
+ userRepository.setSelectedUserInfo(SETTING_ENABLED_USER)
+ val enabled by collectValues(repository.boolSettingForActiveUser(SETTING_NAME))
+ runCurrent()
+
+ setSettingValueForUser(enabled = false, userInfo = SETTING_ENABLED_USER)
+
+ assertThat(enabled).containsExactly(true, false).inOrder()
+ }
+ }
+
+ @Test
+ fun settingEnabledEmitsValueForNewUserWhenUserChanges() {
+ testScope.runTest {
+ userRepository.setSelectedUserInfo(SETTING_ENABLED_USER)
+ val enabled by collectLastValue(repository.boolSettingForActiveUser(SETTING_NAME))
+ runCurrent()
+
+ userRepository.setSelectedUserInfo(SETTING_DISABLED_USER)
+
+ assertThat(enabled).isFalse()
+ }
+ }
+
+ private fun setSettingValueForUser(enabled: Boolean, userInfo: UserInfo) {
+ secureSettings.putBoolForUser(SETTING_NAME, enabled, userInfo.id)
+ }
+
+ private companion object {
+ const val SETTING_NAME = "SETTING_NAME"
+ val SETTING_ENABLED_USER = UserInfo(/* id= */ 0, "user1", /* flags= */ 0)
+ val SETTING_DISABLED_USER = UserInfo(/* id= */ 1, "user2", /* flags= */ 0)
+ val USER_INFOS = listOf(SETTING_ENABLED_USER, SETTING_DISABLED_USER)
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index 1d428c8..d45a9a9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -95,11 +95,9 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository;
-import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository;
import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor;
-import com.android.systemui.communal.domain.interactor.CommunalInteractor;
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FakeFeatureFlags;
@@ -107,7 +105,6 @@
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.data.repository.FakeCommandQueue;
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository;
-import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository;
import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor;
import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
@@ -428,17 +425,8 @@
shadeRepository,
() -> sceneInteractor);
- FakeKeyguardTransitionRepository keyguardTransitionRepository =
- new FakeKeyguardTransitionRepository();
-
KeyguardTransitionInteractor keyguardTransitionInteractor =
- new KeyguardTransitionInteractor(
- mTestScope.getBackgroundScope(),
- keyguardTransitionRepository,
- () -> keyguardInteractor,
- () -> mFromLockscreenTransitionInteractor,
- () -> mFromPrimaryBouncerTransitionInteractor);
- CommunalInteractor communalInteractor = mKosmos.getCommunalInteractor();
+ mKosmos.getKeyguardTransitionInteractor();
mFromLockscreenTransitionInteractor = mKosmos.getFromLockscreenTransitionInteractor();
mFromPrimaryBouncerTransitionInteractor =
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorKosmos.kt
new file mode 100644
index 0000000..da5cd67
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorKosmos.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.domain.interactor
+
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
+
+val Kosmos.fromAodTransitionInteractor by
+ Kosmos.Fixture {
+ FromAodTransitionInteractor(
+ transitionRepository = fakeKeyguardTransitionRepository,
+ transitionInteractor = keyguardTransitionInteractor,
+ scope = testScope,
+ bgDispatcher = testDispatcher,
+ mainDispatcher = testDispatcher,
+ keyguardInteractor = keyguardInteractor,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractorKosmos.kt
new file mode 100644
index 0000000..25fc67a
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractorKosmos.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.domain.interactor
+
+import com.android.systemui.communal.domain.interactor.communalInteractor
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.power.domain.interactor.powerInteractor
+
+val Kosmos.fromGoneTransitionInteractor by
+ Kosmos.Fixture {
+ FromGoneTransitionInteractor(
+ transitionRepository = fakeKeyguardTransitionRepository,
+ transitionInteractor = keyguardTransitionInteractor,
+ scope = applicationCoroutineScope,
+ bgDispatcher = testDispatcher,
+ mainDispatcher = testDispatcher,
+ keyguardInteractor = keyguardInteractor,
+ powerInteractor = powerInteractor,
+ communalInteractor = communalInteractor,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorKosmos.kt
index a646bc6..c9c17d9 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorKosmos.kt
@@ -19,6 +19,7 @@
import android.content.applicationContext
import com.android.systemui.keyguard.data.repository.keyguardSurfaceBehindRepository
import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.statusbar.notification.domain.interactor.notificationLaunchAnimationInteractor
var Kosmos.keyguardSurfaceBehindInteractor by
Kosmos.Fixture {
@@ -30,5 +31,6 @@
inWindowLauncherUnlockAnimationInteractor
},
swipeToDismissInteractor = swipeToDismissInteractor,
+ notificationLaunchInteractor = notificationLaunchAnimationInteractor,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorKosmos.kt
index e4d115e..0c38fd9 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorKosmos.kt
@@ -30,5 +30,6 @@
fromLockscreenTransitionInteractor = Lazy { fromLockscreenTransitionInteractor },
fromPrimaryBouncerTransitionInteractor =
Lazy { fromPrimaryBouncerTransitionInteractor },
+ fromAodTransitionInteractor = Lazy { fromAodTransitionInteractor },
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorKosmos.kt
index 0207280..d84988d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorKosmos.kt
@@ -17,6 +17,7 @@
package com.android.systemui.keyguard.domain.interactor
import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.statusbar.notification.domain.interactor.notificationLaunchAnimationInteractor
val Kosmos.windowManagerLockscreenVisibilityInteractor by
Kosmos.Fixture {
@@ -26,5 +27,6 @@
surfaceBehindInteractor = keyguardSurfaceBehindInteractor,
fromLockscreenInteractor = fromLockscreenTransitionInteractor,
fromBouncerInteractor = fromPrimaryBouncerTransitionInteractor,
+ notificationLaunchAnimationInteractor = notificationLaunchAnimationInteractor,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/repository/NotificationLaunchAnimationRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/repository/NotificationLaunchAnimationRepositoryKosmos.kt
new file mode 100644
index 0000000..5638cfc
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/repository/NotificationLaunchAnimationRepositoryKosmos.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.data.repository
+
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.notificationLaunchAnimationRepository by
+ Kosmos.Fixture { NotificationLaunchAnimationRepository() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationLaunchAnimationInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationLaunchAnimationInteractorKosmos.kt
new file mode 100644
index 0000000..0d84bab
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationLaunchAnimationInteractorKosmos.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.domain.interactor
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.statusbar.notification.data.repository.notificationLaunchAnimationRepository
+
+val Kosmos.notificationLaunchAnimationInteractor by
+ Kosmos.Fixture {
+ NotificationLaunchAnimationInteractor(
+ repository = notificationLaunchAnimationRepository,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeUserAwareSecureSettingsRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeUserAwareSecureSettingsRepository.kt
new file mode 100644
index 0000000..5054e29
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeUserAwareSecureSettingsRepository.kt
@@ -0,0 +1,35 @@
+/*
+ * 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.util.settings
+
+import com.android.systemui.util.settings.repository.UserAwareSecureSettingsRepository
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.map
+
+class FakeUserAwareSecureSettingsRepository : UserAwareSecureSettingsRepository {
+
+ private val settings = MutableStateFlow<Map<String, Boolean>>(mutableMapOf())
+
+ override fun boolSettingForActiveUser(name: String, defaultValue: Boolean): Flow<Boolean> {
+ return settings.map { it.getOrDefault(name, defaultValue) }
+ }
+
+ fun setBoolSettingForActiveUser(name: String, value: Boolean) {
+ settings.value = settings.value.toMutableMap().apply { this[name] = value }
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/UserAwareSecureSettingsRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/UserAwareSecureSettingsRepositoryKosmos.kt
new file mode 100644
index 0000000..94b2bdf
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/UserAwareSecureSettingsRepositoryKosmos.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util.settings
+
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.userAwareSecureSettingsRepository by
+ Kosmos.Fixture { FakeUserAwareSecureSettingsRepository() }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 260fdb9..c860b5a 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -962,6 +962,21 @@
getInstallSource().mInstallerPackageName, mInstallerUid);
}
+ private boolean isEmergencyInstallerEnabled(String packageName, Computer snapshot) {
+ final PackageStateInternal ps = snapshot.getPackageStateInternal(packageName);
+ if (ps == null || ps.getPkg() == null || !ps.isSystem()) {
+ return false;
+ }
+ String emergencyInstaller = ps.getPkg().getEmergencyInstaller();
+ if (emergencyInstaller == null || !ArrayUtils.contains(
+ snapshot.getPackagesForUid(mInstallerUid),
+ emergencyInstaller)) {
+ return false;
+ }
+ return (snapshot.checkUidPermission(Manifest.permission.EMERGENCY_INSTALL_PACKAGES,
+ mInstallerUid) == PackageManager.PERMISSION_GRANTED);
+ }
+
private static final int USER_ACTION_NOT_NEEDED = 0;
private static final int USER_ACTION_REQUIRED = 1;
private static final int USER_ACTION_PENDING_APK_PARSING = 2;
@@ -1046,6 +1061,8 @@
final boolean isUpdateOwner = TextUtils.equals(existingUpdateOwnerPackageName,
getInstallerPackageName());
final boolean isSelfUpdate = targetPackageUid == mInstallerUid;
+ final boolean isEmergencyInstall =
+ isEmergencyInstallerEnabled(packageName, snapshot);
final boolean isPermissionGranted = isInstallPermissionGranted
|| (isUpdatePermissionGranted && isUpdate)
|| (isSelfUpdatePermissionGranted && isSelfUpdate)
@@ -1062,7 +1079,7 @@
// Device owners and affiliated profile owners are allowed to silently install packages, so
// the permission check is waived if the installer is the device owner.
final boolean noUserActionNecessary = isInstallerRoot || isInstallerSystem
- || isInstallerDeviceOwnerOrAffiliatedProfileOwner();
+ || isInstallerDeviceOwnerOrAffiliatedProfileOwner() || isEmergencyInstall;
if (noUserActionNecessary) {
return userActionNotTypicallyNeededResponse;
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 04e8205..5575f52 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -5044,6 +5044,10 @@
pw.print(prefix); pw.print(" updatableSystem=false");
pw.println();
}
+ if (pkg.getEmergencyInstaller() != null) {
+ pw.print(prefix); pw.print(" emergencyInstaller=");
+ pw.println(pkg.getEmergencyInstaller());
+ }
if (pkg.hasPreserveLegacyExternalStorage()) {
pw.print(prefix); pw.print(" hasPreserveLegacyExternalStorage=true");
pw.println();
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
index ef9c62f..cfe701f 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
@@ -272,7 +272,8 @@
AndroidPackage::hasPreserveLegacyExternalStorage,
AndroidPackage::hasRequestForegroundServiceExemption,
AndroidPackage::hasRequestRawExternalStorageAccess,
- AndroidPackage::isUpdatableSystem
+ AndroidPackage::isUpdatableSystem,
+ AndroidPackage::getEmergencyInstaller
)
override fun extraParams() = listOf(
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 3426cbe..f396b24 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -9746,8 +9746,11 @@
throws RemoteException {
IRingtonePlayer mockPlayer = mock(IRingtonePlayer.class);
when(mAudioManager.getRingtonePlayer()).thenReturn(mockPlayer);
- // Set up volume to be above 0 for the sound to actually play
+ // Set up volume to be above 0, and for AudioManager to signal playback should happen,
+ // for the sound to actually play
when(mAudioManager.getStreamVolume(anyInt())).thenReturn(10);
+ when(mAudioManager.shouldNotificationSoundPlay(any(android.media.AudioAttributes.class)))
+ .thenReturn(true);
setUpPrefsForBubbles(PKG, mUid,
true /* global */,