Make clock editor support blueprint clock view in new customization picker

Bug: 366519734
Test: manual test with flag on and off, observe clock on the correct
position
Flag: com.android.systemui.shared.new_customization_picker_ui

Change-Id: I350f640cf3cfc54fa9d34692d0850e4b83c7ceb0
diff --git a/res/layout/clock_host_view.xml b/res/layout/clock_host_view.xml
index 33cca01..d6f5275 100644
--- a/res/layout/clock_host_view.xml
+++ b/res/layout/clock_host_view.xml
@@ -13,7 +13,7 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<com.android.customization.picker.clock.ui.view.ClockHostView2
+<com.android.customization.picker.clock.ui.view.ClockConstraintLayoutHostView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/clock_host_view"
     android:importantForAccessibility="noHideDescendants"
diff --git a/src/com/android/customization/picker/clock/ui/binder/ClockSettingsBinder.kt b/src/com/android/customization/picker/clock/ui/binder/ClockSettingsBinder.kt
index 99dfc26..764c671 100644
--- a/src/com/android/customization/picker/clock/ui/binder/ClockSettingsBinder.kt
+++ b/src/com/android/customization/picker/clock/ui/binder/ClockSettingsBinder.kt
@@ -41,10 +41,10 @@
 import com.android.customization.picker.clock.shared.ClockSize
 import com.android.customization.picker.clock.ui.adapter.ClockSettingsTabAdapter
 import com.android.customization.picker.clock.ui.view.ClockCarouselView
-import com.android.customization.picker.clock.ui.view.ClockHostView
 import com.android.customization.picker.clock.ui.view.ClockViewFactory
 import com.android.customization.picker.clock.ui.viewmodel.ClockSettingsViewModel
 import com.android.customization.picker.color.ui.binder.ColorOptionIconBinder
+import com.android.systemui.shared.Flags
 import com.android.themepicker.R
 import com.android.wallpaper.picker.common.ui.view.ItemSpacing
 import com.android.wallpaper.picker.option.ui.binder.OptionItemBinder
@@ -64,7 +64,10 @@
         clockViewFactory: ClockViewFactory,
         lifecycleOwner: LifecycleOwner,
     ) {
-        val clockHostView: ClockHostView = view.requireViewById(R.id.clock_host_view)
+        if (Flags.newCustomizationPickerUi()) {
+            return
+        }
+        val clockHostView: ViewGroup = view.requireViewById(R.id.clock_host_view)
         val tabView: RecyclerView = view.requireViewById(R.id.tabs)
         val tabAdapter = ClockSettingsTabAdapter()
         tabView.adapter = tabAdapter
@@ -204,10 +207,11 @@
                                     ClockSize.DYNAMIC -> clockViewFactory.getLargeView(clockId)
                                     ClockSize.SMALL -> clockViewFactory.getSmallView(clockId)
                                 }
-                            // The clock view might still be attached to an existing parent. Detach
-                            // before adding to another parent.
+                            // The clock view might still be attached to an existing parent.
+                            // Detach before adding to another parent.
                             (clockView.parent as? ViewGroup)?.removeView(clockView)
                             clockHostView.addView(clockView)
