Merge "Update thermal related string to support non-phone device" into udc-qpr-dev
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 3be8c3d..bd7f5a0 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -413,6 +413,13 @@
/** Class cookies of the Parcel this instance was read from. */
private Map<Class, Object> mClassCookies;
+ /**
+ * {@link LayoutInflater.Factory2} which will be passed into a {@link LayoutInflater} instance
+ * used by this class.
+ */
+ @Nullable
+ private LayoutInflater.Factory2 mLayoutInflaterFactory2;
+
private static final InteractionHandler DEFAULT_INTERACTION_HANDLER =
(view, pendingIntent, response) ->
startPendingIntent(view, pendingIntent, response.getLaunchOptions(view));
@@ -432,6 +439,29 @@
}
/**
+ * Sets {@link LayoutInflater.Factory2} to be passed into {@link LayoutInflater} used
+ * by this class instance. It has to be set before the views are inflated to have any effect.
+ *
+ * The factory callbacks will be called on the background thread so the implementation needs
+ * to be thread safe.
+ *
+ * @hide
+ */
+ public void setLayoutInflaterFactory(@Nullable LayoutInflater.Factory2 factory) {
+ mLayoutInflaterFactory2 = factory;
+ }
+
+ /**
+ * Returns currently set {@link LayoutInflater.Factory2}.
+ *
+ * @hide
+ */
+ @Nullable
+ public LayoutInflater.Factory2 getLayoutInflaterFactory() {
+ return mLayoutInflaterFactory2;
+ }
+
+ /**
* Reduces all images and ensures that they are all below the given sizes.
*
* @param maxWidth the maximum width allowed
@@ -5659,6 +5689,9 @@
// we don't add a filter to the static version returned by getSystemService.
inflater = inflater.cloneInContext(inflationContext);
inflater.setFilter(shouldUseStaticFilter() ? INFLATER_FILTER : this);
+ if (mLayoutInflaterFactory2 != null) {
+ inflater.setFactory2(mLayoutInflaterFactory2);
+ }
View v = inflater.inflate(rv.getLayoutId(), parent, false);
if (mViewId != View.NO_ID) {
v.setId(mViewId);
diff --git a/core/tests/coretests/src/android/widget/RemoteViewsTest.java b/core/tests/coretests/src/android/widget/RemoteViewsTest.java
index 73aa936..c442755 100644
--- a/core/tests/coretests/src/android/widget/RemoteViewsTest.java
+++ b/core/tests/coretests/src/android/widget/RemoteViewsTest.java
@@ -22,6 +22,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.spy;
@@ -39,11 +40,15 @@
import android.os.Binder;
import android.os.Looper;
import android.os.Parcel;
+import android.util.AttributeSet;
import android.util.SizeF;
import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -827,4 +832,71 @@
verify(visitor, times(1)).accept(eq(icon3S.getUri()));
verify(visitor, times(1)).accept(eq(icon4S.getUri()));
}
+
+ @Test
+ public void layoutInflaterFactory_nothingSet_returnsNull() {
+ final RemoteViews rv = new RemoteViews(mPackage, R.layout.remote_views_test);
+ assertNull(rv.getLayoutInflaterFactory());
+ }
+
+ @Test
+ public void layoutInflaterFactory_replacesImageView_viewReplaced() {
+ final RemoteViews rv = new RemoteViews(mPackage, R.layout.remote_views_test);
+ final View replacement = new FrameLayout(mContext);
+ replacement.setId(1337);
+
+ LayoutInflater.Factory2 factory = createLayoutInflaterFactory("ImageView", replacement);
+ rv.setLayoutInflaterFactory(factory);
+
+ // Now inflate the views.
+ View inflated = rv.apply(mContext, mContainer);
+
+ assertEquals(factory, rv.getLayoutInflaterFactory());
+ View replacedFrameLayout = inflated.findViewById(1337);
+ assertNotNull(replacedFrameLayout);
+ assertEquals(replacement, replacedFrameLayout);
+ // ImageView should be fully replaced.
+ assertNull(inflated.findViewById(R.id.image));
+ }
+
+ @Test
+ public void layoutInflaterFactory_replacesImageView_settersStillFunctional() {
+ final RemoteViews rv = new RemoteViews(mPackage, R.layout.remote_views_test);
+ final TextView replacement = new TextView(mContext);
+ replacement.setId(R.id.text);
+ final String testText = "testText";
+ rv.setLayoutInflaterFactory(createLayoutInflaterFactory("TextView", replacement));
+ rv.setTextViewText(R.id.text, testText);
+
+
+ // Now inflate the views.
+ View inflated = rv.apply(mContext, mContainer);
+
+ TextView replacedTextView = inflated.findViewById(R.id.text);
+ assertSame(replacement, replacedTextView);
+ assertEquals(testText, replacedTextView.getText());
+ }
+
+ private static LayoutInflater.Factory2 createLayoutInflaterFactory(String viewTypeToReplace,
+ View replacementView) {
+ return new LayoutInflater.Factory2() {
+ @Nullable
+ @Override
+ public View onCreateView(@Nullable View parent, @NonNull String name,
+ @NonNull Context context, @NonNull AttributeSet attrs) {
+ if (viewTypeToReplace.equals(name)) {
+ return replacementView;
+ }
+
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull String name, @NonNull Context context,
+ @NonNull AttributeSet attrs) {
+ return null;
+ }
+ };
+ }
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt
index e07a629..90a723f 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt
@@ -50,7 +50,7 @@
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.Stable
import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.Alignment
@@ -286,21 +286,22 @@
)
}
val pinnedHeightPx: Float
- val density = LocalDensity.current
- val maxHeightPx = density.run {
- remember { mutableStateOf((MaxHeightWithoutTitle + DefaultTitleHeight).toPx()) }
- }
val titleBottomPaddingPx: Int
+ val defaultMaxHeightPx: Float
+ val density = LocalDensity.current
density.run {
pinnedHeightPx = pinnedHeight.toPx()
titleBottomPaddingPx = titleBottomPadding.roundToPx()
+ defaultMaxHeightPx = (MaxHeightWithoutTitle + DefaultTitleHeight).toPx()
}
+ val maxHeightPx = remember(density) { mutableFloatStateOf(defaultMaxHeightPx) }
+
// Sets the app bar's height offset limit to hide just the bottom title area and keep top title
// visible when collapsed.
SideEffect {
- if (scrollBehavior?.state?.heightOffsetLimit != pinnedHeightPx - maxHeightPx.value) {
- scrollBehavior?.state?.heightOffsetLimit = pinnedHeightPx - maxHeightPx.value
+ if (scrollBehavior?.state?.heightOffsetLimit != pinnedHeightPx - maxHeightPx.floatValue) {
+ scrollBehavior?.state?.heightOffsetLimit = pinnedHeightPx - maxHeightPx.floatValue
}
}
@@ -370,16 +371,20 @@
)
TopAppBarLayout(
modifier = Modifier.clipToBounds(),
- heightPx = maxHeightPx.value - pinnedHeightPx +
+ heightPx = maxHeightPx.floatValue - pinnedHeightPx +
(scrollBehavior?.state?.heightOffset ?: 0f),
navigationIconContentColor = colors.navigationIconContentColor,
titleContentColor = colors.titleContentColor,
actionIconContentColor = colors.actionIconContentColor,
title = {
Box(modifier = Modifier.onGloballyPositioned { coordinates ->
- density.run {
- maxHeightPx.value =
- MaxHeightWithoutTitle.toPx() + coordinates.size.height.toFloat()
+ val measuredMaxHeightPx = density.run {
+ MaxHeightWithoutTitle.toPx() + coordinates.size.height.toFloat()
+ }
+ // Allow larger max height for multi-line title, but do not reduce
+ // max height to prevent flaky.
+ if (measuredMaxHeightPx > defaultMaxHeightPx) {
+ maxHeightPx.floatValue = measuredMaxHeightPx
}
}) { title() }
},
@@ -506,7 +511,7 @@
0
}
- val layoutHeight = heightPx.roundToInt()
+ val layoutHeight = if (heightPx.isNaN()) 0 else heightPx.roundToInt()
layout(constraints.maxWidth, layoutHeight) {
// Navigation icon
@@ -612,9 +617,9 @@
// Medium or Large app bar.
private val TopTitleAlphaEasing = CubicBezierEasing(.8f, 0f, .8f, .15f)
-private val MaxHeightWithoutTitle = 124.dp
-private val DefaultTitleHeight = 52.dp
-private val ContainerHeight = 56.dp
+internal val MaxHeightWithoutTitle = 124.dp
+internal val DefaultTitleHeight = 52.dp
+internal val ContainerHeight = 56.dp
private val LargeTitleBottomPadding = 28.dp
private val TopAppBarHorizontalPadding = 4.dp
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt
index 67c4cdc..67f4418 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt
@@ -163,7 +163,6 @@
BackHandler { onClose() }
}
-@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun SearchBox(query: TextFieldValue, onQueryChange: (TextFieldValue) -> Unit) {
val focusRequester = remember { FocusRequester() }
@@ -186,8 +185,9 @@
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search),
keyboardActions = KeyboardActions(onSearch = { hideKeyboardAction() }),
singleLine = true,
- colors = TextFieldDefaults.textFieldColors(
- containerColor = Color.Transparent,
+ colors = TextFieldDefaults.colors(
+ focusedContainerColor = Color.Transparent,
+ unfocusedContainerColor = Color.Transparent,
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
),
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBarTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBarTest.kt
new file mode 100644
index 0000000..a6a5ed22
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBarTest.kt
@@ -0,0 +1,457 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.widget.scaffold
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.LazyListState
+import androidx.compose.foundation.lazy.LazyRow
+import androidx.compose.foundation.lazy.rememberLazyListState
+import androidx.compose.material3.CenterAlignedTopAppBar
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.LocalContentColor
+import androidx.compose.material3.LocalTextStyle
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.Text
+import androidx.compose.material3.TopAppBarDefaults
+import androidx.compose.material3.TopAppBarScrollBehavior
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.painter.ColorPainter
+import androidx.compose.ui.input.nestedscroll.nestedScroll
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.test.assertHeightIsEqualTo
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.assertLeftPositionInRootIsEqualTo
+import androidx.compose.ui.test.assertTopPositionInRootIsEqualTo
+import androidx.compose.ui.test.assertWidthIsEqualTo
+import androidx.compose.ui.test.getUnclippedBoundsInRoot
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.test.performTouchInput
+import androidx.compose.ui.test.swipeLeft
+import androidx.compose.ui.test.swipeRight
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.height
+import androidx.compose.ui.unit.width
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.testutils.rootWidth
+import com.android.settingslib.spa.testutils.setContentForSizeAssertions
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalMaterial3Api::class)
+@RunWith(AndroidJUnit4::class)
+class CustomizedAppBarTest {
+
+ @get:Rule
+ val rule = createComposeRule()
+
+ @Test
+ fun smallTopAppBar_expandsToScreen() {
+ rule
+ .setContentForSizeAssertions {
+ CustomizedTopAppBar(title = { Text("Title") })
+ }
+ .assertHeightIsEqualTo(ContainerHeight)
+ .assertWidthIsEqualTo(rule.rootWidth())
+ }
+
+ @Test
+ fun smallTopAppBar_withTitle() {
+ val title = "Title"
+ rule.setContent {
+ Box(Modifier.testTag(TopAppBarTestTag)) {
+ CustomizedTopAppBar(title = { Text(title) })
+ }
+ }
+ rule.onNodeWithText(title).assertIsDisplayed()
+ }
+
+ @Test
+ fun smallTopAppBar_default_positioning() {
+ rule.setContent {
+ Box(Modifier.testTag(TopAppBarTestTag)) {
+ CustomizedTopAppBar(
+ navigationIcon = {
+ FakeIcon(Modifier.testTag(NavigationIconTestTag))
+ },
+ title = {
+ Text("Title", Modifier.testTag(TitleTestTag))
+ },
+ actions = {
+ FakeIcon(Modifier.testTag(ActionsTestTag))
+ }
+ )
+ }
+ }
+ assertSmallDefaultPositioning()
+ }
+
+ @Test
+ fun smallTopAppBar_noNavigationIcon_positioning() {
+ rule.setContent {
+ Box(Modifier.testTag(TopAppBarTestTag)) {
+ CustomizedTopAppBar(
+ title = {
+ Text("Title", Modifier.testTag(TitleTestTag))
+ },
+ actions = {
+ FakeIcon(Modifier.testTag(ActionsTestTag))
+ }
+ )
+ }
+ }
+ assertSmallPositioningWithoutNavigation()
+ }
+
+ @Test
+ fun smallTopAppBar_titleDefaultStyle() {
+ var textStyle: TextStyle? = null
+ var expectedTextStyle: TextStyle? = null
+ rule.setContent {
+ CustomizedTopAppBar(
+ title = {
+ Text("Title")
+ textStyle = LocalTextStyle.current
+ expectedTextStyle = MaterialTheme.typography.titleMedium
+ },
+ )
+ }
+ assertThat(textStyle).isNotNull()
+ assertThat(textStyle).isEqualTo(expectedTextStyle)
+ }
+
+ @Test
+ fun smallTopAppBar_contentColor() {
+ var titleColor: Color = Color.Unspecified
+ var navigationIconColor: Color = Color.Unspecified
+ var actionsColor: Color = Color.Unspecified
+ var expectedTitleColor: Color = Color.Unspecified
+ var expectedNavigationIconColor: Color = Color.Unspecified
+ var expectedActionsColor: Color = Color.Unspecified
+
+ rule.setContent {
+ CustomizedTopAppBar(
+ navigationIcon = {
+ FakeIcon(Modifier.testTag(NavigationIconTestTag))
+ navigationIconColor = LocalContentColor.current
+ expectedNavigationIconColor =
+ TopAppBarDefaults.topAppBarColors().navigationIconContentColor
+ // fraction = 0f to indicate no scroll.
+ },
+ title = {
+ Text("Title", Modifier.testTag(TitleTestTag))
+ titleColor = LocalContentColor.current
+ expectedTitleColor = TopAppBarDefaults.topAppBarColors().titleContentColor
+ },
+ actions = {
+ FakeIcon(Modifier.testTag(ActionsTestTag))
+ actionsColor = LocalContentColor.current
+ expectedActionsColor =
+ TopAppBarDefaults.topAppBarColors().actionIconContentColor
+ }
+ )
+ }
+ assertThat(navigationIconColor).isNotNull()
+ assertThat(titleColor).isNotNull()
+ assertThat(actionsColor).isNotNull()
+ assertThat(navigationIconColor).isEqualTo(expectedNavigationIconColor)
+ assertThat(titleColor).isEqualTo(expectedTitleColor)
+ assertThat(actionsColor).isEqualTo(expectedActionsColor)
+ }
+
+ @Test
+ fun largeTopAppBar_scrolled_positioning() {
+ val content = @Composable { scrollBehavior: TopAppBarScrollBehavior? ->
+ Box(Modifier.testTag(TopAppBarTestTag)) {
+ CustomizedLargeTopAppBar(
+ navigationIcon = {
+ FakeIcon(Modifier.testTag(NavigationIconTestTag))
+ },
+ title = "Title",
+ actions = {
+ FakeIcon(Modifier.testTag(ActionsTestTag))
+ },
+ scrollBehavior = scrollBehavior,
+ )
+ }
+ }
+ assertLargeScrolledHeight(
+ MaxHeightWithoutTitle + DefaultTitleHeight,
+ MaxHeightWithoutTitle + DefaultTitleHeight,
+ content,
+ )
+ }
+
+ @OptIn(ExperimentalMaterial3Api::class)
+ @Test
+ fun topAppBar_enterAlways_allowHorizontalScroll() {
+ lateinit var state: LazyListState
+ rule.setContent {
+ state = rememberLazyListState()
+ MultiPageContent(TopAppBarDefaults.enterAlwaysScrollBehavior(), state)
+ }
+
+ rule.onNodeWithTag(LazyListTag).performTouchInput { swipeLeft() }
+ rule.runOnIdle {
+ assertThat(state.firstVisibleItemIndex).isEqualTo(1)
+ }
+
+ rule.onNodeWithTag(LazyListTag).performTouchInput { swipeRight() }
+ rule.runOnIdle {
+ assertThat(state.firstVisibleItemIndex).isEqualTo(0)
+ }
+ }
+
+ @OptIn(ExperimentalMaterial3Api::class)
+ @Test
+ fun topAppBar_exitUntilCollapsed_allowHorizontalScroll() {
+ lateinit var state: LazyListState
+ rule.setContent {
+ state = rememberLazyListState()
+ MultiPageContent(TopAppBarDefaults.exitUntilCollapsedScrollBehavior(), state)
+ }
+
+ rule.onNodeWithTag(LazyListTag).performTouchInput { swipeLeft() }
+ rule.runOnIdle {
+ assertThat(state.firstVisibleItemIndex).isEqualTo(1)
+ }
+
+ rule.onNodeWithTag(LazyListTag).performTouchInput { swipeRight() }
+ rule.runOnIdle {
+ assertThat(state.firstVisibleItemIndex).isEqualTo(0)
+ }
+ }
+
+ @OptIn(ExperimentalMaterial3Api::class)
+ @Test
+ fun topAppBar_pinned_allowHorizontalScroll() {
+ lateinit var state: LazyListState
+ rule.setContent {
+ state = rememberLazyListState()
+ MultiPageContent(
+ TopAppBarDefaults.pinnedScrollBehavior(),
+ state
+ )
+ }
+
+ rule.onNodeWithTag(LazyListTag).performTouchInput { swipeLeft() }
+ rule.runOnIdle {
+ assertThat(state.firstVisibleItemIndex).isEqualTo(1)
+ }
+
+ rule.onNodeWithTag(LazyListTag).performTouchInput { swipeRight() }
+ rule.runOnIdle {
+ assertThat(state.firstVisibleItemIndex).isEqualTo(0)
+ }
+ }
+
+ @OptIn(ExperimentalMaterial3Api::class)
+ @Composable
+ private fun MultiPageContent(scrollBehavior: TopAppBarScrollBehavior, state: LazyListState) {
+ Scaffold(
+ modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
+ topBar = {
+ CustomizedTopAppBar(
+ title = { Text(text = "Title") },
+ )
+ }
+ ) { contentPadding ->
+ LazyRow(
+ Modifier
+ .fillMaxSize()
+ .testTag(LazyListTag), state
+ ) {
+ items(2) { page ->
+ LazyColumn(
+ modifier = Modifier.fillParentMaxSize(),
+ contentPadding = contentPadding
+ ) {
+ items(50) {
+ Text(
+ modifier = Modifier.fillParentMaxWidth(),
+ text = "Item #$page x $it"
+ )
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Checks the app bar's components positioning when it's a [CustomizedTopAppBar], a
+ * [CenterAlignedTopAppBar], or a larger app bar that is scrolled up and collapsed into a small
+ * configuration and there is no navigation icon.
+ */
+ private fun assertSmallPositioningWithoutNavigation(isCenteredTitle: Boolean = false) {
+ val appBarBounds = rule.onNodeWithTag(TopAppBarTestTag).getUnclippedBoundsInRoot()
+ val titleBounds = rule.onNodeWithTag(TitleTestTag).getUnclippedBoundsInRoot()
+
+ val titleNode = rule.onNodeWithTag(TitleTestTag)
+ // Title should be vertically centered
+ titleNode.assertTopPositionInRootIsEqualTo((appBarBounds.height - titleBounds.height) / 2)
+ if (isCenteredTitle) {
+ // Title should be horizontally centered
+ titleNode.assertLeftPositionInRootIsEqualTo(
+ (appBarBounds.width - titleBounds.width) / 2
+ )
+ } else {
+ // Title should now be placed 16.dp from the start, as there is no navigation icon
+ // 4.dp padding for the whole app bar + 12.dp inset
+ titleNode.assertLeftPositionInRootIsEqualTo(4.dp + 12.dp)
+ }
+
+ rule.onNodeWithTag(ActionsTestTag)
+ // Action should still be placed at the end
+ .assertLeftPositionInRootIsEqualTo(expectedActionPosition(appBarBounds.width))
+ }
+
+ /**
+ * Checks the app bar's components positioning when it's a [CustomizedTopAppBar] or a
+ * [CenterAlignedTopAppBar].
+ */
+ private fun assertSmallDefaultPositioning(isCenteredTitle: Boolean = false) {
+ val appBarBounds = rule.onNodeWithTag(TopAppBarTestTag).getUnclippedBoundsInRoot()
+ val titleBounds = rule.onNodeWithTag(TitleTestTag).getUnclippedBoundsInRoot()
+ val appBarBottomEdgeY = appBarBounds.top + appBarBounds.height
+
+ rule.onNodeWithTag(NavigationIconTestTag)
+ // Navigation icon should be 4.dp from the start
+ .assertLeftPositionInRootIsEqualTo(AppBarStartAndEndPadding)
+ // Navigation icon should be centered within the height of the app bar.
+ .assertTopPositionInRootIsEqualTo(
+ appBarBottomEdgeY - AppBarTopAndBottomPadding - FakeIconSize
+ )
+
+ val titleNode = rule.onNodeWithTag(TitleTestTag)
+ // Title should be vertically centered
+ titleNode.assertTopPositionInRootIsEqualTo((appBarBounds.height - titleBounds.height) / 2)
+ if (isCenteredTitle) {
+ // Title should be horizontally centered
+ titleNode.assertLeftPositionInRootIsEqualTo(
+ (appBarBounds.width - titleBounds.width) / 2
+ )
+ } else {
+ // Title should be 56.dp from the start
+ // 4.dp padding for the whole app bar + 48.dp icon size + 4.dp title padding.
+ titleNode.assertLeftPositionInRootIsEqualTo(4.dp + FakeIconSize + 4.dp)
+ }
+
+ rule.onNodeWithTag(ActionsTestTag)
+ // Action should be placed at the end
+ .assertLeftPositionInRootIsEqualTo(expectedActionPosition(appBarBounds.width))
+ // Action should be 8.dp from the top
+ .assertTopPositionInRootIsEqualTo(
+ appBarBottomEdgeY - AppBarTopAndBottomPadding - FakeIconSize
+ )
+ }
+
+ /**
+ * Checks that changing values at a [CustomizedLargeTopAppBar] scroll behavior
+ * affects the height of the app bar.
+ *
+ * This check partially and fully collapses the app bar to test its height.
+ *
+ * @param appBarMaxHeight the max height of the app bar [content]
+ * @param appBarMinHeight the min height of the app bar [content]
+ * @param content a Composable that adds a CustomizedLargeTopAppBar
+ */
+ @OptIn(ExperimentalMaterial3Api::class)
+ private fun assertLargeScrolledHeight(
+ appBarMaxHeight: Dp,
+ appBarMinHeight: Dp,
+ content: @Composable (TopAppBarScrollBehavior?) -> Unit
+ ) {
+ val fullyCollapsedOffsetDp = appBarMaxHeight - appBarMinHeight
+ val partiallyCollapsedOffsetDp = fullyCollapsedOffsetDp / 3
+ var partiallyCollapsedHeightOffsetPx = 0f
+ var fullyCollapsedHeightOffsetPx = 0f
+ lateinit var scrollBehavior: TopAppBarScrollBehavior
+ rule.setContent {
+ scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
+ with(LocalDensity.current) {
+ partiallyCollapsedHeightOffsetPx = partiallyCollapsedOffsetDp.toPx()
+ fullyCollapsedHeightOffsetPx = fullyCollapsedOffsetDp.toPx()
+ }
+
+ content(scrollBehavior)
+ }
+
+ // Simulate a partially collapsed app bar.
+ rule.runOnIdle {
+ scrollBehavior.state.heightOffset = -partiallyCollapsedHeightOffsetPx
+ scrollBehavior.state.contentOffset = -partiallyCollapsedHeightOffsetPx
+ }
+ rule.waitForIdle()
+ rule.onNodeWithTag(TopAppBarTestTag)
+ .assertHeightIsEqualTo(
+ appBarMaxHeight - partiallyCollapsedOffsetDp
+ )
+
+ // Simulate a fully collapsed app bar.
+ rule.runOnIdle {
+ scrollBehavior.state.heightOffset = -fullyCollapsedHeightOffsetPx
+ // Simulate additional content scroll beyond the max offset scroll.
+ scrollBehavior.state.contentOffset =
+ -fullyCollapsedHeightOffsetPx - partiallyCollapsedHeightOffsetPx
+ }
+ rule.waitForIdle()
+ // Check that the app bar collapsed to its min height.
+ rule.onNodeWithTag(TopAppBarTestTag).assertHeightIsEqualTo(appBarMinHeight)
+ }
+
+ /**
+ * An [IconButton] with an [Icon] inside for testing positions.
+ *
+ * An [IconButton] is defaulted to be 48X48dp, while its child [Icon] is defaulted to 24x24dp.
+ */
+ private val FakeIcon = @Composable { modifier: Modifier ->
+ IconButton(
+ onClick = { /* doSomething() */ },
+ modifier = modifier.semantics(mergeDescendants = true) {}
+ ) {
+ Icon(ColorPainter(Color.Red), null)
+ }
+ }
+
+ private fun expectedActionPosition(appBarWidth: Dp): Dp =
+ appBarWidth - AppBarStartAndEndPadding - FakeIconSize
+
+ private val FakeIconSize = 48.dp
+ private val AppBarStartAndEndPadding = 4.dp
+ private val AppBarTopAndBottomPadding = (ContainerHeight - FakeIconSize) / 2
+
+ private val LazyListTag = "lazyList"
+ private val TopAppBarTestTag = "bar"
+ private val NavigationIconTestTag = "navigationIcon"
+ private val TitleTestTag = "title"
+ private val ActionsTestTag = "actions"
+}
diff --git a/packages/SettingsLib/Spa/testutils/src/com/android/settingslib/spa/testutils/ComposeContentTestRuleExt.kt b/packages/SettingsLib/Spa/testutils/src/com/android/settingslib/spa/testutils/ComposeContentTestRuleExt.kt
index a5d1f40..0436fc2 100644
--- a/packages/SettingsLib/Spa/testutils/src/com/android/settingslib/spa/testutils/ComposeContentTestRuleExt.kt
+++ b/packages/SettingsLib/Spa/testutils/src/com/android/settingslib/spa/testutils/ComposeContentTestRuleExt.kt
@@ -16,13 +16,28 @@
package com.android.settingslib.spa.testutils
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.sizeIn
+import androidx.compose.material3.Surface
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.testTag
import androidx.compose.ui.test.ComposeTimeoutException
import androidx.compose.ui.test.SemanticsMatcher
import androidx.compose.ui.test.SemanticsNodeInteraction
+import androidx.compose.ui.test.getUnclippedBoundsInRoot
import androidx.compose.ui.test.hasAnyAncestor
import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.isDialog
import androidx.compose.ui.test.junit4.ComposeContentTestRule
+import androidx.compose.ui.test.junit4.ComposeTestRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.onRoot
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.height
+import androidx.compose.ui.unit.width
+import com.android.settingslib.spa.framework.theme.SettingsTheme
/** Blocks until the found a semantics node that match the given condition. */
fun ComposeContentTestRule.waitUntilExists(matcher: SemanticsMatcher) = waitUntil {
@@ -39,3 +54,39 @@
/** Finds a text node that within dialog. */
fun ComposeContentTestRule.onDialogText(text: String): SemanticsNodeInteraction =
onNode(hasAnyAncestor(isDialog()) and hasText(text))
+
+fun ComposeTestRule.rootWidth(): Dp = onRoot().getUnclippedBoundsInRoot().width
+
+fun ComposeTestRule.rootHeight(): Dp = onRoot().getUnclippedBoundsInRoot().height
+
+/**
+ * Constant to emulate very big but finite constraints
+ */
+private val sizeAssertionMaxSize = 5000.dp
+
+private const val SIZE_ASSERTION_TAG = "containerForSizeAssertion"
+
+fun ComposeContentTestRule.setContentForSizeAssertions(
+ parentMaxWidth: Dp = sizeAssertionMaxSize,
+ parentMaxHeight: Dp = sizeAssertionMaxSize,
+ // TODO : figure out better way to make it flexible
+ content: @Composable () -> Unit
+): SemanticsNodeInteraction {
+ setContent {
+ SettingsTheme {
+ Surface {
+ Box {
+ Box(
+ Modifier
+ .sizeIn(maxWidth = parentMaxWidth, maxHeight = parentMaxHeight)
+ .testTag(SIZE_ASSERTION_TAG)
+ ) {
+ content()
+ }
+ }
+ }
+ }
+ }
+
+ return onNodeWithTag(SIZE_ASSERTION_TAG)
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/InterestingConfigChanges.java b/packages/SettingsLib/src/com/android/settingslib/applications/InterestingConfigChanges.java
index 64a0781..5d520ce 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/InterestingConfigChanges.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/InterestingConfigChanges.java
@@ -28,11 +28,11 @@
public class InterestingConfigChanges {
private final Configuration mLastConfiguration = new Configuration();
private final int mFlags;
- private int mLastDensity;
public InterestingConfigChanges() {
this(ActivityInfo.CONFIG_LOCALE | ActivityInfo.CONFIG_LAYOUT_DIRECTION
- | ActivityInfo.CONFIG_UI_MODE | ActivityInfo.CONFIG_ASSETS_PATHS);
+ | ActivityInfo.CONFIG_UI_MODE | ActivityInfo.CONFIG_ASSETS_PATHS
+ | ActivityInfo.CONFIG_DENSITY);
}
public InterestingConfigChanges(int flags) {
@@ -50,11 +50,6 @@
public boolean applyNewConfig(Resources res) {
int configChanges = mLastConfiguration.updateFrom(
Configuration.generateDelta(mLastConfiguration, res.getConfiguration()));
- boolean densityChanged = mLastDensity != res.getDisplayMetrics().densityDpi;
- if (densityChanged || (configChanges & (mFlags)) != 0) {
- mLastDensity = res.getDisplayMetrics().densityDpi;
- return true;
- }
- return false;
+ return (configChanges & (mFlags)) != 0;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/authentication/AuthenticationModule.kt b/packages/SystemUI/src/com/android/systemui/authentication/AuthenticationModule.kt
index 7c394a6..6128d91 100644
--- a/packages/SystemUI/src/com/android/systemui/authentication/AuthenticationModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/authentication/AuthenticationModule.kt
@@ -16,8 +16,11 @@
package com.android.systemui.authentication
+import com.android.keyguard.KeyguardSecurityModel
import com.android.systemui.authentication.data.repository.AuthenticationRepositoryModule
import dagger.Module
+import dagger.Provides
+import java.util.function.Function
@Module(
includes =
@@ -25,4 +28,12 @@
AuthenticationRepositoryModule::class,
],
)
-object AuthenticationModule
+object AuthenticationModule {
+
+ @Provides
+ fun getSecurityMode(
+ model: KeyguardSecurityModel,
+ ): Function<Int, KeyguardSecurityModel.SecurityMode> {
+ return Function { userId -> model.getSecurityMode(userId) }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt b/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt
index 0530aed..35830da 100644
--- a/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt
@@ -16,13 +16,20 @@
package com.android.systemui.authentication.data.repository
+import com.android.internal.widget.LockPatternUtils
+import com.android.keyguard.KeyguardSecurityModel
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.user.data.repository.UserRepository
import dagger.Binds
import dagger.Module
-import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.withContext
+import java.util.function.Function
+import javax.inject.Inject
/** Defines interface for classes that can access authentication-related application state. */
interface AuthenticationRepository {
@@ -38,12 +45,6 @@
val isUnlocked: StateFlow<Boolean>
/**
- * The currently-configured authentication method. This determines how the authentication
- * challenge is completed in order to unlock an otherwise locked device.
- */
- val authenticationMethod: StateFlow<AuthenticationMethodModel>
-
- /**
* Whether lock screen bypass is enabled. When enabled, the lock screen will be automatically
* dismisses once the authentication challenge is completed. For example, completing a biometric
* authentication challenge via face unlock or fingerprint sensor can automatically bypass the
@@ -57,12 +58,15 @@
*/
val failedAuthenticationAttempts: StateFlow<Int>
+ /**
+ * Returns the currently-configured authentication method. This determines how the
+ * authentication challenge is completed in order to unlock an otherwise locked device.
+ */
+ suspend fun getAuthenticationMethod(): AuthenticationMethodModel
+
/** See [isUnlocked]. */
fun setUnlocked(isUnlocked: Boolean)
- /** See [authenticationMethod]. */
- fun setAuthenticationMethod(authenticationMethod: AuthenticationMethodModel)
-
/** See [isBypassEnabled]. */
fun setBypassEnabled(isBypassEnabled: Boolean)
@@ -70,19 +74,18 @@
fun setFailedAuthenticationAttempts(failedAuthenticationAttempts: Int)
}
-class AuthenticationRepositoryImpl @Inject constructor() : AuthenticationRepository {
- // TODO(b/280883900): get data from real data sources in SysUI.
+class AuthenticationRepositoryImpl
+@Inject
+constructor(
+ private val getSecurityMode: Function<Int, KeyguardSecurityModel.SecurityMode>,
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
+ private val userRepository: UserRepository,
+ private val lockPatternUtils: LockPatternUtils,
+) : AuthenticationRepository {
private val _isUnlocked = MutableStateFlow(false)
override val isUnlocked: StateFlow<Boolean> = _isUnlocked.asStateFlow()
- private val _authenticationMethod =
- MutableStateFlow<AuthenticationMethodModel>(
- AuthenticationMethodModel.Pin(listOf(1, 2, 3, 4), autoConfirm = false)
- )
- override val authenticationMethod: StateFlow<AuthenticationMethodModel> =
- _authenticationMethod.asStateFlow()
-
private val _isBypassEnabled = MutableStateFlow(false)
override val isBypassEnabled: StateFlow<Boolean> = _isBypassEnabled.asStateFlow()
@@ -90,6 +93,41 @@
override val failedAuthenticationAttempts: StateFlow<Int> =
_failedAuthenticationAttempts.asStateFlow()
+ override suspend fun getAuthenticationMethod(): AuthenticationMethodModel {
+ return withContext(backgroundDispatcher) {
+ val selectedUserId = userRepository.getSelectedUserInfo().id
+ when (getSecurityMode.apply(selectedUserId)) {
+ KeyguardSecurityModel.SecurityMode.PIN,
+ KeyguardSecurityModel.SecurityMode.SimPin ->
+ AuthenticationMethodModel.Pin(
+ code = listOf(1, 2, 3, 4), // TODO(b/280883900): remove this
+ autoConfirm = lockPatternUtils.isAutoPinConfirmEnabled(selectedUserId),
+ )
+ KeyguardSecurityModel.SecurityMode.Password,
+ KeyguardSecurityModel.SecurityMode.SimPuk ->
+ AuthenticationMethodModel.Password(
+ password = "password", // TODO(b/280883900): remove this
+ )
+ KeyguardSecurityModel.SecurityMode.Pattern ->
+ AuthenticationMethodModel.Pattern(
+ coordinates =
+ listOf(
+ AuthenticationMethodModel.Pattern.PatternCoordinate(2, 0),
+ AuthenticationMethodModel.Pattern.PatternCoordinate(2, 1),
+ AuthenticationMethodModel.Pattern.PatternCoordinate(2, 2),
+ AuthenticationMethodModel.Pattern.PatternCoordinate(1, 1),
+ AuthenticationMethodModel.Pattern.PatternCoordinate(0, 0),
+ AuthenticationMethodModel.Pattern.PatternCoordinate(0, 1),
+ AuthenticationMethodModel.Pattern.PatternCoordinate(0, 2),
+ ), // TODO(b/280883900): remove this
+ )
+ KeyguardSecurityModel.SecurityMode.None -> AuthenticationMethodModel.None
+ KeyguardSecurityModel.SecurityMode.Invalid -> error("Invalid security mode!")
+ null -> error("Invalid security is null!")
+ }
+ }
+ }
+
override fun setUnlocked(isUnlocked: Boolean) {
_isUnlocked.value = isUnlocked
}
@@ -98,10 +136,6 @@
_isBypassEnabled.value = isBypassEnabled
}
- override fun setAuthenticationMethod(authenticationMethod: AuthenticationMethodModel) {
- _authenticationMethod.value = authenticationMethod
- }
-
override fun setFailedAuthenticationAttempts(failedAuthenticationAttempts: Int) {
_failedAuthenticationAttempts.value = failedAuthenticationAttempts
}
diff --git a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
index 20e82f7..9ae27556 100644
--- a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
@@ -25,9 +25,8 @@
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
-import kotlinx.coroutines.launch
/** Hosts application business logic related to authentication. */
@SysUISingleton
@@ -38,12 +37,6 @@
private val repository: AuthenticationRepository,
) {
/**
- * The currently-configured authentication method. This determines how the authentication
- * challenge is completed in order to unlock an otherwise locked device.
- */
- val authenticationMethod: StateFlow<AuthenticationMethodModel> = repository.authenticationMethod
-
- /**
* Whether the device is unlocked.
*
* A device that is not yet unlocked requires unlocking by completing an authentication
@@ -52,20 +45,18 @@
* Note that this state has no real bearing on whether the lock screen is showing or dismissed.
*/
val isUnlocked: StateFlow<Boolean> =
- combine(authenticationMethod, repository.isUnlocked) { authMethod, isUnlocked ->
- isUnlockedWithAuthMethod(
- isUnlocked = isUnlocked,
- authMethod = authMethod,
- )
+ repository.isUnlocked
+ .map { isUnlocked ->
+ if (getAuthenticationMethod() is AuthenticationMethodModel.None) {
+ true
+ } else {
+ isUnlocked
+ }
}
.stateIn(
scope = applicationScope,
started = SharingStarted.Eagerly,
- initialValue =
- isUnlockedWithAuthMethod(
- isUnlocked = repository.isUnlocked.value,
- authMethod = repository.authenticationMethod.value,
- )
+ initialValue = true,
)
/**
@@ -82,25 +73,20 @@
*/
val failedAuthenticationAttempts: StateFlow<Int> = repository.failedAuthenticationAttempts
- init {
- // UNLOCKS WHEN AUTH METHOD REMOVED.
- //
- // Unlocks the device if the auth method becomes None.
- applicationScope.launch {
- repository.authenticationMethod.collect {
- if (it is AuthenticationMethodModel.None) {
- unlockDevice()
- }
- }
- }
+ /**
+ * Returns the currently-configured authentication method. This determines how the
+ * authentication challenge is completed in order to unlock an otherwise locked device.
+ */
+ suspend fun getAuthenticationMethod(): AuthenticationMethodModel {
+ return repository.getAuthenticationMethod()
}
/**
* Returns `true` if the device currently requires authentication before content can be viewed;
* `false` if content can be displayed without unlocking first.
*/
- fun isAuthenticationRequired(): Boolean {
- return !isUnlocked.value && authenticationMethod.value.isSecure
+ suspend fun isAuthenticationRequired(): Boolean {
+ return !isUnlocked.value && getAuthenticationMethod().isSecure
}
/**
@@ -133,8 +119,8 @@
* @return `true` if the authentication succeeded and the device is now unlocked; `false` when
* authentication failed, `null` if the check was not performed.
*/
- fun authenticate(input: List<Any>, tryAutoConfirm: Boolean = false): Boolean? {
- val authMethod = this.authenticationMethod.value
+ suspend fun authenticate(input: List<Any>, tryAutoConfirm: Boolean = false): Boolean? {
+ val authMethod = getAuthenticationMethod()
if (tryAutoConfirm) {
if ((authMethod as? AuthenticationMethodModel.Pin)?.autoConfirm != true) {
// Do not attempt to authenticate unless the PIN lock is set to auto-confirm.
@@ -176,28 +162,12 @@
repository.setUnlocked(true)
}
- /** See [authenticationMethod]. */
- fun setAuthenticationMethod(authenticationMethod: AuthenticationMethodModel) {
- repository.setAuthenticationMethod(authenticationMethod)
- }
-
/** See [isBypassEnabled]. */
fun toggleBypassEnabled() {
repository.setBypassEnabled(!repository.isBypassEnabled.value)
}
companion object {
- private fun isUnlockedWithAuthMethod(
- isUnlocked: Boolean,
- authMethod: AuthenticationMethodModel,
- ): Boolean {
- return if (authMethod is AuthenticationMethodModel.None) {
- true
- } else {
- isUnlocked
- }
- }
-
/**
* Returns a PIN code from the given list. It's assumed the given list elements are all
* [Int] in the range [0-9].
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
index 256c635..cb84162 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
@@ -68,44 +68,40 @@
)
)
- /**
- * The currently-configured authentication method. This determines how the authentication
- * challenge is completed in order to unlock an otherwise locked device.
- */
- val authenticationMethod: StateFlow<AuthenticationMethodModel> =
- authenticationInteractor.authenticationMethod
-
/** The current authentication throttling state. If `null`, there's no throttling. */
val throttling: StateFlow<AuthenticationThrottledModel?> = repository.throttling
init {
applicationScope.launch {
- combine(
- sceneInteractor.currentScene(containerName),
- authenticationInteractor.authenticationMethod,
- ::Pair,
- )
- .collect { (currentScene, authMethod) ->
- if (currentScene.key == SceneKey.Bouncer) {
- when (authMethod) {
- is AuthenticationMethodModel.None ->
- sceneInteractor.setCurrentScene(
- containerName,
- SceneModel(SceneKey.Gone),
- )
- is AuthenticationMethodModel.Swipe ->
- sceneInteractor.setCurrentScene(
- containerName,
- SceneModel(SceneKey.Lockscreen),
- )
- else -> Unit
- }
+ sceneInteractor.currentScene(containerName).collect { currentScene ->
+ if (currentScene.key == SceneKey.Bouncer) {
+ when (getAuthenticationMethod()) {
+ is AuthenticationMethodModel.None ->
+ sceneInteractor.setCurrentScene(
+ containerName,
+ SceneModel(SceneKey.Gone),
+ )
+ is AuthenticationMethodModel.Swipe ->
+ sceneInteractor.setCurrentScene(
+ containerName,
+ SceneModel(SceneKey.Lockscreen),
+ )
+ else -> Unit
}
}
+ }
}
}
/**
+ * Returns the currently-configured authentication method. This determines how the
+ * authentication challenge is completed in order to unlock an otherwise locked device.
+ */
+ suspend fun getAuthenticationMethod(): AuthenticationMethodModel {
+ return authenticationInteractor.getAuthenticationMethod()
+ }
+
+ /**
* Either shows the bouncer or unlocks the device, if the bouncer doesn't need to be shown.
*
* @param containerName The name of the scene container to show the bouncer in.
@@ -115,18 +111,20 @@
containerName: String,
message: String? = null,
) {
- if (authenticationInteractor.isAuthenticationRequired()) {
- repository.setMessage(message ?: promptMessage(authenticationMethod.value))
- sceneInteractor.setCurrentScene(
- containerName = containerName,
- scene = SceneModel(SceneKey.Bouncer),
- )
- } else {
- authenticationInteractor.unlockDevice()
- sceneInteractor.setCurrentScene(
- containerName = containerName,
- scene = SceneModel(SceneKey.Gone),
- )
+ applicationScope.launch {
+ if (authenticationInteractor.isAuthenticationRequired()) {
+ repository.setMessage(message ?: promptMessage(getAuthenticationMethod()))
+ sceneInteractor.setCurrentScene(
+ containerName = containerName,
+ scene = SceneModel(SceneKey.Bouncer),
+ )
+ } else {
+ authenticationInteractor.unlockDevice()
+ sceneInteractor.setCurrentScene(
+ containerName = containerName,
+ scene = SceneModel(SceneKey.Gone),
+ )
+ }
}
}
@@ -135,7 +133,7 @@
* method.
*/
fun resetMessage() {
- repository.setMessage(promptMessage(authenticationMethod.value))
+ applicationScope.launch { repository.setMessage(promptMessage(getAuthenticationMethod())) }
}
/** Removes the user-facing message. */
@@ -160,7 +158,7 @@
* @return `true` if the authentication succeeded and the device is now unlocked; `false` when
* authentication failed, `null` if the check was not performed.
*/
- fun authenticate(
+ suspend fun authenticate(
input: List<Any>,
tryAutoConfirm: Boolean = false,
): Boolean? {
@@ -198,7 +196,7 @@
repository.setThrottling(null)
clearMessage()
}
- else -> repository.setMessage(errorMessage(authenticationMethod.value))
+ else -> repository.setMessage(errorMessage(getAuthenticationMethod()))
}
return isAuthenticated
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt
index 527fe6e..7448f27 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt
@@ -32,6 +32,7 @@
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
@@ -66,6 +67,7 @@
private val password: PasswordBouncerViewModel by lazy {
PasswordBouncerViewModel(
+ applicationScope = applicationScope,
interactor = interactor,
isInputEnabled = isInputEnabled,
)
@@ -81,14 +83,25 @@
}
/** View-model for the current UI, based on the current authentication method. */
- val authMethod: StateFlow<AuthMethodBouncerViewModel?> =
- interactor.authenticationMethod
- .map { authMethod -> toViewModel(authMethod) }
- .stateIn(
- scope = applicationScope,
- started = SharingStarted.WhileSubscribed(),
- initialValue = toViewModel(interactor.authenticationMethod.value),
- )
+ val authMethod: StateFlow<AuthMethodBouncerViewModel?>
+ get() =
+ flow {
+ emit(null)
+ emit(interactor.getAuthenticationMethod())
+ }
+ .map { authMethod ->
+ when (authMethod) {
+ is AuthenticationMethodModel.Pin -> pin
+ is AuthenticationMethodModel.Password -> password
+ is AuthenticationMethodModel.Pattern -> pattern
+ else -> null
+ }
+ }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = null,
+ )
/** The user-facing message to show in the bouncer. */
val message: StateFlow<MessageViewModel> =
@@ -125,7 +138,7 @@
interactor.throttling
.map { model ->
model?.let {
- when (interactor.authenticationMethod.value) {
+ when (interactor.getAuthenticationMethod()) {
is AuthenticationMethodModel.Pin ->
R.string.kg_too_many_failed_pin_attempts_dialog_message
is AuthenticationMethodModel.Password ->
@@ -161,17 +174,6 @@
_throttlingDialogMessage.value = null
}
- private fun toViewModel(
- authMethod: AuthenticationMethodModel,
- ): AuthMethodBouncerViewModel? {
- return when (authMethod) {
- is AuthenticationMethodModel.Pin -> pin
- is AuthenticationMethodModel.Password -> password
- is AuthenticationMethodModel.Pattern -> pattern
- else -> null
- }
- }
-
private fun toMessageViewModel(
message: String?,
throttling: AuthenticationThrottledModel?,
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt
index 0146e40..ca15f4e 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt
@@ -17,12 +17,15 @@
package com.android.systemui.bouncer.ui.viewmodel
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.launch
/** Holds UI state and handles user input for the password bouncer UI. */
class PasswordBouncerViewModel(
+ private val applicationScope: CoroutineScope,
private val interactor: BouncerInteractor,
isInputEnabled: StateFlow<Boolean>,
) :
@@ -50,10 +53,13 @@
/** Notifies that the user has pressed the key for attempting to authenticate the password. */
fun onAuthenticateKeyPressed() {
- if (interactor.authenticate(password.value.toCharArray().toList()) != true) {
- showFailureAnimation()
- }
-
+ val password = _password.value.toCharArray().toList()
_password.value = ""
+
+ applicationScope.launch {
+ if (interactor.authenticate(password) != true) {
+ showFailureAnimation()
+ }
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt
index 700703e..5efa6f0 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt
@@ -29,13 +29,15 @@
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
/** Holds UI state and handles user input for the pattern bouncer UI. */
class PatternBouncerViewModel(
private val applicationContext: Context,
- applicationScope: CoroutineScope,
+ private val applicationScope: CoroutineScope,
private val interactor: BouncerInteractor,
isInputEnabled: StateFlow<Boolean>,
) :
@@ -69,12 +71,17 @@
/** Whether the pattern itself should be rendered visibly. */
val isPatternVisible: StateFlow<Boolean> =
- interactor.authenticationMethod
- .map { authMethod -> isPatternVisible(authMethod) }
+ flow {
+ emit(null)
+ emit(interactor.getAuthenticationMethod())
+ }
+ .map { authMethod ->
+ (authMethod as? AuthenticationMethodModel.Pattern)?.isPatternVisible ?: false
+ }
.stateIn(
scope = applicationScope,
started = SharingStarted.Eagerly,
- initialValue = isPatternVisible(interactor.authenticationMethod.value),
+ initialValue = false,
)
/** Notifies that the UI has been shown to the user. */
@@ -154,17 +161,15 @@
/** Notifies that the user has ended the drag gesture across the dot grid. */
fun onDragEnd() {
val pattern = _selectedDots.value.map { it.toCoordinate() }
- if (interactor.authenticate(pattern) != true) {
- showFailureAnimation()
- }
-
_dots.value = defaultDots()
_currentDot.value = null
_selectedDots.value = linkedSetOf()
- }
- private fun isPatternVisible(authMethodModel: AuthenticationMethodModel): Boolean {
- return (authMethodModel as? AuthenticationMethodModel.Pattern)?.isPatternVisible ?: false
+ applicationScope.launch {
+ if (interactor.authenticate(pattern) != true) {
+ showFailureAnimation()
+ }
+ }
}
private fun defaultDots(): List<PatternDotViewModel> {
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
index 1944c74..7c96e82 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
@@ -22,13 +22,14 @@
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
/** Holds UI state and handles user input for the PIN code bouncer UI. */
class PinBouncerViewModel(
- applicationScope: CoroutineScope,
+ private val applicationScope: CoroutineScope,
private val interactor: BouncerInteractor,
isInputEnabled: StateFlow<Boolean>,
) :
@@ -39,40 +40,48 @@
private val mutablePinEntries = MutableStateFlow<List<EnteredKey>>(emptyList())
val pinEntries: StateFlow<List<EnteredKey>> = mutablePinEntries
- /** The length of the hinted PIN, or null if pin length hint should not be shown. */
+ /** The length of the hinted PIN, or `null` if pin length hint should not be shown. */
val hintedPinLength: StateFlow<Int?> =
- interactor.authenticationMethod
- .map { authMethod -> computeHintedPinLength(authMethod) }
- .stateIn(
- scope = applicationScope,
- started = SharingStarted.Eagerly,
- initialValue = computeHintedPinLength(interactor.authenticationMethod.value),
- )
-
- /** Appearance of the backspace button. */
- val backspaceButtonAppearance: StateFlow<ActionButtonAppearance> =
- combine(interactor.authenticationMethod, mutablePinEntries) { authMethod, enteredPin ->
- computeBackspaceButtonAppearance(authMethod, enteredPin)
+ flow {
+ emit(null)
+ emit(interactor.getAuthenticationMethod())
+ }
+ .map { authMethod ->
+ // Hinting is enabled for 6-digit codes only
+ autoConfirmPinLength(authMethod).takeIf { it == HINTING_PASSCODE_LENGTH }
}
.stateIn(
scope = applicationScope,
started = SharingStarted.Eagerly,
- initialValue =
- computeBackspaceButtonAppearance(
- interactor.authenticationMethod.value,
- mutablePinEntries.value
- ),
+ initialValue = null,
+ )
+
+ /** Appearance of the backspace button. */
+ val backspaceButtonAppearance: StateFlow<ActionButtonAppearance> =
+ mutablePinEntries
+ .map { mutablePinEntries ->
+ computeBackspaceButtonAppearance(
+ interactor.getAuthenticationMethod(),
+ mutablePinEntries
+ )
+ }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.Eagerly,
+ initialValue = ActionButtonAppearance.Hidden,
)
/** Appearance of the confirm button. */
val confirmButtonAppearance: StateFlow<ActionButtonAppearance> =
- interactor.authenticationMethod
+ flow {
+ emit(null)
+ emit(interactor.getAuthenticationMethod())
+ }
.map { authMethod -> computeConfirmButtonAppearance(authMethod) }
.stateIn(
scope = applicationScope,
started = SharingStarted.Eagerly,
- initialValue =
- computeConfirmButtonAppearance(interactor.authenticationMethod.value),
+ initialValue = ActionButtonAppearance.Hidden,
)
/** Notifies that the UI has been shown to the user. */
@@ -111,30 +120,28 @@
private fun tryAuthenticate(useAutoConfirm: Boolean) {
val pinCode = mutablePinEntries.value.map { it.input }
- val isSuccess = interactor.authenticate(pinCode, useAutoConfirm) ?: return
- if (!isSuccess) {
- showFailureAnimation()
+ applicationScope.launch {
+ val isSuccess = interactor.authenticate(pinCode, useAutoConfirm) ?: return@launch
+
+ if (!isSuccess) {
+ showFailureAnimation()
+ }
+
+ mutablePinEntries.value = emptyList()
}
-
- mutablePinEntries.value = emptyList()
}
- private fun isAutoConfirmEnabled(authMethodModel: AuthenticationMethodModel): Boolean {
+ private fun isAutoConfirmEnabled(authMethodModel: AuthenticationMethodModel?): Boolean {
return (authMethodModel as? AuthenticationMethodModel.Pin)?.autoConfirm == true
}
- private fun autoConfirmPinLength(authMethodModel: AuthenticationMethodModel): Int? {
+ private fun autoConfirmPinLength(authMethodModel: AuthenticationMethodModel?): Int? {
if (!isAutoConfirmEnabled(authMethodModel)) return null
return (authMethodModel as? AuthenticationMethodModel.Pin)?.code?.size
}
- private fun computeHintedPinLength(authMethodModel: AuthenticationMethodModel): Int? {
- // Hinting is enabled for 6-digit codes only
- return autoConfirmPinLength(authMethodModel).takeIf { it == HINTING_PASSCODE_LENGTH }
- }
-
private fun computeBackspaceButtonAppearance(
authMethodModel: AuthenticationMethodModel,
enteredPin: List<EnteredKey>
@@ -149,7 +156,7 @@
}
}
private fun computeConfirmButtonAppearance(
- authMethodModel: AuthenticationMethodModel
+ authMethodModel: AuthenticationMethodModel?
): ActionButtonAppearance {
return if (isAutoConfirmEnabled(authMethodModel)) {
ActionButtonAppearance.Hidden
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
new file mode 100644
index 0000000..b18f7bf
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.display.data.repository
+
+import android.hardware.display.DisplayManager
+import android.hardware.display.DisplayManager.DisplayListener
+import android.hardware.display.DisplayManager.EVENT_FLAG_DISPLAY_ADDED
+import android.hardware.display.DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
+import android.hardware.display.DisplayManager.EVENT_FLAG_DISPLAY_REMOVED
+import android.os.Handler
+import android.view.Display
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.util.traceSection
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.stateIn
+
+/** Provides a [Flow] of [Display] as returned by [DisplayManager]. */
+interface DisplayRepository {
+ /** Provides a nullable set of displays. */
+ val displays: Flow<Set<Display>>
+}
+
+@SysUISingleton
+class DisplayRepositoryImpl
+@Inject
+constructor(
+ private val displayManager: DisplayManager,
+ @Background backgroundHandler: Handler,
+ @Application applicationScope: CoroutineScope,
+ @Background backgroundCoroutineDispatcher: CoroutineDispatcher
+) : DisplayRepository {
+
+ override val displays: Flow<Set<Display>> =
+ conflatedCallbackFlow {
+ val callback =
+ object : DisplayListener {
+ override fun onDisplayAdded(displayId: Int) {
+ trySend(getDisplays())
+ }
+
+ override fun onDisplayRemoved(displayId: Int) {
+ trySend(getDisplays())
+ }
+
+ override fun onDisplayChanged(displayId: Int) {
+ trySend(getDisplays())
+ }
+ }
+ displayManager.registerDisplayListener(
+ callback,
+ backgroundHandler,
+ EVENT_FLAG_DISPLAY_ADDED or
+ EVENT_FLAG_DISPLAY_CHANGED or
+ EVENT_FLAG_DISPLAY_REMOVED,
+ )
+ awaitClose { displayManager.unregisterDisplayListener(callback) }
+ }
+ .flowOn(backgroundCoroutineDispatcher)
+ .stateIn(
+ applicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = getDisplays()
+ )
+
+ fun getDisplays(): Set<Display> =
+ traceSection("DisplayRepository#getDisplays()") {
+ displayManager.displays?.toSet() ?: emptySet()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index b50c6de..6242492 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -314,7 +314,7 @@
)
@JvmField
- val QS_PIPELINE_NEW_HOST = unreleasedFlag(504, "qs_pipeline_new_host", teamfood = true)
+ val QS_PIPELINE_NEW_HOST = releasedFlag(504, "qs_pipeline_new_host")
// TODO(b/278068252): Tracking Bug
@JvmField
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
index 38eacce..8f0b91b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
@@ -22,7 +22,6 @@
import com.android.systemui.dagger.qualifiers.Application
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.WakefulnessState
import com.android.systemui.util.kotlin.Utils.Companion.toQuad
import com.android.systemui.util.kotlin.Utils.Companion.toQuint
@@ -38,11 +37,14 @@
class FromAlternateBouncerTransitionInteractor
@Inject
constructor(
+ override val transitionRepository: KeyguardTransitionRepository,
+ override val transitionInteractor: KeyguardTransitionInteractor,
@Application private val scope: CoroutineScope,
private val keyguardInteractor: KeyguardInteractor,
- private val keyguardTransitionRepository: KeyguardTransitionRepository,
- private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
-) : TransitionInteractor(FromAlternateBouncerTransitionInteractor::class.simpleName!!) {
+) :
+ TransitionInteractor(
+ fromState = KeyguardState.ALTERNATE_BOUNCER,
+ ) {
override fun start() {
listenForAlternateBouncerToGone()
@@ -60,7 +62,7 @@
.sample(
combine(
keyguardInteractor.primaryBouncerShowing,
- keyguardTransitionInteractor.startedKeyguardTransitionStep,
+ transitionInteractor.startedKeyguardTransitionStep,
keyguardInteractor.wakefulnessModel,
keyguardInteractor.isAodAvailable,
::toQuad
@@ -92,14 +94,7 @@
} else {
KeyguardState.LOCKSCREEN
}
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- ownerName = name,
- from = KeyguardState.ALTERNATE_BOUNCER,
- to = to,
- animator = getAnimator(),
- )
- )
+ startTransitionTo(to)
}
}
}
@@ -108,17 +103,10 @@
private fun listenForAlternateBouncerToGone() {
scope.launch {
keyguardInteractor.isKeyguardGoingAway
- .sample(keyguardTransitionInteractor.finishedKeyguardState, ::Pair)
+ .sample(transitionInteractor.finishedKeyguardState, ::Pair)
.collect { (isKeyguardGoingAway, keyguardState) ->
if (isKeyguardGoingAway && keyguardState == KeyguardState.ALTERNATE_BOUNCER) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- ownerName = name,
- from = KeyguardState.ALTERNATE_BOUNCER,
- to = KeyguardState.GONE,
- animator = getAnimator(),
- )
- )
+ startTransitionTo(KeyguardState.GONE)
}
}
}
@@ -127,26 +115,19 @@
private fun listenForAlternateBouncerToPrimaryBouncer() {
scope.launch {
keyguardInteractor.primaryBouncerShowing
- .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
.collect { (isPrimaryBouncerShowing, startedKeyguardState) ->
if (
isPrimaryBouncerShowing &&
startedKeyguardState.to == KeyguardState.ALTERNATE_BOUNCER
) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- ownerName = name,
- from = KeyguardState.ALTERNATE_BOUNCER,
- to = KeyguardState.PRIMARY_BOUNCER,
- animator = getAnimator(),
- )
- )
+ startTransitionTo(KeyguardState.PRIMARY_BOUNCER)
}
}
}
}
- private fun getAnimator(): ValueAnimator {
+ override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator {
return ValueAnimator().apply {
interpolator = Interpolators.LINEAR
duration = TRANSITION_DURATION_MS
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 7e9cbc1..2085c87 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
@@ -24,7 +24,6 @@
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.TransitionInfo
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -34,11 +33,14 @@
class FromAodTransitionInteractor
@Inject
constructor(
+ override val transitionRepository: KeyguardTransitionRepository,
+ override val transitionInteractor: KeyguardTransitionInteractor,
@Application private val scope: CoroutineScope,
private val keyguardInteractor: KeyguardInteractor,
- private val keyguardTransitionRepository: KeyguardTransitionRepository,
- private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
-) : TransitionInteractor(FromAodTransitionInteractor::class.simpleName!!) {
+) :
+ TransitionInteractor(
+ fromState = KeyguardState.AOD,
+ ) {
override fun start() {
listenForAodToLockscreen()
@@ -49,18 +51,11 @@
scope.launch {
keyguardInteractor
.dozeTransitionTo(DozeStateModel.FINISH)
- .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
.collect { pair ->
val (dozeToAod, lastStartedStep) = pair
if (lastStartedStep.to == KeyguardState.AOD) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.AOD,
- KeyguardState.LOCKSCREEN,
- getAnimator(),
- )
- )
+ startTransitionTo(KeyguardState.LOCKSCREEN)
}
}
}
@@ -69,29 +64,22 @@
private fun listenForAodToGone() {
scope.launch {
keyguardInteractor.biometricUnlockState
- .sample(keyguardTransitionInteractor.finishedKeyguardState, ::Pair)
+ .sample(transitionInteractor.finishedKeyguardState, ::Pair)
.collect { pair ->
val (biometricUnlockState, keyguardState) = pair
if (
keyguardState == KeyguardState.AOD && isWakeAndUnlock(biometricUnlockState)
) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.AOD,
- KeyguardState.GONE,
- getAnimator(),
- )
- )
+ startTransitionTo(KeyguardState.GONE)
}
}
}
}
- private fun getAnimator(): ValueAnimator {
+ override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator {
return ValueAnimator().apply {
- setInterpolator(Interpolators.LINEAR)
- setDuration(TRANSITION_DURATION_MS)
+ interpolator = Interpolators.LINEAR
+ duration = TRANSITION_DURATION_MS
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
index ee2c2df..c867c43 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
@@ -23,10 +23,8 @@
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.KeyguardState
-import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
-import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
@@ -35,11 +33,14 @@
class FromDozingTransitionInteractor
@Inject
constructor(
+ override val transitionRepository: KeyguardTransitionRepository,
+ override val transitionInteractor: KeyguardTransitionInteractor,
@Application private val scope: CoroutineScope,
private val keyguardInteractor: KeyguardInteractor,
- private val keyguardTransitionRepository: KeyguardTransitionRepository,
- private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
-) : TransitionInteractor(FromDozingTransitionInteractor::class.simpleName!!) {
+) :
+ TransitionInteractor(
+ fromState = KeyguardState.DOZING,
+ ) {
override fun start() {
listenForDozingToLockscreen()
@@ -49,20 +50,13 @@
private fun listenForDozingToLockscreen() {
scope.launch {
keyguardInteractor.wakefulnessModel
- .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
.collect { (wakefulnessModel, lastStartedTransition) ->
if (
wakefulnessModel.isStartingToWakeOrAwake() &&
lastStartedTransition.to == KeyguardState.DOZING
) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.DOZING,
- KeyguardState.LOCKSCREEN,
- getAnimator(),
- )
- )
+ startTransitionTo(KeyguardState.LOCKSCREEN)
}
}
}
@@ -71,29 +65,22 @@
private fun listenForDozingToGone() {
scope.launch {
keyguardInteractor.biometricUnlockState
- .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
.collect { (biometricUnlockState, lastStartedTransition) ->
if (
lastStartedTransition.to == KeyguardState.DOZING &&
isWakeAndUnlock(biometricUnlockState)
) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.DOZING,
- KeyguardState.GONE,
- getAnimator(),
- )
- )
+ startTransitionTo(KeyguardState.GONE)
}
}
}
}
- private fun getAnimator(duration: Duration = DEFAULT_DURATION): ValueAnimator {
+ override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator {
return ValueAnimator().apply {
- setInterpolator(Interpolators.LINEAR)
- setDuration(duration.inWholeMilliseconds)
+ interpolator = Interpolators.LINEAR
+ duration = DEFAULT_DURATION.inWholeMilliseconds
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
index ccf4bc1..98d7434 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
@@ -24,11 +24,9 @@
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
import com.android.systemui.keyguard.shared.model.DozeStateModel
import com.android.systemui.keyguard.shared.model.KeyguardState
-import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.util.kotlin.Utils.Companion.toTriple
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
-import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
@@ -40,11 +38,14 @@
class FromDreamingTransitionInteractor
@Inject
constructor(
+ override val transitionRepository: KeyguardTransitionRepository,
+ override val transitionInteractor: KeyguardTransitionInteractor,
@Application private val scope: CoroutineScope,
private val keyguardInteractor: KeyguardInteractor,
- private val keyguardTransitionRepository: KeyguardTransitionRepository,
- private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
-) : TransitionInteractor(FromDreamingTransitionInteractor::class.simpleName!!) {
+) :
+ TransitionInteractor(
+ fromState = KeyguardState.DREAMING,
+ ) {
override fun start() {
listenForDreamingToOccluded()
@@ -54,15 +55,8 @@
fun startToLockscreenTransition() {
scope.launch {
- if (keyguardTransitionInteractor.startedKeyguardState.value == KeyguardState.DREAMING) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.DREAMING,
- KeyguardState.LOCKSCREEN,
- getAnimator(TO_LOCKSCREEN_DURATION),
- )
- )
+ if (transitionInteractor.startedKeyguardState.value == KeyguardState.DREAMING) {
+ startTransitionTo(KeyguardState.LOCKSCREEN)
}
}
}
@@ -76,7 +70,7 @@
.sample(
combine(
keyguardInteractor.isKeyguardOccluded,
- keyguardTransitionInteractor.startedKeyguardTransitionStep,
+ transitionInteractor.startedKeyguardTransitionStep,
::Pair,
),
::toTriple
@@ -92,14 +86,7 @@
// action. There's no great signal to determine when the dream is ending
// and a transition to OCCLUDED is beginning directly. For now, the solution
// is DREAMING->LOCKSCREEN->OCCLUDED
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- lastStartedTransition.to,
- KeyguardState.OCCLUDED,
- getAnimator(),
- )
- )
+ startTransitionTo(KeyguardState.OCCLUDED)
}
}
}
@@ -109,14 +96,7 @@
scope.launch {
keyguardInteractor.biometricUnlockState.collect { biometricUnlockState ->
if (biometricUnlockState == BiometricUnlockModel.WAKE_AND_UNLOCK_FROM_DREAM) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.DREAMING,
- KeyguardState.GONE,
- getAnimator(),
- )
- )
+ startTransitionTo(KeyguardState.GONE)
}
}
}
@@ -126,7 +106,7 @@
scope.launch {
combine(
keyguardInteractor.dozeTransitionModel,
- keyguardTransitionInteractor.finishedKeyguardState,
+ transitionInteractor.finishedKeyguardState,
::Pair
)
.collect { (dozeTransitionModel, keyguardState) ->
@@ -134,23 +114,18 @@
dozeTransitionModel.to == DozeStateModel.DOZE &&
keyguardState == KeyguardState.DREAMING
) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.DREAMING,
- KeyguardState.DOZING,
- getAnimator(),
- )
- )
+ startTransitionTo(KeyguardState.DOZING)
}
}
}
}
- private fun getAnimator(duration: Duration = DEFAULT_DURATION): ValueAnimator {
+ override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator {
return ValueAnimator().apply {
- setInterpolator(Interpolators.LINEAR)
- setDuration(duration.inWholeMilliseconds)
+ interpolator = Interpolators.LINEAR
+ duration =
+ if (toState == KeyguardState.LOCKSCREEN) TO_LOCKSCREEN_DURATION.inWholeMilliseconds
+ else DEFAULT_DURATION.inWholeMilliseconds
}
}
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 cfcb654..f82633f 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
@@ -22,12 +22,10 @@
import com.android.systemui.dagger.qualifiers.Application
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.WakefulnessState
import com.android.systemui.util.kotlin.Utils.Companion.toTriple
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
-import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.combine
@@ -37,11 +35,14 @@
class FromGoneTransitionInteractor
@Inject
constructor(
+ override val transitionRepository: KeyguardTransitionRepository,
+ override val transitionInteractor: KeyguardTransitionInteractor,
@Application private val scope: CoroutineScope,
private val keyguardInteractor: KeyguardInteractor,
- private val keyguardTransitionRepository: KeyguardTransitionRepository,
- private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
-) : TransitionInteractor(FromGoneTransitionInteractor::class.simpleName!!) {
+) :
+ TransitionInteractor(
+ fromState = KeyguardState.GONE,
+ ) {
override fun start() {
listenForGoneToAodOrDozing()
@@ -53,17 +54,10 @@
private fun listenForGoneToLockscreen() {
scope.launch {
keyguardInteractor.isKeyguardShowing
- .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
.collect { (isKeyguardShowing, lastStartedStep) ->
if (isKeyguardShowing && lastStartedStep.to == KeyguardState.GONE) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.GONE,
- KeyguardState.LOCKSCREEN,
- getAnimator(),
- )
- )
+ startTransitionTo(KeyguardState.LOCKSCREEN)
}
}
}
@@ -72,17 +66,10 @@
private fun listenForGoneToDreaming() {
scope.launch {
keyguardInteractor.isAbleToDream
- .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
.collect { (isAbleToDream, lastStartedStep) ->
if (isAbleToDream && lastStartedStep.to == KeyguardState.GONE) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.GONE,
- KeyguardState.DREAMING,
- getAnimator(TO_DREAMING_DURATION),
- )
- )
+ startTransitionTo(KeyguardState.DREAMING)
}
}
}
@@ -93,7 +80,7 @@
keyguardInteractor.wakefulnessModel
.sample(
combine(
- keyguardTransitionInteractor.startedKeyguardTransitionStep,
+ transitionInteractor.startedKeyguardTransitionStep,
keyguardInteractor.isAodAvailable,
::Pair
),
@@ -104,30 +91,24 @@
lastStartedStep.to == KeyguardState.GONE &&
wakefulnessState.state == WakefulnessState.STARTING_TO_SLEEP
) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.GONE,
- if (isAodAvailable) {
- KeyguardState.AOD
- } else {
- KeyguardState.DOZING
- },
- getAnimator(),
- )
+ startTransitionTo(
+ if (isAodAvailable) KeyguardState.AOD else KeyguardState.DOZING
)
}
}
}
}
- private fun getAnimator(duration: Duration = DEFAULT_DURATION): ValueAnimator {
+ override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator {
return ValueAnimator().apply {
- setInterpolator(Interpolators.LINEAR)
- setDuration(duration.inWholeMilliseconds)
+ interpolator = Interpolators.LINEAR
+ duration =
+ when (toState) {
+ KeyguardState.DREAMING -> TO_DREAMING_DURATION
+ else -> DEFAULT_DURATION
+ }.inWholeMilliseconds
}
}
-
companion object {
private val DEFAULT_DURATION = 500.milliseconds
val TO_DREAMING_DURATION = 933.milliseconds
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
index b5e289f..b796334 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
@@ -32,7 +32,6 @@
import com.android.systemui.util.kotlin.sample
import java.util.UUID
import javax.inject.Inject
-import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.combine
@@ -42,12 +41,15 @@
class FromLockscreenTransitionInteractor
@Inject
constructor(
+ override val transitionRepository: KeyguardTransitionRepository,
+ override val transitionInteractor: KeyguardTransitionInteractor,
@Application private val scope: CoroutineScope,
private val keyguardInteractor: KeyguardInteractor,
private val shadeRepository: ShadeRepository,
- private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
- private val keyguardTransitionRepository: KeyguardTransitionRepository,
-) : TransitionInteractor(FromLockscreenTransitionInteractor::class.simpleName!!) {
+) :
+ TransitionInteractor(
+ fromState = KeyguardState.LOCKSCREEN,
+ ) {
override fun start() {
listenForLockscreenToGone()
@@ -66,8 +68,8 @@
keyguardInteractor.isAbleToDream
.sample(
combine(
- keyguardTransitionInteractor.startedKeyguardTransitionStep,
- keyguardTransitionInteractor.finishedKeyguardState,
+ transitionInteractor.startedKeyguardTransitionStep,
+ transitionInteractor.finishedKeyguardState,
::Pair
),
::toTriple
@@ -78,14 +80,7 @@
lastStartedTransition.to == KeyguardState.LOCKSCREEN &&
!invalidFromStates.contains(lastStartedTransition.from)
if (isAbleToDream && (isOnLockscreen || isTransitionInterruptible)) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.LOCKSCREEN,
- KeyguardState.DREAMING,
- getAnimator(TO_DREAMING_DURATION),
- )
- )
+ startTransitionTo(KeyguardState.DREAMING)
}
}
}
@@ -94,20 +89,13 @@
private fun listenForLockscreenToPrimaryBouncer() {
scope.launch {
keyguardInteractor.primaryBouncerShowing
- .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
.collect { pair ->
val (isBouncerShowing, lastStartedTransitionStep) = pair
if (
isBouncerShowing && lastStartedTransitionStep.to == KeyguardState.LOCKSCREEN
) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- ownerName = name,
- from = KeyguardState.LOCKSCREEN,
- to = KeyguardState.PRIMARY_BOUNCER,
- animator = getAnimator(),
- )
- )
+ startTransitionTo(KeyguardState.PRIMARY_BOUNCER)
}
}
}
@@ -116,21 +104,14 @@
private fun listenForLockscreenToAlternateBouncer() {
scope.launch {
keyguardInteractor.alternateBouncerShowing
- .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
.collect { pair ->
val (isAlternateBouncerShowing, lastStartedTransitionStep) = pair
if (
isAlternateBouncerShowing &&
lastStartedTransitionStep.to == KeyguardState.LOCKSCREEN
) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- ownerName = name,
- from = KeyguardState.LOCKSCREEN,
- to = KeyguardState.ALTERNATE_BOUNCER,
- animator = getAnimator(),
- )
- )
+ startTransitionTo(KeyguardState.ALTERNATE_BOUNCER)
}
}
}
@@ -143,7 +124,7 @@
shadeRepository.shadeModel
.sample(
combine(
- keyguardTransitionInteractor.startedKeyguardTransitionStep,
+ transitionInteractor.startedKeyguardTransitionStep,
keyguardInteractor.statusBarState,
keyguardInteractor.isKeyguardUnlocked,
::Triple
@@ -164,7 +145,7 @@
} else {
TransitionState.RUNNING
}
- keyguardTransitionRepository.updateTransition(
+ transitionRepository.updateTransition(
id,
1f - shadeModel.expansionAmount,
nextState,
@@ -178,13 +159,17 @@
}
// If canceled, just put the state back
+ // TODO: This logic should happen in FromPrimaryBouncerInteractor.
if (nextState == TransitionState.CANCELED) {
- keyguardTransitionRepository.startTransition(
+ transitionRepository.startTransition(
TransitionInfo(
ownerName = name,
from = KeyguardState.PRIMARY_BOUNCER,
to = KeyguardState.LOCKSCREEN,
- animator = getAnimator(0.milliseconds)
+ animator =
+ getDefaultAnimatorForTransitionsToState(KeyguardState.LOCKSCREEN).apply {
+ duration = 0
+ }
)
)
}
@@ -198,15 +183,7 @@
!isKeyguardUnlocked &&
statusBarState == KEYGUARD
) {
- transitionId =
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- ownerName = name,
- from = KeyguardState.LOCKSCREEN,
- to = KeyguardState.PRIMARY_BOUNCER,
- animator = null,
- )
- )
+ transitionId = startTransitionTo(KeyguardState.PRIMARY_BOUNCER)
}
}
}
@@ -216,18 +193,11 @@
private fun listenForLockscreenToGone() {
scope.launch {
keyguardInteractor.isKeyguardGoingAway
- .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
.collect { pair ->
val (isKeyguardGoingAway, lastStartedStep) = pair
if (isKeyguardGoingAway && lastStartedStep.to == KeyguardState.LOCKSCREEN) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.LOCKSCREEN,
- KeyguardState.GONE,
- getAnimator(),
- )
- )
+ startTransitionTo(KeyguardState.GONE)
}
}
}
@@ -238,7 +208,7 @@
keyguardInteractor.isKeyguardOccluded
.sample(
combine(
- keyguardTransitionInteractor.finishedKeyguardState,
+ transitionInteractor.finishedKeyguardState,
keyguardInteractor.isDreaming,
::Pair
),
@@ -246,14 +216,7 @@
)
.collect { (isOccluded, keyguardState, isDreaming) ->
if (isOccluded && !isDreaming && keyguardState == KeyguardState.LOCKSCREEN) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- keyguardState,
- KeyguardState.OCCLUDED,
- getAnimator(TO_OCCLUDED_DURATION),
- )
- )
+ startTransitionTo(KeyguardState.OCCLUDED)
}
}
}
@@ -263,7 +226,7 @@
private fun listenForLockscreenToCamera() {
scope.launch {
keyguardInteractor.onCameraLaunchDetected
- .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
.collect { (_, lastStartedStep) ->
// DREAMING/AOD/OFF may trigger on the first power button push, so include this
// state in order to cancel and correct the transition
@@ -274,14 +237,7 @@
lastStartedStep.to == KeyguardState.AOD ||
lastStartedStep.to == KeyguardState.OFF
) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.LOCKSCREEN,
- KeyguardState.OCCLUDED,
- getAnimator(TO_OCCLUDED_DURATION),
- )
- )
+ startTransitionTo(KeyguardState.OCCLUDED)
}
}
}
@@ -292,7 +248,7 @@
keyguardInteractor.wakefulnessModel
.sample(
combine(
- keyguardTransitionInteractor.startedKeyguardTransitionStep,
+ transitionInteractor.startedKeyguardTransitionStep,
keyguardInteractor.isAodAvailable,
::Pair
),
@@ -303,27 +259,23 @@
lastStartedStep.to == KeyguardState.LOCKSCREEN &&
wakefulnessState.state == WakefulnessState.STARTING_TO_SLEEP
) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.LOCKSCREEN,
- if (isAodAvailable) {
- KeyguardState.AOD
- } else {
- KeyguardState.DOZING
- },
- getAnimator(),
- )
+ startTransitionTo(
+ if (isAodAvailable) KeyguardState.AOD else KeyguardState.DOZING
)
}
}
}
}
- private fun getAnimator(duration: Duration = DEFAULT_DURATION): ValueAnimator {
+ override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator {
return ValueAnimator().apply {
- setInterpolator(Interpolators.LINEAR)
- setDuration(duration.inWholeMilliseconds)
+ interpolator = Interpolators.LINEAR
+ duration =
+ when (toState) {
+ KeyguardState.DREAMING -> TO_DREAMING_DURATION
+ KeyguardState.OCCLUDED -> TO_OCCLUDED_DURATION
+ else -> DEFAULT_DURATION
+ }.inWholeMilliseconds
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
index b0dbc59..a8147d0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
@@ -22,12 +22,10 @@
import com.android.systemui.dagger.qualifiers.Application
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.WakefulnessState
import com.android.systemui.util.kotlin.Utils.Companion.toTriple
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
-import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.combine
@@ -37,11 +35,14 @@
class FromOccludedTransitionInteractor
@Inject
constructor(
+ override val transitionRepository: KeyguardTransitionRepository,
+ override val transitionInteractor: KeyguardTransitionInteractor,
@Application private val scope: CoroutineScope,
private val keyguardInteractor: KeyguardInteractor,
- private val keyguardTransitionRepository: KeyguardTransitionRepository,
- private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
-) : TransitionInteractor(FromOccludedTransitionInteractor::class.simpleName!!) {
+) :
+ TransitionInteractor(
+ fromState = KeyguardState.OCCLUDED,
+ ) {
override fun start() {
listenForOccludedToLockscreen()
@@ -54,18 +55,11 @@
private fun listenForOccludedToDreaming() {
scope.launch {
keyguardInteractor.isAbleToDream
- .sample(keyguardTransitionInteractor.finishedKeyguardState, ::Pair)
+ .sample(transitionInteractor.finishedKeyguardState, ::Pair)
.collect { pair ->
val (isAbleToDream, keyguardState) = pair
if (isAbleToDream && keyguardState == KeyguardState.OCCLUDED) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.OCCLUDED,
- KeyguardState.DREAMING,
- getAnimator(),
- )
- )
+ startTransitionTo(KeyguardState.DREAMING)
}
}
}
@@ -77,7 +71,7 @@
.sample(
combine(
keyguardInteractor.isKeyguardShowing,
- keyguardTransitionInteractor.startedKeyguardTransitionStep,
+ transitionInteractor.startedKeyguardTransitionStep,
::Pair
),
::toTriple
@@ -90,14 +84,7 @@
isShowing &&
lastStartedKeyguardState.to == KeyguardState.OCCLUDED
) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.OCCLUDED,
- KeyguardState.LOCKSCREEN,
- getAnimator(TO_LOCKSCREEN_DURATION),
- )
- )
+ startTransitionTo(KeyguardState.LOCKSCREEN)
}
}
}
@@ -109,7 +96,7 @@
.sample(
combine(
keyguardInteractor.isKeyguardShowing,
- keyguardTransitionInteractor.startedKeyguardTransitionStep,
+ transitionInteractor.startedKeyguardTransitionStep,
::Pair
),
::toTriple
@@ -122,14 +109,7 @@
!isShowing &&
lastStartedKeyguardState.to == KeyguardState.OCCLUDED
) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.OCCLUDED,
- KeyguardState.GONE,
- getAnimator(),
- )
- )
+ startTransitionTo(KeyguardState.GONE)
}
}
}
@@ -140,7 +120,7 @@
keyguardInteractor.wakefulnessModel
.sample(
combine(
- keyguardTransitionInteractor.startedKeyguardTransitionStep,
+ transitionInteractor.startedKeyguardTransitionStep,
keyguardInteractor.isAodAvailable,
::Pair
),
@@ -151,17 +131,8 @@
lastStartedStep.to == KeyguardState.OCCLUDED &&
wakefulnessState.state == WakefulnessState.STARTING_TO_SLEEP
) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.OCCLUDED,
- if (isAodAvailable) {
- KeyguardState.AOD
- } else {
- KeyguardState.DOZING
- },
- getAnimator(),
- )
+ startTransitionTo(
+ if (isAodAvailable) KeyguardState.AOD else KeyguardState.DOZING
)
}
}
@@ -171,29 +142,26 @@
private fun listenForOccludedToAlternateBouncer() {
scope.launch {
keyguardInteractor.alternateBouncerShowing
- .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
.collect { (isAlternateBouncerShowing, lastStartedTransitionStep) ->
if (
isAlternateBouncerShowing &&
lastStartedTransitionStep.to == KeyguardState.OCCLUDED
) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- ownerName = name,
- from = KeyguardState.OCCLUDED,
- to = KeyguardState.ALTERNATE_BOUNCER,
- animator = getAnimator(),
- )
- )
+ startTransitionTo(KeyguardState.ALTERNATE_BOUNCER)
}
}
}
}
- private fun getAnimator(duration: Duration = DEFAULT_DURATION): ValueAnimator {
+ override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator {
return ValueAnimator().apply {
- setInterpolator(Interpolators.LINEAR)
- setDuration(duration.inWholeMilliseconds)
+ interpolator = Interpolators.LINEAR
+ duration =
+ when (toState) {
+ KeyguardState.LOCKSCREEN -> TO_LOCKSCREEN_DURATION
+ else -> DEFAULT_DURATION
+ }.inWholeMilliseconds
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
index da09e1f..e1754f5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
@@ -25,12 +25,10 @@
import com.android.systemui.dagger.qualifiers.Application
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.WakefulnessState
import com.android.systemui.util.kotlin.Utils.Companion.toQuad
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
-import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.combine
@@ -40,12 +38,15 @@
class FromPrimaryBouncerTransitionInteractor
@Inject
constructor(
+ override val transitionRepository: KeyguardTransitionRepository,
+ override val transitionInteractor: KeyguardTransitionInteractor,
@Application private val scope: CoroutineScope,
private val keyguardInteractor: KeyguardInteractor,
- private val keyguardTransitionRepository: KeyguardTransitionRepository,
- private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
private val keyguardSecurityModel: KeyguardSecurityModel,
-) : TransitionInteractor(FromPrimaryBouncerTransitionInteractor::class.simpleName!!) {
+) :
+ TransitionInteractor(
+ fromState = KeyguardState.PRIMARY_BOUNCER,
+ ) {
override fun start() {
listenForPrimaryBouncerToGone()
@@ -59,7 +60,7 @@
.sample(
combine(
keyguardInteractor.wakefulnessModel,
- keyguardTransitionInteractor.startedKeyguardTransitionStep,
+ transitionInteractor.startedKeyguardTransitionStep,
keyguardInteractor.isKeyguardOccluded,
::Triple
),
@@ -73,20 +74,8 @@
(wakefulnessState.state == WakefulnessState.AWAKE ||
wakefulnessState.state == WakefulnessState.STARTING_TO_WAKE)
) {
- val to =
- if (occluded) {
- KeyguardState.OCCLUDED
- } else {
- KeyguardState.LOCKSCREEN
- }
-
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- ownerName = name,
- from = KeyguardState.PRIMARY_BOUNCER,
- to = to,
- animator = getAnimator(),
- )
+ startTransitionTo(
+ if (occluded) KeyguardState.OCCLUDED else KeyguardState.LOCKSCREEN
)
}
}
@@ -99,7 +88,7 @@
.sample(
combine(
keyguardInteractor.wakefulnessModel,
- keyguardTransitionInteractor.startedKeyguardTransitionStep,
+ transitionInteractor.startedKeyguardTransitionStep,
keyguardInteractor.isAodAvailable,
::Triple
),
@@ -114,20 +103,8 @@
(wakefulnessState.state == WakefulnessState.STARTING_TO_SLEEP ||
wakefulnessState.state == WakefulnessState.ASLEEP)
) {
- val to =
- if (isAodAvailable) {
- KeyguardState.AOD
- } else {
- KeyguardState.DOZING
- }
-
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- ownerName = name,
- from = KeyguardState.PRIMARY_BOUNCER,
- to = to,
- animator = getAnimator(),
- )
+ startTransitionTo(
+ if (isAodAvailable) KeyguardState.AOD else KeyguardState.DOZING
)
}
}
@@ -137,7 +114,7 @@
private fun listenForPrimaryBouncerToGone() {
scope.launch {
keyguardInteractor.isKeyguardGoingAway
- .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
.collect { (isKeyguardGoingAway, lastStartedTransitionStep) ->
if (
isKeyguardGoingAway &&
@@ -154,24 +131,24 @@
} else {
TO_GONE_DURATION
}
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- ownerName = name,
- from = KeyguardState.PRIMARY_BOUNCER,
- to = KeyguardState.GONE,
- animator = getAnimator(duration),
- ),
- resetIfCanceled = true,
+
+ startTransitionTo(
+ toState = KeyguardState.GONE,
+ animator =
+ getDefaultAnimatorForTransitionsToState(KeyguardState.GONE).apply {
+ this.duration = duration.inWholeMilliseconds
+ },
+ resetIfCancelled = true
)
}
}
}
}
- private fun getAnimator(duration: Duration = DEFAULT_DURATION): ValueAnimator {
+ override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator {
return ValueAnimator().apply {
- setInterpolator(Interpolators.LINEAR)
- setDuration(duration.inWholeMilliseconds)
+ interpolator = Interpolators.LINEAR
+ duration = DEFAULT_DURATION.inWholeMilliseconds
}
}
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 42f12f8..df7c79f 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
@@ -47,6 +47,8 @@
private val repository: KeyguardTransitionRepository,
@Application val scope: CoroutineScope,
) {
+ private val TAG = this::class.simpleName
+
/** (any)->GONE transition information */
val anyStateToGoneTransition: Flow<TransitionStep> =
repository.transitions.filter { step -> step.to == KeyguardState.GONE }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractor.kt
index d0bc25f..7bbc0d6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractor.kt
@@ -61,23 +61,16 @@
/** Whether it's currently possible to swipe up to dismiss the lockscreen. */
val isSwipeToDismissEnabled: StateFlow<Boolean> =
- combine(
- authenticationInteractor.isUnlocked,
- authenticationInteractor.authenticationMethod,
- ) { isUnlocked, authMethod ->
- isSwipeToUnlockEnabled(
- isUnlocked = isUnlocked,
- authMethod = authMethod,
- )
+ authenticationInteractor.isUnlocked
+ .map { isUnlocked ->
+ !isUnlocked &&
+ authenticationInteractor.getAuthenticationMethod() is
+ AuthenticationMethodModel.Swipe
}
.stateIn(
scope = applicationScope,
started = SharingStarted.WhileSubscribed(),
- initialValue =
- isSwipeToUnlockEnabled(
- isUnlocked = authenticationInteractor.isUnlocked.value,
- authMethod = authenticationInteractor.authenticationMethod.value,
- ),
+ initialValue = false,
)
init {
@@ -124,44 +117,17 @@
// If switched from the lockscreen to the gone scene and the auth method was a swipe,
// unlocks the device.
applicationScope.launch {
- combine(
- authenticationInteractor.authenticationMethod,
- sceneInteractor.currentScene(containerName).pairwise(),
- ::Pair,
- )
- .collect { (authMethod, scenes) ->
- val (previousScene, currentScene) = scenes
- if (
- authMethod is AuthenticationMethodModel.Swipe &&
- previousScene.key == SceneKey.Lockscreen &&
- currentScene.key == SceneKey.Gone
- ) {
- authenticationInteractor.unlockDevice()
- }
+ sceneInteractor.currentScene(containerName).pairwise().collect {
+ (previousScene, currentScene) ->
+ if (
+ authenticationInteractor.getAuthenticationMethod() is
+ AuthenticationMethodModel.Swipe &&
+ previousScene.key == SceneKey.Lockscreen &&
+ currentScene.key == SceneKey.Gone
+ ) {
+ authenticationInteractor.unlockDevice()
}
- }
-
- // DISMISS Lockscreen IF AUTH METHOD IS REMOVED.
- //
- // If the auth method becomes None while on the lockscreen scene, dismisses the lock
- // screen.
- applicationScope.launch {
- combine(
- authenticationInteractor.authenticationMethod,
- sceneInteractor.currentScene(containerName),
- ::Pair,
- )
- .collect { (authMethod, scene) ->
- if (
- scene.key == SceneKey.Lockscreen &&
- authMethod == AuthenticationMethodModel.None
- ) {
- sceneInteractor.setCurrentScene(
- containerName = containerName,
- scene = SceneModel(SceneKey.Gone),
- )
- }
- }
+ }
}
}
@@ -170,13 +136,6 @@
bouncerInteractor.showOrUnlockDevice(containerName = containerName)
}
- private fun isSwipeToUnlockEnabled(
- isUnlocked: Boolean,
- authMethod: AuthenticationMethodModel,
- ): Boolean {
- return !isUnlocked && authMethod is AuthenticationMethodModel.Swipe
- }
-
@AssistedFactory
interface Factory {
fun create(
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 b7dd1a5..ae6fc9e 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
@@ -15,6 +15,14 @@
*/
package com.android.systemui.keyguard.domain.interactor
+
+import android.animation.ValueAnimator
+import android.util.Log
+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 java.util.UUID
+
/**
* Each TransitionInteractor is responsible for determining under which conditions to notify
* [KeyguardTransitionRepository] to signal a transition. When (and if) the transition occurs is
@@ -26,6 +34,50 @@
* MUST list implementing classes in dagger module [StartKeyguardTransitionModule] and also in the
* 'when' clause of [KeyguardTransitionCoreStartable]
*/
-sealed class TransitionInteractor(val name: String) {
+sealed class TransitionInteractor(
+ val fromState: KeyguardState,
+) {
+ val name = this::class.simpleName ?: "UnknownTransitionInteractor"
+
+ abstract val transitionRepository: KeyguardTransitionRepository
+ abstract val transitionInteractor: KeyguardTransitionInteractor
abstract fun start()
+
+ fun startTransitionTo(
+ toState: KeyguardState,
+ animator: ValueAnimator? = getDefaultAnimatorForTransitionsToState(toState),
+ resetIfCancelled: Boolean = false
+ ): UUID? {
+ if (
+ fromState != transitionInteractor.startedKeyguardState.value &&
+ fromState != transitionInteractor.finishedKeyguardState.value
+ ) {
+ Log.e(
+ name,
+ "startTransition: We were asked to transition from " +
+ "$fromState to $toState, however we last finished a transition to " +
+ "${transitionInteractor.finishedKeyguardState.value}, " +
+ "and last started a transition to " +
+ "${transitionInteractor.startedKeyguardState.value}. " +
+ "Ignoring startTransition, but this should never happen."
+ )
+ return null
+ }
+
+ return transitionRepository.startTransition(
+ TransitionInfo(
+ name,
+ fromState,
+ toState,
+ animator,
+ ),
+ resetIfCancelled
+ )
+ }
+
+ /**
+ * Returns a ValueAnimator to be used for transitions to [toState], if one is not explicitly
+ * passed to [startTransitionTo].
+ */
+ abstract fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator?
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt
index ac2d492..c783325 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt
@@ -25,7 +25,6 @@
import com.android.systemui.scene.SceneTestUtils
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Test
@@ -37,8 +36,8 @@
@RunWith(JUnit4::class)
class AuthenticationInteractorTest : SysuiTestCase() {
- private val testScope = TestScope()
- private val utils = SceneTestUtils(this, testScope)
+ private val utils = SceneTestUtils(this)
+ private val testScope = utils.testScope
private val repository: AuthenticationRepository = utils.authenticationRepository()
private val underTest =
utils.authenticationInteractor(
@@ -46,23 +45,23 @@
)
@Test
- fun authMethod() =
+ fun getAuthenticationMethod() =
testScope.runTest {
- val authMethod by collectLastValue(underTest.authenticationMethod)
- assertThat(authMethod).isEqualTo(AuthenticationMethodModel.Pin(1234))
+ assertThat(underTest.getAuthenticationMethod())
+ .isEqualTo(AuthenticationMethodModel.Pin(1234))
- underTest.setAuthenticationMethod(AuthenticationMethodModel.Password("password"))
- assertThat(authMethod).isEqualTo(AuthenticationMethodModel.Password("password"))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Password("password")
+ )
+ assertThat(underTest.getAuthenticationMethod())
+ .isEqualTo(AuthenticationMethodModel.Password("password"))
}
@Test
fun isUnlocked_whenAuthMethodIsNone_isTrue() =
testScope.runTest {
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.None)
val isUnlocked by collectLastValue(underTest.isUnlocked)
- assertThat(isUnlocked).isFalse()
-
- underTest.setAuthenticationMethod(AuthenticationMethodModel.None)
-
assertThat(isUnlocked).isTrue()
}
@@ -108,7 +107,9 @@
testScope.runTest {
underTest.lockDevice()
runCurrent()
- underTest.setAuthenticationMethod(AuthenticationMethodModel.Password("password"))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Password("password")
+ )
assertThat(underTest.isAuthenticationRequired()).isTrue()
}
@@ -118,7 +119,7 @@
testScope.runTest {
underTest.lockDevice()
runCurrent()
- underTest.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
assertThat(underTest.isAuthenticationRequired()).isFalse()
}
@@ -128,7 +129,9 @@
testScope.runTest {
underTest.unlockDevice()
runCurrent()
- underTest.setAuthenticationMethod(AuthenticationMethodModel.Password("password"))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Password("password")
+ )
assertThat(underTest.isAuthenticationRequired()).isFalse()
}
@@ -138,7 +141,7 @@
testScope.runTest {
underTest.unlockDevice()
runCurrent()
- underTest.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
assertThat(underTest.isAuthenticationRequired()).isFalse()
}
@@ -148,7 +151,9 @@
testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
val isUnlocked by collectLastValue(underTest.isUnlocked)
- underTest.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
assertThat(isUnlocked).isFalse()
assertThat(underTest.authenticate(listOf(1, 2, 3, 4))).isTrue()
@@ -161,7 +166,9 @@
testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
val isUnlocked by collectLastValue(underTest.isUnlocked)
- underTest.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
assertThat(isUnlocked).isFalse()
assertThat(underTest.authenticate(listOf(9, 8, 7))).isFalse()
@@ -174,7 +181,9 @@
testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
val isUnlocked by collectLastValue(underTest.isUnlocked)
- underTest.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
assertThat(isUnlocked).isFalse()
assertThat(underTest.authenticate(listOf())).isFalse()
@@ -187,7 +196,9 @@
testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
val isUnlocked by collectLastValue(underTest.isUnlocked)
- underTest.setAuthenticationMethod(AuthenticationMethodModel.Pin(9999999999999999))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(9999999999999999)
+ )
assertThat(isUnlocked).isFalse()
assertThat(underTest.authenticate(List(16) { 9 })).isTrue()
@@ -206,7 +217,9 @@
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
val isUnlocked by collectLastValue(underTest.isUnlocked)
- underTest.setAuthenticationMethod(AuthenticationMethodModel.Pin(99999999999999999))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(99999999999999999)
+ )
assertThat(isUnlocked).isFalse()
assertThat(underTest.authenticate(List(17) { 9 })).isFalse()
@@ -219,7 +232,9 @@
testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
val isUnlocked by collectLastValue(underTest.isUnlocked)
- underTest.setAuthenticationMethod(AuthenticationMethodModel.Password("password"))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Password("password")
+ )
assertThat(isUnlocked).isFalse()
assertThat(underTest.authenticate("password".toList())).isTrue()
@@ -232,7 +247,9 @@
testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
val isUnlocked by collectLastValue(underTest.isUnlocked)
- underTest.setAuthenticationMethod(AuthenticationMethodModel.Password("password"))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Password("password")
+ )
assertThat(isUnlocked).isFalse()
assertThat(underTest.authenticate("alohomora".toList())).isFalse()
@@ -245,7 +262,7 @@
testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
val isUnlocked by collectLastValue(underTest.isUnlocked)
- underTest.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pattern(
listOf(
AuthenticationMethodModel.Pattern.PatternCoordinate(
@@ -293,7 +310,7 @@
testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
val isUnlocked by collectLastValue(underTest.isUnlocked)
- underTest.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pattern(
listOf(
AuthenticationMethodModel.Pattern.PatternCoordinate(
@@ -341,7 +358,7 @@
testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
val isUnlocked by collectLastValue(underTest.isUnlocked)
- underTest.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
)
assertThat(isUnlocked).isFalse()
@@ -356,7 +373,7 @@
testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
val isUnlocked by collectLastValue(underTest.isUnlocked)
- underTest.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
)
assertThat(isUnlocked).isFalse()
@@ -371,7 +388,7 @@
testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
val isUnlocked by collectLastValue(underTest.isUnlocked)
- underTest.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
)
assertThat(isUnlocked).isFalse()
@@ -386,7 +403,7 @@
testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
val isUnlocked by collectLastValue(underTest.isUnlocked)
- underTest.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
)
assertThat(isUnlocked).isFalse()
@@ -402,7 +419,7 @@
testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
val isUnlocked by collectLastValue(underTest.isUnlocked)
- underTest.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
)
assertThat(isUnlocked).isFalse()
@@ -417,7 +434,7 @@
testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
val isUnlocked by collectLastValue(underTest.isUnlocked)
- underTest.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = false)
)
assertThat(isUnlocked).isFalse()
@@ -432,22 +449,13 @@
testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
val isUnlocked by collectLastValue(underTest.isUnlocked)
- underTest.setAuthenticationMethod(AuthenticationMethodModel.Password("password"))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Password("password")
+ )
assertThat(isUnlocked).isFalse()
assertThat(underTest.authenticate("password".toList(), tryAutoConfirm = true)).isNull()
assertThat(isUnlocked).isFalse()
assertThat(failedAttemptCount).isEqualTo(0)
}
-
- @Test
- fun unlocksDevice_whenAuthMethodBecomesNone() =
- testScope.runTest {
- val isUnlocked by collectLastValue(underTest.isUnlocked)
- assertThat(isUnlocked).isFalse()
-
- repository.setAuthenticationMethod(AuthenticationMethodModel.None)
-
- assertThat(isUnlocked).isTrue()
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt
index 9483667..92cf0a5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt
@@ -26,7 +26,6 @@
import com.android.systemui.scene.shared.model.SceneModel
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
@@ -40,8 +39,8 @@
@RunWith(JUnit4::class)
class BouncerInteractorTest : SysuiTestCase() {
- private val testScope = TestScope()
- private val utils = SceneTestUtils(this, testScope)
+ private val utils = SceneTestUtils(this)
+ private val testScope = utils.testScope
private val authenticationInteractor =
utils.authenticationInteractor(
repository = utils.authenticationRepository(),
@@ -69,7 +68,9 @@
val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
val message by collectLastValue(underTest.message)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
authenticationInteractor.lockDevice()
underTest.showOrUnlockDevice("container1")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
@@ -100,7 +101,7 @@
val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
val message by collectLastValue(underTest.message)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
)
authenticationInteractor.lockDevice()
@@ -130,7 +131,7 @@
val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
val message by collectLastValue(underTest.message)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = false)
)
authenticationInteractor.lockDevice()
@@ -154,7 +155,7 @@
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
val message by collectLastValue(underTest.message)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password("password")
)
authenticationInteractor.lockDevice()
@@ -186,7 +187,7 @@
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
val message by collectLastValue(underTest.message)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pattern(emptyList())
)
authenticationInteractor.lockDevice()
@@ -222,7 +223,9 @@
fun showOrUnlockDevice_notLocked_switchesToGoneScene() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
authenticationInteractor.unlockDevice()
runCurrent()
@@ -235,7 +238,7 @@
fun showOrUnlockDevice_authMethodNotSecure_switchesToGoneScene() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
authenticationInteractor.lockDevice()
underTest.showOrUnlockDevice("container1")
@@ -248,7 +251,7 @@
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
val message by collectLastValue(underTest.message)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password("password")
)
authenticationInteractor.lockDevice()
@@ -266,7 +269,9 @@
val throttling by collectLastValue(underTest.throttling)
val message by collectLastValue(underTest.message)
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
assertThat(throttling).isNull()
assertThat(message).isEqualTo("")
assertThat(isUnlocked).isFalse()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt
index b53e034..22ac1b6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt
@@ -24,7 +24,6 @@
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
@@ -35,8 +34,8 @@
@RunWith(JUnit4::class)
class AuthMethodBouncerViewModelTest : SysuiTestCase() {
- private val testScope = TestScope()
- private val utils = SceneTestUtils(this, testScope)
+ private val utils = SceneTestUtils(this)
+ private val testScope = utils.testScope
private val authenticationInteractor =
utils.authenticationInteractor(
utils.authenticationRepository(),
@@ -55,7 +54,9 @@
@Test
fun animateFailure() =
testScope.runTest {
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
val animateFailure by collectLastValue(underTest.animateFailure)
assertThat(animateFailure).isFalse()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt
index c607496..53f972e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt
@@ -26,7 +26,6 @@
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.flatMapLatest
-import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runTest
import org.junit.Test
@@ -38,8 +37,8 @@
@RunWith(JUnit4::class)
class BouncerViewModelTest : SysuiTestCase() {
- private val testScope = TestScope()
- private val utils = SceneTestUtils(this, testScope)
+ private val utils = SceneTestUtils(this)
+ private val testScope = utils.testScope
private val authenticationInteractor =
utils.authenticationInteractor(
repository = utils.authenticationRepository(),
@@ -54,11 +53,11 @@
@Test
fun authMethod_nonNullForSecureMethods_nullForNotSecureMethods() =
testScope.runTest {
- val authMethodViewModel: AuthMethodBouncerViewModel? by
- collectLastValue(underTest.authMethod)
authMethodsToTest().forEach { authMethod ->
- authenticationInteractor.setAuthenticationMethod(authMethod)
+ utils.authenticationRepository.setAuthenticationMethod(authMethod)
+ val authMethodViewModel: AuthMethodBouncerViewModel? by
+ collectLastValue(underTest.authMethod)
if (authMethod.isSecure) {
assertThat(authMethodViewModel).isNotNull()
} else {
@@ -75,13 +74,13 @@
collectLastValue(underTest.authMethod)
// First pass, populate our "seen" map:
authMethodsToTest().forEach { authMethod ->
- authenticationInteractor.setAuthenticationMethod(authMethod)
+ utils.authenticationRepository.setAuthenticationMethod(authMethod)
authMethodViewModel?.let { seen[authMethod] = it }
}
// Second pass, assert same instances are reused:
authMethodsToTest().forEach { authMethod ->
- authenticationInteractor.setAuthenticationMethod(authMethod)
+ utils.authenticationRepository.setAuthenticationMethod(authMethod)
authMethodViewModel?.let { assertThat(it).isSameInstanceAs(seen[authMethod]) }
}
}
@@ -97,7 +96,9 @@
testScope.runTest {
val message by collectLastValue(underTest.message)
val throttling by collectLastValue(bouncerInteractor.throttling)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
assertThat(message?.isUpdateAnimated).isTrue()
repeat(BouncerInteractor.THROTTLE_EVERY) {
@@ -120,7 +121,9 @@
}
)
val throttling by collectLastValue(bouncerInteractor.throttling)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
assertThat(isInputEnabled).isTrue()
repeat(BouncerInteractor.THROTTLE_EVERY) {
@@ -137,7 +140,9 @@
fun throttlingDialogMessage() =
testScope.runTest {
val throttlingDialogMessage by collectLastValue(underTest.throttlingDialogMessage)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
repeat(BouncerInteractor.THROTTLE_EVERY) {
// Wrong PIN.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
index f436aa3..7d65c80 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
@@ -28,7 +28,7 @@
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
-import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
@@ -40,8 +40,8 @@
@RunWith(JUnit4::class)
class PasswordBouncerViewModelTest : SysuiTestCase() {
- private val testScope = TestScope()
- private val utils = SceneTestUtils(this, testScope)
+ private val utils = SceneTestUtils(this)
+ private val testScope = utils.testScope
private val authenticationInteractor =
utils.authenticationInteractor(
repository = utils.authenticationRepository(),
@@ -58,6 +58,7 @@
)
private val underTest =
PasswordBouncerViewModel(
+ applicationScope = testScope.backgroundScope,
interactor = bouncerInteractor,
isInputEnabled = MutableStateFlow(true).asStateFlow(),
)
@@ -75,7 +76,7 @@
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message)
val password by collectLastValue(underTest.password)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password("password")
)
authenticationInteractor.lockDevice()
@@ -98,7 +99,7 @@
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message)
val password by collectLastValue(underTest.password)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password("password")
)
authenticationInteractor.lockDevice()
@@ -106,6 +107,7 @@
assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
+ runCurrent()
underTest.onPasswordInputChanged("password")
@@ -120,7 +122,7 @@
testScope.runTest {
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password("password")
)
authenticationInteractor.lockDevice()
@@ -143,7 +145,7 @@
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message)
val password by collectLastValue(underTest.password)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password("password")
)
authenticationInteractor.lockDevice()
@@ -168,7 +170,7 @@
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message)
val password by collectLastValue(underTest.password)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password("password")
)
authenticationInteractor.lockDevice()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt
index d7d7154..9f16358 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt
@@ -29,7 +29,7 @@
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
-import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
@@ -41,8 +41,8 @@
@RunWith(JUnit4::class)
class PatternBouncerViewModelTest : SysuiTestCase() {
- private val testScope = TestScope()
- private val utils = SceneTestUtils(this, testScope)
+ private val utils = SceneTestUtils(this)
+ private val testScope = utils.testScope
private val authenticationInteractor =
utils.authenticationInteractor(
repository = utils.authenticationRepository(),
@@ -79,7 +79,7 @@
val message by collectLastValue(bouncerViewModel.message)
val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pattern(CORRECT_PATTERN)
)
authenticationInteractor.lockDevice()
@@ -104,7 +104,7 @@
val message by collectLastValue(bouncerViewModel.message)
val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pattern(CORRECT_PATTERN)
)
authenticationInteractor.lockDevice()
@@ -112,6 +112,7 @@
assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
+ runCurrent()
underTest.onDragStart()
@@ -129,7 +130,7 @@
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pattern(CORRECT_PATTERN)
)
authenticationInteractor.lockDevice()
@@ -180,7 +181,7 @@
val message by collectLastValue(bouncerViewModel.message)
val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pattern(CORRECT_PATTERN)
)
authenticationInteractor.lockDevice()
@@ -215,7 +216,7 @@
val message by collectLastValue(bouncerViewModel.message)
val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pattern(CORRECT_PATTERN)
)
authenticationInteractor.lockDevice()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
index 7e358d2..a9907c0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
@@ -29,7 +29,7 @@
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
-import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
@@ -41,8 +41,8 @@
@RunWith(JUnit4::class)
class PinBouncerViewModelTest : SysuiTestCase() {
- private val testScope = TestScope()
- private val utils = SceneTestUtils(this, testScope)
+ private val utils = SceneTestUtils(this)
+ private val testScope = utils.testScope
private val sceneInteractor = utils.sceneInteractor()
private val authenticationInteractor =
utils.authenticationInteractor(
@@ -85,7 +85,6 @@
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message)
val entries by collectLastValue(underTest.pinEntries)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
authenticationInteractor.lockDevice()
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
assertThat(isUnlocked).isFalse()
@@ -106,12 +105,15 @@
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message)
val entries by collectLastValue(underTest.pinEntries)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
authenticationInteractor.lockDevice()
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
+ runCurrent()
underTest.onPinButtonClicked(1)
@@ -129,12 +131,15 @@
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message)
val entries by collectLastValue(underTest.pinEntries)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
authenticationInteractor.lockDevice()
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
+ runCurrent()
underTest.onPinButtonClicked(1)
assertThat(entries).hasSize(1)
@@ -153,7 +158,9 @@
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message)
val entries by collectLastValue(underTest.pinEntries)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
authenticationInteractor.lockDevice()
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
assertThat(isUnlocked).isFalse()
@@ -180,12 +187,15 @@
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message)
val entries by collectLastValue(underTest.pinEntries)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
authenticationInteractor.lockDevice()
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
+ runCurrent()
underTest.onPinButtonClicked(1)
underTest.onPinButtonClicked(2)
underTest.onPinButtonClicked(3)
@@ -204,7 +214,9 @@
testScope.runTest {
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
authenticationInteractor.lockDevice()
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
assertThat(isUnlocked).isFalse()
@@ -228,7 +240,9 @@
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message)
val entries by collectLastValue(underTest.pinEntries)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
authenticationInteractor.lockDevice()
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
assertThat(isUnlocked).isFalse()
@@ -255,7 +269,9 @@
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message)
val entries by collectLastValue(underTest.pinEntries)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
authenticationInteractor.lockDevice()
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
assertThat(isUnlocked).isFalse()
@@ -290,7 +306,7 @@
testScope.runTest {
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
)
authenticationInteractor.lockDevice()
@@ -314,7 +330,7 @@
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message)
val entries by collectLastValue(underTest.pinEntries)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
)
authenticationInteractor.lockDevice()
@@ -338,7 +354,7 @@
testScope.runTest {
val backspaceButtonAppearance by collectLastValue(underTest.backspaceButtonAppearance)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = false)
)
@@ -349,7 +365,7 @@
fun backspaceButtonAppearance_withAutoConfirmButNoInput_isHidden() =
testScope.runTest {
val backspaceButtonAppearance by collectLastValue(underTest.backspaceButtonAppearance)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
)
@@ -360,7 +376,7 @@
fun backspaceButtonAppearance_withAutoConfirmAndInput_isShownQuiet() =
testScope.runTest {
val backspaceButtonAppearance by collectLastValue(underTest.backspaceButtonAppearance)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
)
@@ -374,7 +390,7 @@
testScope.runTest {
val confirmButtonAppearance by collectLastValue(underTest.confirmButtonAppearance)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = false)
)
@@ -385,7 +401,7 @@
fun confirmButtonAppearance_withAutoConfirm_isHidden() =
testScope.runTest {
val confirmButtonAppearance by collectLastValue(underTest.confirmButtonAppearance)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
)
@@ -396,7 +412,7 @@
fun hintedPinLength_withoutAutoConfirm_isNull() =
testScope.runTest {
val hintedPinLength by collectLastValue(underTest.hintedPinLength)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = false)
)
@@ -407,7 +423,7 @@
fun hintedPinLength_withAutoConfirmPinLessThanSixDigits_isNull() =
testScope.runTest {
val hintedPinLength by collectLastValue(underTest.hintedPinLength)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(12345, autoConfirm = true)
)
@@ -418,7 +434,7 @@
fun hintedPinLength_withAutoConfirmPinExactlySixDigits_isSix() =
testScope.runTest {
val hintedPinLength by collectLastValue(underTest.hintedPinLength)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(123456, autoConfirm = true)
)
@@ -429,7 +445,7 @@
fun hintedPinLength_withAutoConfirmPinMoreThanSixDigits_isNull() =
testScope.runTest {
val hintedPinLength by collectLastValue(underTest.hintedPinLength)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234567, autoConfirm = true)
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
new file mode 100644
index 0000000..9be54fb
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.display.data.repository
+
+import android.hardware.display.DisplayManager
+import android.os.Looper
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.Display
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.FlowValue
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.kotlinArgumentCaptor
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.utils.os.FakeHandler
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyLong
+import org.mockito.Mockito.never
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+class DisplayRepositoryTest : SysuiTestCase() {
+
+ private val displayManager = mock<DisplayManager>()
+ private val displayListener = kotlinArgumentCaptor<DisplayManager.DisplayListener>()
+
+ private val testHandler = FakeHandler(Looper.getMainLooper())
+ private val testScope = TestScope(UnconfinedTestDispatcher())
+
+ private lateinit var displayRepository: DisplayRepositoryImpl
+
+ @Before
+ fun setup() {
+ setDisplays(emptyList())
+ displayRepository =
+ DisplayRepositoryImpl(
+ displayManager,
+ testHandler,
+ TestScope(UnconfinedTestDispatcher()),
+ UnconfinedTestDispatcher()
+ )
+ verify(displayManager, never()).registerDisplayListener(any(), any())
+ }
+
+ @Test
+ fun onFlowCollection_displayListenerRegistered() =
+ testScope.runTest {
+ val value by latestDisplayFlowValue()
+
+ assertThat(value).isEmpty()
+
+ verify(displayManager).registerDisplayListener(any(), eq(testHandler), anyLong())
+ }
+
+ @Test
+ fun afterFlowCollection_displayListenerUnregistered() {
+ testScope.runTest {
+ val value by latestDisplayFlowValue()
+
+ assertThat(value).isEmpty()
+
+ verify(displayManager).registerDisplayListener(any(), eq(testHandler), anyLong())
+ }
+ verify(displayManager).unregisterDisplayListener(any())
+ }
+
+ @Test
+ fun afterFlowCollection_multipleSusbcriptions_oneRemoved_displayListenerNotUnregistered() {
+ testScope.runTest {
+ val firstSubscriber by latestDisplayFlowValue()
+
+ assertThat(firstSubscriber).isEmpty()
+ verify(displayManager, times(1))
+ .registerDisplayListener(displayListener.capture(), eq(testHandler), anyLong())
+
+ val innerScope = TestScope()
+ innerScope.runTest {
+ val secondSubscriber by latestDisplayFlowValue()
+ assertThat(secondSubscriber).isEmpty()
+
+ // No new registration, just the precedent one.
+ verify(displayManager, times(1))
+ .registerDisplayListener(any(), eq(testHandler), anyLong())
+ }
+
+ // Let's make sure it has *NOT* been unregistered, as there is still a subscriber.
+ setDisplays(1)
+ displayListener.value.onDisplayAdded(1)
+ assertThat(firstSubscriber?.ids()).containsExactly(1)
+ }
+
+ // All subscribers are done, unregister should have been called.
+ verify(displayManager).unregisterDisplayListener(any())
+ }
+ @Test
+ fun onDisplayAdded_propagated() =
+ testScope.runTest {
+ val value by latestDisplayFlowValue()
+
+ setDisplays(1)
+ displayListener.value.onDisplayAdded(1)
+
+ assertThat(value?.ids()).containsExactly(1)
+ }
+
+ @Test
+ fun onDisplayRemoved_propagated() =
+ testScope.runTest {
+ val value by latestDisplayFlowValue()
+
+ setDisplays(1, 2, 3, 4)
+ displayListener.value.onDisplayAdded(1)
+ displayListener.value.onDisplayAdded(2)
+ displayListener.value.onDisplayAdded(3)
+ displayListener.value.onDisplayAdded(4)
+
+ setDisplays(1, 2, 3)
+ displayListener.value.onDisplayRemoved(4)
+
+ assertThat(value?.ids()).containsExactly(1, 2, 3)
+ }
+
+ @Test
+ fun onDisplayChanged_propagated() =
+ testScope.runTest {
+ val value by latestDisplayFlowValue()
+
+ setDisplays(1, 2, 3, 4)
+ displayListener.value.onDisplayAdded(1)
+ displayListener.value.onDisplayAdded(2)
+ displayListener.value.onDisplayAdded(3)
+ displayListener.value.onDisplayAdded(4)
+
+ displayListener.value.onDisplayChanged(4)
+
+ assertThat(value?.ids()).containsExactly(1, 2, 3, 4)
+ }
+
+ private fun Iterable<Display>.ids(): List<Int> = map { it.displayId }
+
+ // Wrapper to capture the displayListener.
+ private fun TestScope.latestDisplayFlowValue(): FlowValue<Set<Display>?> {
+ val flowValue = collectLastValue(displayRepository.displays)
+ verify(displayManager)
+ .registerDisplayListener(displayListener.capture(), eq(testHandler), anyLong())
+ return flowValue
+ }
+
+ private fun setDisplays(displays: List<Display>) {
+ whenever(displayManager.displays).thenReturn(displays.toTypedArray())
+ }
+
+ private fun setDisplays(vararg ids: Int) {
+ setDisplays(ids.map { display(it) })
+ }
+
+ private fun display(id: Int): Display {
+ return mock<Display>().also { mockDisplay ->
+ whenever(mockDisplay.displayId).thenReturn(id)
+ }
+ }
+}
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 50075b5..b559015 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
@@ -25,7 +25,6 @@
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
-import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
import com.android.systemui.keyguard.shared.model.DozeStateModel
import com.android.systemui.keyguard.shared.model.DozeTransitionModel
@@ -56,6 +55,7 @@
import org.mockito.Mock
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
+import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@@ -72,10 +72,10 @@
private lateinit var bouncerRepository: FakeKeyguardBouncerRepository
private lateinit var shadeRepository: ShadeRepository
private lateinit var transitionRepository: FakeKeyguardTransitionRepository
+ private lateinit var transitionInteractor: KeyguardTransitionInteractor
private lateinit var featureFlags: FakeFeatureFlags
// Used to verify transition requests for test output
- @Mock private lateinit var mockTransitionRepository: KeyguardTransitionRepository
@Mock private lateinit var keyguardSecurityModel: KeyguardSecurityModel
private lateinit var fromLockscreenTransitionInteractor: FromLockscreenTransitionInteractor
@@ -97,92 +97,71 @@
keyguardRepository = FakeKeyguardRepository()
bouncerRepository = FakeKeyguardBouncerRepository()
shadeRepository = FakeShadeRepository()
- transitionRepository = FakeKeyguardTransitionRepository()
+ transitionRepository = spy(FakeKeyguardTransitionRepository())
+ transitionInteractor = KeyguardTransitionInteractor(
+ transitionRepository, testScope.backgroundScope)
whenever(keyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(PIN)
featureFlags = FakeFeatureFlags().apply { set(Flags.FACE_AUTH_REFACTOR, true) }
- fromLockscreenTransitionInteractor =
- FromLockscreenTransitionInteractor(
+
+ fromLockscreenTransitionInteractor = FromLockscreenTransitionInteractor(
scope = testScope,
keyguardInteractor = createKeyguardInteractor(),
+ transitionRepository = transitionRepository,
+ transitionInteractor = transitionInteractor,
shadeRepository = shadeRepository,
- keyguardTransitionRepository = mockTransitionRepository,
- keyguardTransitionInteractor =
- KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
- )
- fromLockscreenTransitionInteractor.start()
+ ).apply { start() }
- fromDreamingTransitionInteractor =
- FromDreamingTransitionInteractor(
+ fromPrimaryBouncerTransitionInteractor = FromPrimaryBouncerTransitionInteractor(
scope = testScope,
keyguardInteractor = createKeyguardInteractor(),
- keyguardTransitionRepository = mockTransitionRepository,
- keyguardTransitionInteractor =
- KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
- )
- fromDreamingTransitionInteractor.start()
-
- fromAodTransitionInteractor =
- FromAodTransitionInteractor(
- scope = testScope,
- keyguardInteractor = createKeyguardInteractor(),
- keyguardTransitionRepository = mockTransitionRepository,
- keyguardTransitionInteractor =
- KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
- )
- fromAodTransitionInteractor.start()
-
- fromGoneTransitionInteractor =
- FromGoneTransitionInteractor(
- scope = testScope,
- keyguardInteractor = createKeyguardInteractor(),
- keyguardTransitionRepository = mockTransitionRepository,
- keyguardTransitionInteractor =
- KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
- )
- fromGoneTransitionInteractor.start()
-
- fromDozingTransitionInteractor =
- FromDozingTransitionInteractor(
- scope = testScope,
- keyguardInteractor = createKeyguardInteractor(),
- keyguardTransitionRepository = mockTransitionRepository,
- keyguardTransitionInteractor =
- KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
- )
- fromDozingTransitionInteractor.start()
-
- fromOccludedTransitionInteractor =
- FromOccludedTransitionInteractor(
- scope = testScope,
- keyguardInteractor = createKeyguardInteractor(),
- keyguardTransitionRepository = mockTransitionRepository,
- keyguardTransitionInteractor =
- KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
- )
- fromOccludedTransitionInteractor.start()
-
- fromAlternateBouncerTransitionInteractor =
- FromAlternateBouncerTransitionInteractor(
- scope = testScope,
- keyguardInteractor = createKeyguardInteractor(),
- keyguardTransitionRepository = mockTransitionRepository,
- keyguardTransitionInteractor =
- KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
- )
- fromAlternateBouncerTransitionInteractor.start()
-
- fromPrimaryBouncerTransitionInteractor =
- FromPrimaryBouncerTransitionInteractor(
- scope = testScope,
- keyguardInteractor = createKeyguardInteractor(),
- keyguardTransitionRepository = mockTransitionRepository,
- keyguardTransitionInteractor =
- KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
+ transitionRepository = transitionRepository,
+ transitionInteractor = transitionInteractor,
keyguardSecurityModel = keyguardSecurityModel,
- )
- fromPrimaryBouncerTransitionInteractor.start()
+ ).apply { start() }
+
+ fromDreamingTransitionInteractor = FromDreamingTransitionInteractor(
+ scope = testScope,
+ keyguardInteractor = createKeyguardInteractor(),
+ transitionRepository = transitionRepository,
+ transitionInteractor = transitionInteractor,
+ ).apply { start() }
+
+ fromAodTransitionInteractor = FromAodTransitionInteractor(
+ scope = testScope,
+ keyguardInteractor = createKeyguardInteractor(),
+ transitionRepository = transitionRepository,
+ transitionInteractor = transitionInteractor,
+ ).apply { start() }
+
+ fromGoneTransitionInteractor = FromGoneTransitionInteractor(
+ scope = testScope,
+ keyguardInteractor = createKeyguardInteractor(),
+ transitionRepository = transitionRepository,
+ transitionInteractor = transitionInteractor,
+ ).apply { start() }
+
+ fromDozingTransitionInteractor = FromDozingTransitionInteractor(
+ scope = testScope,
+ keyguardInteractor = createKeyguardInteractor(),
+ transitionRepository = transitionRepository,
+ transitionInteractor = transitionInteractor,
+ ).apply { start() }
+
+ fromOccludedTransitionInteractor = FromOccludedTransitionInteractor(
+ scope = testScope,
+ keyguardInteractor = createKeyguardInteractor(),
+ transitionRepository = transitionRepository,
+ transitionInteractor = transitionInteractor,
+ ).apply { start() }
+
+ fromAlternateBouncerTransitionInteractor = FromAlternateBouncerTransitionInteractor(
+ scope = testScope,
+ keyguardInteractor = createKeyguardInteractor(),
+ transitionRepository = transitionRepository,
+ transitionInteractor = transitionInteractor,
+ ).apply { start() }
}
@Test
@@ -201,7 +180,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to PRIMARY_BOUNCER should occur
assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor")
@@ -228,7 +207,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromOccludedTransitionInteractor")
@@ -255,7 +234,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromOccludedTransitionInteractor")
@@ -286,7 +265,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DREAMING should occur
assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor")
@@ -313,7 +292,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor")
@@ -340,7 +319,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor")
@@ -363,7 +342,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromDozingTransitionInteractor")
@@ -388,14 +367,14 @@
)
)
runCurrent()
- reset(mockTransitionRepository)
+ reset(transitionRepository)
// WHEN a signal comes that dreaming is enabled
keyguardRepository.setDreamingWithOverlay(true)
advanceUntilIdle()
// THEN the transition is ignored
- verify(mockTransitionRepository, never()).startTransition(any(), anyBoolean())
+ verify(transitionRepository, never()).startTransition(any(), anyBoolean())
coroutineContext.cancelChildren()
}
@@ -412,7 +391,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromDozingTransitionInteractor")
@@ -439,7 +418,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor")
@@ -466,7 +445,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to AOD should occur
assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor")
@@ -489,7 +468,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to AOD should occur
assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor")
@@ -520,7 +499,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DREAMING should occur
assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor")
@@ -543,7 +522,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to PRIMARY_BOUNCER should occur
assertThat(info.ownerName).isEqualTo("FromAlternateBouncerTransitionInteractor")
@@ -572,7 +551,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to AOD should occur
assertThat(info.ownerName).isEqualTo("FromAlternateBouncerTransitionInteractor")
@@ -602,7 +581,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromAlternateBouncerTransitionInteractor")
@@ -630,7 +609,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to LOCKSCREEN should occur
assertThat(info.ownerName).isEqualTo("FromAlternateBouncerTransitionInteractor")
@@ -658,7 +637,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to AOD should occur
assertThat(info.ownerName).isEqualTo("FromPrimaryBouncerTransitionInteractor")
@@ -686,7 +665,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromPrimaryBouncerTransitionInteractor")
@@ -713,7 +692,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to LOCKSCREEN should occur
assertThat(info.ownerName).isEqualTo("FromPrimaryBouncerTransitionInteractor")
@@ -744,7 +723,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to GONE should occur
assertThat(info.ownerName).isEqualTo("FromOccludedTransitionInteractor")
@@ -773,7 +752,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to LOCKSCREEN should occur
assertThat(info.ownerName).isEqualTo("FromOccludedTransitionInteractor")
@@ -799,7 +778,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to AlternateBouncer should occur
assertThat(info.ownerName).isEqualTo("FromOccludedTransitionInteractor")
@@ -828,7 +807,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to AlternateBouncer should occur
assertThat(info.ownerName).isEqualTo("FromPrimaryBouncerTransitionInteractor")
@@ -890,6 +869,6 @@
)
)
runCurrent()
- reset(mockTransitionRepository)
+ reset(transitionRepository)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractorTest.kt
index 65781c4..c9fce94 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractorTest.kt
@@ -26,7 +26,6 @@
import com.android.systemui.scene.shared.model.SceneModel
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Test
@@ -38,8 +37,8 @@
@RunWith(JUnit4::class)
class LockscreenSceneInteractorTest : SysuiTestCase() {
- private val testScope = TestScope()
- private val utils = SceneTestUtils(this, testScope)
+ private val utils = SceneTestUtils(this)
+ private val testScope = utils.testScope
private val sceneInteractor = utils.sceneInteractor()
private val authenticationInteractor =
utils.authenticationInteractor(
@@ -74,7 +73,7 @@
val isSwipeToDismissEnabled by collectLastValue(underTest.isSwipeToDismissEnabled)
authenticationInteractor.lockDevice()
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
assertThat(isSwipeToDismissEnabled).isTrue()
}
@@ -85,7 +84,7 @@
val isSwipeToDismissEnabled by collectLastValue(underTest.isSwipeToDismissEnabled)
authenticationInteractor.unlockDevice()
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
assertThat(isSwipeToDismissEnabled).isFalse()
}
@@ -95,7 +94,9 @@
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
authenticationInteractor.lockDevice()
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
underTest.dismissLockscreen()
@@ -108,7 +109,9 @@
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
authenticationInteractor.unlockDevice()
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
underTest.dismissLockscreen()
@@ -121,7 +124,7 @@
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
authenticationInteractor.lockDevice()
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
underTest.dismissLockscreen()
@@ -182,7 +185,7 @@
testScope.runTest {
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Lockscreen))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
assertThat(isUnlocked).isFalse()
sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Gone))
@@ -195,7 +198,9 @@
testScope.runTest {
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Lockscreen))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
assertThat(isUnlocked).isFalse()
sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Gone))
@@ -210,7 +215,7 @@
runCurrent()
sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Shade))
runCurrent()
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
runCurrent()
assertThat(isUnlocked).isFalse()
@@ -220,29 +225,16 @@
}
@Test
- fun authMethodChangedToNone_onLockScreenScene_dismissesLockScreen() =
- testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Lockscreen))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
-
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.None)
-
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
- }
-
- @Test
fun authMethodChangedToNone_notOnLockScreenScene_doesNotDismissLockScreen() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
runCurrent()
sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.QuickSettings))
runCurrent()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.QuickSettings))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.None)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.None)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.QuickSettings))
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
index f0ea007..e8c01f0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
@@ -29,7 +29,6 @@
import com.android.systemui.scene.shared.model.SceneModel
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Test
@@ -41,8 +40,8 @@
@RunWith(JUnit4::class)
class LockscreenSceneViewModelTest : SysuiTestCase() {
- private val testScope = TestScope()
- private val utils = SceneTestUtils(this, testScope)
+ private val utils = SceneTestUtils(this)
+ private val testScope = utils.testScope
private val sceneInteractor = utils.sceneInteractor()
private val authenticationInteractor =
utils.authenticationInteractor(
@@ -73,7 +72,7 @@
fun lockButtonIcon_whenLocked() =
testScope.runTest {
val lockButtonIcon by collectLastValue(underTest.lockButtonIcon)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password("password")
)
authenticationInteractor.lockDevice()
@@ -86,7 +85,7 @@
fun lockButtonIcon_whenUnlocked() =
testScope.runTest {
val lockButtonIcon by collectLastValue(underTest.lockButtonIcon)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password("password")
)
authenticationInteractor.unlockDevice()
@@ -99,7 +98,7 @@
fun upTransitionSceneKey_swipeToUnlockedEnabled_gone() =
testScope.runTest {
val upTransitionSceneKey by collectLastValue(underTest.upDestinationSceneKey)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
authenticationInteractor.lockDevice()
assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Gone)
@@ -109,7 +108,9 @@
fun upTransitionSceneKey_swipeToUnlockedNotEnabled_bouncer() =
testScope.runTest {
val upTransitionSceneKey by collectLastValue(underTest.upDestinationSceneKey)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
authenticationInteractor.lockDevice()
assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Bouncer)
@@ -119,7 +120,9 @@
fun onLockButtonClicked_deviceLockedSecurely_switchesToBouncer() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
authenticationInteractor.lockDevice()
runCurrent()
@@ -132,7 +135,9 @@
fun onContentClicked_deviceUnlocked_switchesToGone() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
authenticationInteractor.unlockDevice()
runCurrent()
@@ -145,7 +150,9 @@
fun onContentClicked_deviceLockedSecurely_switchesToBouncer() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
authenticationInteractor.lockDevice()
runCurrent()
@@ -158,7 +165,9 @@
fun onLockButtonClicked_deviceUnlocked_switchesToGone() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
authenticationInteractor.unlockDevice()
runCurrent()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
index 05a1699..1f9ec94 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
@@ -27,7 +27,6 @@
import com.android.systemui.scene.shared.model.SceneModel
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Test
@@ -39,8 +38,8 @@
@RunWith(JUnit4::class)
class QuickSettingsSceneViewModelTest : SysuiTestCase() {
- private val testScope = TestScope()
- private val utils = SceneTestUtils(this, testScope)
+ private val utils = SceneTestUtils(this)
+ private val testScope = utils.testScope
private val sceneInteractor = utils.sceneInteractor()
private val authenticationInteractor =
utils.authenticationInteractor(
@@ -70,7 +69,9 @@
fun onContentClicked_deviceUnlocked_switchesToGone() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
authenticationInteractor.unlockDevice()
runCurrent()
@@ -83,7 +84,9 @@
fun onContentClicked_deviceLockedSecurely_switchesToBouncer() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
authenticationInteractor.lockDevice()
runCurrent()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
index f8e1a9d..aaa0816 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
@@ -27,7 +27,6 @@
import com.android.systemui.scene.shared.model.SceneModel
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Test
@@ -39,8 +38,8 @@
@RunWith(JUnit4::class)
class ShadeSceneViewModelTest : SysuiTestCase() {
- private val testScope = TestScope()
- private val utils = SceneTestUtils(this, testScope)
+ private val utils = SceneTestUtils(this)
+ private val testScope = utils.testScope
private val sceneInteractor = utils.sceneInteractor()
private val authenticationInteractor =
utils.authenticationInteractor(
@@ -71,7 +70,9 @@
fun upTransitionSceneKey_deviceLocked_lockScreen() =
testScope.runTest {
val upTransitionSceneKey by collectLastValue(underTest.upDestinationSceneKey)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
authenticationInteractor.lockDevice()
assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Lockscreen)
@@ -81,7 +82,9 @@
fun upTransitionSceneKey_deviceUnlocked_gone() =
testScope.runTest {
val upTransitionSceneKey by collectLastValue(underTest.upDestinationSceneKey)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
authenticationInteractor.unlockDevice()
assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Gone)
@@ -91,7 +94,9 @@
fun onContentClicked_deviceUnlocked_switchesToGone() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
authenticationInteractor.unlockDevice()
runCurrent()
@@ -104,7 +109,9 @@
fun onContentClicked_deviceLockedSecurely_switchesToBouncer() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
authenticationInteractor.lockDevice()
runCurrent()
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt
new file mode 100644
index 0000000..a12393e
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.authentication.data.repository
+
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode
+import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
+
+class FakeAuthenticationRepository(
+ private val delegate: AuthenticationRepository,
+ private val onSecurityModeChanged: (SecurityMode) -> Unit,
+) : AuthenticationRepository by delegate {
+
+ private var authenticationMethod: AuthenticationMethodModel = DEFAULT_AUTHENTICATION_METHOD
+
+ override suspend fun getAuthenticationMethod(): AuthenticationMethodModel {
+ return authenticationMethod
+ }
+
+ fun setAuthenticationMethod(authenticationMethod: AuthenticationMethodModel) {
+ this.authenticationMethod = authenticationMethod
+ onSecurityModeChanged(authenticationMethod.toSecurityMode())
+ }
+
+ companion object {
+ val DEFAULT_AUTHENTICATION_METHOD =
+ AuthenticationMethodModel.Pin(listOf(1, 2, 3, 4), autoConfirm = false)
+
+ fun AuthenticationMethodModel.toSecurityMode(): SecurityMode {
+ return when (this) {
+ is AuthenticationMethodModel.Pin -> SecurityMode.PIN
+ is AuthenticationMethodModel.Password -> SecurityMode.Password
+ is AuthenticationMethodModel.Pattern -> SecurityMode.Pattern
+ is AuthenticationMethodModel.Swipe,
+ is AuthenticationMethodModel.None -> SecurityMode.None
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
index 9c4fd94..6f228f4 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
@@ -16,9 +16,12 @@
package com.android.systemui.scene
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode
import com.android.systemui.SysuiTestCase
import com.android.systemui.authentication.data.repository.AuthenticationRepository
import com.android.systemui.authentication.data.repository.AuthenticationRepositoryImpl
+import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
+import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository.Companion.toSecurityMode
import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
import com.android.systemui.bouncer.data.repository.BouncerRepository
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
@@ -28,8 +31,12 @@
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.model.SceneContainerConfig
import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.user.data.repository.FakeUserRepository
+import com.android.systemui.util.mockito.mock
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestDispatcher
import kotlinx.coroutines.test.TestScope
/**
@@ -39,9 +46,23 @@
@OptIn(ExperimentalCoroutinesApi::class)
class SceneTestUtils(
test: SysuiTestCase,
- private val testScope: TestScope? = null,
) {
-
+ val testDispatcher: TestDispatcher by lazy { StandardTestDispatcher() }
+ val testScope: TestScope by lazy { TestScope(testDispatcher) }
+ private var securityMode: SecurityMode =
+ FakeAuthenticationRepository.DEFAULT_AUTHENTICATION_METHOD.toSecurityMode()
+ val authenticationRepository: FakeAuthenticationRepository by lazy {
+ FakeAuthenticationRepository(
+ delegate =
+ AuthenticationRepositoryImpl(
+ getSecurityMode = { securityMode },
+ backgroundDispatcher = testDispatcher,
+ userRepository = FakeUserRepository(),
+ lockPatternUtils = mock(),
+ ),
+ onSecurityModeChanged = { securityMode = it },
+ )
+ }
private val context = test.context
fun fakeSceneContainerRepository(
@@ -82,7 +103,7 @@
}
fun authenticationRepository(): AuthenticationRepository {
- return AuthenticationRepositoryImpl()
+ return authenticationRepository
}
fun authenticationInteractor(
@@ -94,17 +115,6 @@
)
}
- private fun applicationScope(): CoroutineScope {
- return checkNotNull(testScope) {
- """
- TestScope not initialized, please create a TestScope and inject it into
- SceneTestUtils.
- """
- .trimIndent()
- }
- .backgroundScope
- }
-
fun bouncerInteractor(
authenticationInteractor: AuthenticationInteractor,
sceneInteractor: SceneInteractor,
@@ -154,6 +164,10 @@
)
}
+ private fun applicationScope(): CoroutineScope {
+ return testScope.backgroundScope
+ }
+
companion object {
const val CONTAINER_1 = "container1"
const val CONTAINER_2 = "container2"
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 719b2d2..2c381ca 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -347,9 +347,10 @@
@Override
public void showScreenPinningRequest(int taskId) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.showScreenPinningRequest(taskId);
+ bar.showScreenPinningRequest(taskId);
} catch (RemoteException e) {
}
}
@@ -357,9 +358,10 @@
@Override
public void showAssistDisclosure() {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.showAssistDisclosure();
+ bar.showAssistDisclosure();
} catch (RemoteException e) {
}
}
@@ -367,9 +369,10 @@
@Override
public void startAssist(Bundle args) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.startAssist(args);
+ bar.startAssist(args);
} catch (RemoteException e) {
}
}
@@ -377,9 +380,10 @@
@Override
public void onCameraLaunchGestureDetected(int source) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.onCameraLaunchGestureDetected(source);
+ bar.onCameraLaunchGestureDetected(source);
} catch (RemoteException e) {
}
}
@@ -393,9 +397,10 @@
@Override
public void onEmergencyActionLaunchGestureDetected() {
if (SPEW) Slog.d(TAG, "Launching emergency action");
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.onEmergencyActionLaunchGestureDetected();
+ bar.onEmergencyActionLaunchGestureDetected();
} catch (RemoteException e) {
if (SPEW) Slog.d(TAG, "Failed to launch emergency action");
}
@@ -410,9 +415,10 @@
@Override
public void toggleSplitScreen() {
enforceStatusBarService();
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.toggleSplitScreen();
+ bar.toggleSplitScreen();
} catch (RemoteException ex) {}
}
}
@@ -420,27 +426,30 @@
@Override
public void appTransitionFinished(int displayId) {
enforceStatusBarService();
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.appTransitionFinished(displayId);
+ bar.appTransitionFinished(displayId);
} catch (RemoteException ex) {}
}
}
@Override
public void toggleTaskbar() {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.toggleTaskbar();
+ bar.toggleTaskbar();
} catch (RemoteException ex) {}
}
}
@Override
public void toggleRecentApps() {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.toggleRecentApps();
+ bar.toggleRecentApps();
} catch (RemoteException ex) {}
}
}
@@ -454,45 +463,50 @@
@Override
public void preloadRecentApps() {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.preloadRecentApps();
+ bar.preloadRecentApps();
} catch (RemoteException ex) {}
}
}
@Override
public void cancelPreloadRecentApps() {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.cancelPreloadRecentApps();
+ bar.cancelPreloadRecentApps();
} catch (RemoteException ex) {}
}
}
@Override
public void showRecentApps(boolean triggeredFromAltTab) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.showRecentApps(triggeredFromAltTab);
+ bar.showRecentApps(triggeredFromAltTab);
} catch (RemoteException ex) {}
}
}
@Override
public void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.hideRecentApps(triggeredFromAltTab, triggeredFromHomeKey);
+ bar.hideRecentApps(triggeredFromAltTab, triggeredFromHomeKey);
} catch (RemoteException ex) {}
}
}
@Override
public void collapsePanels() {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.animateCollapsePanels();
+ bar.animateCollapsePanels();
} catch (RemoteException ex) {
}
}
@@ -500,18 +514,20 @@
@Override
public void dismissKeyboardShortcutsMenu() {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.dismissKeyboardShortcutsMenu();
+ bar.dismissKeyboardShortcutsMenu();
} catch (RemoteException ex) {}
}
}
@Override
public void toggleKeyboardShortcutsMenu(int deviceId) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.toggleKeyboardShortcutsMenu(deviceId);
+ bar.toggleKeyboardShortcutsMenu(deviceId);
} catch (RemoteException ex) {}
}
}
@@ -539,9 +555,10 @@
@Override
public void showChargingAnimation(int batteryLevel) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.showWirelessChargingAnimation(batteryLevel);
+ bar.showWirelessChargingAnimation(batteryLevel);
} catch (RemoteException ex){
}
}
@@ -549,7 +566,8 @@
@Override
public void showPictureInPictureMenu() {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
mBar.showPictureInPictureMenu();
} catch (RemoteException ex) {}
@@ -558,27 +576,30 @@
@Override
public void setWindowState(int displayId, int window, int state) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.setWindowState(displayId, window, state);
+ bar.setWindowState(displayId, window, state);
} catch (RemoteException ex) {}
}
}
@Override
public void appTransitionPending(int displayId) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.appTransitionPending(displayId);
+ bar.appTransitionPending(displayId);
} catch (RemoteException ex) {}
}
}
@Override
public void appTransitionCancelled(int displayId) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.appTransitionCancelled(displayId);
+ bar.appTransitionCancelled(displayId);
} catch (RemoteException ex) {}
}
}
@@ -586,9 +607,10 @@
@Override
public void appTransitionStarting(int displayId, long statusBarAnimationsStartTime,
long statusBarAnimationsDuration) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.appTransitionStarting(
+ bar.appTransitionStarting(
displayId, statusBarAnimationsStartTime, statusBarAnimationsDuration);
} catch (RemoteException ex) {}
}
@@ -596,9 +618,10 @@
@Override
public void setTopAppHidesStatusBar(boolean hidesStatusBar) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.setTopAppHidesStatusBar(hidesStatusBar);
+ bar.setTopAppHidesStatusBar(hidesStatusBar);
} catch (RemoteException ex) {}
}
}
@@ -608,9 +631,10 @@
if (!mContext.getResources().getBoolean(R.bool.config_showSysuiShutdown)) {
return false;
}
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.showShutdownUi(isReboot, reason);
+ bar.showShutdownUi(isReboot, reason);
return true;
} catch (RemoteException ex) {}
}
@@ -629,18 +653,20 @@
@Override
public void onDisplayReady(int displayId) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.onDisplayReady(displayId);
+ bar.onDisplayReady(displayId);
} catch (RemoteException ex) {}
}
}
@Override
public void onRecentsAnimationStateChanged(boolean running) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.onRecentsAnimationStateChanged(running);
+ bar.onRecentsAnimationStateChanged(running);
} catch (RemoteException ex) {}
}
@@ -654,9 +680,10 @@
getUiState(displayId).setBarAttributes(appearance, appearanceRegions,
navbarColorManagedByIme, behavior, requestedVisibleTypes, packageName,
letterboxDetails);
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.onSystemBarAttributesChanged(displayId, appearance, appearanceRegions,
+ bar.onSystemBarAttributesChanged(displayId, appearance, appearanceRegions,
navbarColorManagedByIme, behavior, requestedVisibleTypes, packageName,
letterboxDetails);
} catch (RemoteException ex) { }
@@ -667,9 +694,10 @@
public void showTransient(int displayId, @InsetsType int types,
boolean isGestureOnSystemBar) {
getUiState(displayId).showTransient(types);
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.showTransient(displayId, types, isGestureOnSystemBar);
+ bar.showTransient(displayId, types, isGestureOnSystemBar);
} catch (RemoteException ex) { }
}
}
@@ -677,9 +705,10 @@
@Override
public void abortTransient(int displayId, @InsetsType int types) {
getUiState(displayId).clearTransient(types);
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.abortTransient(displayId, types);
+ bar.abortTransient(displayId, types);
} catch (RemoteException ex) { }
}
}
@@ -688,9 +717,10 @@
public void showToast(int uid, String packageName, IBinder token, CharSequence text,
IBinder windowToken, int duration,
@Nullable ITransientNotificationCallback callback, int displayId) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.showToast(uid, packageName, token, text, windowToken, duration, callback,
+ bar.showToast(uid, packageName, token, text, windowToken, duration, callback,
displayId);
} catch (RemoteException ex) { }
}
@@ -698,18 +728,20 @@
@Override
public void hideToast(String packageName, IBinder token) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.hideToast(packageName, token);
+ bar.hideToast(packageName, token);
} catch (RemoteException ex) { }
}
}
@Override
public boolean requestWindowMagnificationConnection(boolean request) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.requestWindowMagnificationConnection(request);
+ bar.requestWindowMagnificationConnection(request);
return true;
} catch (RemoteException ex) { }
}
@@ -718,9 +750,10 @@
@Override
public void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.setNavigationBarLumaSamplingEnabled(displayId, enable);
+ bar.setNavigationBarLumaSamplingEnabled(displayId, enable);
} catch (RemoteException ex) { }
}
}
@@ -730,45 +763,50 @@
synchronized (mLock) {
mUdfpsRefreshRateRequestCallback = callback;
}
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.setUdfpsRefreshRateCallback(callback);
+ bar.setUdfpsRefreshRateCallback(callback);
} catch (RemoteException ex) { }
}
}
@Override
public void showRearDisplayDialog(int currentBaseState) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.showRearDisplayDialog(currentBaseState);
+ bar.showRearDisplayDialog(currentBaseState);
} catch (RemoteException ex) { }
}
}
@Override
public void goToFullscreenFromSplit() {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.goToFullscreenFromSplit();
+ bar.goToFullscreenFromSplit();
} catch (RemoteException ex) { }
}
}
@Override
public void enterStageSplitFromRunningApp(boolean leftOrTop) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.enterStageSplitFromRunningApp(leftOrTop);
+ bar.enterStageSplitFromRunningApp(leftOrTop);
} catch (RemoteException ex) { }
}
}
@Override
public void showMediaOutputSwitcher(String packageName) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.showMediaOutputSwitcher(packageName);
+ bar.showMediaOutputSwitcher(packageName);
} catch (RemoteException ex) {
}
}
@@ -791,9 +829,10 @@
@Override
public void showGlobalActions() {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.showGlobalActionsMenu();
+ bar.showGlobalActionsMenu();
} catch (RemoteException ex) {}
}
}
@@ -1116,9 +1155,10 @@
if (!state.disableEquals(net1, net2)) {
state.setDisabled(net1, net2);
mHandler.post(() -> mNotificationDelegate.onSetDisabled(net1));
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.disable(displayId, net1, net2);
+ bar.disable(displayId, net1, net2);
} catch (RemoteException ex) {
}
}
@@ -1176,9 +1216,10 @@
//Slog.d(TAG, "setIcon slot=" + slot + " index=" + index + " icon=" + icon);
mIcons.put(slot, icon);
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.setIcon(slot, icon);
+ bar.setIcon(slot, icon);
} catch (RemoteException ex) {
}
}
@@ -1197,9 +1238,10 @@
if (icon.visible != visibility) {
icon.visible = visibility;
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.setIcon(slot, icon);
+ bar.setIcon(slot, icon);
} catch (RemoteException ex) {
}
}
@@ -1214,9 +1256,10 @@
synchronized (mIcons) {
mIcons.remove(slot);
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.removeIcon(slot);
+ bar.removeIcon(slot);
} catch (RemoteException ex) {
}
}
@@ -1823,9 +1866,10 @@
@Override
public void showInattentiveSleepWarning() {
enforceStatusBarService();
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.showInattentiveSleepWarning();
+ bar.showInattentiveSleepWarning();
} catch (RemoteException ex) {
}
}
@@ -1834,9 +1878,10 @@
@Override
public void dismissInattentiveSleepWarning(boolean animated) {
enforceStatusBarService();
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.dismissInattentiveSleepWarning(animated);
+ bar.dismissInattentiveSleepWarning(animated);
} catch (RemoteException ex) {
}
}
@@ -1845,9 +1890,10 @@
@Override
public void suppressAmbientDisplay(boolean suppress) {
enforceStatusBarService();
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.suppressAmbientDisplay(suppress);
+ bar.suppressAmbientDisplay(suppress);
} catch (RemoteException ex) {
}
}
@@ -1921,9 +1967,10 @@
}
}
}
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.requestTileServiceListeningState(componentName);
+ bar.requestTileServiceListeningState(componentName);
} catch (RemoteException e) {
Slog.e(TAG, "requestTileServiceListeningState", e);
}
@@ -2036,9 +2083,10 @@
CharSequence appName = r.serviceInfo.applicationInfo
.loadLabel(mContext.getPackageManager());
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.requestAddTile(componentName, appName, label, icon, proxyCallback);
+ bar.requestAddTile(componentName, appName, label, icon, proxyCallback);
return;
} catch (RemoteException e) {
Slog.e(TAG, "requestAddTile", e);
@@ -2060,9 +2108,10 @@
private void cancelRequestAddTileInternal(String packageName) {
clearTileAddRequest(packageName);
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.cancelRequestAddTile(packageName);
+ bar.cancelRequestAddTile(packageName);
} catch (RemoteException e) {
Slog.e(TAG, "requestAddTile", e);
}
@@ -2191,9 +2240,10 @@
@Nullable IUndoMediaTransferCallback undoCallback
) {
enforceMediaContentControl();
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.updateMediaTapToTransferSenderDisplay(displayState, routeInfo, undoCallback);
+ bar.updateMediaTapToTransferSenderDisplay(displayState, routeInfo, undoCallback);
} catch (RemoteException e) {
Slog.e(TAG, "updateMediaTapToTransferSenderDisplay", e);
}
@@ -2214,9 +2264,10 @@
@Nullable Icon appIcon,
@Nullable CharSequence appName) {
enforceMediaContentControl();
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.updateMediaTapToTransferReceiverDisplay(
+ bar.updateMediaTapToTransferReceiverDisplay(
displayState, routeInfo, appIcon, appName);
} catch (RemoteException e) {
Slog.e(TAG, "updateMediaTapToTransferReceiverDisplay", e);
@@ -2240,9 +2291,10 @@
@NonNull INearbyMediaDevicesProvider provider
) {
enforceMediaContentControl();
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.registerNearbyMediaDevicesProvider(provider);
+ bar.registerNearbyMediaDevicesProvider(provider);
} catch (RemoteException e) {
Slog.e(TAG, "registerNearbyMediaDevicesProvider", e);
}
@@ -2265,9 +2317,10 @@
@NonNull INearbyMediaDevicesProvider provider
) {
enforceMediaContentControl();
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.unregisterNearbyMediaDevicesProvider(provider);
+ bar.unregisterNearbyMediaDevicesProvider(provider);
} catch (RemoteException e) {
Slog.e(TAG, "unregisterNearbyMediaDevicesProvider", e);
}
@@ -2278,9 +2331,10 @@
@Override
public void showRearDisplayDialog(int currentState) {
enforceControlDeviceStatePermission();
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.showRearDisplayDialog(currentState);
+ bar.showRearDisplayDialog(currentState);
} catch (RemoteException e) {
Slog.e(TAG, "showRearDisplayDialog", e);
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index e1132db..12b5f5f 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1713,9 +1713,7 @@
}
private int getMinimalTaskSizeDp() {
- final Context displayConfigurationContext =
- mAtmService.mContext.createConfigurationContext(getConfiguration());
- final Resources res = displayConfigurationContext.getResources();
+ final Resources res = getDisplayUiContext().getResources();
final TypedValue value = new TypedValue();
res.getValue(R.dimen.default_minimal_size_resizable_task, value, true /* resolveRefs */);
final int valueUnit = ((value.data >> COMPLEX_UNIT_SHIFT) & COMPLEX_UNIT_MASK);
@@ -2716,6 +2714,7 @@
if (mDisplayPolicy != null) {
mDisplayPolicy.onConfigurationChanged();
mPinnedTaskController.onPostDisplayConfigurationChanged();
+ mMinSizeOfResizeableTaskDp = getMinimalTaskSizeDp();
}
// Update IME parent if needed.
updateImeParent();
@@ -2857,7 +2856,6 @@
void onDisplayInfoChanged() {
updateDisplayFrames(false /* notifyInsetsChange */);
- mMinSizeOfResizeableTaskDp = getMinimalTaskSizeDp();
mInputMonitor.layoutInputConsumers(mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
mDisplayPolicy.onDisplayInfoChanged(mDisplayInfo);
}
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 0059f0b..79a54c3 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -2674,7 +2674,10 @@
mController.mStateValidators.add(() -> {
for (int i = mTargets.size() - 1; i >= 0; --i) {
final ChangeInfo change = mTargets.get(i);
- if (!change.mContainer.isVisibleRequested()) continue;
+ if (!change.mContainer.isVisibleRequested()
+ || change.mContainer.mSurfaceControl == null) {
+ continue;
+ }
Slog.e(TAG, "Force show for visible " + change.mContainer
+ " which may be hidden by transition unexpectedly");
change.mContainer.getSyncTransaction().show(change.mContainer.mSurfaceControl);
diff --git a/services/tests/displayservicetests/Android.bp b/services/tests/displayservicetests/Android.bp
new file mode 100644
index 0000000..b242ec2
--- /dev/null
+++ b/services/tests/displayservicetests/Android.bp
@@ -0,0 +1,49 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+// Include all test java files.
+filegroup {
+ name: "displayservicetests-sources",
+ srcs: [
+ "src/**/*.java",
+ ],
+}
+
+android_test {
+ name: "DisplayServiceTests",
+
+ srcs: [
+ "src/**/*.java",
+ ],
+
+ static_libs: [
+ "services.core",
+ "androidx.test.runner",
+ "androidx.test.rules",
+ "platform-test-annotations",
+ ],
+
+ defaults: [
+ "modules-utils-testable-device-config-defaults",
+ ],
+
+ platform_apis: true,
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
+ certificate: "platform",
+
+ dxflags: ["--multi-dex"],
+
+ optimize: {
+ enabled: false,
+ },
+}
diff --git a/services/tests/displayservicetests/AndroidManifest.xml b/services/tests/displayservicetests/AndroidManifest.xml
new file mode 100644
index 0000000..c2e4174
--- /dev/null
+++ b/services/tests/displayservicetests/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.displayservicetests">
+
+ <!--
+ Insert permissions here. eg:
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+ -->
+
+ <application android:debuggable="true"
+ android:testOnly="true">
+ <uses-library android:name="android.test.mock" android:required="true" />
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:label="Display Service Tests"
+ android:targetPackage="com.android.frameworks.displayservicetests" />
+</manifest>
diff --git a/services/tests/displayservicetests/AndroidTest.xml b/services/tests/displayservicetests/AndroidTest.xml
new file mode 100644
index 0000000..2985f98
--- /dev/null
+++ b/services/tests/displayservicetests/AndroidTest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<configuration description="Runs Display Service Tests.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-instrumentation" />
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="install-arg" value="-t" />
+ <option name="test-file-name" value="DisplayServiceTests.apk" />
+ </target_preparer>
+
+ <option name="test-tag" value="DisplayServiceTests" />
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="com.android.frameworks.displayservicetests" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ <option name="hidden-api-checks" value="false" />
+ </test>
+</configuration>
diff --git a/services/tests/displayservicetests/TEST_MAPPING b/services/tests/displayservicetests/TEST_MAPPING
new file mode 100644
index 0000000..d865519
--- /dev/null
+++ b/services/tests/displayservicetests/TEST_MAPPING
@@ -0,0 +1,13 @@
+{
+ "presubmit": [
+ {
+ "name": "DisplayServiceTests",
+ "options": [
+ {"include-filter": "com.android.server.display"},
+ {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
+ {"exclude-annotation": "androidx.test.filters.FlakyTest"},
+ {"exclude-annotation": "org.junit.Ignore"}
+ ]
+ }
+ ]
+}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/OWNERS b/services/tests/displayservicetests/src/com/android/server/display/OWNERS
new file mode 100644
index 0000000..6ce1ee4
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/display/OWNERS
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationVisitUrisTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationVisitUrisTest.java
index a88ab18..d32289d 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationVisitUrisTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationVisitUrisTest.java
@@ -34,6 +34,7 @@
import android.os.IBinder;
import android.os.Parcel;
import android.util.Log;
+import android.view.LayoutInflater;
import android.view.View;
import android.widget.RemoteViews;
@@ -95,7 +96,8 @@
// Types that we can't really produce. No methods receiving these parameters will be invoked.
private static final ImmutableSet<Class<?>> UNUSABLE_TYPES =
ImmutableSet.of(Consumer.class, IBinder.class, MediaSession.Token.class, Parcel.class,
- PrintWriter.class, Resources.Theme.class, View.class);
+ PrintWriter.class, Resources.Theme.class, View.class,
+ LayoutInflater.Factory2.class);
// Maximum number of times we allow generating the same class recursively.
// E.g. new RemoteViews.addView(new RemoteViews()) but stop there.
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 340b591..5369b93 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -797,6 +797,7 @@
final int baseDensity = 320;
final float baseXDpi = 60;
final float baseYDpi = 60;
+ final int originalMinTaskSizeDp = displayContent.mMinSizeOfResizeableTaskDp;
displayContent.mInitialDisplayWidth = baseWidth;
displayContent.mInitialDisplayHeight = baseHeight;
@@ -814,6 +815,9 @@
displayContent.setForcedDensity(forcedDensity, 0 /* userId */);
verifySizes(displayContent, baseWidth, baseHeight, forcedDensity);
+ // Verify that minimal task size (dp) doesn't change with density of display.
+ assertEquals(originalMinTaskSizeDp, displayContent.mMinSizeOfResizeableTaskDp);
+
// Verify that forcing resolution won't affect the already forced density.
displayContent.setForcedSize(1800, 1200);
verifySizes(displayContent, 1800, 1200, forcedDensity);
@@ -1811,30 +1815,6 @@
assertFalse(mDisplayContent.hasTopFixedRotationLaunchingApp());
}
- /**
- * Creates different types of displays, verifies that minimal task size doesn't change
- * with density of display.
- */
- @Test
- public void testCalculatesDisplaySpecificMinTaskSizes() {
- DisplayContent defaultTestDisplay =
- new TestDisplayContent.Builder(mAtm, 1000, 2000).build();
- final int defaultMinTaskSize = defaultTestDisplay.mMinSizeOfResizeableTaskDp;
- DisplayContent firstDisplay = new TestDisplayContent.Builder(mAtm, 1000, 2000)
- .setDensityDpi(300)
- .updateDisplayMetrics()
- .setDefaultMinTaskSizeDp(defaultMinTaskSize + 10)
- .build();
- assertEquals(defaultMinTaskSize + 10, firstDisplay.mMinSizeOfResizeableTaskDp);
-
- DisplayContent secondDisplay = new TestDisplayContent.Builder(mAtm, 200, 200)
- .setDensityDpi(320)
- .updateDisplayMetrics()
- .setDefaultMinTaskSizeDp(defaultMinTaskSize + 20)
- .build();
- assertEquals(defaultMinTaskSize + 20, secondDisplay.mMinSizeOfResizeableTaskDp);
- }
-
@Test
public void testRecentsNotRotatingWithFixedRotation() {
unblockDisplayRotation(mDisplayContent);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
index 7e4a9de..4639ee0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
@@ -30,30 +30,18 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.content.Context;
import android.content.res.Configuration;
-import android.content.res.Resources;
import android.graphics.Insets;
import android.graphics.Rect;
import android.hardware.display.DisplayManagerGlobal;
-import android.util.DisplayMetrics;
-import android.util.TypedValue;
import android.view.Display;
import android.view.DisplayCutout;
import android.view.DisplayInfo;
import com.android.server.wm.DisplayWindowSettings.SettingsProvider.SettingsEntry;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-
class TestDisplayContent extends DisplayContent {
public static final int DEFAULT_LOGICAL_DISPLAY_DENSITY = 300;
@@ -105,13 +93,8 @@
private boolean mSystemDecorations = false;
private int mStatusBarHeight = 0;
private SettingsEntry mOverrideSettings;
- private DisplayMetrics mDisplayMetrics;
@NonNull
private DeviceStateController mDeviceStateController = mock(DeviceStateController.class);
- @Mock
- Context mMockContext;
- @Mock
- Resources mResources;
Builder(ActivityTaskManagerService service, int width, int height) {
mService = service;
@@ -124,8 +107,6 @@
// Set unique ID so physical display overrides are not inheritted from
// DisplayWindowSettings.
mInfo.uniqueId = generateUniqueId();
- mDisplayMetrics = new DisplayMetrics();
- updateDisplayMetrics();
}
Builder(ActivityTaskManagerService service, DisplayInfo info) {
mService = service;
@@ -195,31 +176,7 @@
mInfo.logicalDensityDpi = dpi;
return this;
}
- Builder updateDisplayMetrics() {
- mInfo.getAppMetrics(mDisplayMetrics);
- return this;
- }
- Builder setDefaultMinTaskSizeDp(int valueDp) {
- MockitoAnnotations.initMocks(this);
- doReturn(mMockContext).when(mService.mContext).createConfigurationContext(any());
- doReturn(mResources).when(mMockContext).getResources();
- doAnswer(
- new Answer() {
- @Override
- public Object answer(InvocationOnMock i) {
- Object[] args = i.getArguments();
- TypedValue v = (TypedValue) args[1];
- v.type = TypedValue.TYPE_DIMENSION;
- v.data = TypedValue.createComplexDimension(valueDp,
- TypedValue.COMPLEX_UNIT_DIP);
- return null;
- }
- }
- ).when(mResources).getValue(
- eq(com.android.internal.R.dimen.default_minimal_size_resizable_task),
- any(TypedValue.class), eq(true));
- return this;
- }
+
Builder setDeviceStateController(@NonNull DeviceStateController deviceStateController) {
mDeviceStateController = deviceStateController;
return this;