summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/WallpaperManager.java10
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/common/ui/view/LongPressHandlingViewInteractionHandlerTest.kt53
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java3
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/util/WallpaperControllerTest.kt2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt7
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/domain/interactor/WallpaperFocalAreaInteractorTest.kt312
-rw-r--r--packages/SystemUI/src/com/android/systemui/common/ui/view/LongPressHandlingView.kt37
-rw-r--r--packages/SystemUI/src/com/android/systemui/common/ui/view/LongPressHandlingViewInteractionHandler.kt44
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt37
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardLongPressViewBinder.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperFocalAreaRepository.kt92
-rw-r--r--packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt22
-rw-r--r--packages/SystemUI/src/com/android/systemui/wallpapers/domain/interactor/WallpaperFocalAreaInteractor.kt (renamed from packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WallpaperFocalAreaInteractor.kt)89
-rw-r--r--packages/SystemUI/src/com/android/systemui/wallpapers/ui/viewmodel/WallpaperFocalAreaViewModel.kt37
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardClockRepository.kt8
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt25
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt5
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperFocalAreaRepository.kt62
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt44
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/WallpaperFocalAreaRepositoryKosmos.kt (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt)17
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryKosmos.kt21
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/domain/interactor/WallpaperFocalAreaInteractor.kt (renamed from packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/WallpaperFocalAreaInteractorKosmos.kt)8
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/ui/viewmodel/WallpaperFocalAreaViewModel.kt25
35 files changed, 766 insertions, 284 deletions
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 076f856635b5..957482450893 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -297,6 +297,16 @@ public class WallpaperManager {
"android.wallpaper.lockscreen_layout_changed";
/**
+ * Command for {@link #sendWallpaperCommand}: Include the tap position within the wallpaper
+ * focal area.The x and y arguments are the absolute tap coordinates, already scaled to match
+ * the wallpaper's dimensions.
+ *
+ * @hide
+ */
+ public static final String COMMAND_LOCKSCREEN_TAP =
+ "android.wallpaper.lockscreen_tap";
+
+ /**
* Extra passed back from setWallpaper() giving the new wallpaper's assigned ID.
* @hide
*/
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/common/ui/view/LongPressHandlingViewInteractionHandlerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/common/ui/view/LongPressHandlingViewInteractionHandlerTest.kt
index 262c5903ec83..30da8d8d47ad 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/common/ui/view/LongPressHandlingViewInteractionHandlerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/common/ui/view/LongPressHandlingViewInteractionHandlerTest.kt
@@ -44,7 +44,7 @@ class LongPressHandlingViewInteractionHandlerTest : SysuiTestCase() {
@Mock private lateinit var postDelayed: (Runnable, Long) -> DisposableHandle
@Mock private lateinit var onLongPressDetected: (Int, Int) -> Unit
- @Mock private lateinit var onSingleTapDetected: () -> Unit
+ @Mock private lateinit var onSingleTapDetected: (Int, Int) -> Unit
private lateinit var underTest: LongPressHandlingViewInteractionHandler
@@ -76,74 +76,51 @@ class LongPressHandlingViewInteractionHandlerTest : SysuiTestCase() {
val downX = 123
val downY = 456
dispatchTouchEvents(
- Down(
- x = downX,
- y = downY,
- ),
- Move(
- distanceMoved = ViewConfiguration.getTouchSlop() - 0.1f,
- ),
+ Down(x = downX, y = downY),
+ Move(distanceMoved = ViewConfiguration.getTouchSlop() - 0.1f),
)
delayedRunnable?.run()
verify(onLongPressDetected).invoke(downX, downY)
- verify(onSingleTapDetected, never()).invoke()
+ verify(onSingleTapDetected, never()).invoke(any(), any())
}
@Test
fun longPressButFeatureNotEnabled() = runTest {
underTest.isLongPressHandlingEnabled = false
- dispatchTouchEvents(
- Down(
- x = 123,
- y = 456,
- ),
- )
+ dispatchTouchEvents(Down(x = 123, y = 456))
assertThat(delayedRunnable).isNull()
verify(onLongPressDetected, never()).invoke(any(), any())
- verify(onSingleTapDetected, never()).invoke()
+ verify(onSingleTapDetected, never()).invoke(any(), any())
}
@Test
fun longPressButViewNotAttached() = runTest {
isAttachedToWindow = false
- dispatchTouchEvents(
- Down(
- x = 123,
- y = 456,
- ),
- )
+ dispatchTouchEvents(Down(x = 123, y = 456))
delayedRunnable?.run()
verify(onLongPressDetected, never()).invoke(any(), any())
- verify(onSingleTapDetected, never()).invoke()
+ verify(onSingleTapDetected, never()).invoke(any(), any())
}
@Test
fun draggedTooFarToBeConsideredAlongPress() = runTest {
dispatchTouchEvents(
- Down(
- x = 123,
- y = 456,
- ),
- Move(
- distanceMoved = ViewConfiguration.getTouchSlop() + 0.1f,
- ),
+ Down(x = 123, y = 456),
+ Move(distanceMoved = ViewConfiguration.getTouchSlop() + 0.1f),
)
assertThat(delayedRunnable).isNull()
verify(onLongPressDetected, never()).invoke(any(), any())
- verify(onSingleTapDetected, never()).invoke()
+ verify(onSingleTapDetected, never()).invoke(any(), any())
}
@Test
fun heldDownTooBrieflyToBeConsideredAlongPress() = runTest {
dispatchTouchEvents(
- Down(
- x = 123,
- y = 456,
- ),
+ Down(x = 123, y = 456),
Up(
distanceMoved = ViewConfiguration.getTouchSlop().toFloat(),
gestureDuration = ViewConfiguration.getLongPressTimeout() - 1L,
@@ -152,12 +129,10 @@ class LongPressHandlingViewInteractionHandlerTest : SysuiTestCase() {
assertThat(delayedRunnable).isNull()
verify(onLongPressDetected, never()).invoke(any(), any())
- verify(onSingleTapDetected).invoke()
+ verify(onSingleTapDetected).invoke(123, 456)
}
- private fun dispatchTouchEvents(
- vararg models: MotionEventModel,
- ) {
+ private fun dispatchTouchEvents(vararg models: MotionEventModel) {
models.forEach { model -> underTest.onTouchEvent(model) }
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index 85e59364d6b6..2dce4aa01d24 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -167,6 +167,7 @@ import com.android.systemui.user.domain.interactor.UserSwitcherInteractor;
import com.android.systemui.util.kotlin.JavaAdapter;
import com.android.systemui.util.time.FakeSystemClock;
import com.android.systemui.util.time.SystemClock;
+import com.android.systemui.wallpapers.ui.viewmodel.WallpaperFocalAreaViewModel;
import com.android.wm.shell.animation.FlingAnimationUtils;
import dagger.Lazy;
@@ -270,6 +271,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {
mDreamingToLockscreenTransitionViewModel;
@Mock protected KeyguardTransitionInteractor mKeyguardTransitionInteractor;
@Mock protected KeyguardTouchHandlingViewModel mKeyuardTouchHandlingViewModel;
+ @Mock protected WallpaperFocalAreaViewModel mWallpaperFocalAreaViewModel;
@Mock protected AlternateBouncerInteractor mAlternateBouncerInteractor;
@Mock protected MotionEvent mDownMotionEvent;
@Mock protected CoroutineDispatcher mMainDispatcher;
@@ -574,6 +576,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {
mKeyguardTransitionInteractor,
mDumpManager,
mKeyuardTouchHandlingViewModel,
+ mWallpaperFocalAreaViewModel,
mKeyguardInteractor,
mActivityStarter,
mSharedNotificationContainerInteractor,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/util/WallpaperControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/WallpaperControllerTest.kt
index 6271904b2f04..9f2f60342d7c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/util/WallpaperControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/WallpaperControllerTest.kt
@@ -86,7 +86,7 @@ class WallpaperControllerTest : SysuiTestCase() {
@Test
fun setUnfoldTransitionZoom_defaultUnfoldTransitionIsDisabled_doesNotUpdateWallpaperZoom() {
- wallpaperRepository.wallpaperInfo.value = createWallpaperInfo(useDefaultTransition = false)
+ wallpaperRepository.setWallpaperInfo(createWallpaperInfo(useDefaultTransition = false))
wallaperController.setUnfoldTransitionZoom(0.5f)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt
index 1f5e7cace8eb..5afc6b1b85a3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt
@@ -27,8 +27,6 @@ import androidx.test.filters.SmallTest
import com.android.internal.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.keyguard.data.repository.FakeKeyguardClockRepository
-import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.res.R as SysUIR
import com.android.systemui.shared.Flags as SharedFlags
import com.android.systemui.user.data.model.SelectedUserModel
@@ -53,8 +51,7 @@ class WallpaperRepositoryImplTest : SysuiTestCase() {
private val testDispatcher = StandardTestDispatcher()
private val testScope = TestScope(testDispatcher)
private val userRepository = FakeUserRepository()
- private val keyguardClockRepository = FakeKeyguardClockRepository()
- private val keyguardRepository = FakeKeyguardRepository()
+ private val wallpaperFocalAreaRepository = FakeWallpaperFocalAreaRepository()
private val wallpaperManager: WallpaperManager = mock()
private val underTest: WallpaperRepositoryImpl by lazy {
@@ -63,7 +60,7 @@ class WallpaperRepositoryImplTest : SysuiTestCase() {
testDispatcher,
fakeBroadcastDispatcher,
userRepository,
- keyguardRepository,
+ wallpaperFocalAreaRepository,
wallpaperManager,
context,
)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/domain/interactor/WallpaperFocalAreaInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/domain/interactor/WallpaperFocalAreaInteractorTest.kt
new file mode 100644
index 000000000000..cd6e18a69c4d
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/domain/interactor/WallpaperFocalAreaInteractorTest.kt
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2025 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.wallpapers.domain.interactor
+
+import android.content.mockedContext
+import android.content.res.Resources
+import android.graphics.PointF
+import android.graphics.RectF
+import android.util.DisplayMetrics
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.currentValue
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.res.R
+import com.android.systemui.shade.data.repository.ShadeRepository
+import com.android.systemui.shade.data.repository.shadeRepository
+import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
+import com.android.systemui.statusbar.notification.data.repository.setActiveNotifs
+import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
+import com.android.systemui.testKosmos
+import com.android.systemui.wallpapers.data.repository.fakeWallpaperFocalAreaRepository
+import com.android.systemui.wallpapers.data.repository.wallpaperFocalAreaRepository
+import com.android.systemui.wallpapers.data.repository.wallpaperRepository
+import com.android.systemui.wallpapers.ui.viewmodel.wallpaperFocalAreaViewModel
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.advanceUntilIdle
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
+
+@ExperimentalCoroutinesApi
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class WallpaperFocalAreaInteractorTest : SysuiTestCase() {
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+ lateinit var shadeRepository: ShadeRepository
+ private lateinit var mockedResources: Resources
+ lateinit var underTest: WallpaperFocalAreaInteractor
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ mockedResources = mock<Resources>()
+ whenever(kosmos.mockedContext.resources).thenReturn(mockedResources)
+ whenever(
+ mockedResources.getFloat(
+ Resources.getSystem()
+ .getIdentifier(
+ /* name= */ "config_wallpaperMaxScale",
+ /* defType= */ "dimen",
+ /* defPackage= */ "android",
+ )
+ )
+ )
+ .thenReturn(2f)
+ underTest =
+ WallpaperFocalAreaInteractor(
+ applicationScope = testScope.backgroundScope,
+ context = kosmos.mockedContext,
+ wallpaperFocalAreaRepository = kosmos.fakeWallpaperFocalAreaRepository,
+ shadeRepository = kosmos.shadeRepository,
+ activeNotificationsInteractor = kosmos.activeNotificationsInteractor,
+ wallpaperRepository = kosmos.wallpaperRepository,
+ )
+ }
+
+ private fun overrideMockedResources(overrideResources: OverrideResources) {
+ val displayMetrics =
+ DisplayMetrics().apply {
+ widthPixels = overrideResources.screenWidth
+ heightPixels = overrideResources.screenHeight
+ density = 2f
+ }
+ whenever(mockedResources.displayMetrics).thenReturn(displayMetrics)
+ whenever(mockedResources.getBoolean(R.bool.center_align_focal_area_shape))
+ .thenReturn(overrideResources.centerAlignFocalArea)
+ }
+
+ @Test
+ fun focalAreaBounds_withoutNotifications_inHandheldDevices() =
+ testScope.runTest {
+ overrideMockedResources(
+ OverrideResources(
+ screenWidth = 1000,
+ screenHeight = 2000,
+ centerAlignFocalArea = false,
+ )
+ )
+ val bounds by collectLastValue(underTest.wallpaperFocalAreaBounds)
+ kosmos.shadeRepository.setShadeLayoutWide(false)
+ kosmos.activeNotificationListRepository.setActiveNotifs(0)
+ kosmos.wallpaperFocalAreaRepository.setShortcutAbsoluteTop(1800F)
+ kosmos.wallpaperFocalAreaRepository.setNotificationDefaultTop(400F)
+ kosmos.wallpaperFocalAreaRepository.setNotificationStackAbsoluteBottom(400F)
+
+ assertThat(bounds).isEqualTo(RectF(250f, 700F, 750F, 1400F))
+ }
+
+ @Test
+ fun focalAreaBounds_withNotifications_inHandheldDevices() =
+ testScope.runTest {
+ overrideMockedResources(
+ OverrideResources(
+ screenWidth = 1000,
+ screenHeight = 2000,
+ centerAlignFocalArea = false,
+ )
+ )
+ val bounds by collectLastValue(underTest.wallpaperFocalAreaBounds)
+ kosmos.shadeRepository.setShadeLayoutWide(false)
+ kosmos.activeNotificationListRepository.setActiveNotifs(1)
+ kosmos.wallpaperFocalAreaRepository.setShortcutAbsoluteTop(1800F)
+ kosmos.wallpaperFocalAreaRepository.setNotificationDefaultTop(400F)
+ kosmos.wallpaperFocalAreaRepository.setNotificationStackAbsoluteBottom(600F)
+
+ assertThat(bounds).isEqualTo(RectF(250f, 800F, 750F, 1400F))
+ }
+
+ @Test
+ fun focalAreaBounds_withNotifications_inUnfoldLandscape() =
+ testScope.runTest {
+ overrideMockedResources(
+ OverrideResources(
+ screenWidth = 2000,
+ screenHeight = 1600,
+ centerAlignFocalArea = false,
+ )
+ )
+ val bounds by collectLastValue(underTest.wallpaperFocalAreaBounds)
+ kosmos.shadeRepository.setShadeLayoutWide(true)
+ kosmos.activeNotificationListRepository.setActiveNotifs(1)
+ kosmos.wallpaperFocalAreaRepository.setShortcutAbsoluteTop(1400F)
+ kosmos.wallpaperFocalAreaRepository.setNotificationDefaultTop(400F)
+ kosmos.wallpaperFocalAreaRepository.setNotificationStackAbsoluteBottom(600F)
+
+ assertThat(bounds).isEqualTo(RectF(500f, 600F, 1000F, 1100F))
+ }
+
+ @Test
+ fun focalAreaBounds_withoutNotifications_inUnfoldLandscape() =
+ testScope.runTest {
+ overrideMockedResources(
+ OverrideResources(
+ screenWidth = 2000,
+ screenHeight = 1600,
+ centerAlignFocalArea = false,
+ )
+ )
+ val bounds by collectLastValue(underTest.wallpaperFocalAreaBounds)
+ kosmos.shadeRepository.setShadeLayoutWide(true)
+ kosmos.activeNotificationListRepository.setActiveNotifs(0)
+ kosmos.wallpaperFocalAreaRepository.setShortcutAbsoluteTop(1400F)
+ kosmos.wallpaperFocalAreaRepository.setNotificationDefaultTop(400F)
+ kosmos.wallpaperFocalAreaRepository.setNotificationStackAbsoluteBottom(400F)
+
+ assertThat(bounds).isEqualTo(RectF(1000f, 600F, 1500F, 1100F))
+ }
+
+ @Test
+ fun focalAreaBounds_withNotifications_inUnfoldPortrait() =
+ testScope.runTest {
+ overrideMockedResources(
+ OverrideResources(
+ screenWidth = 1600,
+ screenHeight = 2000,
+ centerAlignFocalArea = false,
+ )
+ )
+ val bounds by collectLastValue(underTest.wallpaperFocalAreaBounds)
+ kosmos.shadeRepository.setShadeLayoutWide(false)
+ kosmos.activeNotificationListRepository.setActiveNotifs(1)
+ kosmos.wallpaperFocalAreaRepository.setShortcutAbsoluteTop(1800F)
+ kosmos.wallpaperFocalAreaRepository.setNotificationDefaultTop(400F)
+ kosmos.wallpaperFocalAreaRepository.setNotificationStackAbsoluteBottom(600F)
+
+ assertThat(bounds).isEqualTo(RectF(400f, 800F, 1200F, 1400F))
+ }
+
+ @Test
+ fun focalAreaBounds_withoutNotifications_inUnfoldPortrait() =
+ testScope.runTest {
+ overrideMockedResources(
+ OverrideResources(
+ screenWidth = 1600,
+ screenHeight = 2000,
+ centerAlignFocalArea = false,
+ )
+ )
+ val bounds by collectLastValue(underTest.wallpaperFocalAreaBounds)
+ kosmos.shadeRepository.setShadeLayoutWide(false)
+ kosmos.activeNotificationListRepository.setActiveNotifs(0)
+ kosmos.wallpaperFocalAreaRepository.setShortcutAbsoluteTop(1800F)
+ kosmos.wallpaperFocalAreaRepository.setNotificationDefaultTop(400F)
+ kosmos.wallpaperFocalAreaRepository.setNotificationStackAbsoluteBottom(600F)
+
+ assertThat(bounds).isEqualTo(RectF(400f, 800F, 1200F, 1400F))
+ }
+
+ @Test
+ fun focalAreaBounds_withNotifications_inTabletLandscape() =
+ testScope.runTest {
+ overrideMockedResources(
+ OverrideResources(
+ screenWidth = 3000,
+ screenHeight = 2000,
+ centerAlignFocalArea = true,
+ )
+ )
+ val bounds by collectLastValue(underTest.wallpaperFocalAreaBounds)
+ kosmos.shadeRepository.setShadeLayoutWide(true)
+ kosmos.activeNotificationListRepository.setActiveNotifs(1)
+ kosmos.wallpaperFocalAreaRepository.setShortcutAbsoluteTop(1800F)
+ kosmos.wallpaperFocalAreaRepository.setNotificationDefaultTop(200F)
+ kosmos.wallpaperFocalAreaRepository.setNotificationStackAbsoluteBottom(200F)
+
+ assertThat(bounds).isEqualTo(RectF(1000f, 600F, 2000F, 1400F))
+ }
+
+ @Test
+ fun focalAreaBounds_withoutNotifications_inTabletLandscape() =
+ testScope.runTest {
+ overrideMockedResources(
+ OverrideResources(
+ screenWidth = 3000,
+ screenHeight = 2000,
+ centerAlignFocalArea = true,
+ )
+ )
+ val bounds by collectLastValue(underTest.wallpaperFocalAreaBounds)
+ kosmos.shadeRepository.setShadeLayoutWide(true)
+ kosmos.activeNotificationListRepository.setActiveNotifs(0)
+ kosmos.wallpaperFocalAreaRepository.setShortcutAbsoluteTop(1800F)
+ kosmos.wallpaperFocalAreaRepository.setNotificationDefaultTop(400F)
+ kosmos.wallpaperFocalAreaRepository.setNotificationStackAbsoluteBottom(400F)
+
+ assertThat(bounds).isEqualTo(RectF(1000f, 600F, 2000F, 1400F))
+ }
+
+ @Test
+ fun onTap_inFocalBounds() =
+ testScope.runTest {
+ kosmos.wallpaperFocalAreaRepository.setTapPosition(PointF(0F, 0F))
+ overrideMockedResources(
+ OverrideResources(
+ screenWidth = 1000,
+ screenHeight = 2000,
+ centerAlignFocalArea = false,
+ )
+ )
+ kosmos.wallpaperFocalAreaRepository.setWallpaperFocalAreaBounds(
+ RectF(250f, 700F, 750F, 1400F)
+ )
+ advanceUntilIdle()
+ assertThat(currentValue(kosmos.wallpaperFocalAreaRepository.wallpaperFocalAreaBounds))
+ .isEqualTo(RectF(250f, 700F, 750F, 1400F))
+ underTest.setTapPosition(750F, 750F)
+ assertThat(
+ currentValue(kosmos.wallpaperFocalAreaRepository.wallpaperFocalAreaTapPosition)
+ )
+ .isEqualTo(PointF(625F, 875F))
+ }
+
+ @Test
+ fun onTap_outFocalBounds() =
+ testScope.runTest {
+ kosmos.wallpaperFocalAreaRepository.setTapPosition(PointF(0F, 0F))
+ overrideMockedResources(
+ OverrideResources(
+ screenWidth = 1000,
+ screenHeight = 2000,
+ centerAlignFocalArea = false,
+ )
+ )
+ kosmos.wallpaperFocalAreaViewModel = mock()
+ kosmos.wallpaperFocalAreaRepository.setWallpaperFocalAreaBounds(
+ RectF(500F, 500F, 1000F, 1000F)
+ )
+ underTest.setTapPosition(250F, 250F)
+ assertThat(
+ currentValue(kosmos.wallpaperFocalAreaRepository.wallpaperFocalAreaTapPosition)
+ )
+ .isEqualTo(PointF(0F, 0F))
+ }
+
+ data class OverrideResources(
+ val screenWidth: Int,
+ val screenHeight: Int,
+ val centerAlignFocalArea: Boolean,
+ )
+}
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/view/LongPressHandlingView.kt b/packages/SystemUI/src/com/android/systemui/common/ui/view/LongPressHandlingView.kt
index 9c4736a13b46..dbe3dd09cb13 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/view/LongPressHandlingView.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/view/LongPressHandlingView.kt
@@ -45,11 +45,7 @@ class LongPressHandlingView(
longPressDuration: () -> Long,
allowedTouchSlop: Int = ViewConfiguration.getTouchSlop(),
logger: LongPressHandlingViewLogger? = null,
-) :
- View(
- context,
- attrs,
- ) {
+) : View(context, attrs) {
init {
setupAccessibilityDelegate()
@@ -62,15 +58,10 @@ class LongPressHandlingView(
interface Listener {
/** Notifies that a long-press has been detected by the given view. */
- fun onLongPressDetected(
- view: View,
- x: Int,
- y: Int,
- isA11yAction: Boolean = false,
- )
+ fun onLongPressDetected(view: View, x: Int, y: Int, isA11yAction: Boolean = false)
/** Notifies that the gesture was too short for a long press, it is actually a click. */
- fun onSingleTapDetected(view: View) = Unit
+ fun onSingleTapDetected(view: View, x: Int, y: Int) = Unit
}
var listener: Listener? = null
@@ -82,23 +73,17 @@ class LongPressHandlingView(
postDelayed = { block, timeoutMs ->
val dispatchToken = Any()
- handler.postDelayed(
- block,
- dispatchToken,
- timeoutMs,
- )
+ handler.postDelayed(block, dispatchToken, timeoutMs)
DisposableHandle { handler.removeCallbacksAndMessages(dispatchToken) }
},
isAttachedToWindow = ::isAttachedToWindow,
onLongPressDetected = { x, y ->
- listener?.onLongPressDetected(
- view = this,
- x = x,
- y = y,
- )
+ listener?.onLongPressDetected(view = this, x = x, y = y)
+ },
+ onSingleTapDetected = { x, y ->
+ listener?.onSingleTapDetected(this@LongPressHandlingView, x = x, y = y)
},
- onSingleTapDetected = { listener?.onSingleTapDetected(this@LongPressHandlingView) },
longPressDuration = longPressDuration,
allowedTouchSlop = allowedTouchSlop,
logger = logger,
@@ -129,7 +114,7 @@ class LongPressHandlingView(
object : AccessibilityDelegate() {
override fun onInitializeAccessibilityNodeInfo(
v: View,
- info: AccessibilityNodeInfo
+ info: AccessibilityNodeInfo,
) {
super.onInitializeAccessibilityNodeInfo(v, info)
if (
@@ -143,7 +128,7 @@ class LongPressHandlingView(
override fun performAccessibilityAction(
host: View,
action: Int,
- args: Bundle?
+ args: Bundle?,
): Boolean {
return if (
interactionHandler.isLongPressHandlingEnabled &&
@@ -179,7 +164,7 @@ private fun MotionEvent.toModel(): LongPressHandlingViewInteractionHandler.Motio
)
MotionEvent.ACTION_MOVE ->
LongPressHandlingViewInteractionHandler.MotionEventModel.Move(
- distanceMoved = distanceMoved(),
+ distanceMoved = distanceMoved()
)
MotionEvent.ACTION_UP ->
LongPressHandlingViewInteractionHandler.MotionEventModel.Up(
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/view/LongPressHandlingViewInteractionHandler.kt b/packages/SystemUI/src/com/android/systemui/common/ui/view/LongPressHandlingViewInteractionHandler.kt
index 4e38a4913fe6..a5d45aff4dc7 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/view/LongPressHandlingViewInteractionHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/view/LongPressHandlingViewInteractionHandler.kt
@@ -17,6 +17,7 @@
package com.android.systemui.common.ui.view
+import android.graphics.Point
import com.android.systemui.log.LongPressHandlingViewLogger
import kotlinx.coroutines.DisposableHandle
@@ -32,7 +33,7 @@ class LongPressHandlingViewInteractionHandler(
/** Callback reporting the a long-press gesture was detected at the given coordinates. */
private val onLongPressDetected: (x: Int, y: Int) -> Unit,
/** Callback reporting the a single tap gesture was detected at the given coordinates. */
- private val onSingleTapDetected: () -> Unit,
+ private val onSingleTapDetected: (x: Int, y: Int) -> Unit,
/** Time for the touch to be considered a long-press in ms */
var longPressDuration: () -> Long,
/**
@@ -47,19 +48,11 @@ class LongPressHandlingViewInteractionHandler(
sealed class MotionEventModel {
object Other : MotionEventModel()
- data class Down(
- val x: Int,
- val y: Int,
- ) : MotionEventModel()
+ data class Down(val x: Int, val y: Int) : MotionEventModel()
- data class Move(
- val distanceMoved: Float,
- ) : MotionEventModel()
+ data class Move(val distanceMoved: Float) : MotionEventModel()
- data class Up(
- val distanceMoved: Float,
- val gestureDuration: Long,
- ) : MotionEventModel()
+ data class Up(val distanceMoved: Float, val gestureDuration: Long) : MotionEventModel()
object Cancel : MotionEventModel()
}
@@ -67,14 +60,18 @@ class LongPressHandlingViewInteractionHandler(
var isLongPressHandlingEnabled: Boolean = false
var scheduledLongPressHandle: DisposableHandle? = null
+ /** Record coordinate for last DOWN event for single tap */
+ val lastEventDownCoordinate = Point(-1, -1)
+
fun onTouchEvent(event: MotionEventModel?): Boolean {
if (!isLongPressHandlingEnabled) {
return false
}
-
return when (event) {
is MotionEventModel.Down -> {
scheduleLongPress(event.x, event.y)
+ lastEventDownCoordinate.x = event.x
+ lastEventDownCoordinate.y = event.y
true
}
is MotionEventModel.Move -> {
@@ -92,7 +89,7 @@ class LongPressHandlingViewInteractionHandler(
event.gestureDuration < longPressDuration()
) {
logger?.dispatchingSingleTap()
- dispatchSingleTap()
+ dispatchSingleTap(lastEventDownCoordinate.x, lastEventDownCoordinate.y)
}
false
}
@@ -105,29 +102,20 @@ class LongPressHandlingViewInteractionHandler(
}
}
- private fun scheduleLongPress(
- x: Int,
- y: Int,
- ) {
+ private fun scheduleLongPress(x: Int, y: Int) {
val duration = longPressDuration()
logger?.schedulingLongPress(duration)
scheduledLongPressHandle =
postDelayed(
{
logger?.longPressTriggered()
- dispatchLongPress(
- x = x,
- y = y,
- )
+ dispatchLongPress(x = x, y = y)
},
duration,
)
}
- private fun dispatchLongPress(
- x: Int,
- y: Int,
- ) {
+ private fun dispatchLongPress(x: Int, y: Int) {
if (!isAttachedToWindow()) {
return
}
@@ -139,11 +127,11 @@ class LongPressHandlingViewInteractionHandler(
scheduledLongPressHandle?.dispose()
}
- private fun dispatchSingleTap() {
+ private fun dispatchSingleTap(x: Int, y: Int) {
if (!isAttachedToWindow()) {
return
}
- onSingleTapDetected()
+ onSingleTapDetected(x, y)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
index 869edfa2b886..23be5c52ab5c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
@@ -27,7 +27,6 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryHapticsInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
-import com.android.systemui.keyguard.domain.interactor.WallpaperFocalAreaInteractor
import com.android.systemui.keyguard.ui.binder.KeyguardBlueprintViewBinder
import com.android.systemui.keyguard.ui.binder.KeyguardJankBinder
import com.android.systemui.keyguard.ui.binder.KeyguardRootViewBinder
@@ -53,6 +52,8 @@ import com.android.systemui.statusbar.VibratorHelper
import com.android.systemui.statusbar.phone.ScreenOffAnimationController
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
import com.android.systemui.temporarydisplay.chipbar.ChipbarCoordinator
+import com.android.systemui.wallpapers.domain.interactor.WallpaperFocalAreaInteractor
+import com.android.systemui.wallpapers.ui.viewmodel.WallpaperFocalAreaViewModel
import com.android.systemui.wallpapers.ui.viewmodel.WallpaperViewModel
import com.google.android.msdl.domain.MSDLPlayer
import java.util.Optional
@@ -93,6 +94,7 @@ constructor(
@Main private val mainDispatcher: CoroutineDispatcher,
private val msdlPlayer: MSDLPlayer,
@KeyguardBlueprintLog private val blueprintLog: LogBuffer,
+ private val wallpaperFocalAreaViewModel: WallpaperFocalAreaViewModel,
) : CoreStartable {
private var rootViewHandle: DisposableHandle? = null
@@ -148,7 +150,6 @@ constructor(
screenOffAnimationController,
shadeInteractor,
clockInteractor,
- wallpaperFocalAreaInteractor,
keyguardClockViewModel,
deviceEntryHapticsInteractor,
vibratorHelper,
@@ -157,6 +158,7 @@ constructor(
mainDispatcher,
msdlPlayer,
blueprintLog,
+ wallpaperFocalAreaViewModel,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt
index 9718e7508df2..a4b9135d708f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt
@@ -69,16 +69,11 @@ interface KeyguardClockRepository {
val previewClock: Flow<ClockController>
- /** top of notifications without bcsmartspace in small clock settings */
- val notificationDefaultTop: StateFlow<Float>
-
val clockEventController: ClockEventController
val shouldForceSmallClock: Boolean
fun setClockSize(size: ClockSize)
-
- fun setNotificationDefaultTop(top: Float)
}
@SysUISingleton
@@ -155,14 +150,6 @@ constructor(
clockRegistry.createCurrentClock()
}
- private val _notificationDefaultTop: MutableStateFlow<Float> = MutableStateFlow(0F)
-
- override val notificationDefaultTop: StateFlow<Float> = _notificationDefaultTop.asStateFlow()
-
- override fun setNotificationDefaultTop(top: Float) {
- _notificationDefaultTop.value = top
- }
-
override val shouldForceSmallClock: Boolean
get() =
featureFlags.isEnabled(Flags.LOCKSCREEN_ENABLE_LANDSCAPE) &&
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
index 4b36e7a43dcb..acb98ede3e80 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
@@ -17,7 +17,6 @@
package com.android.systemui.keyguard.data.repository
import android.graphics.Point
-import android.graphics.RectF
import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.internal.widget.LockPatternUtils
import com.android.keyguard.KeyguardUpdateMonitor
@@ -255,13 +254,6 @@ interface KeyguardRepository {
*/
val isEncryptedOrLockdown: Flow<Boolean>
- /** The top of shortcut in screen, used by wallpaper to find remaining space in lockscreen */
- val shortcutAbsoluteTop: StateFlow<Float>
-
- val notificationStackAbsoluteBottom: StateFlow<Float>
-
- val wallpaperFocalAreaBounds: StateFlow<RectF>
-
/**
* Returns `true` if the keyguard is showing; `false` otherwise.
*
@@ -328,13 +320,6 @@ interface KeyguardRepository {
* otherwise.
*/
fun isShowKeyguardWhenReenabled(): Boolean
-
- fun setShortcutAbsoluteTop(top: Float)
-
- /** Set bottom of notifications from notification stack */
- fun setNotificationStackAbsoluteBottom(bottom: Float)
-
- fun setWallpaperFocalAreaBounds(bounds: RectF)
}
/** Encapsulates application state for the keyguard. */
@@ -621,16 +606,6 @@ constructor(
private val _isQuickSettingsVisible = MutableStateFlow(false)
override val isQuickSettingsVisible: Flow<Boolean> = _isQuickSettingsVisible.asStateFlow()
- private val _shortcutAbsoluteTop = MutableStateFlow(0F)
- override val shortcutAbsoluteTop = _shortcutAbsoluteTop.asStateFlow()
-
- private val _notificationStackAbsoluteBottom = MutableStateFlow(0F)
- override val notificationStackAbsoluteBottom = _notificationStackAbsoluteBottom.asStateFlow()
-
- private val _wallpaperFocalAreaBounds = MutableStateFlow(RectF(0F, 0F, 0F, 0F))
- override val wallpaperFocalAreaBounds: StateFlow<RectF> =
- _wallpaperFocalAreaBounds.asStateFlow()
-
init {
val callback =
object : KeyguardStateController.Callback {
@@ -705,18 +680,6 @@ constructor(
}
}
- override fun setShortcutAbsoluteTop(top: Float) {
- _shortcutAbsoluteTop.value = top
- }
-
- override fun setNotificationStackAbsoluteBottom(bottom: Float) {
- _notificationStackAbsoluteBottom.value = bottom
- }
-
- override fun setWallpaperFocalAreaBounds(bounds: RectF) {
- _wallpaperFocalAreaBounds.value = bounds
- }
-
private fun dozeMachineStateToModel(state: DozeMachine.State): DozeStateModel {
return when (state) {
DozeMachine.State.UNINITIALIZED -> DozeStateModel.UNINITIALIZED
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
index 126b375efb7d..4411437188f2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
@@ -22,6 +22,8 @@ import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository
import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepositoryImpl
import com.android.systemui.keyguard.shared.transition.KeyguardTransitionAnimationCallback
import com.android.systemui.keyguard.shared.transition.KeyguardTransitionAnimationCallbackDelegator
+import com.android.systemui.wallpapers.data.repository.WallpaperFocalAreaRepository
+import com.android.systemui.wallpapers.data.repository.WallpaperFocalAreaRepositoryImpl
import dagger.Binds
import dagger.Module
@@ -73,4 +75,9 @@ interface KeyguardRepositoryModule {
fun keyguardSmartspaceRepository(
impl: KeyguardSmartspaceRepositoryImpl
): KeyguardSmartspaceRepository
+
+ @Binds
+ fun bindWallpaperFocalAreaRepository(
+ impl: WallpaperFocalAreaRepositoryImpl
+ ): WallpaperFocalAreaRepository
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt
index ab5fdd608d03..dab4b5f4183c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt
@@ -37,6 +37,7 @@ import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor
import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationInteractor
import com.android.systemui.util.kotlin.combine
+import com.android.systemui.wallpapers.domain.interactor.WallpaperFocalAreaInteractor
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
@@ -62,6 +63,7 @@ constructor(
headsUpNotificationInteractor: HeadsUpNotificationInteractor,
@Application private val applicationScope: CoroutineScope,
val keyguardClockRepository: KeyguardClockRepository,
+ private val wallpaperFocalAreaInteractor: WallpaperFocalAreaInteractor,
) {
private val isOnAod: Flow<Boolean> =
keyguardTransitionInteractor.currentKeyguardState.map { it == KeyguardState.AOD }
@@ -183,6 +185,6 @@ constructor(
}
fun setNotificationStackDefaultTop(top: Float) {
- keyguardClockRepository.setNotificationDefaultTop(top)
+ wallpaperFocalAreaInteractor.setNotificationDefaultTop(top)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index 3652c17309f4..f84d29f57cc7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -52,6 +52,7 @@ import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.shade.data.repository.ShadeRepository
import com.android.systemui.util.kotlin.Utils.Companion.sample as sampleCombine
import com.android.systemui.util.kotlin.sample
+import com.android.systemui.wallpapers.data.repository.WallpaperFocalAreaRepository
import javax.inject.Inject
import javax.inject.Provider
import kotlinx.coroutines.CoroutineScope
@@ -85,6 +86,7 @@ class KeyguardInteractor
constructor(
private val repository: KeyguardRepository,
bouncerRepository: KeyguardBouncerRepository,
+ private val wallpaperFocalAreaRepository: WallpaperFocalAreaRepository,
@ShadeDisplayAware configurationInteractor: ConfigurationInteractor,
shadeRepository: ShadeRepository,
private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
@@ -532,7 +534,7 @@ constructor(
}
fun setShortcutAbsoluteTop(top: Float) {
- repository.setShortcutAbsoluteTop(top)
+ wallpaperFocalAreaRepository.setShortcutAbsoluteTop(top)
}
fun setIsKeyguardGoingAway(isGoingAway: Boolean) {
@@ -540,7 +542,7 @@ constructor(
}
fun setNotificationStackAbsoluteBottom(bottom: Float) {
- repository.setNotificationStackAbsoluteBottom(bottom)
+ wallpaperFocalAreaRepository.setNotificationStackAbsoluteBottom(bottom)
}
suspend fun hydrateTableLogBuffer(tableLogBuffer: TableLogBuffer) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardLongPressViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardLongPressViewBinder.kt
index 2fd9818a38f0..f0e5e16b092b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardLongPressViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardLongPressViewBinder.kt
@@ -43,13 +43,13 @@ object KeyguardLongPressViewBinder {
fun bind(
view: LongPressHandlingView,
viewModel: KeyguardTouchHandlingViewModel,
- onSingleTap: () -> Unit,
+ onSingleTap: (x: Int, y: Int) -> Unit,
falsingManager: FalsingManager,
) {
view.accessibilityHintLongPressAction =
AccessibilityNodeInfo.AccessibilityAction(
AccessibilityNodeInfoCompat.ACTION_LONG_CLICK,
- view.resources.getString(R.string.lock_screen_settings)
+ view.resources.getString(R.string.lock_screen_settings),
)
view.listener =
object : LongPressHandlingView.Listener {
@@ -57,7 +57,7 @@ object KeyguardLongPressViewBinder {
view: View,
x: Int,
y: Int,
- isA11yAction: Boolean
+ isA11yAction: Boolean,
) {
if (
!isA11yAction && falsingManager.isFalseLongTap(FalsingManager.LOW_PENALTY)
@@ -68,12 +68,12 @@ object KeyguardLongPressViewBinder {
viewModel.onLongPress(isA11yAction)
}
- override fun onSingleTapDetected(view: View) {
+ override fun onSingleTapDetected(view: View, x: Int, y: Int) {
if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
return
}
- onSingleTap()
+ onSingleTap(x, y)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
index b8020b19ce86..00710c97d00a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
@@ -50,7 +50,6 @@ import com.android.systemui.common.ui.view.onTouchListener
import com.android.systemui.customization.R as customR
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryHapticsInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
-import com.android.systemui.keyguard.domain.interactor.WallpaperFocalAreaInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.ui.view.layout.sections.AodPromotedNotificationSection
import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters
@@ -80,6 +79,7 @@ import com.android.systemui.util.ui.AnimatedValue
import com.android.systemui.util.ui.isAnimating
import com.android.systemui.util.ui.stopAnimating
import com.android.systemui.util.ui.value
+import com.android.systemui.wallpapers.ui.viewmodel.WallpaperFocalAreaViewModel
import com.google.android.msdl.data.model.MSDLToken
import com.google.android.msdl.domain.MSDLPlayer
import kotlin.math.min
@@ -104,7 +104,6 @@ object KeyguardRootViewBinder {
screenOffAnimationController: ScreenOffAnimationController,
shadeInteractor: ShadeInteractor,
clockInteractor: KeyguardClockInteractor,
- wallpaperFocalAreaInteractor: WallpaperFocalAreaInteractor,
clockViewModel: KeyguardClockViewModel,
deviceEntryHapticsInteractor: DeviceEntryHapticsInteractor?,
vibratorHelper: VibratorHelper?,
@@ -113,6 +112,7 @@ object KeyguardRootViewBinder {
mainImmediateDispatcher: CoroutineDispatcher,
msdlPlayer: MSDLPlayer?,
@KeyguardBlueprintLog blueprintLog: LogBuffer,
+ wallpaperFocalAreaViewModel: WallpaperFocalAreaViewModel,
): DisposableHandle {
val disposables = DisposableHandles()
val childViews = mutableMapOf<Int, View>()
@@ -368,13 +368,11 @@ object KeyguardRootViewBinder {
disposables +=
view.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.STARTED) {
- if (viewModel.shouldSendFocalArea.value) {
+ if (wallpaperFocalAreaViewModel.hasFocalArea.value) {
launch {
- wallpaperFocalAreaInteractor.wallpaperFocalAreaBounds
+ wallpaperFocalAreaViewModel.wallpaperFocalAreaBounds
.filterNotNull()
- .collect {
- wallpaperFocalAreaInteractor.setWallpaperFocalAreaBounds(it)
- }
+ .collect { wallpaperFocalAreaViewModel.setFocalAreaBounds(it) }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
index cff5cebf2011..85eae6ed98b3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
@@ -55,7 +55,6 @@ import com.android.systemui.customization.R as customR
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.keyguard.domain.interactor.WallpaperFocalAreaInteractor
import com.android.systemui.keyguard.shared.model.ClockSizeSetting
import com.android.systemui.keyguard.ui.binder.KeyguardPreviewClockViewBinder
import com.android.systemui.keyguard.ui.binder.KeyguardPreviewSmartspaceViewBinder
@@ -82,6 +81,7 @@ import com.android.systemui.statusbar.KeyguardIndicationController
import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController
import com.android.systemui.util.kotlin.DisposableHandles
import com.android.systemui.util.settings.SecureSettings
+import com.android.systemui.wallpapers.domain.interactor.WallpaperFocalAreaInteractor
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import kotlinx.coroutines.CoroutineDispatcher
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
index 53a063d1baf0..62a5ebab29e0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
@@ -28,7 +28,6 @@ import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.domain.interactor.PulseExpansionInteractor
-import com.android.systemui.keyguard.domain.interactor.WallpaperFocalAreaInteractor
import com.android.systemui.keyguard.shared.model.Edge
import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING
@@ -54,6 +53,7 @@ import com.android.systemui.util.ui.AnimatableEvent
import com.android.systemui.util.ui.AnimatedValue
import com.android.systemui.util.ui.toAnimatedValueFlow
import com.android.systemui.util.ui.zip
+import com.android.systemui.wallpapers.domain.interactor.WallpaperFocalAreaInteractor
import javax.inject.Inject
import kotlin.math.max
import kotlinx.coroutines.CoroutineScope
@@ -377,8 +377,6 @@ constructor(
initialValue = AnimatedValue.NotAnimating(false),
)
- val shouldSendFocalArea = wallpaperFocalAreaInteractor.shouldSendFocalArea
-
fun onNotificationContainerBoundsChanged(top: Float, bottom: Float, animate: Boolean = false) {
keyguardInteractor.setNotificationContainerBounds(
NotificationContainerBounds(top = top, bottom = bottom, isAnimated = animate)
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index e535019cd3d7..10d76fbd13a1 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -187,6 +187,7 @@ import com.android.systemui.unfold.SysUIUnfoldComponent;
import com.android.systemui.util.Compile;
import com.android.systemui.util.Utils;
import com.android.systemui.util.time.SystemClock;
+import com.android.systemui.wallpapers.ui.viewmodel.WallpaperFocalAreaViewModel;
import com.android.wm.shell.animation.FlingAnimationUtils;
import dalvik.annotation.optimization.NeverCompile;
@@ -261,7 +262,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
private final ShadeLogger mShadeLog;
private final DozeParameters mDozeParameters;
private final NotificationStackScrollLayout.OnEmptySpaceClickListener
- mOnEmptySpaceClickListener = (x, y) -> onEmptySpaceClick();
+ mOnEmptySpaceClickListener = this::onEmptySpaceClick;
private final ShadeHeadsUpChangedListener mOnHeadsUpChangedListener =
new ShadeHeadsUpChangedListener();
private final ConfigurationListener mConfigurationListener = new ConfigurationListener();
@@ -459,6 +460,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
private final NotificationListContainer mNotificationListContainer;
private final NPVCDownEventState.Buffer mLastDownEvents;
private final KeyguardClockInteractor mKeyguardClockInteractor;
+ private final WallpaperFocalAreaViewModel mWallpaperFocalAreaViewModel;
private float mMinExpandHeight;
private boolean mPanelUpdateWhenAnimatorEnds;
private boolean mHasVibratedOnOpen = false;
@@ -592,6 +594,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
KeyguardTransitionInteractor keyguardTransitionInteractor,
DumpManager dumpManager,
KeyguardTouchHandlingViewModel keyguardTouchHandlingViewModel,
+ WallpaperFocalAreaViewModel wallpaperFocalAreaViewModel,
KeyguardInteractor keyguardInteractor,
ActivityStarter activityStarter,
SharedNotificationContainerInteractor sharedNotificationContainerInteractor,
@@ -747,11 +750,13 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
SysUIUnfoldComponent::getKeyguardUnfoldTransition);
mKeyguardClockInteractor = keyguardClockInteractor;
+ mWallpaperFocalAreaViewModel = wallpaperFocalAreaViewModel;
+
KeyguardLongPressViewBinder.bind(
mView.requireViewById(R.id.keyguard_long_press),
keyguardTouchHandlingViewModel,
- () -> {
- onEmptySpaceClick();
+ (x, y) -> {
+ onEmptySpaceClick(x, y);
return Unit.INSTANCE;
},
mFalsingManager);
@@ -2071,7 +2076,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
}
}
- private void onMiddleClicked() {
+ private void onMiddleClicked(float x, float y) {
switch (mBarState) {
case KEYGUARD:
if (!mDozingOnDown) {
@@ -2090,6 +2095,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
mLockscreenGestureLogger
.log(LockscreenUiEvent.LOCKSCREEN_LOCK_SHOW_HINT);
mKeyguardIndicationController.showActionToUnlock();
+ mWallpaperFocalAreaViewModel.setTapPosition(x, y);
}
}
break;
@@ -2834,7 +2840,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
} else if (!mCentralSurfaces.isBouncerShowing()
&& !mAlternateBouncerInteractor.isVisibleState()
&& !mKeyguardStateController.isKeyguardGoingAway()) {
- onEmptySpaceClick();
+ onEmptySpaceClick(x, y);
onTrackingStopped(true);
}
mVelocityTracker.clear();
@@ -3142,8 +3148,8 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
}
/** Called when the user performs a click anywhere in the empty area of the panel. */
- private void onEmptySpaceClick() {
- onMiddleClicked();
+ private void onEmptySpaceClick(float x, float y) {
+ onMiddleClicked(x, y);
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperFocalAreaRepository.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperFocalAreaRepository.kt
new file mode 100644
index 000000000000..2c3491b06a90
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperFocalAreaRepository.kt
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2025 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.wallpapers.data.repository
+
+import android.graphics.PointF
+import android.graphics.RectF
+import com.android.systemui.dagger.SysUISingleton
+import javax.inject.Inject
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+interface WallpaperFocalAreaRepository {
+
+ /** The top of shortcut in screen, used by wallpaper to find remaining space in lockscreen */
+ val shortcutAbsoluteTop: StateFlow<Float>
+
+ val notificationStackAbsoluteBottom: StateFlow<Float>
+
+ val wallpaperFocalAreaBounds: StateFlow<RectF>
+
+ val wallpaperFocalAreaTapPosition: StateFlow<PointF>
+
+ /** top of notifications without bcsmartspace in small clock settings */
+ val notificationDefaultTop: StateFlow<Float>
+
+ fun setShortcutAbsoluteTop(top: Float)
+
+ /** Set bottom of notifications from notification stack, used as top for focal area bounds */
+ fun setNotificationStackAbsoluteBottom(bottom: Float)
+
+ fun setWallpaperFocalAreaBounds(bounds: RectF)
+
+ fun setNotificationDefaultTop(top: Float)
+
+ fun setTapPosition(tapPosition: PointF)
+}
+
+@SysUISingleton
+class WallpaperFocalAreaRepositoryImpl @Inject constructor() : WallpaperFocalAreaRepository {
+
+ private val _shortcutAbsoluteTop = MutableStateFlow(0F)
+ override val shortcutAbsoluteTop = _shortcutAbsoluteTop.asStateFlow()
+
+ private val _notificationStackAbsoluteBottom = MutableStateFlow(0F)
+ override val notificationStackAbsoluteBottom = _notificationStackAbsoluteBottom.asStateFlow()
+
+ private val _wallpaperFocalAreaBounds = MutableStateFlow(RectF(0F, 0F, 0F, 0F))
+ override val wallpaperFocalAreaBounds: StateFlow<RectF> =
+ _wallpaperFocalAreaBounds.asStateFlow()
+
+ private val _wallpaperFocalAreaTapPosition = MutableStateFlow(PointF(0F, 0F))
+ override val wallpaperFocalAreaTapPosition: StateFlow<PointF> =
+ _wallpaperFocalAreaTapPosition.asStateFlow()
+
+ private val _notificationDefaultTop = MutableStateFlow(0F)
+ override val notificationDefaultTop: StateFlow<Float> = _notificationDefaultTop.asStateFlow()
+
+ override fun setShortcutAbsoluteTop(top: Float) {
+ _shortcutAbsoluteTop.value = top
+ }
+
+ override fun setNotificationStackAbsoluteBottom(bottom: Float) {
+ _notificationStackAbsoluteBottom.value = bottom
+ }
+
+ override fun setNotificationDefaultTop(top: Float) {
+ _notificationDefaultTop.value = top
+ }
+
+ override fun setWallpaperFocalAreaBounds(bounds: RectF) {
+ _wallpaperFocalAreaBounds.value = bounds
+ }
+
+ override fun setTapPosition(point: PointF) {
+ _wallpaperFocalAreaTapPosition.value = point
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt
index 79a9630e6887..990c76f60ded 100644
--- a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt
@@ -30,7 +30,6 @@ import com.android.internal.R
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.keyguard.data.repository.KeyguardRepository
import com.android.systemui.res.R as SysUIR
import com.android.systemui.shared.Flags.ambientAod
import com.android.systemui.shared.Flags.extendedWallpaperEffects
@@ -79,7 +78,7 @@ constructor(
@Background private val bgDispatcher: CoroutineDispatcher,
broadcastDispatcher: BroadcastDispatcher,
userRepository: UserRepository,
- keyguardRepository: KeyguardRepository,
+ wallpaperFocalAreaRepository: WallpaperFocalAreaRepository,
private val wallpaperManager: WallpaperManager,
private val context: Context,
) : WallpaperRepository {
@@ -101,6 +100,7 @@ constructor(
.filter { it.selectionStatus == SelectionStatus.SELECTION_COMPLETE }
@VisibleForTesting var sendLockscreenLayoutJob: Job? = null
+ @VisibleForTesting var sendTapInShapeEffectsJob: Job? = null
override val wallpaperInfo: StateFlow<WallpaperInfo?> =
if (!wallpaperManager.isWallpaperSupported) {
@@ -131,7 +131,7 @@ constructor(
if (shouldSendNotificationLayout) {
sendLockscreenLayoutJob =
scope.launch {
- keyguardRepository.wallpaperFocalAreaBounds.collect {
+ wallpaperFocalAreaRepository.wallpaperFocalAreaBounds.collect {
wallpaperFocalAreaBounds ->
wallpaperManager.sendWallpaperCommand(
/* windowToken = */ rootView?.windowToken,
@@ -161,8 +161,24 @@ constructor(
)
}
}
+
+ sendTapInShapeEffectsJob =
+ scope.launch {
+ wallpaperFocalAreaRepository.wallpaperFocalAreaTapPosition.collect {
+ wallpaperFocalAreaTapPosition ->
+ wallpaperManager.sendWallpaperCommand(
+ /* windowToken = */ rootView?.windowToken,
+ /* action = */ WallpaperManager.COMMAND_LOCKSCREEN_TAP,
+ /* x = */ wallpaperFocalAreaTapPosition.x.toInt(),
+ /* y = */ wallpaperFocalAreaTapPosition.y.toInt(),
+ /* z = */ 0,
+ /* extras = */ null,
+ )
+ }
+ }
} else {
sendLockscreenLayoutJob?.cancel()
+ sendTapInShapeEffectsJob?.cancel()
}
shouldSendNotificationLayout
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WallpaperFocalAreaInteractor.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/domain/interactor/WallpaperFocalAreaInteractor.kt
index 9c744d63a093..187d6c7801c0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WallpaperFocalAreaInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/domain/interactor/WallpaperFocalAreaInteractor.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2024 The Android Open Source Project
+ * Copyright (C) 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,44 +14,43 @@
* limitations under the License.
*/
-package com.android.systemui.keyguard.domain.interactor
+package com.android.systemui.wallpapers.domain.interactor
import android.content.Context
import android.content.res.Resources
+import android.graphics.PointF
import android.graphics.RectF
import android.util.TypedValue
-import com.android.app.animation.MathUtils.max
+import androidx.annotation.VisibleForTesting
+import com.android.app.animation.MathUtils
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.keyguard.data.repository.KeyguardClockRepository
-import com.android.systemui.keyguard.data.repository.KeyguardRepository
import com.android.systemui.res.R
import com.android.systemui.shade.data.repository.ShadeRepository
import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor
+import com.android.systemui.wallpapers.data.repository.WallpaperFocalAreaRepository
import com.android.systemui.wallpapers.data.repository.WallpaperRepository
import javax.inject.Inject
import kotlin.math.min
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.flow.distinctUntilChanged
@SysUISingleton
class WallpaperFocalAreaInteractor
@Inject
constructor(
@Application private val applicationScope: CoroutineScope,
- context: Context,
- private val keyguardRepository: KeyguardRepository,
+ private val context: Context,
+ private val wallpaperFocalAreaRepository: WallpaperFocalAreaRepository,
shadeRepository: ShadeRepository,
activeNotificationsInteractor: ActiveNotificationsInteractor,
- keyguardClockRepository: KeyguardClockRepository,
- wallpaperRepository: WallpaperRepository,
+ val wallpaperRepository: WallpaperRepository,
) {
- // When there's notifications in splitshade, the focal area shape effect should be left aligned
- private val notificationInShadeWideLayout: Flow<Boolean> =
+ // When there's notifications in splitshade, the focal area should be left aligned
+ @VisibleForTesting
+ val notificationInShadeWideLayout: Flow<Boolean> =
combine(
shadeRepository.isShadeLayoutWide,
activeNotificationsInteractor.areAnyNotificationsPresent,
@@ -63,14 +62,15 @@ constructor(
}
}
- val shouldSendFocalArea = wallpaperRepository.shouldSendFocalArea
- val wallpaperFocalAreaBounds: StateFlow<RectF?> =
+ val hasFocalArea = wallpaperRepository.shouldSendFocalArea
+
+ val wallpaperFocalAreaBounds: Flow<RectF> =
combine(
shadeRepository.isShadeLayoutWide,
notificationInShadeWideLayout,
- keyguardRepository.notificationStackAbsoluteBottom,
- keyguardRepository.shortcutAbsoluteTop,
- keyguardClockRepository.notificationDefaultTop,
+ wallpaperFocalAreaRepository.notificationStackAbsoluteBottom,
+ wallpaperFocalAreaRepository.shortcutAbsoluteTop,
+ wallpaperFocalAreaRepository.notificationDefaultTop,
) {
isShadeLayoutWide,
notificationInShadeWideLayout,
@@ -80,6 +80,7 @@ constructor(
// Wallpaper will be zoomed in with config_wallpaperMaxScale in lockscreen
// so we need to give a bounds taking this scale in consideration
val wallpaperZoomedInScale = getSystemWallpaperMaximumScale(context)
+
val screenBounds =
RectF(
0F,
@@ -95,12 +96,14 @@ constructor(
screenBounds.centerX() + screenBounds.width() / 2F / wallpaperZoomedInScale,
screenBounds.centerY() + screenBounds.height() / 2F / wallpaperZoomedInScale,
)
+
val maxFocalAreaWidth =
TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
FOCAL_AREA_MAX_WIDTH_DP.toFloat(),
context.resources.displayMetrics,
)
+
val (left, right) =
// tablet landscape
if (context.resources.getBoolean(R.bool.center_align_focal_area_shape)) {
@@ -140,32 +143,48 @@ constructor(
// handheld / portrait
} else {
scaledBounds.top +
- max(notificationDefaultTop, notificationStackAbsoluteBottom) /
+ MathUtils.max(notificationDefaultTop, notificationStackAbsoluteBottom) /
wallpaperZoomedInScale
}
val bottom = scaledBounds.bottom - scaledBottomMargin
RectF(left, top, right, bottom)
}
- .stateIn(
- applicationScope,
- started = SharingStarted.WhileSubscribed(),
- initialValue = null,
- )
+ .distinctUntilChanged()
+
+ fun setFocalAreaBounds(bounds: RectF) {
+ wallpaperFocalAreaRepository.setWallpaperFocalAreaBounds(bounds)
+ }
- fun setWallpaperFocalAreaBounds(bounds: RectF) {
- keyguardRepository.setWallpaperFocalAreaBounds(bounds)
+ fun setNotificationDefaultTop(top: Float) {
+ wallpaperFocalAreaRepository.setNotificationDefaultTop(top)
+ }
+
+ fun setTapPosition(x: Float, y: Float) {
+ // Focal area should only react to touch event within its bounds
+ val wallpaperZoomedInScale = getSystemWallpaperMaximumScale(context)
+ // Because there's a scale applied on wallpaper in lockscreen
+ // we should map it to the unscaled position on wallpaper
+ val screenCenterX = context.resources.displayMetrics.widthPixels / 2F
+ val newX = (x - screenCenterX) / wallpaperZoomedInScale + screenCenterX
+ val screenCenterY = context.resources.displayMetrics.heightPixels / 2F
+ val newY = (y - screenCenterY) / wallpaperZoomedInScale + screenCenterY
+ if (wallpaperFocalAreaRepository.wallpaperFocalAreaBounds.value.contains(newX, newY)) {
+ wallpaperFocalAreaRepository.setTapPosition(PointF(newX, newY))
+ }
}
companion object {
fun getSystemWallpaperMaximumScale(context: Context): Float {
- return context.resources.getFloat(
- Resources.getSystem()
- .getIdentifier(
- /* name= */ "config_wallpaperMaxScale",
- /* defType= */ "dimen",
- /* defPackage= */ "android",
- )
- )
+ val scale =
+ context.resources.getFloat(
+ Resources.getSystem()
+ .getIdentifier(
+ /* name= */ "config_wallpaperMaxScale",
+ /* defType= */ "dimen",
+ /* defPackage= */ "android",
+ )
+ )
+ return if (scale == 0f) 1f else scale
}
// A max width for focal area shape effects bounds, to avoid
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/ui/viewmodel/WallpaperFocalAreaViewModel.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/ui/viewmodel/WallpaperFocalAreaViewModel.kt
new file mode 100644
index 000000000000..70a97d473c49
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/ui/viewmodel/WallpaperFocalAreaViewModel.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2025 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.wallpapers.ui.viewmodel
+
+import android.graphics.RectF
+import com.android.systemui.wallpapers.domain.interactor.WallpaperFocalAreaInteractor
+import javax.inject.Inject
+
+class WallpaperFocalAreaViewModel
+@Inject
+constructor(private val wallpaperFocalAreaInteractor: WallpaperFocalAreaInteractor) {
+ val hasFocalArea = wallpaperFocalAreaInteractor.hasFocalArea
+
+ val wallpaperFocalAreaBounds = wallpaperFocalAreaInteractor.wallpaperFocalAreaBounds
+
+ fun setFocalAreaBounds(bounds: RectF) {
+ wallpaperFocalAreaInteractor.setFocalAreaBounds(bounds)
+ }
+
+ fun setTapPosition(x: Float, y: Float) {
+ wallpaperFocalAreaInteractor.setTapPosition(x, y)
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardClockRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardClockRepository.kt
index 159dd34efbbc..25a9120651a6 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardClockRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardClockRepository.kt
@@ -47,10 +47,6 @@ class FakeKeyguardClockRepository() : KeyguardClockRepository {
override val previewClock: Flow<ClockController>
get() = _previewClock
- private val _notificationDefaultTop = MutableStateFlow(0F)
- override val notificationDefaultTop: StateFlow<Float>
- get() = _notificationDefaultTop
-
override val clockEventController: ClockEventController
get() = mock()
@@ -63,10 +59,6 @@ class FakeKeyguardClockRepository() : KeyguardClockRepository {
_clockSize.value = size
}
- override fun setNotificationDefaultTop(top: Float) {
- _notificationDefaultTop.value = top
- }
-
fun setSelectedClockSize(size: ClockSizeSetting) {
_selectedClockSize.value = size
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
index 1952f26b4e6a..591f493cc129 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
@@ -18,7 +18,6 @@
package com.android.systemui.keyguard.data.repository
import android.graphics.Point
-import android.graphics.RectF
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.shared.model.BiometricUnlockMode
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
@@ -123,18 +122,6 @@ class FakeKeyguardRepository @Inject constructor() : KeyguardRepository {
private val _isEncryptedOrLockdown = MutableStateFlow(true)
override val isEncryptedOrLockdown: Flow<Boolean> = _isEncryptedOrLockdown
- private val _shortcutAbsoluteTop = MutableStateFlow(0F)
- override val shortcutAbsoluteTop: StateFlow<Float>
- get() = _shortcutAbsoluteTop.asStateFlow()
-
- private val _notificationStackAbsoluteBottom = MutableStateFlow(0F)
- override val notificationStackAbsoluteBottom: StateFlow<Float>
- get() = _notificationStackAbsoluteBottom.asStateFlow()
-
- private val _wallpaperFocalAreaBounds = MutableStateFlow(RectF(0f, 0f, 0f, 0f))
- override val wallpaperFocalAreaBounds: StateFlow<RectF>
- get() = _wallpaperFocalAreaBounds.asStateFlow()
-
private val _isKeyguardEnabled = MutableStateFlow(true)
override val isKeyguardEnabled: StateFlow<Boolean> = _isKeyguardEnabled.asStateFlow()
@@ -289,18 +276,6 @@ class FakeKeyguardRepository @Inject constructor() : KeyguardRepository {
return isShowKeyguardWhenReenabled
}
- override fun setShortcutAbsoluteTop(top: Float) {
- _shortcutAbsoluteTop.value = top
- }
-
- override fun setNotificationStackAbsoluteBottom(bottom: Float) {
- _notificationStackAbsoluteBottom.value = bottom
- }
-
- override fun setWallpaperFocalAreaBounds(bounds: RectF) {
- _wallpaperFocalAreaBounds.value = bounds
- }
-
override fun setCanIgnoreAuthAndReturnToGone(canWake: Boolean) {
_canIgnoreAuthAndReturnToGone.value = canWake
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorKosmos.kt
index bdb9abb03c5f..8844eb040f02 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorKosmos.kt
@@ -23,6 +23,7 @@ import com.android.systemui.media.controls.domain.pipeline.interactor.mediaCarou
import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
import com.android.systemui.statusbar.notification.stack.domain.interactor.headsUpNotificationInteractor
+import com.android.systemui.wallpapers.domain.interactor.wallpaperFocalAreaInteractor
val Kosmos.keyguardClockInteractor by
Kosmos.Fixture {
@@ -35,5 +36,6 @@ val Kosmos.keyguardClockInteractor by
headsUpNotificationInteractor = headsUpNotificationInteractor,
applicationScope = applicationCoroutineScope,
keyguardClockRepository = keyguardClockRepository,
+ wallpaperFocalAreaInteractor = wallpaperFocalAreaInteractor,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt
index ee21bdc0b4c2..4e5abb883afd 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt
@@ -28,6 +28,8 @@ import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.shade.data.repository.FakeShadeRepository
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
+import com.android.systemui.wallpapers.data.repository.FakeWallpaperFocalAreaRepository
+import com.android.systemui.wallpapers.data.repository.WallpaperFocalAreaRepository
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -48,6 +50,8 @@ object KeyguardInteractorFactory {
bouncerRepository: FakeKeyguardBouncerRepository = FakeKeyguardBouncerRepository(),
configurationRepository: FakeConfigurationRepository = FakeConfigurationRepository(),
shadeRepository: FakeShadeRepository = FakeShadeRepository(),
+ wallpaperFocalAreaRepository: WallpaperFocalAreaRepository =
+ FakeWallpaperFocalAreaRepository(),
sceneInteractor: SceneInteractor = mock(),
fromGoneTransitionInteractor: FromGoneTransitionInteractor = mock(),
fromLockscreenTransitionInteractor: FromLockscreenTransitionInteractor = mock(),
@@ -84,6 +88,7 @@ object KeyguardInteractorFactory {
fromAlternateBouncerTransitionInteractor
},
applicationScope = testScope,
+ wallpaperFocalAreaRepository = wallpaperFocalAreaRepository,
),
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorKosmos.kt
index 869bae236d5c..f9b0290fe339 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorKosmos.kt
@@ -23,6 +23,7 @@ import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testScope
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.shade.data.repository.shadeRepository
+import com.android.systemui.wallpapers.data.repository.wallpaperFocalAreaRepository
val Kosmos.keyguardInteractor: KeyguardInteractor by
Kosmos.Fixture {
@@ -38,5 +39,6 @@ val Kosmos.keyguardInteractor: KeyguardInteractor by
fromOccludedTransitionInteractor = { fromOccludedTransitionInteractor },
fromAlternateBouncerTransitionInteractor = { fromAlternateBouncerTransitionInteractor },
applicationScope = testScope.backgroundScope,
+ wallpaperFocalAreaRepository = wallpaperFocalAreaRepository,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt
index dc54eabba060..ea3feeaf0854 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt
@@ -20,7 +20,6 @@ import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.keyguard.domain.interactor.pulseExpansionInteractor
-import com.android.systemui.keyguard.domain.interactor.wallpaperFocalAreaInteractor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
import com.android.systemui.kosmos.applicationCoroutineScope
@@ -30,6 +29,7 @@ import com.android.systemui.statusbar.notification.icon.ui.viewmodel.notificatio
import com.android.systemui.statusbar.notification.stack.domain.interactor.notificationsKeyguardInteractor
import com.android.systemui.statusbar.phone.dozeParameters
import com.android.systemui.statusbar.phone.screenOffAnimationController
+import com.android.systemui.wallpapers.domain.interactor.wallpaperFocalAreaInteractor
val Kosmos.keyguardRootViewModel by Fixture {
KeyguardRootViewModel(
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperFocalAreaRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperFocalAreaRepository.kt
new file mode 100644
index 000000000000..aeff86ed89bb
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperFocalAreaRepository.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2025 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.wallpapers.data.repository
+
+import android.graphics.PointF
+import android.graphics.RectF
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+class FakeWallpaperFocalAreaRepository : WallpaperFocalAreaRepository {
+ private val _shortcutAbsoluteTop = MutableStateFlow(0F)
+ override val shortcutAbsoluteTop = _shortcutAbsoluteTop.asStateFlow()
+
+ private val _notificationStackAbsoluteBottom = MutableStateFlow(0F)
+ override val notificationStackAbsoluteBottom = _notificationStackAbsoluteBottom.asStateFlow()
+
+ private val _wallpaperFocalAreaBounds = MutableStateFlow(RectF(0F, 0F, 0F, 0F))
+ override val wallpaperFocalAreaBounds: StateFlow<RectF> =
+ _wallpaperFocalAreaBounds.asStateFlow()
+
+ private val _wallpaperFocalAreaTapPosition = MutableStateFlow(PointF(0F, 0F))
+ override val wallpaperFocalAreaTapPosition: StateFlow<PointF> =
+ _wallpaperFocalAreaTapPosition.asStateFlow()
+
+ private val _notificationDefaultTop = MutableStateFlow(0F)
+ override val notificationDefaultTop: StateFlow<Float> = _notificationDefaultTop.asStateFlow()
+
+ override fun setShortcutAbsoluteTop(top: Float) {
+ _shortcutAbsoluteTop.value = top
+ }
+
+ override fun setNotificationStackAbsoluteBottom(bottom: Float) {
+ _notificationStackAbsoluteBottom.value = bottom
+ }
+
+ override fun setNotificationDefaultTop(top: Float) {
+ _notificationDefaultTop.value = top
+ }
+
+ override fun setWallpaperFocalAreaBounds(bounds: RectF) {
+ _wallpaperFocalAreaBounds.value = bounds
+ }
+
+ override fun setTapPosition(point: PointF) {
+ _wallpaperFocalAreaTapPosition.value = point
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt
new file mode 100644
index 000000000000..8689e04e62dd
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt
@@ -0,0 +1,44 @@
+/*
+ * 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.wallpapers.data.repository
+
+import android.app.WallpaperInfo
+import android.view.View
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+/** Fake implementation of the wallpaper repository. */
+class FakeWallpaperRepository : WallpaperRepository {
+ private val _wallpaperInfo: MutableStateFlow<WallpaperInfo?> = MutableStateFlow(null)
+ override val wallpaperInfo: StateFlow<WallpaperInfo?> = _wallpaperInfo.asStateFlow()
+ private val _wallpaperSupportsAmbientMode = MutableStateFlow(false)
+ override val wallpaperSupportsAmbientMode: Flow<Boolean> =
+ _wallpaperSupportsAmbientMode.asStateFlow()
+ override var rootView: View? = null
+ private val _shouldSendFocalArea = MutableStateFlow(false)
+ override val shouldSendFocalArea: StateFlow<Boolean> = _shouldSendFocalArea.asStateFlow()
+
+ fun setShouldSendFocalArea(shouldSendFocalArea: Boolean) {
+ _shouldSendFocalArea.value = shouldSendFocalArea
+ }
+
+ fun setWallpaperInfo(wallpaperInfo: WallpaperInfo?) {
+ _wallpaperInfo.value = wallpaperInfo
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/WallpaperFocalAreaRepositoryKosmos.kt
index d6343c840d9b..c1032b14d478 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/WallpaperFocalAreaRepositoryKosmos.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2025 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.
@@ -16,15 +16,8 @@
package com.android.systemui.wallpapers.data.repository
-import android.app.WallpaperInfo
-import android.view.View
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.flowOf
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
-/** Fake implementation of the wallpaper repository. */
-class FakeWallpaperRepository : WallpaperRepository {
- override val wallpaperInfo = MutableStateFlow<WallpaperInfo?>(null)
- override val wallpaperSupportsAmbientMode = flowOf(false)
- override var rootView: View? = null
- override val shouldSendFocalArea = MutableStateFlow(false)
-}
+val Kosmos.wallpaperFocalAreaRepository by Fixture { fakeWallpaperFocalAreaRepository }
+val Kosmos.fakeWallpaperFocalAreaRepository by Fixture { FakeWallpaperFocalAreaRepository() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryKosmos.kt
index f0c0d30e6db4..6b955ffb0b68 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryKosmos.kt
@@ -16,24 +16,9 @@
package com.android.systemui.wallpapers.data.repository
-import android.content.applicationContext
-import com.android.app.wallpaperManager
-import com.android.systemui.broadcast.broadcastDispatcher
-import com.android.systemui.keyguard.data.repository.keyguardRepository
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
-import com.android.systemui.kosmos.testDispatcher
-import com.android.systemui.kosmos.testScope
-import com.android.systemui.user.data.repository.userRepository
-val Kosmos.wallpaperRepository by Fixture {
- WallpaperRepositoryImpl(
- context = applicationContext,
- scope = testScope.backgroundScope,
- bgDispatcher = testDispatcher,
- broadcastDispatcher = broadcastDispatcher,
- userRepository = userRepository,
- keyguardRepository = keyguardRepository,
- wallpaperManager = wallpaperManager,
- )
-}
+var Kosmos.fakeWallpaperRepository by Kosmos.Fixture { FakeWallpaperRepository() }
+
+var Kosmos.wallpaperRepository: WallpaperRepository by Kosmos.Fixture { fakeWallpaperRepository }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/WallpaperFocalAreaInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/domain/interactor/WallpaperFocalAreaInteractor.kt
index 8fd6f62b315f..88eb5511160b 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/WallpaperFocalAreaInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/domain/interactor/WallpaperFocalAreaInteractor.kt
@@ -14,15 +14,14 @@
* limitations under the License.
*/
-package com.android.systemui.keyguard.domain.interactor
+package com.android.systemui.wallpapers.domain.interactor
import android.content.applicationContext
-import com.android.systemui.keyguard.data.repository.keyguardClockRepository
-import com.android.systemui.keyguard.data.repository.keyguardRepository
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.shade.data.repository.shadeRepository
import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
+import com.android.systemui.wallpapers.data.repository.wallpaperFocalAreaRepository
import com.android.systemui.wallpapers.data.repository.wallpaperRepository
val Kosmos.wallpaperFocalAreaInteractor by
@@ -30,10 +29,9 @@ val Kosmos.wallpaperFocalAreaInteractor by
WallpaperFocalAreaInteractor(
applicationScope = applicationCoroutineScope,
context = applicationContext,
- keyguardRepository = keyguardRepository,
+ wallpaperFocalAreaRepository = wallpaperFocalAreaRepository,
shadeRepository = shadeRepository,
activeNotificationsInteractor = activeNotificationsInteractor,
- keyguardClockRepository = keyguardClockRepository,
wallpaperRepository = wallpaperRepository,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/ui/viewmodel/WallpaperFocalAreaViewModel.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/ui/viewmodel/WallpaperFocalAreaViewModel.kt
new file mode 100644
index 000000000000..7e232c526732
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/ui/viewmodel/WallpaperFocalAreaViewModel.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2025 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.wallpapers.ui.viewmodel
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.wallpapers.domain.interactor.wallpaperFocalAreaInteractor
+
+var Kosmos.wallpaperFocalAreaViewModel by
+ Kosmos.Fixture {
+ WallpaperFocalAreaViewModel(wallpaperFocalAreaInteractor = wallpaperFocalAreaInteractor)
+ }