/* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.keyguard; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.database.ContentObserver; import android.os.UserHandle; import android.provider.Settings; import android.testing.AndroidTestingRunner; import android.view.View; import androidx.test.filters.SmallTest; import com.android.systemui.Flags; import com.android.systemui.plugins.clocks.ClockFaceConfig; import com.android.systemui.plugins.clocks.ClockTickRate; import com.android.systemui.shared.clocks.ClockRegistry; import com.android.systemui.statusbar.StatusBarState; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.verification.VerificationMode; @SmallTest @RunWith(AndroidTestingRunner.class) public class KeyguardClockSwitchControllerTest extends KeyguardClockSwitchControllerBaseTest { @Test public void testInit_viewAlreadyAttached() { mSetFlagsRule.disableFlags(Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT); mController.init(); verifyAttachment(times(1)); } @Test public void testInit_viewNotYetAttached() { mSetFlagsRule.disableFlags(Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT); ArgumentCaptor<View.OnAttachStateChangeListener> listenerArgumentCaptor = ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class); when(mView.isAttachedToWindow()).thenReturn(false); mController.init(); verify(mView).addOnAttachStateChangeListener(listenerArgumentCaptor.capture()); verifyAttachment(never()); listenerArgumentCaptor.getValue().onViewAttachedToWindow(mView); verifyAttachment(times(1)); } @Test public void testInitSubControllers() { mSetFlagsRule.disableFlags(Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT); mController.init(); verify(mKeyguardSliceViewController).init(); } @Test public void testInit_viewDetached() { mSetFlagsRule.disableFlags(Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT); ArgumentCaptor<View.OnAttachStateChangeListener> listenerArgumentCaptor = ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class); mController.init(); verify(mView).addOnAttachStateChangeListener(listenerArgumentCaptor.capture()); verifyAttachment(times(1)); listenerArgumentCaptor.getValue().onViewDetachedFromWindow(mView); verify(mClockEventController).unregisterListeners(); } @Test public void testPluginPassesStatusBarState() { mSetFlagsRule.disableFlags(Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT); ArgumentCaptor<ClockRegistry.ClockChangeListener> listenerArgumentCaptor = ArgumentCaptor.forClass(ClockRegistry.ClockChangeListener.class); mController.init(); verify(mClockRegistry).registerClockChangeListener(listenerArgumentCaptor.capture()); listenerArgumentCaptor.getValue().onCurrentClockChanged(); verify(mView, times(2)).setClock(mClockController, StatusBarState.SHADE); verify(mClockEventController, times(2)).setClock(mClockController); } @Test public void testSmartspaceEnabledRemovesKeyguardStatusArea() { mSetFlagsRule.disableFlags(Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT); when(mSmartspaceController.isEnabled()).thenReturn(true); mController.init(); assertEquals(View.GONE, mSliceView.getVisibility()); } @Test public void onLocaleListChangedRebuildsSmartspaceView() { mSetFlagsRule.disableFlags(Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT); when(mSmartspaceController.isEnabled()).thenReturn(true); mController.init(); mController.onLocaleListChanged(); // Should be called once on initial setup, then once again for locale change verify(mSmartspaceController, times(2)).buildAndConnectView(mView); } @Test public void onLocaleListChanged_rebuildsSmartspaceViews_whenDecouplingEnabled() { mSetFlagsRule.disableFlags(Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT); when(mSmartspaceController.isEnabled()).thenReturn(true); when(mSmartspaceController.isDateWeatherDecoupled()).thenReturn(true); mController.init(); mController.onLocaleListChanged(); // Should be called once on initial setup, then once again for locale change verify(mSmartspaceController, times(2)).buildAndConnectDateView(mView); verify(mSmartspaceController, times(2)).buildAndConnectWeatherView(mView); verify(mSmartspaceController, times(2)).buildAndConnectView(mView); } @Test public void testSmartspaceDisabledShowsKeyguardStatusArea() { mSetFlagsRule.disableFlags(Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT); when(mSmartspaceController.isEnabled()).thenReturn(false); mController.init(); assertEquals(View.VISIBLE, mSliceView.getVisibility()); } @Test public void testRefresh() { mSetFlagsRule.disableFlags(Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT); mController.refresh(); verify(mSmartspaceController).requestSmartspaceUpdate(); } @Test public void testChangeToDoubleLineClockSetsSmallClock() { mSetFlagsRule.disableFlags(Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT); when(mSecureSettings.getIntForUser(Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK, 1, UserHandle.USER_CURRENT)) .thenReturn(0); ArgumentCaptor<ContentObserver> observerCaptor = ArgumentCaptor.forClass(ContentObserver.class); mController.init(); mExecutor.runAllReady(); verify(mSecureSettings).registerContentObserverForUserSync( eq(Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK), anyBoolean(), observerCaptor.capture(), eq(UserHandle.USER_ALL)); ContentObserver observer = observerCaptor.getValue(); mExecutor.runAllReady(); // When a settings change has occurred to the small clock, make sure the view is adjusted reset(mView); when(mView.getResources()).thenReturn(mResources); observer.onChange(true); mExecutor.runAllReady(); verify(mView).switchToClock(KeyguardClockSwitch.SMALL, /* animate */ true); } @Test public void testGetClock_ForwardsToClock() { mSetFlagsRule.disableFlags(Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT); assertEquals(mClockController, mController.getClock()); } @Test public void testGetLargeClockBottom_returnsExpectedValue() { mSetFlagsRule.disableFlags(Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT); when(mLargeClockFrame.getVisibility()).thenReturn(View.VISIBLE); when(mLargeClockFrame.getHeight()).thenReturn(100); when(mSmallClockFrame.getHeight()).thenReturn(50); when(mLargeClockView.getHeight()).thenReturn(40); when(mSmallClockView.getHeight()).thenReturn(20); mController.init(); assertEquals(170, mController.getClockBottom(1000)); } @Test public void testGetSmallLargeClockBottom_returnsExpectedValue() { mSetFlagsRule.disableFlags(Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT); when(mLargeClockFrame.getVisibility()).thenReturn(View.GONE); when(mLargeClockFrame.getHeight()).thenReturn(100); when(mSmallClockFrame.getHeight()).thenReturn(50); when(mLargeClockView.getHeight()).thenReturn(40); when(mSmallClockView.getHeight()).thenReturn(20); mController.init(); assertEquals(1120, mController.getClockBottom(1000)); } @Test public void testGetClockBottom_nullClock_returnsZero() { mSetFlagsRule.disableFlags(Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT); when(mClockEventController.getClock()).thenReturn(null); assertEquals(0, mController.getClockBottom(10)); } @Test public void testChangeLockscreenWeatherEnabledSetsWeatherViewVisible() { mSetFlagsRule.disableFlags(Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT); when(mSmartspaceController.isWeatherEnabled()).thenReturn(true); ArgumentCaptor<ContentObserver> observerCaptor = ArgumentCaptor.forClass(ContentObserver.class); mController.init(); mExecutor.runAllReady(); verify(mSecureSettings).registerContentObserverForUserSync( eq(Settings.Secure.LOCK_SCREEN_WEATHER_ENABLED), anyBoolean(), observerCaptor.capture(), eq(UserHandle.USER_ALL)); ContentObserver observer = observerCaptor.getValue(); mExecutor.runAllReady(); // When a settings change has occurred, check that view is visible. observer.onChange(true); mExecutor.runAllReady(); assertEquals(View.VISIBLE, mFakeWeatherView.getVisibility()); } @Test public void testChangeClockDateWeatherEnabled_SetsDateWeatherViewVisibility() { mSetFlagsRule.disableFlags(Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT); ArgumentCaptor<ClockRegistry.ClockChangeListener> listenerArgumentCaptor = ArgumentCaptor.forClass(ClockRegistry.ClockChangeListener.class); when(mSmartspaceController.isEnabled()).thenReturn(true); when(mSmartspaceController.isDateWeatherDecoupled()).thenReturn(true); when(mSmartspaceController.isWeatherEnabled()).thenReturn(true); mController.init(); mExecutor.runAllReady(); assertEquals(View.VISIBLE, mFakeDateView.getVisibility()); when(mSmallClockController.getConfig()) .thenReturn(new ClockFaceConfig(ClockTickRate.PER_MINUTE, true, false, true)); when(mLargeClockController.getConfig()) .thenReturn(new ClockFaceConfig(ClockTickRate.PER_MINUTE, true, false, true)); verify(mClockRegistry).registerClockChangeListener(listenerArgumentCaptor.capture()); listenerArgumentCaptor.getValue().onCurrentClockChanged(); mExecutor.runAllReady(); assertEquals(View.INVISIBLE, mFakeDateView.getVisibility()); } @Test public void testGetClock_nullClock_returnsNull() { mSetFlagsRule.disableFlags(Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT); when(mClockEventController.getClock()).thenReturn(null); assertNull(mController.getClock()); } private void verifyAttachment(VerificationMode times) { mSetFlagsRule.disableFlags(Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT); verify(mClockRegistry, times).registerClockChangeListener( any(ClockRegistry.ClockChangeListener.class)); verify(mClockEventController, times).registerListeners(mView); } @Test public void testSplitShadeEnabledSetToSmartspaceController() { mSetFlagsRule.disableFlags(Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT); mController.setSplitShadeEnabled(true); verify(mSmartspaceController, times(1)).setSplitShadeEnabled(true); verify(mSmartspaceController, times(0)).setSplitShadeEnabled(false); } @Test public void testSplitShadeDisabledSetToSmartspaceController() { mSetFlagsRule.disableFlags(Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT); mController.setSplitShadeEnabled(false); verify(mSmartspaceController, times(1)).setSplitShadeEnabled(false); verify(mSmartspaceController, times(0)).setSplitShadeEnabled(true); } }