Merge "Introduce clock carousel card" into udc-dev
diff --git a/src/com/android/customization/picker/clock/data/repository/ClockPickerRepositoryImpl.kt b/src/com/android/customization/picker/clock/data/repository/ClockPickerRepositoryImpl.kt
index 880a00b..9537365 100644
--- a/src/com/android/customization/picker/clock/data/repository/ClockPickerRepositoryImpl.kt
+++ b/src/com/android/customization/picker/clock/data/repository/ClockPickerRepositoryImpl.kt
@@ -137,6 +137,7 @@
         secureSettingsRepository
             .intSetting(
                 name = Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK,
+                defaultValue = DEFAULT_CLOCK_SIZE,
             )
             .map { setting -> setting == 1 }
             .map { isDynamic -> if (isDynamic) ClockSize.DYNAMIC else ClockSize.SMALL }
@@ -189,5 +190,8 @@
 
         // The color tone to apply to the selected color
         private const val KEY_METADATA_COLOR_TONE_PROGRESS = "metadataColorToneProgress"
+
+        // The default clock size is 1, which means dynamic
+        private const val DEFAULT_CLOCK_SIZE = 1
     }
 }
diff --git a/src/com/android/customization/picker/clock/ui/binder/ClockCarouselViewBinder.kt b/src/com/android/customization/picker/clock/ui/binder/ClockCarouselViewBinder.kt
index cf80dc1..925e293 100644
--- a/src/com/android/customization/picker/clock/ui/binder/ClockCarouselViewBinder.kt
+++ b/src/com/android/customization/picker/clock/ui/binder/ClockCarouselViewBinder.kt
@@ -30,14 +30,6 @@
 import kotlinx.coroutines.launch
 
 object ClockCarouselViewBinder {
-    /**
-     * The binding is used by the view where there is an action executed from another view, e.g.
-     * toggling show/hide of the view that the binder is holding.
-     */
-    interface Binding {
-        fun show()
-        fun hide()
-    }
 
     @JvmStatic
     fun bind(
@@ -46,7 +38,7 @@
         viewModel: ClockCarouselViewModel,
         clockViewFactory: ClockViewFactory,
         lifecycleOwner: LifecycleOwner,
-    ): Binding {
+    ) {
         val singleClockHostView =
             singleClockView.requireViewById<FrameLayout>(R.id.single_clock_host_view)
         lifecycleOwner.lifecycleScope.launch {
@@ -106,15 +98,5 @@
                 }
             }
         )
-
-        return object : Binding {
-            override fun show() {
-                viewModel.showClockCarousel(true)
-            }
-
-            override fun hide() {
-                viewModel.showClockCarousel(false)
-            }
-        }
     }
 }
