1 /*
2  * 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.blueprints
19 
20 import android.testing.TestableLooper.RunWithLooper
21 import androidx.constraintlayout.widget.ConstraintLayout
22 import androidx.constraintlayout.widget.ConstraintSet
23 import androidx.test.ext.junit.runners.AndroidJUnit4
24 import androidx.test.filters.SmallTest
25 import com.android.systemui.SysuiTestCase
26 import com.android.systemui.communal.ui.view.layout.sections.CommunalTutorialIndicatorSection
27 import com.android.systemui.keyguard.shared.model.KeyguardBlueprint
28 import com.android.systemui.keyguard.shared.model.KeyguardSection
29 import com.android.systemui.keyguard.ui.view.KeyguardRootView
30 import com.android.systemui.keyguard.ui.view.layout.sections.AccessibilityActionsSection
31 import com.android.systemui.keyguard.ui.view.layout.sections.AodBurnInSection
32 import com.android.systemui.keyguard.ui.view.layout.sections.AodNotificationIconsSection
33 import com.android.systemui.keyguard.ui.view.layout.sections.ClockSection
34 import com.android.systemui.keyguard.ui.view.layout.sections.DefaultDeviceEntrySection
35 import com.android.systemui.keyguard.ui.view.layout.sections.DefaultIndicationAreaSection
36 import com.android.systemui.keyguard.ui.view.layout.sections.DefaultNotificationStackScrollLayoutSection
37 import com.android.systemui.keyguard.ui.view.layout.sections.DefaultSettingsPopupMenuSection
38 import com.android.systemui.keyguard.ui.view.layout.sections.DefaultShortcutsSection
39 import com.android.systemui.keyguard.ui.view.layout.sections.DefaultStatusBarSection
40 import com.android.systemui.keyguard.ui.view.layout.sections.DefaultStatusViewSection
41 import com.android.systemui.keyguard.ui.view.layout.sections.DefaultUdfpsAccessibilityOverlaySection
42 import com.android.systemui.keyguard.ui.view.layout.sections.KeyguardSliceViewSection
43 import com.android.systemui.keyguard.ui.view.layout.sections.SmartspaceSection
44 import com.android.systemui.keyguard.ui.view.layout.sections.SplitShadeGuidelines
45 import com.android.systemui.util.mockito.whenever
46 import java.util.Optional
47 import kotlinx.coroutines.ExperimentalCoroutinesApi
48 import org.junit.Before
49 import org.junit.Test
50 import org.junit.runner.RunWith
51 import org.mockito.Mock
52 import org.mockito.Mockito.mock
53 import org.mockito.Mockito.never
54 import org.mockito.Mockito.verify
55 import org.mockito.MockitoAnnotations
56 
57 @RunWith(AndroidJUnit4::class)
58 @RunWithLooper(setAsMainLooper = true)
59 @ExperimentalCoroutinesApi
60 @SmallTest
61 class DefaultKeyguardBlueprintTest : SysuiTestCase() {
62     private lateinit var underTest: DefaultKeyguardBlueprint
63     private lateinit var rootView: KeyguardRootView
64     @Mock private lateinit var accessibilityActionsSection: AccessibilityActionsSection
65     @Mock private lateinit var defaultIndicationAreaSection: DefaultIndicationAreaSection
66     @Mock private lateinit var mDefaultDeviceEntrySection: DefaultDeviceEntrySection
67     @Mock private lateinit var defaultShortcutsSection: DefaultShortcutsSection
68     @Mock private lateinit var defaultAmbientIndicationAreaSection: Optional<KeyguardSection>
69     @Mock private lateinit var defaultSettingsPopupMenuSection: DefaultSettingsPopupMenuSection
70     @Mock private lateinit var defaultStatusViewSection: DefaultStatusViewSection
71     @Mock private lateinit var defaultStatusBarViewSection: DefaultStatusBarSection
72     @Mock private lateinit var defaultNSSLSection: DefaultNotificationStackScrollLayoutSection
73     @Mock private lateinit var splitShadeGuidelines: SplitShadeGuidelines
74     @Mock private lateinit var aodNotificationIconsSection: AodNotificationIconsSection
75     @Mock private lateinit var aodBurnInSection: AodBurnInSection
76     @Mock private lateinit var communalTutorialIndicatorSection: CommunalTutorialIndicatorSection
77     @Mock private lateinit var clockSection: ClockSection
78     @Mock private lateinit var smartspaceSection: SmartspaceSection
79     @Mock private lateinit var keyguardSliceViewSection: KeyguardSliceViewSection
80     @Mock
81     private lateinit var udfpsAccessibilityOverlaySection: DefaultUdfpsAccessibilityOverlaySection
82     @Before
setupnull83     fun setup() {
84         MockitoAnnotations.initMocks(this)
85         rootView = KeyguardRootView(context, null)
86         underTest =
87             DefaultKeyguardBlueprint(
88                 accessibilityActionsSection,
89                 defaultIndicationAreaSection,
90                 mDefaultDeviceEntrySection,
91                 defaultShortcutsSection,
92                 defaultAmbientIndicationAreaSection,
93                 defaultSettingsPopupMenuSection,
94                 defaultStatusViewSection,
95                 defaultStatusBarViewSection,
96                 defaultNSSLSection,
97                 aodNotificationIconsSection,
98                 aodBurnInSection,
99                 communalTutorialIndicatorSection,
100                 clockSection,
101                 smartspaceSection,
102                 keyguardSliceViewSection,
103                 udfpsAccessibilityOverlaySection,
104             )
105     }
106 
107     @Test
replaceViewsnull108     fun replaceViews() {
109         val constraintLayout = ConstraintLayout(context, null)
110         underTest.replaceViews(constraintLayout)
111         underTest.sections.forEach { verify(it)?.addViews(constraintLayout) }
112     }
113 
114     @Test
replaceViews_withPrevBlueprintnull115     fun replaceViews_withPrevBlueprint() {
116         val prevBlueprint = mock(KeyguardBlueprint::class.java)
117         val removedSection = mock(KeyguardSection::class.java)
118         val addedSection = mDefaultDeviceEntrySection
119         val rebuildSection = clockSection
120         val prevSections = underTest.sections.minus(addedSection).plus(removedSection)
121         val unchangedSections = underTest.sections.subtract(listOf(addedSection, rebuildSection))
122         whenever(prevBlueprint.sections).thenReturn(prevSections)
123 
124         val constraintLayout = ConstraintLayout(context, null)
125         underTest.replaceViews(constraintLayout, prevBlueprint)
126 
127         unchangedSections.forEach {
128             verify(it, never()).addViews(constraintLayout)
129             verify(it, never()).removeViews(constraintLayout)
130         }
131 
132         verify(addedSection).addViews(constraintLayout)
133         verify(removedSection).removeViews(constraintLayout)
134     }
135 
136     @Test
replaceViews_withPrevBlueprint_withRebuildTargetsnull137     fun replaceViews_withPrevBlueprint_withRebuildTargets() {
138         val prevBlueprint = mock(KeyguardBlueprint::class.java)
139         val removedSection = mock(KeyguardSection::class.java)
140         val addedSection = mDefaultDeviceEntrySection
141         val rebuildSection = clockSection
142         val prevSections = underTest.sections.minus(addedSection).plus(removedSection)
143         val unchangedSections = underTest.sections.subtract(listOf(addedSection, rebuildSection))
144         whenever(prevBlueprint.sections).thenReturn(prevSections)
145 
146         val constraintLayout = ConstraintLayout(context, null)
147         underTest.replaceViews(constraintLayout, prevBlueprint, listOf(rebuildSection))
148 
149         unchangedSections.forEach {
150             verify(it, never()).addViews(constraintLayout)
151             verify(it, never()).removeViews(constraintLayout)
152         }
153 
154         verify(addedSection).addViews(constraintLayout)
155         verify(rebuildSection).addViews(constraintLayout)
156         verify(rebuildSection).removeViews(constraintLayout)
157         verify(removedSection).removeViews(constraintLayout)
158     }
159 
160     @Test
rebuildViewsnull161     fun rebuildViews() {
162         val rebuildSections = listOf(mDefaultDeviceEntrySection, clockSection)
163         val unchangedSections = underTest.sections.subtract(rebuildSections)
164 
165         val constraintLayout = ConstraintLayout(context, null)
166         underTest.rebuildViews(constraintLayout, rebuildSections)
167 
168         unchangedSections.forEach {
169             verify(it, never()).addViews(constraintLayout)
170             verify(it, never()).removeViews(constraintLayout)
171         }
172 
173         rebuildSections.forEach {
174             verify(it).addViews(constraintLayout)
175             verify(it).removeViews(constraintLayout)
176         }
177     }
178 
179     @Test
deviceEntryIconIsOnTopnull180     fun deviceEntryIconIsOnTop() {
181         val constraintLayout = ConstraintLayout(context, null)
182         underTest.replaceViews(constraintLayout)
183         underTest.sections.forEach { verify(it)?.addViews(constraintLayout) }
184     }
185 
186     @Test
applyConstraintsnull187     fun applyConstraints() {
188         val cs = ConstraintSet()
189         underTest.applyConstraints(cs)
190         underTest.sections.forEach { verify(it)?.applyConstraints(cs) }
191     }
192 }
193