+
                             when (size) {
                                 ClockSize.DYNAMIC -> {
                                     // When clock size data flow emits clock size signal, we want
diff --git a/src/com/android/customization/picker/clock/ui/view/ClockConstraintLayoutHostView.kt b/src/com/android/customization/picker/clock/ui/view/ClockConstraintLayoutHostView.kt
new file mode 100644
index 0000000..de5fbd5
--- /dev/null
+++ b/src/com/android/customization/picker/clock/ui/view/ClockConstraintLayoutHostView.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.customization.picker.clock.ui.view
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.View
+import android.view.View.MeasureSpec.EXACTLY
+import android.view.ViewGroup
+import androidx.constraintlayout.widget.ConstraintLayout
+import com.android.customization.picker.clock.shared.ClockSize
+import com.android.systemui.plugins.clocks.ClockController
+import com.android.wallpaper.util.ScreenSizeCalculator
+
+/**
+ * Parent view for the clock view. We will calculate the current display size and the preview size
+ * and scale down the clock view to fit in the preview.
+ */
+class ClockConstraintLayoutHostView(context: Context, attrs: AttributeSet?) :
+    ConstraintLayout(context, attrs) {
+    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+        val screenSize = ScreenSizeCalculator.getInstance().getScreenSize(display)
+        super.onMeasure(
+            MeasureSpec.makeMeasureSpec(screenSize.x, EXACTLY),
+            MeasureSpec.makeMeasureSpec(screenSize.y, EXACTLY),
+        )
+        val ratio = MeasureSpec.getSize(widthMeasureSpec) / screenSize.x.toFloat()
+        scaleX = ratio
+        scaleY = ratio
+    }
+
+    companion object {
+        fun addClockViews(
+            clockController: ClockController,
+            rootView: ClockConstraintLayoutHostView,
+            size: ClockSize,
+        ) {
+            clockController.let { clock ->
+                when (size) {
+                    ClockSize.DYNAMIC -> {
+                        clock.largeClock.layout.views.forEach {
+                            if (it.parent != null) {
+                                (it.parent as ViewGroup).removeView(it)
+                            }
+                            rootView.addView(it).apply { it.visibility = View.VISIBLE }
+                        }
+                    }
+
+                    ClockSize.SMALL -> {
+                        clock.smallClock.layout.views.forEach {
+                            if (it.parent != null) {
+                                (it.parent as ViewGroup).removeView(it)
+                            }
+                            rootView.addView(it).apply { it.visibility = View.VISIBLE }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/src/com/android/customization/picker/clock/ui/view/ClockHostView.kt b/src/com/android/customization/picker/clock/ui/view/ClockHostView.kt
index 512fcd1..2db52f1 100644
--- a/src/com/android/customization/picker/clock/ui/view/ClockHostView.kt
+++ b/src/com/android/customization/picker/clock/ui/view/ClockHostView.kt
@@ -12,10 +12,7 @@
  * same size of lockscreen to layout clock and scale down it to the size in picker carousel
  * according to ratio of preview to LS
  */
-class ClockHostView(
-    context: Context,
-    attrs: AttributeSet?,
-) : FrameLayout(context, attrs) {
+class ClockHostView(context: Context, attrs: AttributeSet?) : FrameLayout(context, attrs) {
     private var previewRatio: Float = 1F
         set(value) {
             if (field != value) {
@@ -41,15 +38,16 @@
         parentWidthMeasureSpec: Int,
         widthUsed: Int,
         parentHeightMeasureSpec: Int,
-        heightUsed: Int
+        heightUsed: Int,
     ) {
+
         val screenSize = ScreenSizeCalculator.getInstance().getScreenSize(display)
         super.measureChildWithMargins(
             child,
             MeasureSpec.makeMeasureSpec(screenSize.x, EXACTLY),
             widthUsed,
             MeasureSpec.makeMeasureSpec(screenSize.y, EXACTLY),
-            heightUsed
+            heightUsed,
         )
     }
 }
diff --git a/src/com/android/customization/picker/clock/ui/view/ClockHostView2.kt b/src/com/android/customization/picker/clock/ui/view/ClockHostView2.kt
deleted file mode 100644
index be2e53d..0000000
--- a/src/com/android/customization/picker/clock/ui/view/ClockHostView2.kt
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.customization.picker.clock.ui.view
-
-import android.content.Context
-import android.util.AttributeSet
-import android.view.View
-import android.view.View.MeasureSpec.EXACTLY
-import android.widget.FrameLayout
-import com.android.customization.picker.clock.shared.ClockSize
-import com.android.wallpaper.util.ScreenSizeCalculator
-
-/**
- * Parent view for the clock view. We will calculate the current display size and the preview size
- * and scale down the clock view to fit in the preview.
- */
-class ClockHostView2(context: Context, attrs: AttributeSet?) : FrameLayout(context, attrs) {
-
-    var clockSize: ClockSize = ClockSize.DYNAMIC
-        set(value) {
-            if (field != value) {
-                field = value
-                updatePivotAndScale()
-                invalidate()
-            }
-        }
-
-    override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
-        super.onLayout(changed, left, top, right, bottom)
-        updatePivotAndScale()
-    }
-
-    override fun measureChildWithMargins(
-        child: View?,
-        parentWidthMeasureSpec: Int,
-        widthUsed: Int,
-        parentHeightMeasureSpec: Int,
-        heightUsed: Int,
-    ) {
-        val screenSize = ScreenSizeCalculator.getInstance().getScreenSize(display)
-        super.measureChildWithMargins(
-            child,
-            MeasureSpec.makeMeasureSpec(screenSize.x, EXACTLY),
-            widthUsed,
-            MeasureSpec.makeMeasureSpec(screenSize.y, EXACTLY),
-            heightUsed,
-        )
-    }
-
-    private fun updatePivotAndScale() {
-        when (clockSize) {
-            ClockSize.DYNAMIC -> {
-                resetPivot()
-            }
-            ClockSize.SMALL -> {
-                pivotX = getCenteredHostViewPivotX(this)
-                pivotY = 0F
-            }
-        }
-        val screenSize = ScreenSizeCalculator.getInstance().getScreenSize(display)
-        val ratio = measuredWidth / screenSize.x.toFloat()
-        scaleX = ratio
-        scaleY = ratio
-    }
-
-    companion object {
-        fun getCenteredHostViewPivotX(hostView: View): Float {
-            return if (hostView.isLayoutRtl) hostView.width.toFloat() else 0F
-        }
-    }
-}
diff --git a/src/com/android/customization/picker/clock/ui/view/ThemePickerClockViewFactory.kt b/src/com/android/customization/picker/clock/ui/view/ThemePickerClockViewFactory.kt
index 6cb9acb..72b0f19 100644
--- a/src/com/android/customization/picker/clock/ui/view/ThemePickerClockViewFactory.kt
+++ b/src/com/android/customization/picker/clock/ui/view/ThemePickerClockViewFactory.kt
@@ -28,6 +28,7 @@
 import com.android.systemui.plugins.clocks.ClockController
 import com.android.systemui.plugins.clocks.ClockFontAxisSetting
 import com.android.systemui.plugins.clocks.WeatherData
+import com.android.systemui.shared.Flags
 import com.android.systemui.shared.clocks.ClockRegistry
 import com.android.wallpaper.util.ScreenSizeCalculator
 import com.android.wallpaper.util.TimeUtils.TimeTicker
@@ -64,6 +65,7 @@
      * configs, e.g. animation state, might change during the reuse of the clock view in the app.
      */
     override fun getLargeView(clockId: String): View {
+        assert(!Flags.newCustomizationPickerUi())
         return getController(clockId).largeClock.let {
             it.animations.onPickerCarouselSwiping(1F)
             it.view
@@ -75,6 +77,7 @@
      * configs, e.g. translation X, might change during the reuse of the clock view in the app.
      */
     override fun getSmallView(clockId: String): View {
+        assert(!Flags.newCustomizationPickerUi())
         val smallClockFrame =
             smallClockFrames[clockId]
                 ?: createSmallClockFrame().also {
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 db43f4b..32b28ad 100644
--- a/src/com/android/customization/picker/preview/ui/section/PreviewWithClockCarouselSectionController.kt
+++ b/src/com/android/customization/picker/preview/ui/section/PreviewWithClockCarouselSectionController.kt
@@ -97,11 +97,7 @@
     ) {
 
     private val viewModel =
-        ViewModelProvider(
-                activity,
-                clockCarouselViewModelFactory,
-            )
-            .get() as ClockCarouselViewModel
+        ViewModelProvider(activity, clockCarouselViewModelFactory).get() as ClockCarouselViewModel
 
     private var clockColorAndSizeButton: View? = null
 
@@ -184,7 +180,7 @@
                                 )
                                 if (onAttachStateChangeListener != null) {
                                     carouselView.carousel.removeOnAttachStateChangeListener(
-                                        onAttachStateChangeListener,
+                                        onAttachStateChangeListener
                                     )
                                 }
                             }
diff --git a/src/com/android/wallpaper/customization/ui/binder/ThemePickerCustomizationOptionBinder.kt b/src/com/android/wallpaper/customization/ui/binder/ThemePickerCustomizationOptionBinder.kt
index dd283c2..469db6d 100644
--- a/src/com/android/wallpaper/customization/ui/binder/ThemePickerCustomizationOptionBinder.kt
+++ b/src/com/android/wallpaper/customization/ui/binder/ThemePickerCustomizationOptionBinder.kt
@@ -16,10 +16,12 @@
 
 package com.android.wallpaper.customization.ui.binder
 
+import android.content.Context
 import android.view.View
 import android.view.ViewGroup
 import android.widget.ImageView
 import android.widget.TextView
+import androidx.constraintlayout.widget.ConstraintSet
 import androidx.core.content.ContextCompat
 import androidx.core.view.isVisible
 import androidx.lifecycle.Lifecycle
@@ -27,10 +29,12 @@
 import androidx.lifecycle.lifecycleScope
 import androidx.lifecycle.repeatOnLifecycle
 import com.android.customization.picker.clock.shared.ClockSize
-import com.android.customization.picker.clock.ui.view.ClockHostView2
+import com.android.customization.picker.clock.ui.view.ClockConstraintLayoutHostView
+import com.android.customization.picker.clock.ui.view.ClockConstraintLayoutHostView.Companion.addClockViews
 import com.android.customization.picker.clock.ui.view.ClockViewFactory
 import com.android.customization.picker.grid.ui.binder.GridIconViewBinder
 import com.android.systemui.plugins.clocks.ClockFontAxisSetting
+import com.android.systemui.shared.Flags
 import com.android.themepicker.R
 import com.android.wallpaper.customization.ui.util.ThemePickerCustomizationOptionUtil.ThemePickerHomeCustomizationOption
 import com.android.wallpaper.customization.ui.util.ThemePickerCustomizationOptionUtil.ThemePickerLockCustomizationOption
@@ -231,12 +235,13 @@
     }
 
     override fun bindClockPreview(
+        context: Context,
         clockHostView: View,
         viewModel: CustomizationPickerViewModel2,
         lifecycleOwner: LifecycleOwner,
         clockViewFactory: ClockViewFactory,
     ) {
-        clockHostView as ClockHostView2
+        clockHostView as ClockConstraintLayoutHostView
         val clockPickerViewModel =
             (viewModel.customizationOptionsViewModel as ThemePickerCustomizationOptionsViewModel)
                 .clockPickerViewModel
@@ -252,17 +257,36 @@
                         }
                         .collect { (clock, size) ->
                             clockHostView.removeAllViews()
-                            val clockView =
-                                when (size) {
-                                    ClockSize.DYNAMIC ->
-                                        clockViewFactory.getLargeView(clock.clockId)
-                                    ClockSize.SMALL -> clockViewFactory.getSmallView(clock.clockId)
+                            // For new customization picker, we should get views from clocklayout
+                            if (Flags.newCustomizationPickerUi()) {
+                                clockViewFactory.getController(clock.clockId).let { clockController
+                                    ->
+                                    addClockViews(clockController, clockHostView, size)
+                                    val cs = ConstraintSet()
+                                    clockController.largeClock.layout.applyPreviewConstraints(
+                                        context,
+                                        cs,
+                                    )
+                                    clockController.smallClock.layout.applyPreviewConstraints(
+                                        context,
+                                        cs,
+                                    )
+                                    cs.applyTo(clockHostView)
                                 }
-                            // The clock view might still be attached to an existing parent. Detach
-                            // before adding to another parent.
-                            (clockView.parent as? ViewGroup)?.removeView(clockView)
-                            clockHostView.addView(clockView)
-                            clockHostView.clockSize = size
+                            } else {
+                                val clockView =
+                                    when (size) {
+                                        ClockSize.DYNAMIC ->
+                                            clockViewFactory.getLargeView(clock.clockId)
+                                        ClockSize.SMALL ->
+                                            clockViewFactory.getSmallView(clock.clockId)
+                                    }
+                                // The clock view might still be attached to an existing parent.
+                                // Detach
+                                // before adding to another parent.
+                                (clockView.parent as? ViewGroup)?.removeView(clockView)
+                                clockHostView.addView(clockView)
+                            }
                         }
                 }