diff --git a/src/com/android/customization/picker/clock/ui/fragment/ClockSettingsFragment.kt b/src/com/android/customization/picker/clock/ui/fragment/ClockSettingsFragment.kt
index b5e7c18..dd4c968 100644
--- a/src/com/android/customization/picker/clock/ui/fragment/ClockSettingsFragment.kt
+++ b/src/com/android/customization/picker/clock/ui/fragment/ClockSettingsFragment.kt
@@ -66,51 +66,50 @@
         val colorViewModel = injector.getWallpaperColorsViewModel()
         val displayUtils = injector.getDisplayUtils(context)
         ScreenPreviewBinder.bind(
-                activity = activity,
-                previewView = lockScreenView,
-                viewModel =
-                    ScreenPreviewViewModel(
-                        previewUtils =
-                            PreviewUtils(
-                                context = context,
-                                authority =
-                                    resources.getString(
-                                        R.string.lock_screen_preview_provider_authority,
-                                    ),
-                            ),
-                        wallpaperInfoProvider = {
-                            suspendCancellableCoroutine { continuation ->
-                                injector
-                                    .getCurrentWallpaperInfoFactory(context)
-                                    .createCurrentWallpaperInfos(
-                                        { homeWallpaper, lockWallpaper, _ ->
-                                            continuation.resume(
-                                                homeWallpaper ?: lockWallpaper,
-                                                null,
-                                            )
-                                        },
-                                        /* forceRefresh= */ true,
-                                    )
-                            }
-                        },
-                        onWallpaperColorChanged = { colors ->
-                            colorViewModel.setLockWallpaperColors(colors)
-                        },
-                        initialExtrasProvider = {
-                            Bundle().apply {
-                                // Hide the clock from the system UI rendered preview so we can
-                                // place the carousel on top of it.
-                                putBoolean(
-                                    ClockPreviewConstants.KEY_HIDE_CLOCK,
-                                    true,
+            activity = activity,
+            previewView = lockScreenView,
+            viewModel =
+                ScreenPreviewViewModel(
+                    previewUtils =
+                        PreviewUtils(
+                            context = context,
+                            authority =
+                                resources.getString(
+                                    R.string.lock_screen_preview_provider_authority,
+                                ),
+                        ),
+                    wallpaperInfoProvider = {
+                        suspendCancellableCoroutine { continuation ->
+                            injector
+                                .getCurrentWallpaperInfoFactory(context)
+                                .createCurrentWallpaperInfos(
+                                    { homeWallpaper, lockWallpaper, _ ->
+                                        continuation.resume(
+                                            homeWallpaper ?: lockWallpaper,
+                                            null,
+                                        )
+                                    },
+                                    /* forceRefresh= */ true,
                                 )
-                            }
-                        },
-                    ),
-                lifecycleOwner = this,
-                offsetToStart = displayUtils.isSingleDisplayOrUnfoldedHorizontalHinge(activity),
-            )
-            .show()
+                        }
+                    },
+                    onWallpaperColorChanged = { colors ->
+                        colorViewModel.setLockWallpaperColors(colors)
+                    },
+                    initialExtrasProvider = {
+                        Bundle().apply {
+                            // Hide the clock from the system UI rendered preview so we can
+                            // place the carousel on top of it.
+                            putBoolean(
+                                ClockPreviewConstants.KEY_HIDE_CLOCK,
+                                true,
+                            )
+                        }
+                    },
+                ),
+            lifecycleOwner = this,
+            offsetToStart = displayUtils.isSingleDisplayOrUnfoldedHorizontalHinge(activity),
+        )
 
         ClockSettingsBinder.bind(
             view,
diff --git a/src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselViewModel.kt b/src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselViewModel.kt
index 60a9e85..c01f56a 100644
--- a/src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselViewModel.kt
+++ b/src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselViewModel.kt
@@ -19,8 +19,6 @@
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.flatMapLatest
 import kotlinx.coroutines.flow.map
@@ -44,14 +42,7 @@
 
     val seedColor: Flow<Int?> = interactor.seedColor
 
-    private val shouldShowCarousel = MutableStateFlow(false)
-    val isCarouselVisible: Flow<Boolean> =
-        combine(allClockIds.map { it.size > 1 }.distinctUntilChanged(), shouldShowCarousel) {
-                hasMoreThanOneClock,
-                shouldShowCarousel ->
-                hasMoreThanOneClock && shouldShowCarousel
-            }
-            .distinctUntilChanged()
+    val isCarouselVisible: Flow<Boolean> = allClockIds.map { it.size > 1 }.distinctUntilChanged()
 
     @OptIn(ExperimentalCoroutinesApi::class)
     val selectedIndex: Flow<Int> =
@@ -69,14 +60,8 @@
             .mapNotNull { it }
 
     // Handle the case when there is only one clock in the carousel
-    private val shouldShowSingleClock = MutableStateFlow(false)
     val isSingleClockViewVisible: Flow<Boolean> =
-        combine(allClockIds.map { it.size == 1 }.distinctUntilChanged(), shouldShowSingleClock) {
-                hasOneClock,
-                shouldShowSingleClock ->
-                hasOneClock && shouldShowSingleClock
-            }
-            .distinctUntilChanged()
+        allClockIds.map { it.size == 1 }.distinctUntilChanged()
 
     val clockId: Flow<String> =
         allClockIds
@@ -87,11 +72,6 @@
         interactor.setSelectedClock(clockId)
     }
 
-    fun showClockCarousel(shouldShow: Boolean) {
-        shouldShowCarousel.value = shouldShow
-        shouldShowSingleClock.value = shouldShow
-    }
-
     companion object {
         const val CLOCKS_EVENT_UPDATE_DELAY_MILLIS: Long = 100
     }
