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.systemui.wmshell;
18 
19 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING;
20 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED;
21 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED;
22 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DIALOG_SHOWING;
23 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE;
24 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
25 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_ONE_HANDED_ACTIVE;
26 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
27 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING;
28 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED;
29 
30 import android.content.Context;
31 import android.content.pm.UserInfo;
32 import android.content.res.Configuration;
33 import android.graphics.Rect;
34 import android.inputmethodservice.InputMethodService;
35 import android.os.IBinder;
36 import android.view.Display;
37 import android.view.KeyEvent;
38 
39 import androidx.annotation.NonNull;
40 
41 import com.android.internal.annotations.VisibleForTesting;
42 import com.android.keyguard.KeyguardUpdateMonitor;
43 import com.android.keyguard.KeyguardUpdateMonitorCallback;
44 import com.android.systemui.CoreStartable;
45 import com.android.systemui.dagger.SysUISingleton;
46 import com.android.systemui.dagger.WMComponent;
47 import com.android.systemui.dagger.qualifiers.Main;
48 import com.android.systemui.keyguard.ScreenLifecycle;
49 import com.android.systemui.keyguard.WakefulnessLifecycle;
50 import com.android.systemui.model.SysUiState;
51 import com.android.systemui.notetask.NoteTaskInitializer;
52 import com.android.systemui.settings.DisplayTracker;
53 import com.android.systemui.settings.UserTracker;
54 import com.android.systemui.statusbar.CommandQueue;
55 import com.android.systemui.statusbar.policy.ConfigurationController;
56 import com.android.systemui.statusbar.policy.KeyguardStateController;
57 import com.android.wm.shell.desktopmode.DesktopMode;
58 import com.android.wm.shell.desktopmode.DesktopModeTaskRepository;
59 import com.android.wm.shell.onehanded.OneHanded;
60 import com.android.wm.shell.onehanded.OneHandedEventCallback;
61 import com.android.wm.shell.onehanded.OneHandedTransitionCallback;
62 import com.android.wm.shell.onehanded.OneHandedUiEventLogger;
63 import com.android.wm.shell.pip.Pip;
64 import com.android.wm.shell.splitscreen.SplitScreen;
65 import com.android.wm.shell.sysui.ShellInterface;
66 
67 import java.io.PrintWriter;
68 import java.util.List;
69 import java.util.Optional;
70 import java.util.concurrent.Executor;
71 
72 import javax.inject.Inject;
73 
74 /**
75  * A SystemUI service that starts with the SystemUI application and sets up any bindings between
76  * Shell and SysUI components.  This service starts happens after the {@link WMComponent} has
77  * already been initialized and may only reference Shell components that are explicitly exported to
78  * SystemUI (see {@link WMComponent}.
79  *
80  * eg. SysUI application starts
81  *     -> SystemUIFactory is initialized
82  *       -> WMComponent is created
83  *         -> WMShellBaseModule dependencies are injected
84  *         -> WMShellModule (form-factory specific) dependencies are injected
85  *       -> SysUIComponent is created
86  *         -> WMComponents are explicitly provided to SysUIComponent for injection into SysUI code
87  *     -> SysUI services are started
88  *       -> WMShell starts and binds SysUI with Shell components via exported Shell interfaces
89  */
90 @SysUISingleton
91 public final class WMShell implements
92         CoreStartable,
93         CommandQueue.Callbacks {
94     private static final String TAG = WMShell.class.getName();
95     private static final int INVALID_SYSUI_STATE_MASK =
96             SYSUI_STATE_DIALOG_SHOWING
97                     | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING
98                     | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED
99                     | SYSUI_STATE_BOUNCER_SHOWING
100                     | SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED
101                     | SYSUI_STATE_BUBBLES_EXPANDED
102                     | SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED
103                     | SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
104 
105     private final Context mContext;
106     // Shell interfaces
107     private final ShellInterface mShell;
108     private final Optional<Pip> mPipOptional;
109     private final Optional<SplitScreen> mSplitScreenOptional;
110     private final Optional<OneHanded> mOneHandedOptional;
111     private final Optional<DesktopMode> mDesktopModeOptional;
112 
113     private final CommandQueue mCommandQueue;
114     private final ConfigurationController mConfigurationController;
115     private final KeyguardStateController mKeyguardStateController;
116     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
117     private final ScreenLifecycle mScreenLifecycle;
118     private final SysUiState mSysUiState;
119     private final WakefulnessLifecycle mWakefulnessLifecycle;
120     private final UserTracker mUserTracker;
121     private final DisplayTracker mDisplayTracker;
122     private final NoteTaskInitializer mNoteTaskInitializer;
123     private final Executor mSysUiMainExecutor;
124 
125     // Listeners and callbacks. Note that we prefer member variable over anonymous class here to
126     // avoid the situation that some implementations, like KeyguardUpdateMonitor, use WeakReference
127     // internally and anonymous class could be released after registration.
128     private final ConfigurationController.ConfigurationListener mConfigurationListener =
129             new ConfigurationController.ConfigurationListener() {
130                 @Override
131                 public void onConfigChanged(Configuration newConfig) {
132                     mShell.onConfigurationChanged(newConfig);
133                 }
134             };
135     private final KeyguardStateController.Callback mKeyguardStateCallback =
136             new KeyguardStateController.Callback() {
137                 @Override
138                 public void onKeyguardShowingChanged() {
139                     mShell.onKeyguardVisibilityChanged(mKeyguardStateController.isShowing(),
140                             mKeyguardStateController.isOccluded(),
141                             mKeyguardStateController.isAnimatingBetweenKeyguardAndSurfaceBehind());
142                 }
143             };
144     private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
145             new KeyguardUpdateMonitorCallback() {
146                 @Override
147                 public void onKeyguardDismissAnimationFinished() {
148                     mShell.onKeyguardDismissAnimationFinished();
149                 }
150             };
151     private final UserTracker.Callback mUserChangedCallback =
152             new UserTracker.Callback() {
153                 @Override
154                 public void onUserChanged(int newUser, @NonNull Context userContext) {
155                     mShell.onUserChanged(newUser, userContext);
156                 }
157 
158                 @Override
159                 public void onProfilesChanged(@NonNull List<UserInfo> profiles) {
160                     mShell.onUserProfilesChanged(profiles);
161                 }
162             };
163 
164     private boolean mIsSysUiStateValid;
165     private WakefulnessLifecycle.Observer mWakefulnessObserver;
166 
167     @Inject
WMShell( Context context, ShellInterface shell, Optional<Pip> pipOptional, Optional<SplitScreen> splitScreenOptional, Optional<OneHanded> oneHandedOptional, Optional<DesktopMode> desktopMode, CommandQueue commandQueue, ConfigurationController configurationController, KeyguardStateController keyguardStateController, KeyguardUpdateMonitor keyguardUpdateMonitor, ScreenLifecycle screenLifecycle, SysUiState sysUiState, WakefulnessLifecycle wakefulnessLifecycle, UserTracker userTracker, DisplayTracker displayTracker, NoteTaskInitializer noteTaskInitializer, @Main Executor sysUiMainExecutor)168     public WMShell(
169             Context context,
170             ShellInterface shell,
171             Optional<Pip> pipOptional,
172             Optional<SplitScreen> splitScreenOptional,
173             Optional<OneHanded> oneHandedOptional,
174             Optional<DesktopMode> desktopMode,
175             CommandQueue commandQueue,
176             ConfigurationController configurationController,
177             KeyguardStateController keyguardStateController,
178             KeyguardUpdateMonitor keyguardUpdateMonitor,
179             ScreenLifecycle screenLifecycle,
180             SysUiState sysUiState,
181             WakefulnessLifecycle wakefulnessLifecycle,
182             UserTracker userTracker,
183             DisplayTracker displayTracker,
184             NoteTaskInitializer noteTaskInitializer,
185             @Main Executor sysUiMainExecutor) {
186         mContext = context;
187         mShell = shell;
188         mCommandQueue = commandQueue;
189         mConfigurationController = configurationController;
190         mKeyguardStateController = keyguardStateController;
191         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
192         mScreenLifecycle = screenLifecycle;
193         mSysUiState = sysUiState;
194         mPipOptional = pipOptional;
195         mSplitScreenOptional = splitScreenOptional;
196         mOneHandedOptional = oneHandedOptional;
197         mDesktopModeOptional = desktopMode;
198         mWakefulnessLifecycle = wakefulnessLifecycle;
199         mUserTracker = userTracker;
200         mDisplayTracker = displayTracker;
201         mNoteTaskInitializer = noteTaskInitializer;
202         mSysUiMainExecutor = sysUiMainExecutor;
203     }
204 
205     @Override
start()206     public void start() {
207         // Notify with the initial configuration and subscribe for new config changes
208         mShell.onConfigurationChanged(mContext.getResources().getConfiguration());
209         mConfigurationController.addCallback(mConfigurationListener);
210 
211         // Subscribe to keyguard changes
212         mKeyguardStateController.addCallback(mKeyguardStateCallback);
213         mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
214 
215         // Subscribe to user changes
216         mUserTracker.addCallback(mUserChangedCallback, mContext.getMainExecutor());
217 
218         mCommandQueue.addCallback(this);
219         mPipOptional.ifPresent(this::initPip);
220         mSplitScreenOptional.ifPresent(this::initSplitScreen);
221         mOneHandedOptional.ifPresent(this::initOneHanded);
222         mDesktopModeOptional.ifPresent(this::initDesktopMode);
223 
224         mNoteTaskInitializer.initialize();
225     }
226 
227     @VisibleForTesting
initPip(Pip pip)228     void initPip(Pip pip) {
229         mCommandQueue.addCallback(new CommandQueue.Callbacks() {
230             @Override
231             public void showPictureInPictureMenu() {
232                 pip.showPictureInPictureMenu();
233             }
234         });
235 
236         mSysUiState.addCallback(sysUiStateFlag -> {
237             mIsSysUiStateValid = (sysUiStateFlag & INVALID_SYSUI_STATE_MASK) == 0;
238             pip.onSystemUiStateChanged(mIsSysUiStateValid, sysUiStateFlag);
239         });
240     }
241 
242     @VisibleForTesting
initSplitScreen(SplitScreen splitScreen)243     void initSplitScreen(SplitScreen splitScreen) {
244         mWakefulnessLifecycle.addObserver(new WakefulnessLifecycle.Observer() {
245             @Override
246             public void onFinishedWakingUp() {
247                 splitScreen.onFinishedWakingUp();
248             }
249         });
250         mCommandQueue.addCallback(new CommandQueue.Callbacks() {
251             @Override
252             public void goToFullscreenFromSplit() {
253                 splitScreen.goToFullscreenFromSplit();
254             }
255         });
256     }
257 
258     @VisibleForTesting
initOneHanded(OneHanded oneHanded)259     void initOneHanded(OneHanded oneHanded) {
260         oneHanded.registerTransitionCallback(new OneHandedTransitionCallback() {
261             @Override
262             public void onStartTransition(boolean isEntering) {
263                 mSysUiMainExecutor.execute(() -> {
264                     mSysUiState.setFlag(SYSUI_STATE_ONE_HANDED_ACTIVE,
265                             true).commitUpdate(mDisplayTracker.getDefaultDisplayId());
266                 });
267             }
268 
269             @Override
270             public void onStartFinished(Rect bounds) {
271                 mSysUiMainExecutor.execute(() -> {
272                     mSysUiState.setFlag(SYSUI_STATE_ONE_HANDED_ACTIVE,
273                             true).commitUpdate(mDisplayTracker.getDefaultDisplayId());
274                 });
275             }
276 
277             @Override
278             public void onStopFinished(Rect bounds) {
279                 mSysUiMainExecutor.execute(() -> {
280                     mSysUiState.setFlag(SYSUI_STATE_ONE_HANDED_ACTIVE,
281                             false).commitUpdate(mDisplayTracker.getDefaultDisplayId());
282                 });
283             }
284         });
285 
286         oneHanded.registerEventCallback(new OneHandedEventCallback() {
287             @Override
288             public void notifyExpandNotification() {
289                 mSysUiMainExecutor.execute(
290                         () -> mCommandQueue.handleSystemKey(new KeyEvent(KeyEvent.ACTION_DOWN,
291                                 KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN)));
292             }
293         });
294 
295         mWakefulnessObserver =
296                 new WakefulnessLifecycle.Observer() {
297                     @Override
298                     public void onFinishedWakingUp() {
299                         // Reset locked for the case keyguard not shown.
300                         oneHanded.setLockedDisabled(false /* locked */, false /* enabled */);
301                     }
302 
303                     @Override
304                     public void onStartedGoingToSleep() {
305                         oneHanded.stopOneHanded();
306                         // When user press power button going to sleep, temperory lock OHM disabled
307                         // to avoid mis-trigger.
308                         oneHanded.setLockedDisabled(true /* locked */, false /* enabled */);
309                     }
310                 };
311         mWakefulnessLifecycle.addObserver(mWakefulnessObserver);
312 
313         mScreenLifecycle.addObserver(new ScreenLifecycle.Observer() {
314             @Override
315             public void onScreenTurningOff() {
316                 oneHanded.stopOneHanded(
317                         OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_SCREEN_OFF_OUT);
318             }
319         });
320 
321         mCommandQueue.addCallback(new CommandQueue.Callbacks() {
322             @Override
323             public void onCameraLaunchGestureDetected(int source) {
324                 oneHanded.stopOneHanded();
325             }
326 
327             @Override
328             public void setImeWindowStatus(int displayId, IBinder token, int vis,
329                     int backDisposition, boolean showImeSwitcher) {
330                 if (displayId == mDisplayTracker.getDefaultDisplayId()
331                         && (vis & InputMethodService.IME_VISIBLE) != 0) {
332                     oneHanded.stopOneHanded(
333                             OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_POP_IME_OUT);
334                 }
335             }
336         });
337     }
338 
initDesktopMode(DesktopMode desktopMode)339     void initDesktopMode(DesktopMode desktopMode) {
340         desktopMode.addVisibleTasksListener(
341                 new DesktopModeTaskRepository.VisibleTasksListener() {
342                     @Override
343                     public void onVisibilityChanged(int displayId, boolean hasFreeformTasks) {
344                         if (displayId == Display.DEFAULT_DISPLAY) {
345                             mSysUiState.setFlag(SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE,
346                                             hasFreeformTasks)
347                                     .commitUpdate(mDisplayTracker.getDefaultDisplayId());
348                         }
349                         // TODO(b/278084491): update sysui state for changes on other displays
350                     }
351                 }, mSysUiMainExecutor);
352     }
353 
354     @Override
isDumpCritical()355     public boolean isDumpCritical() {
356         // Dump can't be critical because the shell has to dump on the main thread for
357         // synchronization reasons, which isn't reliably fast.
358         return false;
359     }
360 
361     @Override
dump(PrintWriter pw, String[] args)362     public void dump(PrintWriter pw, String[] args) {
363         // Handle commands if provided
364         if (mShell.handleCommand(args, pw)) {
365             return;
366         }
367         // Dump WMShell stuff here if no commands were handled
368         mShell.dump(pw);
369     }
370 }
371