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 android.view.View 23 import androidx.test.filters.SmallTest 24 import com.android.systemui.SysuiTestCase 25 import com.android.systemui.broadcast.BroadcastDispatcher 26 import com.android.systemui.shade.domain.interactor.ShadeInteractor 27 import com.android.systemui.util.mockito.any 28 import com.android.systemui.util.mockito.capture 29 import com.android.systemui.util.mockito.mock 30 import com.android.systemui.util.time.FakeSystemClock 31 import com.google.common.truth.Truth.assertThat 32 import kotlinx.coroutines.flow.MutableStateFlow 33 import org.junit.Before 34 import org.junit.Test 35 import org.junit.runner.RunWith 36 import org.mockito.ArgumentCaptor 37 import org.mockito.Captor 38 import org.mockito.Mock 39 import org.mockito.Mockito.anyString 40 import org.mockito.Mockito.verify 41 import org.mockito.Mockito.`when` 42 import org.mockito.MockitoAnnotations 43 import java.util.Date 44 45 @RunWith(AndroidTestingRunner::class) 46 @TestableLooper.RunWithLooper(setAsMainLooper = true) 47 @SmallTest 48 class VariableDateViewControllerTest : SysuiTestCase() { 49 50 companion object { 51 private const val TIME_STAMP = 1_500_000_000_000 52 private const val LONG_PATTERN = "EEEMMMd" 53 private const val SHORT_PATTERN = "MMMd" 54 private const val CHAR_WIDTH = 10f 55 } 56 57 @Mock 58 private lateinit var broadcastDispatcher: BroadcastDispatcher 59 @Mock 60 private lateinit var view: VariableDateView 61 @Mock 62 private lateinit var shadeInteractor: ShadeInteractor 63 @Captor 64 private lateinit var onMeasureListenerCaptor: ArgumentCaptor<VariableDateView.OnMeasureListener> 65 66 private val qsExpansion = MutableStateFlow(0F) 67 68 private var lastText: String? = null 69 70 private lateinit var systemClock: FakeSystemClock 71 private lateinit var testableLooper: TestableLooper 72 private lateinit var testableHandler: Handler 73 private lateinit var controller: VariableDateViewController 74 75 private lateinit var longText: String 76 private lateinit var shortText: String 77 78 @Before setUpnull79 fun setUp() { 80 MockitoAnnotations.initMocks(this) 81 testableLooper = TestableLooper.get(this) 82 testableHandler = Handler(testableLooper.looper) 83 84 systemClock = FakeSystemClock() 85 systemClock.setCurrentTimeMillis(TIME_STAMP) 86 87 `when`(shadeInteractor.qsExpansion).thenReturn(qsExpansion) 88 89 `when`(view.longerPattern).thenReturn(LONG_PATTERN) 90 `when`(view.shorterPattern).thenReturn(SHORT_PATTERN) 91 `when`(view.handler).thenReturn(testableHandler) 92 93 `when`(view.setText(anyString())).thenAnswer { 94 lastText = it.arguments[0] as? String 95 Unit 96 } 97 `when`(view.isAttachedToWindow).thenReturn(true) 98 `when`(view.viewTreeObserver).thenReturn(mock()) 99 100 val date = Date(TIME_STAMP) 101 longText = getTextForFormat(date, getFormatFromPattern(LONG_PATTERN)) 102 shortText = getTextForFormat(date, getFormatFromPattern(SHORT_PATTERN)) 103 104 // Assume some sizes for the text, the controller doesn't need to know if these sizes are 105 // the true ones 106 `when`(view.getDesiredWidthForText(any())).thenAnswer { 107 getTextLength(it.arguments[0] as CharSequence) 108 } 109 110 controller = VariableDateViewController( 111 systemClock, 112 broadcastDispatcher, 113 shadeInteractor, 114 mock(), 115 testableHandler, 116 view 117 ) 118 119 controller.init() 120 testableLooper.processAllMessages() 121 122 verify(view).onAttach(capture(onMeasureListenerCaptor)) 123 } 124 125 @Test testViewStartsWithLongTextnull126 fun testViewStartsWithLongText() { 127 assertThat(lastText).isEqualTo(longText) 128 } 129 130 @Test testListenerNotNullnull131 fun testListenerNotNull() { 132 assertThat(onMeasureListenerCaptor.value).isNotNull() 133 } 134 135 @Test testLotsOfSpaceUseLongTextnull136 fun testLotsOfSpaceUseLongText() { 137 onMeasureListenerCaptor.value.onMeasureAction(10000, View.MeasureSpec.EXACTLY) 138 139 testableLooper.processAllMessages() 140 assertThat(lastText).isEqualTo(longText) 141 } 142 143 @Test testSmallSpaceUseEmptynull144 fun testSmallSpaceUseEmpty() { 145 onMeasureListenerCaptor.value.onMeasureAction(1, View.MeasureSpec.EXACTLY) 146 testableLooper.processAllMessages() 147 148 assertThat(lastText).isEmpty() 149 } 150 151 @Test testSpaceInBetweenUseShortTextnull152 fun testSpaceInBetweenUseShortText() { 153 val average = ((getTextLength(longText) + getTextLength(shortText)) / 2).toInt() 154 155 onMeasureListenerCaptor.value.onMeasureAction(average, View.MeasureSpec.EXACTLY) 156 testableLooper.processAllMessages() 157 158 assertThat(lastText).isEqualTo(shortText) 159 } 160 161 @Test testSwitchBackToLongernull162 fun testSwitchBackToLonger() { 163 onMeasureListenerCaptor.value.onMeasureAction(1, View.MeasureSpec.EXACTLY) 164 testableLooper.processAllMessages() 165 166 onMeasureListenerCaptor.value.onMeasureAction(10000, View.MeasureSpec.EXACTLY) 167 testableLooper.processAllMessages() 168 169 assertThat(lastText).isEqualTo(longText) 170 } 171 172 @Test testNoSwitchingWhenFrozennull173 fun testNoSwitchingWhenFrozen() { 174 `when`(view.freezeSwitching).thenReturn(true) 175 176 val average = ((getTextLength(longText) + getTextLength(shortText)) / 2).toInt() 177 onMeasureListenerCaptor.value.onMeasureAction(average, View.MeasureSpec.EXACTLY) 178 testableLooper.processAllMessages() 179 assertThat(lastText).isEqualTo(longText) 180 181 onMeasureListenerCaptor.value.onMeasureAction(1, View.MeasureSpec.EXACTLY) 182 testableLooper.processAllMessages() 183 assertThat(lastText).isEqualTo(longText) 184 } 185 186 @Test testQsExpansionTrue_ignoreAtMostMeasureRequestsnull187 fun testQsExpansionTrue_ignoreAtMostMeasureRequests() { 188 qsExpansion.value = 0f 189 190 onMeasureListenerCaptor.value.onMeasureAction( 191 getTextLength(shortText).toInt(), 192 View.MeasureSpec.EXACTLY 193 ) 194 testableLooper.processAllMessages() 195 196 onMeasureListenerCaptor.value.onMeasureAction(10000, View.MeasureSpec.AT_MOST) 197 testableLooper.processAllMessages() 198 assertThat(lastText).isEqualTo(shortText) 199 } 200 201 @Test testQsExpansionFalse_acceptAtMostMeasureRequestsnull202 fun testQsExpansionFalse_acceptAtMostMeasureRequests() { 203 qsExpansion.value = 1f 204 205 onMeasureListenerCaptor.value.onMeasureAction( 206 getTextLength(shortText).toInt(), 207 View.MeasureSpec.EXACTLY 208 ) 209 testableLooper.processAllMessages() 210 211 onMeasureListenerCaptor.value.onMeasureAction(10000, View.MeasureSpec.AT_MOST) 212 testableLooper.processAllMessages() 213 assertThat(lastText).isEqualTo(longText) 214 } 215 getTextLengthnull216 private fun getTextLength(text: CharSequence): Float { 217 return text.length * CHAR_WIDTH 218 } 219 }