1 /* 2 * Copyright (C) 2020 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 org.junit.Assert.assertEquals; 20 import static org.mockito.ArgumentMatchers.any; 21 import static org.mockito.ArgumentMatchers.anyInt; 22 import static org.mockito.ArgumentMatchers.eq; 23 import static org.mockito.Mockito.mock; 24 import static org.mockito.Mockito.never; 25 import static org.mockito.Mockito.times; 26 import static org.mockito.Mockito.verify; 27 import static org.mockito.Mockito.when; 28 29 import android.content.res.Resources; 30 import android.testing.AndroidTestingRunner; 31 import android.view.View; 32 import android.widget.FrameLayout; 33 import android.widget.RelativeLayout; 34 35 import androidx.test.filters.SmallTest; 36 37 import com.android.internal.colorextraction.ColorExtractor; 38 import com.android.keyguard.clock.ClockManager; 39 import com.android.systemui.R; 40 import com.android.systemui.SysuiTestCase; 41 import com.android.systemui.broadcast.BroadcastDispatcher; 42 import com.android.systemui.colorextraction.SysuiColorExtractor; 43 import com.android.systemui.keyguard.KeyguardUnlockAnimationController; 44 import com.android.systemui.plugins.ClockPlugin; 45 import com.android.systemui.plugins.statusbar.StatusBarStateController; 46 import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController; 47 import com.android.systemui.statusbar.StatusBarState; 48 import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController; 49 import com.android.systemui.statusbar.phone.KeyguardBypassController; 50 import com.android.systemui.statusbar.phone.NotificationIconAreaController; 51 import com.android.systemui.statusbar.phone.NotificationIconContainer; 52 import com.android.systemui.statusbar.policy.BatteryController; 53 54 import org.junit.Before; 55 import org.junit.Test; 56 import org.junit.runner.RunWith; 57 import org.mockito.ArgumentCaptor; 58 import org.mockito.Mock; 59 import org.mockito.MockitoAnnotations; 60 import org.mockito.verification.VerificationMode; 61 62 @SmallTest 63 @RunWith(AndroidTestingRunner.class) 64 public class KeyguardClockSwitchControllerTest extends SysuiTestCase { 65 66 @Mock 67 private KeyguardClockSwitch mView; 68 @Mock 69 private StatusBarStateController mStatusBarStateController; 70 @Mock 71 private SysuiColorExtractor mColorExtractor; 72 @Mock 73 private ClockManager mClockManager; 74 @Mock 75 KeyguardSliceViewController mKeyguardSliceViewController; 76 @Mock 77 NotificationIconAreaController mNotificationIconAreaController; 78 @Mock 79 BroadcastDispatcher mBroadcastDispatcher; 80 @Mock 81 BatteryController mBatteryController; 82 @Mock 83 KeyguardUpdateMonitor mKeyguardUpdateMonitor; 84 @Mock 85 KeyguardBypassController mBypassController; 86 @Mock 87 LockscreenSmartspaceController mSmartspaceController; 88 89 @Mock 90 Resources mResources; 91 KeyguardUnlockAnimationController mKeyguardUnlockAnimationController; 92 @Mock 93 SmartspaceTransitionController mSmartSpaceTransitionController; 94 @Mock 95 private ClockPlugin mClockPlugin; 96 @Mock 97 ColorExtractor.GradientColors mGradientColors; 98 99 @Mock 100 private NotificationIconContainer mNotificationIcons; 101 @Mock 102 private AnimatableClockView mClockView; 103 @Mock 104 private AnimatableClockView mLargeClockView; 105 @Mock 106 private FrameLayout mLargeClockFrame; 107 108 private final View mFakeSmartspaceView = new View(mContext); 109 110 private KeyguardClockSwitchController mController; 111 private View mStatusArea; 112 113 @Before setup()114 public void setup() { 115 MockitoAnnotations.initMocks(this); 116 117 when(mView.findViewById(R.id.left_aligned_notification_icon_container)) 118 .thenReturn(mNotificationIcons); 119 when(mNotificationIcons.getLayoutParams()).thenReturn( 120 mock(RelativeLayout.LayoutParams.class)); 121 when(mView.getContext()).thenReturn(getContext()); 122 123 when(mView.findViewById(R.id.animatable_clock_view)).thenReturn(mClockView); 124 when(mView.findViewById(R.id.animatable_clock_view_large)).thenReturn(mLargeClockView); 125 when(mView.findViewById(R.id.lockscreen_clock_view_large)).thenReturn(mLargeClockFrame); 126 when(mClockView.getContext()).thenReturn(getContext()); 127 when(mLargeClockView.getContext()).thenReturn(getContext()); 128 129 when(mView.isAttachedToWindow()).thenReturn(true); 130 when(mResources.getString(anyInt())).thenReturn("h:mm"); 131 when(mSmartspaceController.buildAndConnectView(any())).thenReturn(mFakeSmartspaceView); 132 mController = new KeyguardClockSwitchController( 133 mView, 134 mStatusBarStateController, 135 mColorExtractor, 136 mClockManager, 137 mKeyguardSliceViewController, 138 mNotificationIconAreaController, 139 mBroadcastDispatcher, 140 mBatteryController, 141 mKeyguardUpdateMonitor, 142 mBypassController, 143 mSmartspaceController, 144 mKeyguardUnlockAnimationController, 145 mSmartSpaceTransitionController 146 ); 147 148 when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE); 149 when(mColorExtractor.getColors(anyInt())).thenReturn(mGradientColors); 150 151 mStatusArea = new View(getContext()); 152 when(mView.findViewById(R.id.keyguard_status_area)).thenReturn(mStatusArea); 153 } 154 155 @Test testInit_viewAlreadyAttached()156 public void testInit_viewAlreadyAttached() { 157 mController.init(); 158 159 verifyAttachment(times(1)); 160 } 161 162 @Test testInit_viewNotYetAttached()163 public void testInit_viewNotYetAttached() { 164 ArgumentCaptor<View.OnAttachStateChangeListener> listenerArgumentCaptor = 165 ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class); 166 167 when(mView.isAttachedToWindow()).thenReturn(false); 168 mController.init(); 169 verify(mView).addOnAttachStateChangeListener(listenerArgumentCaptor.capture()); 170 171 verifyAttachment(never()); 172 173 listenerArgumentCaptor.getValue().onViewAttachedToWindow(mView); 174 175 verifyAttachment(times(1)); 176 } 177 178 @Test testInitSubControllers()179 public void testInitSubControllers() { 180 mController.init(); 181 verify(mKeyguardSliceViewController).init(); 182 } 183 184 @Test testInit_viewDetached()185 public void testInit_viewDetached() { 186 ArgumentCaptor<View.OnAttachStateChangeListener> listenerArgumentCaptor = 187 ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class); 188 mController.init(); 189 verify(mView).addOnAttachStateChangeListener(listenerArgumentCaptor.capture()); 190 191 verifyAttachment(times(1)); 192 193 listenerArgumentCaptor.getValue().onViewDetachedFromWindow(mView); 194 195 verify(mColorExtractor).removeOnColorsChangedListener( 196 any(ColorExtractor.OnColorsChangedListener.class)); 197 } 198 199 @Test testPluginPassesStatusBarState()200 public void testPluginPassesStatusBarState() { 201 ArgumentCaptor<ClockManager.ClockChangedListener> listenerArgumentCaptor = 202 ArgumentCaptor.forClass(ClockManager.ClockChangedListener.class); 203 204 mController.init(); 205 verify(mClockManager).addOnClockChangedListener(listenerArgumentCaptor.capture()); 206 207 listenerArgumentCaptor.getValue().onClockChanged(mClockPlugin); 208 verify(mView).setClockPlugin(mClockPlugin, StatusBarState.SHADE); 209 } 210 211 @Test testSmartspaceEnabledRemovesKeyguardStatusArea()212 public void testSmartspaceEnabledRemovesKeyguardStatusArea() { 213 when(mSmartspaceController.isEnabled()).thenReturn(true); 214 when(mSmartspaceController.buildAndConnectView(any())).thenReturn(mFakeSmartspaceView); 215 mController.init(); 216 217 assertEquals(View.GONE, mStatusArea.getVisibility()); 218 } 219 220 @Test testSmartspaceDisabledShowsKeyguardStatusArea()221 public void testSmartspaceDisabledShowsKeyguardStatusArea() { 222 when(mSmartspaceController.isEnabled()).thenReturn(false); 223 mController.init(); 224 225 assertEquals(View.VISIBLE, mStatusArea.getVisibility()); 226 } 227 228 @Test testDetachRemovesSmartspaceView()229 public void testDetachRemovesSmartspaceView() { 230 when(mSmartspaceController.isEnabled()).thenReturn(true); 231 when(mSmartspaceController.buildAndConnectView(any())).thenReturn(mFakeSmartspaceView); 232 mController.init(); 233 verify(mView).addView(eq(mFakeSmartspaceView), anyInt(), any()); 234 235 ArgumentCaptor<View.OnAttachStateChangeListener> listenerArgumentCaptor = 236 ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class); 237 verify(mView).addOnAttachStateChangeListener(listenerArgumentCaptor.capture()); 238 239 listenerArgumentCaptor.getValue().onViewDetachedFromWindow(mView); 240 verify(mView).removeView(mFakeSmartspaceView); 241 } 242 243 @Test testRefresh()244 public void testRefresh() { 245 mController.refresh(); 246 247 verify(mSmartspaceController).requestSmartspaceUpdate(); 248 } 249 verifyAttachment(VerificationMode times)250 private void verifyAttachment(VerificationMode times) { 251 verify(mClockManager, times).addOnClockChangedListener( 252 any(ClockManager.ClockChangedListener.class)); 253 verify(mColorExtractor, times).addOnColorsChangedListener( 254 any(ColorExtractor.OnColorsChangedListener.class)); 255 verify(mView, times).updateColors(mGradientColors); 256 } 257 } 258