• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 android.content.ComponentCallbacks2;
20 import android.os.Looper;
21 import android.util.Log;
22 import android.view.MotionEvent;
23 import android.view.ViewTreeObserver;
24 import android.view.WindowManagerGlobal;
25 
26 import com.android.systemui.DejankUtils;
27 import com.android.systemui.assist.AssistManager;
28 import com.android.systemui.dagger.SysUISingleton;
29 import com.android.systemui.dagger.qualifiers.DisplayId;
30 import com.android.systemui.dagger.qualifiers.Main;
31 import com.android.systemui.plugins.statusbar.StatusBarStateController;
32 import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor;
33 import com.android.systemui.scene.shared.flag.SceneContainerFlag;
34 import com.android.systemui.statusbar.CommandQueue;
35 import com.android.systemui.statusbar.NotificationShadeWindowController;
36 import com.android.systemui.statusbar.StatusBarState;
37 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
38 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
39 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
40 import com.android.systemui.statusbar.policy.KeyguardStateController;
41 import com.android.systemui.statusbar.window.StatusBarWindowController;
42 
43 import dagger.Lazy;
44 
45 import java.util.concurrent.Executor;
46 
47 import javax.inject.Inject;
48 
49 /** An implementation of {@link ShadeController}. */
50 @SysUISingleton
51 public final class ShadeControllerImpl extends BaseShadeControllerImpl {
52 
53     private static final String TAG = "ShadeControllerImpl";
54     private static final boolean SPEW = false;
55 
56     private final int mDisplayId;
57 
58     private final CommandQueue mCommandQueue;
59     private final Executor mMainExecutor;
60     private final WindowRootViewVisibilityInteractor mWindowRootViewVisibilityInteractor;
61     private final KeyguardStateController mKeyguardStateController;
62     private final NotificationShadeWindowController mNotificationShadeWindowController;
63     private final StatusBarStateController mStatusBarStateController;
64     private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
65     private final StatusBarWindowController mStatusBarWindowController;
66     private final DeviceProvisionedController mDeviceProvisionedController;
67 
68     private final Lazy<NotificationPanelViewController> mNpvc;
69     private final Lazy<AssistManager> mAssistManagerLazy;
70     private final Lazy<NotificationGutsManager> mGutsManager;
71 
72     private boolean mExpandedVisible;
73     private boolean mLockscreenOrShadeVisible;
74 
75     private NotificationShadeWindowViewController mNotificationShadeWindowViewController;
76     private ShadeVisibilityListener mShadeVisibilityListener;
77 
78     @Inject
ShadeControllerImpl( CommandQueue commandQueue, @Main Executor mainExecutor, WindowRootViewVisibilityInteractor windowRootViewVisibilityInteractor, KeyguardStateController keyguardStateController, StatusBarStateController statusBarStateController, StatusBarKeyguardViewManager statusBarKeyguardViewManager, StatusBarWindowController statusBarWindowController, DeviceProvisionedController deviceProvisionedController, NotificationShadeWindowController notificationShadeWindowController, @DisplayId int displayId, Lazy<NotificationPanelViewController> shadeViewControllerLazy, Lazy<AssistManager> assistManagerLazy, Lazy<NotificationGutsManager> gutsManager )79     public ShadeControllerImpl(
80             CommandQueue commandQueue,
81             @Main Executor mainExecutor,
82             WindowRootViewVisibilityInteractor windowRootViewVisibilityInteractor,
83             KeyguardStateController keyguardStateController,
84             StatusBarStateController statusBarStateController,
85             StatusBarKeyguardViewManager statusBarKeyguardViewManager,
86             StatusBarWindowController statusBarWindowController,
87             DeviceProvisionedController deviceProvisionedController,
88             NotificationShadeWindowController notificationShadeWindowController,
89             @DisplayId int displayId,
90             Lazy<NotificationPanelViewController> shadeViewControllerLazy,
91             Lazy<AssistManager> assistManagerLazy,
92             Lazy<NotificationGutsManager> gutsManager
93     ) {
94         super(commandQueue,
95                 statusBarKeyguardViewManager,
96                 notificationShadeWindowController,
97                 assistManagerLazy);
98         SceneContainerFlag.assertInLegacyMode();
99         mCommandQueue = commandQueue;
100         mMainExecutor = mainExecutor;
101         mWindowRootViewVisibilityInteractor = windowRootViewVisibilityInteractor;
102         mNpvc = shadeViewControllerLazy;
103         mStatusBarStateController = statusBarStateController;
104         mStatusBarWindowController = statusBarWindowController;
105         mDeviceProvisionedController = deviceProvisionedController;
106         mGutsManager = gutsManager;
107         mNotificationShadeWindowController = notificationShadeWindowController;
108         mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
109         mDisplayId = displayId;
110         mKeyguardStateController = keyguardStateController;
111         mAssistManagerLazy = assistManagerLazy;
112     }
113 
114     @Override
isShadeEnabled()115     public boolean isShadeEnabled() {
116         return mCommandQueue.panelsEnabled() && mDeviceProvisionedController.isCurrentUserSetup();
117     }
118 
119     @Override
instantExpandShade()120     public void instantExpandShade() {
121         // Make our window larger and the panel expanded.
122         makeExpandedVisible(true /* force */);
123         getNpvc().expand(false /* animate */);
124         getCommandQueue().recomputeDisableFlags(mDisplayId, false /* animate */);
125     }
126 
127     @Override
animateCollapseShade(int flags, boolean force, boolean delayed, float speedUpFactor)128     public void animateCollapseShade(int flags, boolean force, boolean delayed,
129             float speedUpFactor) {
130         int statusBarState = mStatusBarStateController.getState();
131         if (!force && statusBarState != StatusBarState.SHADE
132                 && statusBarState != StatusBarState.SHADE_LOCKED) {
133             runPostCollapseActions();
134             return;
135         }
136         if (getNotificationShadeWindowView() != null
137                 && getNpvc().canBeCollapsed()
138                 && (flags & CommandQueue.FLAG_EXCLUDE_NOTIFICATION_PANEL) == 0) {
139             // release focus immediately to kick off focus change transition
140             mNotificationShadeWindowController.setNotificationShadeFocusable(false);
141 
142             mNotificationShadeWindowViewController.cancelExpandHelper();
143             getNpvc().collapse(true, delayed, speedUpFactor);
144         }
145     }
146 
147     @Override
collapseWithDuration(int animationDuration)148     public void collapseWithDuration(int animationDuration) {
149         mNpvc.get().collapseWithDuration(animationDuration);
150     }
151 
152     @Override
expandToNotifications()153     protected void expandToNotifications() {
154         getNpvc().expandToNotifications();
155     }
156 
157     @Override
expandToQs()158     protected void expandToQs() {
159         getNpvc().expandToQs();
160     }
161 
162     @Override
closeShadeIfOpen()163     public boolean closeShadeIfOpen() {
164         if (!getNpvc().isFullyCollapsed()) {
165             getCommandQueue().animateCollapsePanels(
166                     CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
167             notifyVisibilityChanged(false);
168             mAssistManagerLazy.get().hideAssist();
169         }
170         return false;
171     }
172 
173     @Override
isShadeFullyOpen()174     public boolean isShadeFullyOpen() {
175         return getNpvc().isShadeFullyExpanded();
176     }
177 
178     @Override
isExpandingOrCollapsing()179     public boolean isExpandingOrCollapsing() {
180         return getNpvc().isExpandingOrCollapsing();
181     }
182     @Override
postAnimateCollapseShade()183     public void postAnimateCollapseShade() {
184         mMainExecutor.execute(this::animateCollapseShade);
185     }
186 
187     @Override
postAnimateForceCollapseShade()188     public void postAnimateForceCollapseShade() {
189         mMainExecutor.execute(this::animateCollapseShadeForced);
190     }
191 
192     @Override
postAnimateExpandQs()193     public void postAnimateExpandQs() {
194         mMainExecutor.execute(this::animateExpandQs);
195     }
196 
197     @Override
postOnShadeExpanded(Runnable executable)198     public void postOnShadeExpanded(Runnable executable) {
199         getNpvc().addOnGlobalLayoutListener(
200                 new ViewTreeObserver.OnGlobalLayoutListener() {
201                     @Override
202                     public void onGlobalLayout() {
203                         if (getNotificationShadeWindowView().isVisibleToUser()) {
204                             getNpvc().removeOnGlobalLayoutListener(this);
205                             getNpvc().postToView(executable);
206                         }
207                     }
208                 });
209     }
210 
211     @Override
collapseShade()212     public void collapseShade() {
213         collapseShadeInternal();
214     }
215 
collapseShadeInternal()216     private boolean collapseShadeInternal() {
217         if (!getNpvc().isFullyCollapsed()) {
218             // close the shade if it was open
219             animateCollapseShadeForcedDelayed();
220             notifyVisibilityChanged(false);
221             return true;
222         } else {
223             return false;
224         }
225     }
226 
227     @Override
collapseShade(boolean animate)228     public void collapseShade(boolean animate) {
229         if (animate) {
230             boolean willCollapse = collapseShadeInternal();
231             if (!willCollapse) {
232                 runPostCollapseActions();
233             }
234         } else if (!getNotifPresenter().isPresenterFullyCollapsed()) {
235             instantCollapseShade();
236             notifyVisibilityChanged(false);
237         } else {
238             runPostCollapseActions();
239         }
240     }
241 
242     @Override
cancelExpansionAndCollapseShade()243     public void cancelExpansionAndCollapseShade() {
244         if (getNpvc().isTracking()) {
245             mNotificationShadeWindowViewController.cancelCurrentTouch();
246         }
247         if (getNpvc().isPanelExpanded()
248                 && mStatusBarStateController.getState() == StatusBarState.SHADE) {
249             animateCollapseShade();
250         }
251     }
252 
253     @Override
collapseOnMainThread()254     public void collapseOnMainThread() {
255         if (Looper.getMainLooper().isCurrentThread()) {
256             collapseShade();
257         } else {
258             mMainExecutor.execute(this::collapseShade);
259         }
260     }
261 
262     @Override
onStatusBarTouch(MotionEvent event)263     public void onStatusBarTouch(MotionEvent event) {
264         if (event.getAction() == MotionEvent.ACTION_UP) {
265             if (mExpandedVisible) {
266                 animateCollapseShade();
267             }
268         }
269     }
270 
271     @Override
performHapticFeedback(int constant)272     public void performHapticFeedback(int constant) {
273         getNpvc().performHapticFeedback(constant);
274     }
275 
276     @Override
instantCollapseShade()277     public void instantCollapseShade() {
278         getNpvc().instantCollapse();
279         runPostCollapseActions();
280     }
281 
282     @Override
makeExpandedVisible(boolean force)283     public void makeExpandedVisible(boolean force) {
284         if (SPEW) Log.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible);
285         if (!force && (mExpandedVisible || !getCommandQueue().panelsEnabled())) {
286             return;
287         }
288 
289         mExpandedVisible = true;
290 
291         // Expand the window to encompass the full screen in anticipation of the drag.
292         // It's only possible to do atomically because the status bar is at the top of the screen!
293         mNotificationShadeWindowController.setPanelVisible(true);
294 
295         notifyVisibilityChanged(true);
296         getCommandQueue().recomputeDisableFlags(mDisplayId, !force /* animate */);
297         notifyExpandedVisibleChanged(true);
298     }
299 
300     @Override
makeExpandedInvisible()301     public void makeExpandedInvisible() {
302         if (SPEW) Log.d(TAG, "makeExpandedInvisible: mExpandedVisible=" + mExpandedVisible);
303 
304         if (!mExpandedVisible || getNotificationShadeWindowView() == null) {
305             return;
306         }
307 
308         // Ensure the panel is fully collapsed (just in case; bug 6765842, 7260868)
309         getNpvc().collapse(false, false, 1.0f);
310 
311         mExpandedVisible = false;
312         notifyVisibilityChanged(false);
313 
314         // Update the visibility of notification shade and status bar window.
315         mNotificationShadeWindowController.setPanelVisible(false);
316         mStatusBarWindowController.setForceStatusBarVisible(false);
317 
318         // Close any guts that might be visible
319         mGutsManager.get().closeAndSaveGuts(
320                 true /* removeLeavebehind */,
321                 true /* force */,
322                 true /* removeControls */,
323                 -1 /* x */,
324                 -1 /* y */,
325                 true /* resetMenu */);
326 
327         runPostCollapseActions();
328         notifyExpandedVisibleChanged(false);
329         getCommandQueue().recomputeDisableFlags(
330                 mDisplayId,
331                 getNpvc().shouldHideStatusBarIconsWhenExpanded());
332 
333         // Trimming will happen later if Keyguard is showing - doing it here might cause a jank in
334         // the bouncer appear animation.
335         if (!mKeyguardStateController.isShowing()) {
336             WindowManagerGlobal.getInstance().trimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
337         }
338     }
339 
340     @Override
isExpandedVisible()341     public boolean isExpandedVisible() {
342         return mExpandedVisible;
343     }
344 
345     @Override
setVisibilityListener(ShadeVisibilityListener listener)346     public void setVisibilityListener(ShadeVisibilityListener listener) {
347         mShadeVisibilityListener = listener;
348     }
349 
notifyVisibilityChanged(boolean visible)350     private void notifyVisibilityChanged(boolean visible) {
351         mWindowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(visible);
352         if (mLockscreenOrShadeVisible != visible) {
353             mLockscreenOrShadeVisible = visible;
354             if (visible) {
355                 // It would be best if this could be done as a side effect of listening to the
356                 // [WindowRootViewVisibilityInteractor.isLockscreenOrShadeVisible] flow inside
357                 // NotificationShadeWindowViewController. However, there's no guarantee that the
358                 // flow will emit in the same frame as when the visibility changed, and we want the
359                 // DejankUtils to be notified immediately, so we do it immediately here.
360                 DejankUtils.notifyRendererOfExpensiveFrame(
361                         getNotificationShadeWindowView(), "onShadeVisibilityChanged");
362             }
363         }
364     }
365 
notifyExpandedVisibleChanged(boolean expandedVisible)366     private void notifyExpandedVisibleChanged(boolean expandedVisible) {
367         mShadeVisibilityListener.expandedVisibleChanged(expandedVisible);
368     }
369 
370     @Override
setNotificationShadeWindowViewController( NotificationShadeWindowViewController controller)371     public void setNotificationShadeWindowViewController(
372             NotificationShadeWindowViewController controller) {
373         mNotificationShadeWindowViewController = controller;
374     }
375 
getNotificationShadeWindowView()376     private NotificationShadeWindowView getNotificationShadeWindowView() {
377         return mNotificationShadeWindowViewController.getView();
378     }
379 
getNpvc()380     private NotificationPanelViewController getNpvc() {
381         return mNpvc.get();
382     }
383 
384     @Override
start()385     public void start() {
386         getNpvc().setTrackingStartedListener(this::runPostCollapseActions);
387         getNpvc().setOpenCloseListener(
388                 new OpenCloseListener() {
389                     @Override
390                     public void onClosingFinished() {
391                         ShadeControllerImpl.this.onClosingFinished();
392                     }
393 
394                     @Override
395                     public void onOpenStarted() {
396                         makeExpandedVisible(false);
397                     }
398                 });
399     }
400 
401     @Override
collapseShadeForActivityStart()402     public void collapseShadeForActivityStart() {
403         if (isExpandedVisible() && !mStatusBarKeyguardViewManager.isBouncerShowing()) {
404             animateCollapseShadeForcedDelayed();
405         } else {
406             // Do it after DismissAction has been processed to conserve the
407             // needed ordering.
408             mMainExecutor.execute(this::runPostCollapseActions);
409         }
410     }
411 
412 }
413