1 /* 2 * Copyright (C) 2018 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.keyguard; 18 19 import static android.view.View.INVISIBLE; 20 import static android.view.View.VISIBLE; 21 22 import static com.android.keyguard.KeyguardClockSwitch.LARGE; 23 import static com.android.keyguard.KeyguardClockSwitch.SMALL; 24 25 import static com.google.common.truth.Truth.assertThat; 26 27 import static junit.framework.TestCase.assertEquals; 28 29 import static org.mockito.Mockito.mock; 30 import static org.mockito.Mockito.when; 31 32 import android.content.Context; 33 import android.test.suitebuilder.annotation.SmallTest; 34 import android.testing.AndroidTestingRunner; 35 import android.testing.TestableLooper.RunWithLooper; 36 import android.util.AttributeSet; 37 import android.view.LayoutInflater; 38 import android.view.View; 39 import android.view.ViewGroup; 40 import android.widget.FrameLayout; 41 import android.widget.TextView; 42 43 import com.android.systemui.R; 44 import com.android.systemui.SysuiTestCase; 45 import com.android.systemui.plugins.ClockController; 46 import com.android.systemui.plugins.ClockFaceController; 47 import com.android.systemui.statusbar.StatusBarState; 48 49 import org.junit.Before; 50 import org.junit.Test; 51 import org.junit.runner.RunWith; 52 import org.mockito.Mock; 53 import org.mockito.MockitoAnnotations; 54 55 @SmallTest 56 @RunWith(AndroidTestingRunner.class) 57 // Need to run on the main thread because KeyguardSliceView$Row init checks for 58 // the main thread before acquiring a wake lock. This class is constructed when 59 // the keyguard_clock_switch layout is inflated. 60 @RunWithLooper(setAsMainLooper = true) 61 public class KeyguardClockSwitchTest extends SysuiTestCase { 62 @Mock 63 ViewGroup mMockKeyguardSliceView; 64 65 @Mock 66 ClockController mClock; 67 68 @Mock 69 ClockFaceController mSmallClock; 70 71 @Mock 72 ClockFaceController mLargeClock; 73 74 private FrameLayout mSmallClockFrame; 75 private FrameLayout mLargeClockFrame; 76 private KeyguardStatusAreaView mStatusArea; 77 78 KeyguardClockSwitch mKeyguardClockSwitch; 79 80 @Before setUp()81 public void setUp() { 82 MockitoAnnotations.initMocks(this); 83 when(mMockKeyguardSliceView.getContext()).thenReturn(mContext); 84 when(mMockKeyguardSliceView.findViewById(R.id.keyguard_status_area)) 85 .thenReturn(mMockKeyguardSliceView); 86 87 when(mClock.getSmallClock()).thenReturn(mSmallClock); 88 when(mClock.getLargeClock()).thenReturn(mLargeClock); 89 90 when(mSmallClock.getView()).thenReturn(new TextView(getContext())); 91 when(mLargeClock.getView()).thenReturn(new TextView(getContext())); 92 93 LayoutInflater layoutInflater = LayoutInflater.from(getContext()); 94 layoutInflater.setPrivateFactory(new LayoutInflater.Factory2() { 95 96 @Override 97 public View onCreateView(View parent, String name, Context context, 98 AttributeSet attrs) { 99 return onCreateView(name, context, attrs); 100 } 101 102 @Override 103 public View onCreateView(String name, Context context, AttributeSet attrs) { 104 if ("com.android.keyguard.KeyguardSliceView".equals(name)) { 105 return mMockKeyguardSliceView; 106 } 107 return null; 108 } 109 }); 110 mKeyguardClockSwitch = 111 (KeyguardClockSwitch) layoutInflater.inflate(R.layout.keyguard_clock_switch, null); 112 mSmallClockFrame = mKeyguardClockSwitch.findViewById(R.id.lockscreen_clock_view); 113 mLargeClockFrame = mKeyguardClockSwitch.findViewById(R.id.lockscreen_clock_view_large); 114 mStatusArea = mKeyguardClockSwitch.findViewById(R.id.keyguard_status_area); 115 mKeyguardClockSwitch.mChildrenAreLaidOut = true; 116 } 117 118 @Test noPluginConnected_showNothing()119 public void noPluginConnected_showNothing() { 120 mKeyguardClockSwitch.setClock(null, StatusBarState.KEYGUARD); 121 assertEquals(mLargeClockFrame.getChildCount(), 0); 122 assertEquals(mSmallClockFrame.getChildCount(), 0); 123 } 124 125 @Test pluginConnectedThenDisconnected_showNothing()126 public void pluginConnectedThenDisconnected_showNothing() { 127 mKeyguardClockSwitch.setClock(mClock, StatusBarState.KEYGUARD); 128 assertEquals(mLargeClockFrame.getChildCount(), 1); 129 assertEquals(mSmallClockFrame.getChildCount(), 1); 130 131 mKeyguardClockSwitch.setClock(null, StatusBarState.KEYGUARD); 132 assertEquals(mLargeClockFrame.getChildCount(), 0); 133 assertEquals(mSmallClockFrame.getChildCount(), 0); 134 } 135 136 @Test onPluginConnected_showClock()137 public void onPluginConnected_showClock() { 138 mKeyguardClockSwitch.setClock(mClock, StatusBarState.KEYGUARD); 139 140 assertEquals(mClock.getSmallClock().getView().getParent(), mSmallClockFrame); 141 assertEquals(mClock.getLargeClock().getView().getParent(), mLargeClockFrame); 142 } 143 144 @Test onPluginConnected_showSecondPluginClock()145 public void onPluginConnected_showSecondPluginClock() { 146 // GIVEN a plugin has already connected 147 ClockController otherClock = mock(ClockController.class); 148 ClockFaceController smallClock = mock(ClockFaceController.class); 149 ClockFaceController largeClock = mock(ClockFaceController.class); 150 when(otherClock.getSmallClock()).thenReturn(smallClock); 151 when(otherClock.getLargeClock()).thenReturn(largeClock); 152 when(smallClock.getView()).thenReturn(new TextView(getContext())); 153 when(largeClock.getView()).thenReturn(new TextView(getContext())); 154 mKeyguardClockSwitch.setClock(mClock, StatusBarState.KEYGUARD); 155 mKeyguardClockSwitch.setClock(otherClock, StatusBarState.KEYGUARD); 156 157 // THEN only the view from the second plugin should be a child of KeyguardClockSwitch. 158 assertThat(otherClock.getSmallClock().getView().getParent()).isEqualTo(mSmallClockFrame); 159 assertThat(otherClock.getLargeClock().getView().getParent()).isEqualTo(mLargeClockFrame); 160 assertThat(mClock.getSmallClock().getView().getParent()).isNull(); 161 assertThat(mClock.getLargeClock().getView().getParent()).isNull(); 162 } 163 164 @Test onPluginDisconnected_secondOfTwoDisconnected()165 public void onPluginDisconnected_secondOfTwoDisconnected() { 166 // GIVEN two plugins are connected 167 ClockController otherClock = mock(ClockController.class); 168 ClockFaceController smallClock = mock(ClockFaceController.class); 169 ClockFaceController largeClock = mock(ClockFaceController.class); 170 when(otherClock.getSmallClock()).thenReturn(smallClock); 171 when(otherClock.getLargeClock()).thenReturn(largeClock); 172 when(smallClock.getView()).thenReturn(new TextView(getContext())); 173 when(largeClock.getView()).thenReturn(new TextView(getContext())); 174 mKeyguardClockSwitch.setClock(otherClock, StatusBarState.KEYGUARD); 175 mKeyguardClockSwitch.setClock(mClock, StatusBarState.KEYGUARD); 176 // WHEN the second plugin is disconnected 177 mKeyguardClockSwitch.setClock(null, StatusBarState.KEYGUARD); 178 // THEN nothing should be shown 179 assertThat(otherClock.getSmallClock().getView().getParent()).isNull(); 180 assertThat(otherClock.getLargeClock().getView().getParent()).isNull(); 181 assertThat(mClock.getSmallClock().getView().getParent()).isNull(); 182 assertThat(mClock.getLargeClock().getView().getParent()).isNull(); 183 } 184 185 @Test switchingToBigClockWithAnimation_makesSmallClockDisappear()186 public void switchingToBigClockWithAnimation_makesSmallClockDisappear() { 187 mKeyguardClockSwitch.switchToClock(LARGE, /* animate */ true); 188 189 mKeyguardClockSwitch.mClockInAnim.end(); 190 mKeyguardClockSwitch.mClockOutAnim.end(); 191 mKeyguardClockSwitch.mStatusAreaAnim.end(); 192 193 assertThat(mLargeClockFrame.getAlpha()).isEqualTo(1); 194 assertThat(mLargeClockFrame.getVisibility()).isEqualTo(VISIBLE); 195 assertThat(mSmallClockFrame.getAlpha()).isEqualTo(0); 196 assertThat(mSmallClockFrame.getVisibility()).isEqualTo(INVISIBLE); 197 } 198 199 @Test switchingToBigClockNoAnimation_makesSmallClockDisappear()200 public void switchingToBigClockNoAnimation_makesSmallClockDisappear() { 201 mKeyguardClockSwitch.switchToClock(LARGE, /* animate */ false); 202 203 assertThat(mLargeClockFrame.getAlpha()).isEqualTo(1); 204 assertThat(mLargeClockFrame.getVisibility()).isEqualTo(VISIBLE); 205 assertThat(mSmallClockFrame.getAlpha()).isEqualTo(0); 206 assertThat(mSmallClockFrame.getVisibility()).isEqualTo(INVISIBLE); 207 } 208 209 @Test switchingToSmallClockWithAnimation_makesBigClockDisappear()210 public void switchingToSmallClockWithAnimation_makesBigClockDisappear() { 211 mKeyguardClockSwitch.switchToClock(SMALL, /* animate */ true); 212 213 mKeyguardClockSwitch.mClockInAnim.end(); 214 mKeyguardClockSwitch.mClockOutAnim.end(); 215 mKeyguardClockSwitch.mStatusAreaAnim.end(); 216 217 assertThat(mSmallClockFrame.getAlpha()).isEqualTo(1); 218 assertThat(mSmallClockFrame.getVisibility()).isEqualTo(VISIBLE); 219 // only big clock is removed at switch 220 assertThat(mLargeClockFrame.getParent()).isNull(); 221 assertThat(mLargeClockFrame.getAlpha()).isEqualTo(0); 222 assertThat(mLargeClockFrame.getVisibility()).isEqualTo(INVISIBLE); 223 } 224 225 @Test switchingToSmallClockNoAnimation_makesBigClockDisappear()226 public void switchingToSmallClockNoAnimation_makesBigClockDisappear() { 227 mKeyguardClockSwitch.switchToClock(SMALL, false); 228 229 assertThat(mSmallClockFrame.getAlpha()).isEqualTo(1); 230 assertThat(mSmallClockFrame.getVisibility()).isEqualTo(VISIBLE); 231 // only big clock is removed at switch 232 assertThat(mLargeClockFrame.getParent()).isNull(); 233 assertThat(mLargeClockFrame.getAlpha()).isEqualTo(0); 234 assertThat(mLargeClockFrame.getVisibility()).isEqualTo(INVISIBLE); 235 } 236 237 @Test switchingToSmallClockAnimation_resetsStatusArea()238 public void switchingToSmallClockAnimation_resetsStatusArea() { 239 mKeyguardClockSwitch.switchToClock(SMALL, true); 240 241 mKeyguardClockSwitch.mClockInAnim.end(); 242 mKeyguardClockSwitch.mClockOutAnim.end(); 243 mKeyguardClockSwitch.mStatusAreaAnim.end(); 244 245 assertThat(mStatusArea.getTranslationX()).isEqualTo(0); 246 assertThat(mStatusArea.getTranslationY()).isEqualTo(0); 247 assertThat(mStatusArea.getScaleX()).isEqualTo(1); 248 assertThat(mStatusArea.getScaleY()).isEqualTo(1); 249 } 250 251 @Test switchingToSmallClockNoAnimation_resetsStatusArea()252 public void switchingToSmallClockNoAnimation_resetsStatusArea() { 253 mKeyguardClockSwitch.switchToClock(SMALL, false); 254 255 assertThat(mStatusArea.getTranslationX()).isEqualTo(0); 256 assertThat(mStatusArea.getTranslationY()).isEqualTo(0); 257 assertThat(mStatusArea.getScaleX()).isEqualTo(1); 258 assertThat(mStatusArea.getScaleY()).isEqualTo(1); 259 } 260 261 262 @Test switchingToBigClock_returnsTrueOnlyWhenItWasNotVisibleBefore()263 public void switchingToBigClock_returnsTrueOnlyWhenItWasNotVisibleBefore() { 264 assertThat(mKeyguardClockSwitch.switchToClock(LARGE, /* animate */ true)).isTrue(); 265 assertThat(mKeyguardClockSwitch.switchToClock(LARGE, /* animate */ true)).isFalse(); 266 } 267 } 268