1 /*
2  * Copyright (C) 2021 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 package com.android.systemui.statusbar.policy
18 
19 import android.os.Handler
20 import android.testing.AndroidTestingRunner
21 import android.testing.TestableLooper
22 import androidx.test.filters.SmallTest
23 import com.android.systemui.SysuiTestCase
24 import com.android.systemui.broadcast.BroadcastDispatcher
25 import com.android.systemui.util.mockito.any
26 import com.android.systemui.util.mockito.capture
27 import com.android.systemui.util.mockito.mock
28 import com.android.systemui.util.time.FakeSystemClock
29 import com.google.common.truth.Truth.assertThat
30 import org.junit.Before
31 import org.junit.Test
32 import org.junit.runner.RunWith
33 import org.mockito.ArgumentCaptor
34 import org.mockito.Captor
35 import org.mockito.Mock
36 import org.mockito.Mockito.`when`
37 import org.mockito.Mockito.anyString
38 import org.mockito.Mockito.verify
39 import org.mockito.MockitoAnnotations
40 import java.util.Date
41 
42 @RunWith(AndroidTestingRunner::class)
43 @TestableLooper.RunWithLooper
44 @SmallTest
45 class VariableDateViewControllerTest : SysuiTestCase() {
46 
47     companion object {
48         private const val TIME_STAMP = 1_500_000_000_000
49         private const val LONG_PATTERN = "EEEMMMd"
50         private const val SHORT_PATTERN = "MMMd"
51         private const val CHAR_WIDTH = 10f
52     }
53 
54     @Mock
55     private lateinit var broadcastDispatcher: BroadcastDispatcher
56     @Mock
57     private lateinit var view: VariableDateView
58     @Captor
59     private lateinit var onMeasureListenerCaptor: ArgumentCaptor<VariableDateView.OnMeasureListener>
60 
61     private var lastText: String? = null
62 
63     private lateinit var systemClock: FakeSystemClock
64     private lateinit var testableLooper: TestableLooper
65     private lateinit var testableHandler: Handler
66     private lateinit var controller: VariableDateViewController
67 
68     private lateinit var longText: String
69     private lateinit var shortText: String
70 
71     @Before
72     fun setUp() {
73         MockitoAnnotations.initMocks(this)
74         testableLooper = TestableLooper.get(this)
75         testableHandler = Handler(testableLooper.looper)
76 
77         systemClock = FakeSystemClock()
78         systemClock.setCurrentTimeMillis(TIME_STAMP)
79 
80         `when`(view.longerPattern).thenReturn(LONG_PATTERN)
81         `when`(view.shorterPattern).thenReturn(SHORT_PATTERN)
82         `when`(view.handler).thenReturn(testableHandler)
83 
84         `when`(view.setText(anyString())).thenAnswer {
85             lastText = it.arguments[0] as? String
86             Unit
87         }
88         `when`(view.isAttachedToWindow).thenReturn(true)
89 
90         val date = Date(TIME_STAMP)
91         longText = getTextForFormat(date, getFormatFromPattern(LONG_PATTERN))
92         shortText = getTextForFormat(date, getFormatFromPattern(SHORT_PATTERN))
93 
94         // Assume some sizes for the text, the controller doesn't need to know if these sizes are
95         // the true ones
96         `when`(view.getDesiredWidthForText(any())).thenAnswer {
97             getTextLength(it.arguments[0] as CharSequence)
98         }
99 
100         controller = VariableDateViewController(
101                 systemClock,
102                 broadcastDispatcher,
103                 mock(),
104                 testableHandler,
105                 view
106         )
107 
108         controller.init()
109         testableLooper.processAllMessages()
110 
111         verify(view).onAttach(capture(onMeasureListenerCaptor))
112     }
113 
114     @Test
115     fun testViewStartsWithLongText() {
116         assertThat(lastText).isEqualTo(longText)
117     }
118 
119     @Test
120     fun testListenerNotNull() {
121         assertThat(onMeasureListenerCaptor.value).isNotNull()
122     }
123 
124     @Test
125     fun testLotsOfSpaceUseLongText() {
126         onMeasureListenerCaptor.value.onMeasureAction(10000)
127 
128         testableLooper.processAllMessages()
129         assertThat(lastText).isEqualTo(longText)
130     }
131 
132     @Test
133     fun testSmallSpaceUseEmpty() {
134         onMeasureListenerCaptor.value.onMeasureAction(1)
135         testableLooper.processAllMessages()
136 
137         assertThat(lastText).isEmpty()
138     }
139 
140     @Test
141     fun testSpaceInBetweenUseShortText() {
142         val average = ((getTextLength(longText) + getTextLength(shortText)) / 2).toInt()
143 
144         onMeasureListenerCaptor.value.onMeasureAction(average)
145         testableLooper.processAllMessages()
146 
147         assertThat(lastText).isEqualTo(shortText)
148     }
149 
150     @Test
151     fun testSwitchBackToLonger() {
152         onMeasureListenerCaptor.value.onMeasureAction(1)
153         testableLooper.processAllMessages()
154 
155         onMeasureListenerCaptor.value.onMeasureAction(10000)
156         testableLooper.processAllMessages()
157 
158         assertThat(lastText).isEqualTo(longText)
159     }
160 
161     @Test
162     fun testNoSwitchingWhenFrozen() {
163         `when`(view.freezeSwitching).thenReturn(true)
164 
165         val average = ((getTextLength(longText) + getTextLength(shortText)) / 2).toInt()
166         onMeasureListenerCaptor.value.onMeasureAction(average)
167         testableLooper.processAllMessages()
168         assertThat(lastText).isEqualTo(longText)
169 
170         onMeasureListenerCaptor.value.onMeasureAction(1)
171         testableLooper.processAllMessages()
172         assertThat(lastText).isEqualTo(longText)
173     }
174 
175     private fun getTextLength(text: CharSequence): Float {
176         return text.length * CHAR_WIDTH
177     }
178 }