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.systemui.shade;
18 
19 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
20 
21 import static com.android.keyguard.KeyguardClockSwitch.LARGE;
22 import static com.android.systemui.dump.LogBufferHelperKt.logcatLogBuffer;
23 
24 import static com.google.common.truth.Truth.assertThat;
25 
26 import static org.mockito.ArgumentMatchers.any;
27 import static org.mockito.ArgumentMatchers.anyBoolean;
28 import static org.mockito.ArgumentMatchers.anyFloat;
29 import static org.mockito.ArgumentMatchers.anyInt;
30 import static org.mockito.ArgumentMatchers.anyLong;
31 import static org.mockito.ArgumentMatchers.eq;
32 import static org.mockito.Mockito.atLeast;
33 import static org.mockito.Mockito.doAnswer;
34 import static org.mockito.Mockito.mock;
35 import static org.mockito.Mockito.reset;
36 import static org.mockito.Mockito.spy;
37 import static org.mockito.Mockito.verify;
38 import static org.mockito.Mockito.when;
39 
40 import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
41 
42 import android.annotation.IdRes;
43 import android.content.ContentResolver;
44 import android.content.res.Configuration;
45 import android.content.res.Resources;
46 import android.database.ContentObserver;
47 import android.os.Handler;
48 import android.os.Looper;
49 import android.os.PowerManager;
50 import android.os.UserManager;
51 import android.util.DisplayMetrics;
52 import android.view.LayoutInflater;
53 import android.view.MotionEvent;
54 import android.view.View;
55 import android.view.ViewGroup;
56 import android.view.ViewParent;
57 import android.view.ViewPropertyAnimator;
58 import android.view.ViewStub;
59 import android.view.ViewTreeObserver;
60 import android.view.accessibility.AccessibilityManager;
61 
62 import androidx.constraintlayout.widget.ConstraintSet;
63 
64 import com.android.internal.jank.InteractionJankMonitor;
65 import com.android.internal.logging.MetricsLogger;
66 import com.android.internal.logging.UiEventLogger;
67 import com.android.internal.logging.testing.UiEventLoggerFake;
68 import com.android.internal.util.LatencyTracker;
69 import com.android.keyguard.KeyguardClockSwitch;
70 import com.android.keyguard.KeyguardClockSwitchController;
71 import com.android.keyguard.KeyguardSliceViewController;
72 import com.android.keyguard.KeyguardStatusView;
73 import com.android.keyguard.KeyguardStatusViewController;
74 import com.android.keyguard.KeyguardUpdateMonitor;
75 import com.android.keyguard.LockIconViewController;
76 import com.android.keyguard.dagger.KeyguardQsUserSwitchComponent;
77 import com.android.keyguard.dagger.KeyguardStatusBarViewComponent;
78 import com.android.keyguard.dagger.KeyguardStatusViewComponent;
79 import com.android.keyguard.dagger.KeyguardUserSwitcherComponent;
80 import com.android.keyguard.logging.KeyguardLogger;
81 import com.android.systemui.R;
82 import com.android.systemui.SysuiTestCase;
83 import com.android.systemui.biometrics.AuthController;
84 import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
85 import com.android.systemui.classifier.FalsingCollectorFake;
86 import com.android.systemui.classifier.FalsingManagerFake;
87 import com.android.systemui.common.ui.view.LongPressHandlingView;
88 import com.android.systemui.doze.DozeLog;
89 import com.android.systemui.dump.DumpManager;
90 import com.android.systemui.flags.FeatureFlags;
91 import com.android.systemui.fragments.FragmentHostManager;
92 import com.android.systemui.fragments.FragmentService;
93 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
94 import com.android.systemui.keyguard.KeyguardViewConfigurator;
95 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository;
96 import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor;
97 import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
98 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
99 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory;
100 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
101 import com.android.systemui.keyguard.ui.view.KeyguardRootView;
102 import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
103 import com.android.systemui.keyguard.ui.viewmodel.GoneToDreamingLockscreenHostedTransitionViewModel;
104 import com.android.systemui.keyguard.ui.viewmodel.GoneToDreamingTransitionViewModel;
105 import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel;
106 import com.android.systemui.keyguard.ui.viewmodel.KeyguardLongPressViewModel;
107 import com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel;
108 import com.android.systemui.keyguard.ui.viewmodel.LockscreenToOccludedTransitionViewModel;
109 import com.android.systemui.keyguard.ui.viewmodel.OccludedToLockscreenTransitionViewModel;
110 import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel;
111 import com.android.systemui.media.controls.pipeline.MediaDataManager;
112 import com.android.systemui.media.controls.ui.KeyguardMediaController;
113 import com.android.systemui.media.controls.ui.MediaHierarchyManager;
114 import com.android.systemui.model.SysUiState;
115 import com.android.systemui.navigationbar.NavigationBarController;
116 import com.android.systemui.navigationbar.NavigationModeController;
117 import com.android.systemui.plugins.ActivityStarter;
118 import com.android.systemui.plugins.FalsingManager;
119 import com.android.systemui.plugins.qs.QS;
120 import com.android.systemui.qs.QSFragment;
121 import com.android.systemui.screenrecord.RecordingController;
122 import com.android.systemui.shade.data.repository.ShadeRepository;
123 import com.android.systemui.shade.domain.interactor.ShadeInteractor;
124 import com.android.systemui.shade.transition.ShadeTransitionController;
125 import com.android.systemui.statusbar.CommandQueue;
126 import com.android.systemui.statusbar.KeyguardIndicationController;
127 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
128 import com.android.systemui.statusbar.NotificationRemoteInputManager;
129 import com.android.systemui.statusbar.NotificationShadeDepthController;
130 import com.android.systemui.statusbar.NotificationShadeWindowController;
131 import com.android.systemui.statusbar.NotificationShelfController;
132 import com.android.systemui.statusbar.PulseExpansionHandler;
133 import com.android.systemui.statusbar.QsFrameTranslateController;
134 import com.android.systemui.statusbar.StatusBarStateControllerImpl;
135 import com.android.systemui.statusbar.SysuiStatusBarStateController;
136 import com.android.systemui.statusbar.VibratorHelper;
137 import com.android.systemui.statusbar.notification.ConversationNotificationManager;
138 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
139 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
140 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinatorLogger;
141 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
142 import com.android.systemui.statusbar.notification.stack.AmbientState;
143 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
144 import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager;
145 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
146 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
147 import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator;
148 import com.android.systemui.statusbar.phone.CentralSurfaces;
149 import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
150 import com.android.systemui.statusbar.phone.DozeParameters;
151 import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
152 import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
153 import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
154 import com.android.systemui.statusbar.phone.KeyguardBottomAreaView;
155 import com.android.systemui.statusbar.phone.KeyguardBottomAreaViewController;
156 import com.android.systemui.statusbar.phone.KeyguardBypassController;
157 import com.android.systemui.statusbar.phone.KeyguardStatusBarView;
158 import com.android.systemui.statusbar.phone.KeyguardStatusBarViewController;
159 import com.android.systemui.statusbar.phone.LightBarController;
160 import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
161 import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
162 import com.android.systemui.statusbar.phone.ScrimController;
163 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
164 import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager;
165 import com.android.systemui.statusbar.phone.TapAgainViewController;
166 import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
167 import com.android.systemui.statusbar.policy.CastController;
168 import com.android.systemui.statusbar.policy.ConfigurationController;
169 import com.android.systemui.statusbar.policy.KeyguardQsUserSwitchController;
170 import com.android.systemui.statusbar.policy.KeyguardStateController;
171 import com.android.systemui.statusbar.policy.KeyguardUserSwitcherController;
172 import com.android.systemui.statusbar.policy.KeyguardUserSwitcherView;
173 import com.android.systemui.statusbar.window.StatusBarWindowStateController;
174 import com.android.systemui.unfold.SysUIUnfoldComponent;
175 import com.android.systemui.util.kotlin.JavaAdapter;
176 import com.android.systemui.util.time.FakeSystemClock;
177 import com.android.systemui.util.time.SystemClock;
178 import com.android.wm.shell.animation.FlingAnimationUtils;
179 
180 import dagger.Lazy;
181 
182 import org.junit.After;
183 import org.junit.Before;
184 import org.mockito.ArgumentCaptor;
185 import org.mockito.Captor;
186 import org.mockito.Mock;
187 import org.mockito.MockitoAnnotations;
188 import org.mockito.stubbing.Answer;
189 
190 import java.util.List;
191 import java.util.Optional;
192 
193 import kotlinx.coroutines.CoroutineDispatcher;
194 
195 public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {
196 
197     protected static final int SPLIT_SHADE_FULL_TRANSITION_DISTANCE = 400;
198     protected static final int NOTIFICATION_SCRIM_TOP_PADDING_IN_SPLIT_SHADE = 50;
199     protected static final int PANEL_WIDTH = 500; // Random value just for the test.
200 
201     @Mock protected CentralSurfaces mCentralSurfaces;
202     @Mock protected NotificationStackScrollLayout mNotificationStackScrollLayout;
203     @Mock protected KeyguardBottomAreaView mKeyguardBottomArea;
204     @Mock protected KeyguardBottomAreaViewController mKeyguardBottomAreaViewController;
205     @Mock protected ViewPropertyAnimator mViewPropertyAnimator;
206     @Mock protected KeyguardBottomAreaView mQsFrame;
207     @Mock protected HeadsUpManagerPhone mHeadsUpManager;
208     @Mock protected NotificationShelfController mNotificationShelfController;
209     @Mock protected NotificationGutsManager mGutsManager;
210     @Mock protected KeyguardStatusBarView mKeyguardStatusBar;
211     @Mock protected KeyguardUserSwitcherView mUserSwitcherView;
212     @Mock protected ViewStub mUserSwitcherStubView;
213     @Mock protected HeadsUpTouchHelper.Callback mHeadsUpCallback;
214     @Mock protected KeyguardUpdateMonitor mUpdateMonitor;
215     @Mock protected KeyguardBypassController mKeyguardBypassController;
216     @Mock protected DozeParameters mDozeParameters;
217     @Mock protected ScreenOffAnimationController mScreenOffAnimationController;
218     @Mock protected NotificationPanelView mView;
219     @Mock protected LayoutInflater mLayoutInflater;
220     @Mock protected FeatureFlags mFeatureFlags;
221     @Mock protected DynamicPrivacyController mDynamicPrivacyController;
222     @Mock protected StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
223     @Mock protected KeyguardStateController mKeyguardStateController;
224     @Mock protected DozeLog mDozeLog;
225     private final ShadeLogger mShadeLog = new ShadeLogger(logcatLogBuffer());
226     @Mock protected CommandQueue mCommandQueue;
227     @Mock protected VibratorHelper mVibratorHelper;
228     @Mock protected LatencyTracker mLatencyTracker;
229     @Mock protected PowerManager mPowerManager;
230     @Mock protected AccessibilityManager mAccessibilityManager;
231     @Mock protected MetricsLogger mMetricsLogger;
232     @Mock protected Resources mResources;
233     @Mock protected Configuration mConfiguration;
234     @Mock protected KeyguardClockSwitch mKeyguardClockSwitch;
235     @Mock protected MediaHierarchyManager mMediaHierarchyManager;
236     @Mock protected ConversationNotificationManager mConversationNotificationManager;
237     @Mock protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
238     @Mock protected KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
239     @Mock protected KeyguardQsUserSwitchComponent.Factory mKeyguardQsUserSwitchComponentFactory;
240     @Mock protected KeyguardQsUserSwitchComponent mKeyguardQsUserSwitchComponent;
241     @Mock protected KeyguardQsUserSwitchController mKeyguardQsUserSwitchController;
242     @Mock protected KeyguardUserSwitcherComponent.Factory mKeyguardUserSwitcherComponentFactory;
243     @Mock protected KeyguardUserSwitcherComponent mKeyguardUserSwitcherComponent;
244     @Mock protected KeyguardUserSwitcherController mKeyguardUserSwitcherController;
245     @Mock protected KeyguardStatusViewComponent mKeyguardStatusViewComponent;
246     @Mock protected KeyguardStatusBarViewComponent.Factory mKeyguardStatusBarViewComponentFactory;
247     @Mock protected KeyguardStatusBarViewComponent mKeyguardStatusBarViewComponent;
248     @Mock protected KeyguardClockSwitchController mKeyguardClockSwitchController;
249     @Mock protected KeyguardStatusBarViewController mKeyguardStatusBarViewController;
250     @Mock protected LightBarController mLightBarController;
251     @Mock protected NotificationStackScrollLayoutController
252             mNotificationStackScrollLayoutController;
253     @Mock protected NotificationShadeDepthController mNotificationShadeDepthController;
254     @Mock protected LockscreenShadeTransitionController mLockscreenShadeTransitionController;
255     @Mock protected AuthController mAuthController;
256     @Mock protected ScrimController mScrimController;
257     @Mock protected MediaDataManager mMediaDataManager;
258     @Mock protected AmbientState mAmbientState;
259     @Mock protected UserManager mUserManager;
260     @Mock protected UiEventLogger mUiEventLogger;
261     @Mock protected LockIconViewController mLockIconViewController;
262     @Mock protected KeyguardViewConfigurator mKeyguardViewConfigurator;
263     @Mock protected KeyguardMediaController mKeyguardMediaController;
264     @Mock protected NavigationModeController mNavigationModeController;
265     @Mock protected NavigationBarController mNavigationBarController;
266     @Mock protected QuickSettingsController mQsController;
267     @Mock protected ShadeHeaderController mShadeHeaderController;
268     @Mock protected ContentResolver mContentResolver;
269     @Mock protected TapAgainViewController mTapAgainViewController;
270     @Mock protected KeyguardIndicationController mKeyguardIndicationController;
271     @Mock protected FragmentService mFragmentService;
272     @Mock protected FragmentHostManager mFragmentHostManager;
273     @Mock protected NotificationRemoteInputManager mNotificationRemoteInputManager;
274     @Mock protected RecordingController mRecordingController;
275     @Mock protected LockscreenGestureLogger mLockscreenGestureLogger;
276     @Mock protected DumpManager mDumpManager;
277     @Mock protected InteractionJankMonitor mInteractionJankMonitor;
278     @Mock protected NotificationsQSContainerController mNotificationsQSContainerController;
279     @Mock protected QsFrameTranslateController mQsFrameTranslateController;
280     @Mock protected StatusBarWindowStateController mStatusBarWindowStateController;
281     @Mock protected KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
282     @Mock protected NotificationShadeWindowController mNotificationShadeWindowController;
283     @Mock protected SysUiState mSysUiState;
284     @Mock protected NotificationListContainer mNotificationListContainer;
285     @Mock protected NotificationStackSizeCalculator mNotificationStackSizeCalculator;
286     @Mock protected UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
287     @Mock protected ShadeTransitionController mShadeTransitionController;
288     @Mock protected QS mQs;
289     @Mock protected QSFragment mQSFragment;
290     @Mock protected ViewGroup mQsHeader;
291     @Mock protected ViewParent mViewParent;
292     @Mock protected ViewTreeObserver mViewTreeObserver;
293     @Mock protected KeyguardBottomAreaViewModel mKeyguardBottomAreaViewModel;
294     @Mock protected DreamingToLockscreenTransitionViewModel
295             mDreamingToLockscreenTransitionViewModel;
296     @Mock protected OccludedToLockscreenTransitionViewModel
297             mOccludedToLockscreenTransitionViewModel;
298     @Mock protected LockscreenToDreamingTransitionViewModel
299             mLockscreenToDreamingTransitionViewModel;
300     @Mock protected LockscreenToOccludedTransitionViewModel
301             mLockscreenToOccludedTransitionViewModel;
302     @Mock protected GoneToDreamingTransitionViewModel mGoneToDreamingTransitionViewModel;
303     @Mock protected GoneToDreamingLockscreenHostedTransitionViewModel
304             mGoneToDreamingLockscreenHostedTransitionViewModel;
305     @Mock protected PrimaryBouncerToGoneTransitionViewModel
306             mPrimaryBouncerToGoneTransitionViewModel;
307     @Mock protected KeyguardTransitionInteractor mKeyguardTransitionInteractor;
308     @Mock protected KeyguardLongPressViewModel mKeyuardLongPressViewModel;
309     @Mock protected AlternateBouncerInteractor mAlternateBouncerInteractor;
310     @Mock protected MotionEvent mDownMotionEvent;
311     @Mock protected CoroutineDispatcher mMainDispatcher;
312     @Mock protected KeyguardSliceViewController mKeyguardSliceViewController;
313     private final KeyguardLogger mKeyguardLogger = new KeyguardLogger(logcatLogBuffer());
314     @Mock protected KeyguardStatusView mKeyguardStatusView;
315     @Captor
316     protected ArgumentCaptor<NotificationStackScrollLayout.OnEmptySpaceClickListener>
317             mEmptySpaceClickListenerCaptor;
318     @Mock protected ActivityStarter mActivityStarter;
319     @Mock protected KeyguardFaceAuthInteractor mKeyguardFaceAuthInteractor;
320     @Mock protected ShadeRepository mShadeRepository;
321     @Mock private ShadeInteractor mShadeInteractor;
322     @Mock private JavaAdapter mJavaAdapter;
323     @Mock private CastController mCastController;
324     @Mock private KeyguardRootView mKeyguardRootView;
325 
326     protected final int mMaxUdfpsBurnInOffsetY = 5;
327     protected KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor;
328     protected FakeKeyguardRepository mFakeKeyguardRepository;
329     protected KeyguardInteractor mKeyguardInteractor;
330     protected NotificationPanelViewController.TouchHandler mTouchHandler;
331     protected ConfigurationController mConfigurationController;
332     protected SysuiStatusBarStateController mStatusBarStateController;
333     protected NotificationPanelViewController mNotificationPanelViewController;
334     protected View.AccessibilityDelegate mAccessibilityDelegate;
335     protected NotificationsQuickSettingsContainer mNotificationContainerParent;
336     protected List<View.OnAttachStateChangeListener> mOnAttachStateChangeListeners;
337     protected Handler mMainHandler;
338     protected View.OnLayoutChangeListener mLayoutChangeListener;
339     protected KeyguardStatusViewController mKeyguardStatusViewController;
340 
341     protected final FalsingManagerFake mFalsingManager = new FalsingManagerFake();
342     protected final Optional<SysUIUnfoldComponent> mSysUIUnfoldComponent = Optional.empty();
343     protected final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
344     protected final ShadeExpansionStateManager mShadeExpansionStateManager =
345             new ShadeExpansionStateManager();
346 
347     protected QuickSettingsController mQuickSettingsController;
348     @Mock protected Lazy<NotificationPanelViewController> mNotificationPanelViewControllerLazy;
349 
350     protected FragmentHostManager.FragmentListener mFragmentListener;
351 
352     @Before
setup()353     public void setup() {
354         MockitoAnnotations.initMocks(this);
355         mMainDispatcher = getMainDispatcher();
356         KeyguardInteractorFactory.WithDependencies keyguardInteractorDeps =
357                 KeyguardInteractorFactory.create();
358         mFakeKeyguardRepository = keyguardInteractorDeps.getRepository();
359         mKeyguardBottomAreaInteractor = new KeyguardBottomAreaInteractor(mFakeKeyguardRepository);
360         mKeyguardInteractor = keyguardInteractorDeps.getKeyguardInteractor();
361 
362         SystemClock systemClock = new FakeSystemClock();
363         mStatusBarStateController = new StatusBarStateControllerImpl(mUiEventLogger, mDumpManager,
364                 mInteractionJankMonitor, mShadeExpansionStateManager);
365 
366         KeyguardStatusView keyguardStatusView = new KeyguardStatusView(mContext);
367         keyguardStatusView.setId(R.id.keyguard_status_view);
368         mKeyguardStatusViewController = spy(new KeyguardStatusViewController(
369                 mKeyguardStatusView,
370                 mKeyguardSliceViewController,
371                 mKeyguardClockSwitchController,
372                 mKeyguardStateController,
373                 mUpdateMonitor,
374                 mConfigurationController,
375                 mDozeParameters,
376                 mScreenOffAnimationController,
377                 mKeyguardLogger,
378                 mFeatureFlags,
379                 mInteractionJankMonitor,
380                 mKeyguardInteractor,
381                 mDumpManager));
382 
383         when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(false);
384         when(mHeadsUpCallback.getContext()).thenReturn(mContext);
385         when(mView.getResources()).thenReturn(mResources);
386         when(mView.getWidth()).thenReturn(PANEL_WIDTH);
387         when(mResources.getConfiguration()).thenReturn(mConfiguration);
388         mConfiguration.orientation = ORIENTATION_PORTRAIT;
389         when(mResources.getDisplayMetrics()).thenReturn(mDisplayMetrics);
390         mDisplayMetrics.density = 100;
391         when(mResources.getBoolean(R.bool.config_enableNotificationShadeDrag)).thenReturn(true);
392         when(mResources.getDimensionPixelSize(R.dimen.udfps_burn_in_offset_y))
393                 .thenReturn(mMaxUdfpsBurnInOffsetY);
394         when(mResources.getDimensionPixelSize(R.dimen.notifications_top_padding_split_shade))
395                 .thenReturn(NOTIFICATION_SCRIM_TOP_PADDING_IN_SPLIT_SHADE);
396         when(mResources.getDimensionPixelSize(R.dimen.notification_panel_margin_horizontal))
397                 .thenReturn(10);
398         when(mResources.getDimensionPixelSize(R.dimen.split_shade_full_transition_distance))
399                 .thenReturn(SPLIT_SHADE_FULL_TRANSITION_DISTANCE);
400         when(mView.getContext()).thenReturn(getContext());
401         when(mView.findViewById(R.id.keyguard_header)).thenReturn(mKeyguardStatusBar);
402         when(mView.findViewById(R.id.keyguard_user_switcher_view)).thenReturn(mUserSwitcherView);
403         when(mView.findViewById(R.id.keyguard_user_switcher_stub)).thenReturn(
404                 mUserSwitcherStubView);
405         when(mView.findViewById(R.id.keyguard_clock_container)).thenReturn(mKeyguardClockSwitch);
406         when(mView.findViewById(R.id.notification_stack_scroller))
407                 .thenReturn(mNotificationStackScrollLayout);
408         when(mNotificationStackScrollLayoutController.getHeight()).thenReturn(1000);
409         when(mNotificationStackScrollLayoutController.getHeadsUpCallback())
410                 .thenReturn(mHeadsUpCallback);
411         when(mKeyguardBottomAreaViewController.getView()).thenReturn(mKeyguardBottomArea);
412         when(mView.findViewById(R.id.keyguard_bottom_area)).thenReturn(mKeyguardBottomArea);
413         when(mKeyguardBottomArea.animate()).thenReturn(mViewPropertyAnimator);
414         when(mView.animate()).thenReturn(mViewPropertyAnimator);
415         when(mKeyguardStatusView.animate()).thenReturn(mViewPropertyAnimator);
416         when(mViewPropertyAnimator.translationX(anyFloat())).thenReturn(mViewPropertyAnimator);
417         when(mViewPropertyAnimator.alpha(anyFloat())).thenReturn(mViewPropertyAnimator);
418         when(mViewPropertyAnimator.setDuration(anyLong())).thenReturn(mViewPropertyAnimator);
419         when(mViewPropertyAnimator.setStartDelay(anyLong())).thenReturn(mViewPropertyAnimator);
420         when(mViewPropertyAnimator.setInterpolator(any())).thenReturn(mViewPropertyAnimator);
421         when(mViewPropertyAnimator.setListener(any())).thenReturn(mViewPropertyAnimator);
422         when(mViewPropertyAnimator.setUpdateListener(any())).thenReturn(mViewPropertyAnimator);
423         when(mViewPropertyAnimator.withEndAction(any())).thenReturn(mViewPropertyAnimator);
424         when(mView.findViewById(R.id.qs_frame)).thenReturn(mQsFrame);
425         when(mView.findViewById(R.id.keyguard_status_view))
426                 .thenReturn(mock(KeyguardStatusView.class));
427         View rootView = mock(View.class);
428         when(mView.getRootView()).thenReturn(rootView);
429         when(rootView.findViewById(R.id.keyguard_status_view))
430                 .thenReturn(mock(KeyguardStatusView.class));
431         mNotificationContainerParent = new NotificationsQuickSettingsContainer(getContext(), null);
432         mNotificationContainerParent.addView(keyguardStatusView);
433         mNotificationContainerParent.onFinishInflate();
434         when(mView.findViewById(R.id.notification_container_parent))
435                 .thenReturn(mNotificationContainerParent);
436         when(mFragmentService.getFragmentHostManager(mView)).thenReturn(mFragmentHostManager);
437         FlingAnimationUtils.Builder flingAnimationUtilsBuilder = new FlingAnimationUtils.Builder(
438                 mDisplayMetrics);
439         when(mKeyguardQsUserSwitchComponentFactory.build(any()))
440                 .thenReturn(mKeyguardQsUserSwitchComponent);
441         when(mKeyguardQsUserSwitchComponent.getKeyguardQsUserSwitchController())
442                 .thenReturn(mKeyguardQsUserSwitchController);
443         when(mKeyguardUserSwitcherComponentFactory.build(any()))
444                 .thenReturn(mKeyguardUserSwitcherComponent);
445         when(mKeyguardUserSwitcherComponent.getKeyguardUserSwitcherController())
446                 .thenReturn(mKeyguardUserSwitcherController);
447         when(mScreenOffAnimationController.shouldAnimateClockChange()).thenReturn(true);
448         when(mQs.getView()).thenReturn(mView);
449         when(mQSFragment.getView()).thenReturn(mView);
450         doAnswer(invocation -> {
451             mFragmentListener = invocation.getArgument(1);
452             return null;
453         }).when(mFragmentHostManager).addTagListener(eq(QS.TAG), any());
454         doAnswer((Answer<Void>) invocation -> {
455             mTouchHandler = invocation.getArgument(0);
456             return null;
457         }).when(mView).setOnTouchListener(any(NotificationPanelViewController.TouchHandler.class));
458 
459         // Dreaming->Lockscreen
460         when(mKeyguardTransitionInteractor.getDreamingToLockscreenTransition())
461                 .thenReturn(emptyFlow());
462         when(mDreamingToLockscreenTransitionViewModel.getLockscreenAlpha())
463                 .thenReturn(emptyFlow());
464         when(mDreamingToLockscreenTransitionViewModel.lockscreenTranslationY(anyInt()))
465                 .thenReturn(emptyFlow());
466 
467         // Occluded->Lockscreen
468         when(mKeyguardTransitionInteractor.getOccludedToLockscreenTransition())
469                 .thenReturn(emptyFlow());
470         when(mOccludedToLockscreenTransitionViewModel.getLockscreenAlpha())
471                 .thenReturn(emptyFlow());
472         when(mOccludedToLockscreenTransitionViewModel.lockscreenTranslationY(anyInt()))
473                 .thenReturn(emptyFlow());
474 
475         // Lockscreen->Dreaming
476         when(mKeyguardTransitionInteractor.getLockscreenToDreamingTransition())
477                 .thenReturn(emptyFlow());
478         when(mLockscreenToDreamingTransitionViewModel.getLockscreenAlpha())
479                 .thenReturn(emptyFlow());
480         when(mLockscreenToDreamingTransitionViewModel.lockscreenTranslationY(anyInt()))
481                 .thenReturn(emptyFlow());
482 
483         // Gone->Dreaming
484         when(mKeyguardTransitionInteractor.getGoneToDreamingTransition())
485                 .thenReturn(emptyFlow());
486         when(mGoneToDreamingTransitionViewModel.getLockscreenAlpha())
487                 .thenReturn(emptyFlow());
488         when(mGoneToDreamingTransitionViewModel.lockscreenTranslationY(anyInt()))
489                 .thenReturn(emptyFlow());
490 
491         // Gone->Dreaming lockscreen hosted
492         when(mKeyguardTransitionInteractor.getGoneToDreamingLockscreenHostedTransition())
493                 .thenReturn(emptyFlow());
494         when(mGoneToDreamingLockscreenHostedTransitionViewModel.getLockscreenAlpha())
495                 .thenReturn(emptyFlow());
496 
497         // Dreaming lockscreen hosted->Lockscreen
498         when(mKeyguardTransitionInteractor.getDreamingLockscreenHostedToLockscreenTransition())
499                 .thenReturn(emptyFlow());
500 
501         // Lockscreen->Dreaming lockscreen hosted
502         when(mKeyguardTransitionInteractor.getLockscreenToDreamingLockscreenHostedTransition())
503                 .thenReturn(emptyFlow());
504 
505         // Lockscreen->Occluded
506         when(mKeyguardTransitionInteractor.getLockscreenToOccludedTransition())
507                 .thenReturn(emptyFlow());
508         when(mLockscreenToOccludedTransitionViewModel.getLockscreenAlpha())
509                 .thenReturn(emptyFlow());
510         when(mLockscreenToOccludedTransitionViewModel.lockscreenTranslationY(anyInt()))
511                 .thenReturn(emptyFlow());
512 
513         // Primary Bouncer->Gone
514         when(mPrimaryBouncerToGoneTransitionViewModel.getLockscreenAlpha())
515                 .thenReturn(emptyFlow());
516 
517         NotificationWakeUpCoordinator coordinator =
518                 new NotificationWakeUpCoordinator(
519                         mDumpManager,
520                         mock(HeadsUpManagerPhone.class),
521                         new StatusBarStateControllerImpl(new UiEventLoggerFake(), mDumpManager,
522                                 mInteractionJankMonitor, mShadeExpansionStateManager),
523                         mKeyguardBypassController,
524                         mDozeParameters,
525                         mScreenOffAnimationController,
526                         new NotificationWakeUpCoordinatorLogger(logcatLogBuffer()));
527         mConfigurationController = new ConfigurationControllerImpl(mContext);
528         PulseExpansionHandler expansionHandler = new PulseExpansionHandler(
529                 mContext,
530                 coordinator,
531                 mKeyguardBypassController, mHeadsUpManager,
532                 mock(NotificationRoundnessManager.class),
533                 mConfigurationController,
534                 mStatusBarStateController,
535                 mFalsingManager,
536                 mShadeExpansionStateManager,
537                 mLockscreenShadeTransitionController,
538                 new FalsingCollectorFake(),
539                 mDumpManager);
540         when(mKeyguardStatusViewComponentFactory.build(any()))
541                 .thenReturn(mKeyguardStatusViewComponent);
542         when(mKeyguardStatusViewComponent.getKeyguardClockSwitchController())
543                 .thenReturn(mKeyguardClockSwitchController);
544         when(mKeyguardStatusViewComponent.getKeyguardStatusViewController())
545                 .thenReturn(mKeyguardStatusViewController);
546         when(mKeyguardStatusBarViewComponentFactory.build(any(), any()))
547                 .thenReturn(mKeyguardStatusBarViewComponent);
548         when(mKeyguardStatusBarViewComponent.getKeyguardStatusBarViewController())
549                 .thenReturn(mKeyguardStatusBarViewController);
550         when(mLayoutInflater.inflate(eq(R.layout.keyguard_status_view), any(), anyBoolean()))
551                 .thenReturn(keyguardStatusView);
552         when(mLayoutInflater.inflate(eq(R.layout.keyguard_user_switcher), any(), anyBoolean()))
553                 .thenReturn(mUserSwitcherView);
554         when(mLayoutInflater.inflate(eq(R.layout.keyguard_bottom_area), any(), anyBoolean()))
555                 .thenReturn(mKeyguardBottomArea);
556         when(mNotificationRemoteInputManager.isRemoteInputActive())
557                 .thenReturn(false);
558         when(mInteractionJankMonitor.begin(any(), anyInt()))
559                 .thenReturn(true);
560         when(mInteractionJankMonitor.end(anyInt()))
561                 .thenReturn(true);
562         doAnswer(invocation -> {
563             ((Runnable) invocation.getArgument(0)).run();
564             return null;
565         }).when(mNotificationShadeWindowController).batchApplyWindowLayoutParams(any());
566         doAnswer(invocation -> {
567             mLayoutChangeListener = invocation.getArgument(0);
568             return null;
569         }).when(mView).addOnLayoutChangeListener(any());
570 
571         when(mView.getViewTreeObserver()).thenReturn(mViewTreeObserver);
572         when(mView.getParent()).thenReturn(mViewParent);
573         when(mQs.getHeader()).thenReturn(mQsHeader);
574         when(mDownMotionEvent.getAction()).thenReturn(MotionEvent.ACTION_DOWN);
575         when(mSysUiState.setFlag(anyInt(), anyBoolean())).thenReturn(mSysUiState);
576 
577         mMainHandler = new Handler(Looper.getMainLooper());
578 
579         when(mView.requireViewById(R.id.keyguard_long_press))
580                 .thenReturn(mock(LongPressHandlingView.class));
581 
582         mNotificationPanelViewController = new NotificationPanelViewController(
583                 mView,
584                 mMainHandler,
585                 mLayoutInflater,
586                 mFeatureFlags,
587                 coordinator, expansionHandler, mDynamicPrivacyController, mKeyguardBypassController,
588                 mFalsingManager, new FalsingCollectorFake(),
589                 mKeyguardStateController,
590                 mStatusBarStateController,
591                 mStatusBarWindowStateController,
592                 mNotificationShadeWindowController,
593                 mDozeLog, mDozeParameters, mCommandQueue, mVibratorHelper,
594                 mLatencyTracker, mPowerManager, mAccessibilityManager, 0, mUpdateMonitor,
595                 mMetricsLogger,
596                 mShadeLog,
597                 mConfigurationController,
598                 () -> flingAnimationUtilsBuilder, mStatusBarTouchableRegionManager,
599                 mConversationNotificationManager, mMediaHierarchyManager,
600                 mStatusBarKeyguardViewManager,
601                 mGutsManager,
602                 mNotificationsQSContainerController,
603                 mNotificationStackScrollLayoutController,
604                 mKeyguardStatusViewComponentFactory,
605                 mKeyguardQsUserSwitchComponentFactory,
606                 mKeyguardUserSwitcherComponentFactory,
607                 mKeyguardStatusBarViewComponentFactory,
608                 mLockscreenShadeTransitionController,
609                 mAuthController,
610                 mScrimController,
611                 mUserManager,
612                 mMediaDataManager,
613                 mNotificationShadeDepthController,
614                 mAmbientState,
615                 mLockIconViewController,
616                 mKeyguardMediaController,
617                 mTapAgainViewController,
618                 mNavigationModeController,
619                 mNavigationBarController,
620                 mQsController,
621                 mFragmentService,
622                 mContentResolver,
623                 mShadeHeaderController,
624                 mScreenOffAnimationController,
625                 mLockscreenGestureLogger,
626                 mShadeExpansionStateManager,
627                 mSysUIUnfoldComponent,
628                 mSysUiState,
629                 () -> mKeyguardBottomAreaViewController,
630                 mKeyguardUnlockAnimationController,
631                 mKeyguardIndicationController,
632                 mNotificationListContainer,
633                 mNotificationStackSizeCalculator,
634                 mUnlockedScreenOffAnimationController,
635                 mShadeTransitionController,
636                 systemClock,
637                 mKeyguardBottomAreaViewModel,
638                 mKeyguardBottomAreaInteractor,
639                 mAlternateBouncerInteractor,
640                 mDreamingToLockscreenTransitionViewModel,
641                 mOccludedToLockscreenTransitionViewModel,
642                 mLockscreenToDreamingTransitionViewModel,
643                 mGoneToDreamingTransitionViewModel,
644                 mGoneToDreamingLockscreenHostedTransitionViewModel,
645                 mLockscreenToOccludedTransitionViewModel,
646                 mPrimaryBouncerToGoneTransitionViewModel,
647                 mMainDispatcher,
648                 mKeyguardTransitionInteractor,
649                 mDumpManager,
650                 mKeyuardLongPressViewModel,
651                 mKeyguardInteractor,
652                 mActivityStarter,
653                 mKeyguardViewConfigurator,
654                 mKeyguardFaceAuthInteractor,
655                 mKeyguardRootView);
656         mNotificationPanelViewController.initDependencies(
657                 mCentralSurfaces,
658                 null,
659                 () -> {},
660                 mNotificationShelfController,
661                 mHeadsUpManager);
662         mNotificationPanelViewController.setTrackingStartedListener(() -> {});
663         mNotificationPanelViewController.setOpenCloseListener(
664                 new OpenCloseListener() {
665                     @Override
666                     public void onClosingFinished() {}
667 
668                     @Override
669                     public void onOpenStarted() {}
670                 });
671         ArgumentCaptor<View.OnAttachStateChangeListener> onAttachStateChangeListenerArgumentCaptor =
672                 ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class);
673         verify(mView, atLeast(1)).addOnAttachStateChangeListener(
674                 onAttachStateChangeListenerArgumentCaptor.capture());
675         mOnAttachStateChangeListeners = onAttachStateChangeListenerArgumentCaptor.getAllValues();
676 
677         ArgumentCaptor<View.AccessibilityDelegate> accessibilityDelegateArgumentCaptor =
678                 ArgumentCaptor.forClass(View.AccessibilityDelegate.class);
679         verify(mView).setAccessibilityDelegate(accessibilityDelegateArgumentCaptor.capture());
680         mAccessibilityDelegate = accessibilityDelegateArgumentCaptor.getValue();
681         mNotificationPanelViewController.getStatusBarStateController()
682                 .addCallback(mNotificationPanelViewController.getStatusBarStateListener());
683         mNotificationPanelViewController.getShadeHeadsUpTracker()
684                 .setHeadsUpAppearanceController(mock(HeadsUpAppearanceController.class));
685         verify(mNotificationStackScrollLayoutController)
686                 .setOnEmptySpaceClickListener(mEmptySpaceClickListenerCaptor.capture());
687         verify(mKeyguardStatusViewController).displayClock(LARGE, /* animate */ true);
688         reset(mKeyguardStatusViewController);
689 
690         when(mNotificationPanelViewControllerLazy.get())
691                 .thenReturn(mNotificationPanelViewController);
692         mQuickSettingsController = new QuickSettingsController(
693                 mNotificationPanelViewControllerLazy,
694                 mView,
695                 mQsFrameTranslateController,
696                 mShadeTransitionController,
697                 expansionHandler,
698                 mNotificationRemoteInputManager,
699                 mShadeExpansionStateManager,
700                 mStatusBarKeyguardViewManager,
701                 mLightBarController,
702                 mNotificationStackScrollLayoutController,
703                 mLockscreenShadeTransitionController,
704                 mNotificationShadeDepthController,
705                 mShadeHeaderController,
706                 mStatusBarTouchableRegionManager,
707                 mKeyguardStateController,
708                 mKeyguardBypassController,
709                 mUpdateMonitor,
710                 mScrimController,
711                 mMediaDataManager,
712                 mMediaHierarchyManager,
713                 mAmbientState,
714                 mRecordingController,
715                 mFalsingManager,
716                 new FalsingCollectorFake(),
717                 mAccessibilityManager,
718                 mLockscreenGestureLogger,
719                 mMetricsLogger,
720                 mFeatureFlags,
721                 mInteractionJankMonitor,
722                 mShadeLog,
723                 mDumpManager,
724                 mKeyguardFaceAuthInteractor,
725                 mShadeRepository,
726                 mShadeInteractor,
727                 mJavaAdapter,
728                 mCastController
729         );
730     }
731 
732     @After
tearDown()733     public void tearDown() {
734         if (mNotificationPanelViewController != null) {
735             mNotificationPanelViewController.mBottomAreaShadeAlphaAnimator.cancel();
736             mNotificationPanelViewController.cancelHeightAnimator();
737         }
738         if (mMainHandler != null) {
739             mMainHandler.removeCallbacksAndMessages(null);
740         }
741     }
742 
setBottomPadding(int stackBottom, int lockIconPadding, int indicationPadding, int ambientPadding)743     protected void setBottomPadding(int stackBottom, int lockIconPadding, int indicationPadding,
744             int ambientPadding) {
745 
746         when(mNotificationStackScrollLayoutController.getTop()).thenReturn(0);
747         when(mNotificationStackScrollLayoutController.getHeight()).thenReturn(stackBottom);
748         when(mNotificationStackScrollLayoutController.getBottom()).thenReturn(stackBottom);
749         when(mLockIconViewController.getTop()).thenReturn((float) (stackBottom - lockIconPadding));
750 
751         when(mResources.getDimensionPixelSize(R.dimen.keyguard_indication_bottom_padding))
752                 .thenReturn(indicationPadding);
753         mNotificationPanelViewController.loadDimens();
754 
755         mNotificationPanelViewController.setAmbientIndicationTop(
756                 /* ambientIndicationTop= */ stackBottom - ambientPadding,
757                 /* ambientTextVisible= */ true);
758     }
759 
triggerPositionClockAndNotifications()760     protected void triggerPositionClockAndNotifications() {
761         mNotificationPanelViewController.onQsSetExpansionHeightCalled(false);
762     }
763 
getFalsingTapListener()764     protected FalsingManager.FalsingTapListener getFalsingTapListener() {
765         for (View.OnAttachStateChangeListener listener : mOnAttachStateChangeListeners) {
766             listener.onViewAttachedToWindow(mView);
767         }
768         assertThat(mFalsingManager.getTapListeners().size()).isEqualTo(1);
769         return mFalsingManager.getTapListeners().get(0);
770     }
771 
givenViewAttached()772     protected void givenViewAttached() {
773         for (View.OnAttachStateChangeListener listener : mOnAttachStateChangeListeners) {
774             listener.onViewAttachedToWindow(mView);
775         }
776     }
777 
getConstraintSetLayout(@dRes int id)778     protected ConstraintSet.Layout getConstraintSetLayout(@IdRes int id) {
779         ConstraintSet constraintSet = new ConstraintSet();
780         constraintSet.clone(mNotificationContainerParent);
781         return constraintSet.getConstraint(id).layout;
782     }
783 
enableSplitShade(boolean enabled)784     protected void enableSplitShade(boolean enabled) {
785         when(mResources.getBoolean(R.bool.config_use_split_notification_shade)).thenReturn(enabled);
786         mNotificationPanelViewController.updateResources();
787     }
788 
updateMultiUserSetting(boolean enabled)789     protected void updateMultiUserSetting(boolean enabled) {
790         when(mResources.getBoolean(R.bool.qs_show_user_switcher_for_single_user)).thenReturn(false);
791         when(mUserManager.isUserSwitcherEnabled(false)).thenReturn(enabled);
792         final ArgumentCaptor<ContentObserver> observerCaptor =
793                 ArgumentCaptor.forClass(ContentObserver.class);
794         verify(mContentResolver)
795                 .registerContentObserver(any(), anyBoolean(), observerCaptor.capture());
796         observerCaptor.getValue().onChange(/* selfChange */ false);
797     }
798 
updateSmallestScreenWidth(int smallestScreenWidthDp)799     protected void updateSmallestScreenWidth(int smallestScreenWidthDp) {
800         Configuration configuration = new Configuration();
801         configuration.smallestScreenWidthDp = smallestScreenWidthDp;
802         mConfigurationController.onConfigurationChanged(configuration);
803     }
804 
onTouchEvent(MotionEvent ev)805     protected void onTouchEvent(MotionEvent ev) {
806         mTouchHandler.onTouch(mView, ev);
807     }
808 
setDozing(boolean dozing, boolean dozingAlwaysOn)809     protected void setDozing(boolean dozing, boolean dozingAlwaysOn) {
810         when(mDozeParameters.getAlwaysOn()).thenReturn(dozingAlwaysOn);
811         mNotificationPanelViewController.setDozing(
812                 /* dozing= */ dozing,
813                 /* animate= */ false
814         );
815     }
816 
assertKeyguardStatusViewCentered()817     protected void assertKeyguardStatusViewCentered() {
818         mNotificationPanelViewController.updateResources();
819         assertThat(getConstraintSetLayout(R.id.keyguard_status_view).endToEnd).isAnyOf(
820                 ConstraintSet.PARENT_ID, ConstraintSet.UNSET);
821     }
822 
assertKeyguardStatusViewNotCentered()823     protected void assertKeyguardStatusViewNotCentered() {
824         mNotificationPanelViewController.updateResources();
825         assertThat(getConstraintSetLayout(R.id.keyguard_status_view).endToEnd).isEqualTo(
826                 R.id.qs_edge_guideline);
827     }
828 
setIsFullWidth(boolean fullWidth)829     protected void setIsFullWidth(boolean fullWidth) {
830         float nsslWidth = fullWidth ? PANEL_WIDTH : PANEL_WIDTH / 2f;
831         when(mNotificationStackScrollLayoutController.getWidth()).thenReturn(nsslWidth);
832         triggerLayoutChange();
833     }
834 
triggerLayoutChange()835     protected void triggerLayoutChange() {
836         mLayoutChangeListener.onLayoutChange(
837                 mView,
838                 /* left= */ 0,
839                 /* top= */ 0,
840                 /* right= */ 0,
841                 /* bottom= */ 0,
842                 /* oldLeft= */ 0,
843                 /* oldTop= */ 0,
844                 /* oldRight= */ 0,
845                 /* oldBottom= */ 0
846         );
847     }
848 
getMainDispatcher()849     protected CoroutineDispatcher getMainDispatcher() {
850         return mMainDispatcher;
851     }
852 }
853