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.phone.ongoingcall 18 19 import android.testing.AndroidTestingRunner 20 import android.testing.TestableLooper 21 import android.view.LayoutInflater 22 import android.view.View 23 import androidx.test.filters.SmallTest 24 import com.android.systemui.R 25 import com.android.systemui.SysuiTestCase 26 import com.google.common.truth.Truth.assertThat 27 import org.junit.Before 28 import org.junit.Test 29 import org.junit.runner.RunWith 30 31 private const val TEXT_VIEW_MAX_WIDTH = 400 32 33 // When a [Chronometer] is created, it starts off with "00:00" as its text. 34 private const val INITIAL_TEXT = "00:00" 35 private const val LARGE_TEXT = "00:000" 36 private const val XL_TEXT = "00:0000" 37 38 @SmallTest 39 @RunWith(AndroidTestingRunner::class) 40 @TestableLooper.RunWithLooper 41 class OngoingCallChronometerTest : SysuiTestCase() { 42 43 private lateinit var textView: OngoingCallChronometer 44 private lateinit var doesNotFitText: String 45 46 @Before 47 fun setUp() { 48 allowTestableLooperAsMainThread() 49 TestableLooper.get(this).runWithLooper { 50 val chipView = LayoutInflater.from(mContext).inflate(R.layout.ongoing_call_chip, null) 51 textView = chipView.findViewById(R.id.ongoing_call_chip_time)!! 52 measureTextView() 53 calculateDoesNotFixText() 54 } 55 } 56 57 @Test 58 fun verifyTextSizes() { 59 val initialTextLength = textView.paint.measureText(INITIAL_TEXT) 60 val largeTextLength = textView.paint.measureText(LARGE_TEXT) 61 val xlTextLength = textView.paint.measureText(XL_TEXT) 62 63 // Assert that our test text sizes do what we expect them to do in the rest of the tests. 64 assertThat(initialTextLength).isLessThan(TEXT_VIEW_MAX_WIDTH) 65 assertThat(largeTextLength).isLessThan(TEXT_VIEW_MAX_WIDTH) 66 assertThat(xlTextLength).isLessThan(TEXT_VIEW_MAX_WIDTH) 67 assertThat(textView.paint.measureText(doesNotFitText)).isGreaterThan(TEXT_VIEW_MAX_WIDTH) 68 69 assertThat(largeTextLength).isGreaterThan(initialTextLength) 70 assertThat(xlTextLength).isGreaterThan(largeTextLength) 71 } 72 73 @Test 74 fun onMeasure_initialTextFitsInSpace_textDisplayed() { 75 assertThat(textView.measuredWidth).isGreaterThan(0) 76 } 77 78 @Test 79 fun onMeasure_newTextLargerThanPreviousText_widthGetsLarger() { 80 val initialTextLength = textView.measuredWidth 81 82 setTextAndMeasure(LARGE_TEXT) 83 84 assertThat(textView.measuredWidth).isGreaterThan(initialTextLength) 85 } 86 87 @Test 88 fun onMeasure_newTextSmallerThanPreviousText_widthDoesNotGetSmaller() { 89 setTextAndMeasure(XL_TEXT) 90 val xlWidth = textView.measuredWidth 91 92 setTextAndMeasure(LARGE_TEXT) 93 94 assertThat(textView.measuredWidth).isEqualTo(xlWidth) 95 } 96 97 @Test 98 fun onMeasure_textDoesNotFit_textHidden() { 99 setTextAndMeasure(doesNotFitText) 100 101 assertThat(textView.measuredWidth).isEqualTo(0) 102 } 103 104 @Test 105 fun onMeasure_newTextFitsButPreviousTextDidNot_textHidden() { 106 setTextAndMeasure(doesNotFitText) 107 108 setTextAndMeasure(LARGE_TEXT) 109 110 assertThat(textView.measuredWidth).isEqualTo(0) 111 } 112 113 @Test 114 fun resetBase_hadLongerTextThenSetBaseThenShorterText_widthIsShort() { 115 setTextAndMeasure(XL_TEXT) 116 val xlWidth = textView.measuredWidth 117 118 textView.base = 0L 119 setTextAndMeasure(INITIAL_TEXT) 120 121 assertThat(textView.measuredWidth).isLessThan(xlWidth) 122 assertThat(textView.measuredWidth).isGreaterThan(0) 123 } 124 125 @Test 126 fun setBase_wasHidingTextThenSetBaseThenShorterText_textShown() { 127 setTextAndMeasure(doesNotFitText) 128 129 textView.base = 0L 130 setTextAndMeasure(INITIAL_TEXT) 131 132 assertThat(textView.measuredWidth).isGreaterThan(0) 133 } 134 135 @Test 136 fun setShouldHideText_true_textHidden() { 137 textView.setShouldHideText(true) 138 measureTextView() 139 140 assertThat(textView.measuredWidth).isEqualTo(0) 141 } 142 143 @Test 144 fun setShouldHideText_false_textShown() { 145 // First, set to true so that setting it to false will definitely have an effect. 146 textView.setShouldHideText(true) 147 measureTextView() 148 149 textView.setShouldHideText(false) 150 measureTextView() 151 152 assertThat(textView.measuredWidth).isGreaterThan(0) 153 } 154 155 private fun setTextAndMeasure(text: String) { 156 textView.text = text 157 measureTextView() 158 } 159 160 private fun measureTextView() { 161 textView.measure( 162 View.MeasureSpec.makeMeasureSpec(TEXT_VIEW_MAX_WIDTH, View.MeasureSpec.AT_MOST), 163 View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED) 164 ) 165 } 166 167 /** 168 * Calculates what [doesNotFitText] should be. Needs to be done dynamically because different 169 * devices have different densities, which means the textView can fit different amounts of 170 * characters. 171 */ 172 private fun calculateDoesNotFixText() { 173 var currentText = XL_TEXT + "0" 174 while (textView.paint.measureText(currentText) <= TEXT_VIEW_MAX_WIDTH) { 175 currentText += "0" 176 } 177 doesNotFitText = currentText 178 } 179 } 180