1 /*
2  * Copyright (C) 2023 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 
21 import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED;
22 
23 import static org.mockito.ArgumentMatchers.any;
24 import static org.mockito.Mockito.atLeast;
25 import static org.mockito.Mockito.mock;
26 import static org.mockito.Mockito.verify;
27 import static org.mockito.Mockito.when;
28 
29 import android.content.res.Resources;
30 import android.view.View;
31 import android.view.ViewGroup;
32 import android.widget.FrameLayout;
33 import android.widget.LinearLayout;
34 import android.widget.RelativeLayout;
35 
36 import com.android.systemui.SysuiTestCase;
37 import com.android.systemui.dump.DumpManager;
38 import com.android.systemui.flags.FakeFeatureFlags;
39 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
40 import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor;
41 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory;
42 import com.android.systemui.keyguard.ui.view.InWindowLauncherUnlockAnimationManager;
43 import com.android.systemui.log.LogBuffer;
44 import com.android.systemui.plugins.clocks.ClockAnimations;
45 import com.android.systemui.plugins.clocks.ClockController;
46 import com.android.systemui.plugins.clocks.ClockEvents;
47 import com.android.systemui.plugins.clocks.ClockFaceConfig;
48 import com.android.systemui.plugins.clocks.ClockFaceController;
49 import com.android.systemui.plugins.clocks.ClockFaceEvents;
50 import com.android.systemui.plugins.clocks.ClockTickRate;
51 import com.android.systemui.plugins.statusbar.StatusBarStateController;
52 import com.android.systemui.res.R;
53 import com.android.systemui.shared.clocks.AnimatableClockView;
54 import com.android.systemui.shared.clocks.ClockRegistry;
55 import com.android.systemui.statusbar.StatusBarState;
56 import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController;
57 import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerAlwaysOnDisplayViewBinder;
58 import com.android.systemui.statusbar.phone.NotificationIconAreaController;
59 import com.android.systemui.statusbar.phone.NotificationIconContainer;
60 import com.android.systemui.util.concurrency.FakeExecutor;
61 import com.android.systemui.util.settings.SecureSettings;
62 import com.android.systemui.util.time.FakeSystemClock;
63 
64 import org.junit.Before;
65 import org.mockito.ArgumentCaptor;
66 import org.mockito.Captor;
67 import org.mockito.Mock;
68 import org.mockito.MockitoAnnotations;
69 
70 public class KeyguardClockSwitchControllerBaseTest extends SysuiTestCase {
71 
72     @Mock
73     protected KeyguardClockSwitch mView;
74     @Mock
75     protected StatusBarStateController mStatusBarStateController;
76     @Mock
77     protected ClockRegistry mClockRegistry;
78     @Mock
79     KeyguardSliceViewController mKeyguardSliceViewController;
80     @Mock
81     NotificationIconAreaController mNotificationIconAreaController;
82     @Mock
83     LockscreenSmartspaceController mSmartspaceController;
84 
85     @Mock
86     Resources mResources;
87     @Mock
88     KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
89     @Mock
90     protected ClockController mClockController;
91     @Mock
92     protected ClockFaceController mLargeClockController;
93     @Mock
94     protected ClockFaceController mSmallClockController;
95     @Mock
96     protected ClockAnimations mClockAnimations;
97     @Mock
98     protected ClockEvents mClockEvents;
99     @Mock
100     protected ClockFaceEvents mClockFaceEvents;
101     @Mock
102     DumpManager mDumpManager;
103     @Mock
104     ClockEventController mClockEventController;
105 
106     @Mock
107     protected NotificationIconContainer mNotificationIcons;
108     @Mock
109     protected AnimatableClockView mSmallClockView;
110     @Mock
111     protected AnimatableClockView mLargeClockView;
112     @Mock
113     protected FrameLayout mSmallClockFrame;
114     @Mock
115     protected FrameLayout mLargeClockFrame;
116     @Mock
117     protected SecureSettings mSecureSettings;
118     @Mock
119     protected LogBuffer mLogBuffer;
120 
121     @Mock
122     protected KeyguardClockInteractor mKeyguardClockInteractor;
123 
124     protected final View mFakeDateView = (View) (new ViewGroup(mContext) {
125         @Override
126         protected void onLayout(boolean changed, int l, int t, int r, int b) {}
127     });
128     protected final View mFakeWeatherView = new View(mContext);
129     protected final View mFakeSmartspaceView = new View(mContext);
130 
131     protected KeyguardClockSwitchController mController;
132     protected View mSliceView;
133     protected LinearLayout mStatusArea;
134     protected FakeExecutor mExecutor;
135     protected FakeFeatureFlags mFakeFeatureFlags;
136     @Captor protected ArgumentCaptor<View.OnAttachStateChangeListener> mAttachCaptor =
137             ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class);
138 
139     @Before
setup()140     public void setup() {
141         MockitoAnnotations.initMocks(this);
142 
143         mFakeDateView.setTag(R.id.tag_smartspace_view, new Object());
144         mFakeWeatherView.setTag(R.id.tag_smartspace_view, new Object());
145         mFakeSmartspaceView.setTag(R.id.tag_smartspace_view, new Object());
146 
147         when(mView.findViewById(R.id.left_aligned_notification_icon_container))
148                 .thenReturn(mNotificationIcons);
149         when(mNotificationIcons.getLayoutParams()).thenReturn(
150                 mock(RelativeLayout.LayoutParams.class));
151         when(mView.getContext()).thenReturn(getContext());
152         when(mView.getResources()).thenReturn(mResources);
153         when(mResources.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin))
154                 .thenReturn(100);
155         when(mResources.getDimensionPixelSize(com.android.systemui.customization.R.dimen.keyguard_large_clock_top_margin))
156                 .thenReturn(-200);
157         when(mResources.getInteger(com.android.internal.R.integer.config_doublelineClockDefault))
158                 .thenReturn(1);
159         when(mResources.getInteger(R.integer.keyguard_date_weather_view_invisibility))
160                 .thenReturn(INVISIBLE);
161 
162         when(mView.findViewById(R.id.lockscreen_clock_view_large)).thenReturn(mLargeClockFrame);
163         when(mView.findViewById(R.id.lockscreen_clock_view)).thenReturn(mSmallClockFrame);
164         when(mSmallClockView.getContext()).thenReturn(getContext());
165         when(mLargeClockView.getContext()).thenReturn(getContext());
166 
167         when(mView.isAttachedToWindow()).thenReturn(true);
168         when(mSmartspaceController.buildAndConnectDateView(any())).thenReturn(mFakeDateView);
169         when(mSmartspaceController.buildAndConnectWeatherView(any())).thenReturn(mFakeWeatherView);
170         when(mSmartspaceController.buildAndConnectView(any())).thenReturn(mFakeSmartspaceView);
171         mExecutor = new FakeExecutor(new FakeSystemClock());
172         mFakeFeatureFlags = new FakeFeatureFlags();
173         mFakeFeatureFlags.set(LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false);
174         mController = new KeyguardClockSwitchController(
175                 mView,
176                 mStatusBarStateController,
177                 mClockRegistry,
178                 mKeyguardSliceViewController,
179                 mNotificationIconAreaController,
180                 mSmartspaceController,
181                 mock(NotificationIconContainerAlwaysOnDisplayViewBinder.class),
182                 mKeyguardUnlockAnimationController,
183                 mSecureSettings,
184                 mExecutor,
185                 mExecutor,
186                 mDumpManager,
187                 mClockEventController,
188                 mLogBuffer,
189                 KeyguardInteractorFactory.create(mFakeFeatureFlags).getKeyguardInteractor(),
190                 mKeyguardClockInteractor,
191                 mFakeFeatureFlags,
192                 mock(InWindowLauncherUnlockAnimationManager.class)
193         );
194 
195         when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
196         when(mLargeClockController.getView()).thenReturn(mLargeClockView);
197         when(mSmallClockController.getView()).thenReturn(mSmallClockView);
198         when(mClockController.getLargeClock()).thenReturn(mLargeClockController);
199         when(mClockController.getSmallClock()).thenReturn(mSmallClockController);
200         when(mClockController.getEvents()).thenReturn(mClockEvents);
201         when(mSmallClockController.getEvents()).thenReturn(mClockFaceEvents);
202         when(mLargeClockController.getEvents()).thenReturn(mClockFaceEvents);
203         when(mLargeClockController.getAnimations()).thenReturn(mClockAnimations);
204         when(mSmallClockController.getAnimations()).thenReturn(mClockAnimations);
205         when(mClockRegistry.createCurrentClock()).thenReturn(mClockController);
206         when(mClockEventController.getClock()).thenReturn(mClockController);
207         when(mSmallClockController.getConfig())
208                 .thenReturn(new ClockFaceConfig(ClockTickRate.PER_MINUTE, false, false, false));
209         when(mLargeClockController.getConfig())
210                 .thenReturn(new ClockFaceConfig(ClockTickRate.PER_MINUTE, false, false, false));
211 
212         mSliceView = new View(getContext());
213         when(mView.findViewById(R.id.keyguard_slice_view)).thenReturn(mSliceView);
214         mStatusArea = new LinearLayout(getContext());
215         when(mView.findViewById(R.id.keyguard_status_area)).thenReturn(mStatusArea);
216     }
217 
removeView(View v)218     private void removeView(View v) {
219         ViewGroup group = ((ViewGroup) v.getParent());
220         if (group != null) {
221             group.removeView(v);
222         }
223     }
224 
init()225     protected void init() {
226         mController.init();
227 
228         verify(mView, atLeast(1)).addOnAttachStateChangeListener(mAttachCaptor.capture());
229         mAttachCaptor.getValue().onViewAttachedToWindow(mView);
230     }
231 }
232