diff --git a/src/com/android/customization/picker/preview/ui/section/PreviewWithClockCarouselSectionController.kt b/src/com/android/customization/picker/preview/ui/section/PreviewWithClockCarouselSectionController.kt
index 0303b41..43fb85b 100644
--- a/src/com/android/customization/picker/preview/ui/section/PreviewWithClockCarouselSectionController.kt
+++ b/src/com/android/customization/picker/preview/ui/section/PreviewWithClockCarouselSectionController.kt
@@ -22,7 +22,6 @@
 import android.view.View
 import android.view.ViewGroup
 import android.view.ViewStub
-import androidx.core.view.isVisible
 import androidx.lifecycle.LifecycleOwner
 import androidx.lifecycle.lifecycleScope
 import com.android.customization.picker.clock.ui.binder.ClockCarouselViewBinder
@@ -46,7 +45,7 @@
 class PreviewWithClockCarouselSectionController(
     activity: Activity,
     private val lifecycleOwner: LifecycleOwner,
-    private val initialScreen: CustomizationSections.Screen,
+    private val screen: CustomizationSections.Screen,
     wallpaperInfoFactory: CurrentWallpaperInfoFactory,
     colorViewModel: WallpaperColorsViewModel,
     displayUtils: DisplayUtils,
@@ -59,7 +58,7 @@
     ScreenPreviewSectionController(
         activity,
         lifecycleOwner,
-        initialScreen,
+        screen,
         wallpaperInfoFactory,
         colorViewModel,
         displayUtils,
@@ -67,32 +66,31 @@
         wallpaperInteractor,
     ) {
 
-    private var clockCarouselBinding: ClockCarouselViewBinder.Binding? = null
     private var clockColorAndSizeButton: View? = null
 
     override val hideLockScreenClockPreview = true
 
     override fun createView(context: Context): ScreenPreviewView {
         val view = super.createView(context)
+        if (screen == CustomizationSections.Screen.LOCK_SCREEN) {
+            val clockColorAndSizeButtonStub: ViewStub =
+                view.requireViewById(R.id.clock_color_and_size_button)
+            clockColorAndSizeButtonStub.layoutResource = R.layout.clock_color_and_size_button
+            clockColorAndSizeButton = clockColorAndSizeButtonStub.inflate() as View
+            clockColorAndSizeButton?.setOnClickListener {
+                navigationController.navigateTo(ClockSettingsFragment())
+            }
 
-        val clockColorAndSizeButtonStub: ViewStub =
-            view.requireViewById(R.id.clock_color_and_size_button)
-        clockColorAndSizeButtonStub.layoutResource = R.layout.clock_color_and_size_button
-        clockColorAndSizeButton = clockColorAndSizeButtonStub.inflate() as View
-        clockColorAndSizeButton?.setOnClickListener {
-            navigationController.navigateTo(ClockSettingsFragment())
-        }
+            val carouselViewStub: ViewStub = view.requireViewById(R.id.clock_carousel_view_stub)
+            carouselViewStub.layoutResource = R.layout.clock_carousel_view
+            val carouselView = carouselViewStub.inflate() as ClockCarouselView
 
-        val carouselViewStub: ViewStub = view.requireViewById(R.id.clock_carousel_view_stub)
-        carouselViewStub.layoutResource = R.layout.clock_carousel_view
-        val carouselView = carouselViewStub.inflate() as ClockCarouselView
-
-        // TODO (b/270716937) We should handle the single clock case in the clock carousel itself
-        val singleClockViewStub: ViewStub = view.requireViewById(R.id.single_clock_view_stub)
-        singleClockViewStub.layoutResource = R.layout.single_clock_view
-        val singleClockView = singleClockViewStub.inflate() as ViewGroup
-        lifecycleOwner.lifecycleScope.launch {
-            clockCarouselBinding =
+            // TODO (b/270716937) We should handle the single clock case in the clock carousel
+            // itself
+            val singleClockViewStub: ViewStub = view.requireViewById(R.id.single_clock_view_stub)
+            singleClockViewStub.layoutResource = R.layout.single_clock_view
+            val singleClockView = singleClockViewStub.inflate() as ViewGroup
+            lifecycleOwner.lifecycleScope.launch {
                 ClockCarouselViewBinder.bind(
                     carouselView = carouselView,
                     singleClockView = singleClockView,
@@ -100,20 +98,9 @@
                     clockViewFactory = clockViewFactory,
                     lifecycleOwner = lifecycleOwner,
                 )
-            onScreenSwitched(
-                isOnLockScreen = initialScreen == CustomizationSections.Screen.LOCK_SCREEN
-            )
+            }
         }
-        return view
-    }
 
-    override fun onScreenSwitched(isOnLockScreen: Boolean) {
-        super.onScreenSwitched(isOnLockScreen)
-        clockColorAndSizeButton?.isVisible = isOnLockScreen
-        if (isOnLockScreen) {
-            clockCarouselBinding?.show()
-        } else {
-            clockCarouselBinding?.hide()
-        }
+        return view
     }
 }
diff --git a/tests/src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselViewModelTest.kt b/tests/src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselViewModelTest.kt
index 63f77bd..5bc7461 100644
--- a/tests/src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselViewModelTest.kt
+++ b/tests/src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselViewModelTest.kt
@@ -75,46 +75,22 @@
     }
 
     @Test
-    fun setShouldShowCarousel() = runTest {
+    fun multipleClockCase() = runTest {
         underTest = ClockCarouselViewModel(ClockPickerInteractor(repositoryWithMultipleClocks))
         val observedIsCarouselVisible = collectLastValue(underTest.isCarouselVisible)
+        val observedIsSingleClockViewVisible = collectLastValue(underTest.isSingleClockViewVisible)
         advanceTimeBy(ClockCarouselViewModel.CLOCKS_EVENT_UPDATE_DELAY_MILLIS)
-        underTest.showClockCarousel(false)
-        assertThat(observedIsCarouselVisible()).isFalse()
-        underTest.showClockCarousel(true)
         assertThat(observedIsCarouselVisible()).isTrue()
+        assertThat(observedIsSingleClockViewVisible()).isFalse()
     }
 
     @Test
-    fun shouldNotShowCarouselWhenSingleClock() = runTest {
+    fun singleClockCase() = runTest {
         underTest = ClockCarouselViewModel(ClockPickerInteractor(repositoryWithSingleClock))
         val observedIsCarouselVisible = collectLastValue(underTest.isCarouselVisible)
-        advanceTimeBy(ClockCarouselViewModel.CLOCKS_EVENT_UPDATE_DELAY_MILLIS)
-        underTest.showClockCarousel(false)
-        assertThat(observedIsCarouselVisible()).isFalse()
-        underTest.showClockCarousel(true)
-        assertThat(observedIsCarouselVisible()).isFalse()
-    }
-
-    @Test
-    fun setShouldShowSingleClock() = runTest {
-        underTest = ClockCarouselViewModel(ClockPickerInteractor(repositoryWithSingleClock))
         val observedIsSingleClockViewVisible = collectLastValue(underTest.isSingleClockViewVisible)
         advanceTimeBy(ClockCarouselViewModel.CLOCKS_EVENT_UPDATE_DELAY_MILLIS)
-        underTest.showClockCarousel(false)
-        assertThat(observedIsSingleClockViewVisible()).isFalse()
-        underTest.showClockCarousel(true)
+        assertThat(observedIsCarouselVisible()).isFalse()
         assertThat(observedIsSingleClockViewVisible()).isTrue()
     }
-
-    @Test
-    fun shouldNotShowSingleClockWhenMultipleClocks() = runTest {
-        underTest = ClockCarouselViewModel(ClockPickerInteractor(repositoryWithMultipleClocks))
-        val observedIsSingleClockViewVisible = collectLastValue(underTest.isSingleClockViewVisible)
-        advanceTimeBy(ClockCarouselViewModel.CLOCKS_EVENT_UPDATE_DELAY_MILLIS)
-        underTest.showClockCarousel(false)
-        assertThat(observedIsSingleClockViewVisible()).isFalse()
-        underTest.showClockCarousel(true)
-        assertThat(observedIsSingleClockViewVisible()).isFalse()
-    }
 }