1 /*
<lambda>null2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17 
18 package com.android.systemui.keyguard.ui.view.layout.sections
19 
20 import android.content.Context
21 import android.view.View
22 import androidx.constraintlayout.widget.Barrier
23 import androidx.constraintlayout.widget.ConstraintLayout
24 import androidx.constraintlayout.widget.ConstraintSet
25 import androidx.constraintlayout.widget.ConstraintSet.BOTTOM
26 import androidx.constraintlayout.widget.ConstraintSet.END
27 import androidx.constraintlayout.widget.ConstraintSet.GONE
28 import androidx.constraintlayout.widget.ConstraintSet.MATCH_CONSTRAINT
29 import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
30 import androidx.constraintlayout.widget.ConstraintSet.START
31 import androidx.constraintlayout.widget.ConstraintSet.TOP
32 import androidx.constraintlayout.widget.ConstraintSet.VISIBLE
33 import androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT
34 import com.android.systemui.customization.R as custR
35 import com.android.systemui.dagger.SysUISingleton
36 import com.android.systemui.keyguard.MigrateClocksToBlueprint
37 import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor
38 import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
39 import com.android.systemui.keyguard.shared.model.KeyguardSection
40 import com.android.systemui.keyguard.ui.binder.KeyguardClockViewBinder
41 import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
42 import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel
43 import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel
44 import com.android.systemui.plugins.clocks.ClockController
45 import com.android.systemui.plugins.clocks.ClockFaceLayout
46 import com.android.systemui.res.R
47 import com.android.systemui.shared.R as sharedR
48 import dagger.Lazy
49 import javax.inject.Inject
50 
51 internal fun ConstraintSet.setVisibility(
52     views: Iterable<View>,
53     visibility: Int,
54 ) = views.forEach { view -> this.setVisibility(view.id, visibility) }
55 
setAlphanull56 internal fun ConstraintSet.setAlpha(
57     views: Iterable<View>,
58     alpha: Float,
59 ) = views.forEach { view -> this.setAlpha(view.id, alpha) }
60 
61 @SysUISingleton
62 class ClockSection
63 @Inject
64 constructor(
65     private val clockInteractor: KeyguardClockInteractor,
66     protected val keyguardClockViewModel: KeyguardClockViewModel,
67     private val context: Context,
68     val smartspaceViewModel: KeyguardSmartspaceViewModel,
69     val blueprintInteractor: Lazy<KeyguardBlueprintInteractor>,
70     private val rootViewModel: KeyguardRootViewModel,
71 ) : KeyguardSection() {
addViewsnull72     override fun addViews(constraintLayout: ConstraintLayout) {}
bindDatanull73     override fun bindData(constraintLayout: ConstraintLayout) {
74         if (!MigrateClocksToBlueprint.isEnabled) {
75             return
76         }
77 
78         KeyguardClockViewBinder.bind(
79             this,
80             constraintLayout,
81             keyguardClockViewModel,
82             clockInteractor,
83             blueprintInteractor.get(),
84             rootViewModel,
85         )
86     }
87 
applyConstraintsnull88     override fun applyConstraints(constraintSet: ConstraintSet) {
89         if (!MigrateClocksToBlueprint.isEnabled) {
90             return
91         }
92 
93         keyguardClockViewModel.currentClock.value?.let { clock ->
94             constraintSet.applyDeltaFrom(buildConstraints(clock, constraintSet))
95         }
96     }
97 
removeViewsnull98     override fun removeViews(constraintLayout: ConstraintLayout) {}
99 
buildConstraintsnull100     private fun buildConstraints(
101         clock: ClockController,
102         constraintSet: ConstraintSet
103     ): ConstraintSet {
104         // Add constraint between rootView and clockContainer
105         applyDefaultConstraints(constraintSet)
106         getNonTargetClockFace(clock).applyConstraints(constraintSet)
107         getTargetClockFace(clock).applyConstraints(constraintSet)
108 
109         // Add constraint between elements in clock and clock container
110         return constraintSet.apply {
111             setVisibility(getTargetClockFace(clock).views, VISIBLE)
112             setVisibility(getNonTargetClockFace(clock).views, GONE)
113             setAlpha(getTargetClockFace(clock).views, 1F)
114             setAlpha(getNonTargetClockFace(clock).views, 0F)
115             if (!keyguardClockViewModel.isLargeClockVisible.value) {
116                 connect(sharedR.id.bc_smartspace_view, TOP, sharedR.id.date_smartspace_view, BOTTOM)
117             }
118         }
119     }
120 
getTargetClockFacenull121     private fun getTargetClockFace(clock: ClockController): ClockFaceLayout =
122         if (keyguardClockViewModel.isLargeClockVisible.value) clock.largeClock.layout
123         else clock.smallClock.layout
124     private fun getNonTargetClockFace(clock: ClockController): ClockFaceLayout =
125         if (keyguardClockViewModel.isLargeClockVisible.value) clock.smallClock.layout
126         else clock.largeClock.layout
127 
128     fun constrainWeatherClockDateIconsBarrier(constraints: ConstraintSet) {
129         constraints.apply {
130             if (keyguardClockViewModel.isAodIconsVisible.value) {
131                 createBarrier(
132                     R.id.weather_clock_date_and_icons_barrier_bottom,
133                     Barrier.BOTTOM,
134                     0,
135                     *intArrayOf(sharedR.id.bc_smartspace_view, R.id.aod_notification_icon_container)
136                 )
137             } else {
138                 if (smartspaceViewModel.bcSmartspaceVisibility.value == VISIBLE) {
139                     createBarrier(
140                         R.id.weather_clock_date_and_icons_barrier_bottom,
141                         Barrier.BOTTOM,
142                         0,
143                         (sharedR.id.bc_smartspace_view)
144                     )
145                 } else {
146                     createBarrier(
147                         R.id.weather_clock_date_and_icons_barrier_bottom,
148                         Barrier.BOTTOM,
149                         getDimen(ENHANCED_SMARTSPACE_HEIGHT),
150                         (R.id.lockscreen_clock_view)
151                     )
152                 }
153             }
154         }
155     }
156 
applyDefaultConstraintsnull157     open fun applyDefaultConstraints(constraints: ConstraintSet) {
158         val guideline =
159             if (keyguardClockViewModel.clockShouldBeCentered.value) PARENT_ID
160             else R.id.split_shade_guideline
161         constraints.apply {
162             connect(R.id.lockscreen_clock_view_large, START, PARENT_ID, START)
163             connect(R.id.lockscreen_clock_view_large, END, guideline, END)
164             connect(R.id.lockscreen_clock_view_large, BOTTOM, R.id.device_entry_icon_view, TOP)
165             val largeClockTopMargin =
166                 keyguardClockViewModel.getLargeClockTopMargin() +
167                     getDimen(DATE_WEATHER_VIEW_HEIGHT) +
168                     getDimen(ENHANCED_SMARTSPACE_HEIGHT)
169             connect(R.id.lockscreen_clock_view_large, TOP, PARENT_ID, TOP, largeClockTopMargin)
170             constrainWidth(R.id.lockscreen_clock_view_large, WRAP_CONTENT)
171             constrainHeight(R.id.lockscreen_clock_view_large, MATCH_CONSTRAINT)
172             constrainWidth(R.id.lockscreen_clock_view, WRAP_CONTENT)
173             constrainHeight(
174                 R.id.lockscreen_clock_view,
175                 context.resources.getDimensionPixelSize(custR.dimen.small_clock_height)
176             )
177             connect(
178                 R.id.lockscreen_clock_view,
179                 START,
180                 PARENT_ID,
181                 START,
182                 context.resources.getDimensionPixelSize(custR.dimen.clock_padding_start) +
183                     context.resources.getDimensionPixelSize(R.dimen.status_view_margin_horizontal)
184             )
185             val smallClockTopMargin = keyguardClockViewModel.getSmallClockTopMargin()
186             create(R.id.small_clock_guideline_top, ConstraintSet.HORIZONTAL_GUIDELINE)
187             setGuidelineBegin(R.id.small_clock_guideline_top, smallClockTopMargin)
188             connect(R.id.lockscreen_clock_view, TOP, R.id.small_clock_guideline_top, BOTTOM)
189         }
190 
191         constrainWeatherClockDateIconsBarrier(constraints)
192     }
193 
getDimennull194     private fun getDimen(name: String): Int {
195         return getDimen(context, name)
196     }
197 
198     companion object {
199         private const val DATE_WEATHER_VIEW_HEIGHT = "date_weather_view_height"
200         private const val ENHANCED_SMARTSPACE_HEIGHT = "enhanced_smartspace_height"
getDimennull201         fun getDimen(context: Context, name: String): Int {
202             val res = context.packageManager.getResourcesForApplication(context.packageName)
203             val id = res.getIdentifier(name, "dimen", context.packageName)
204             return if (id == 0) 0 else res.getDimensionPixelSize(id)
205         }
206     }
207 }
208