• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.car.keyguard;
18 
19 import android.os.Bundle;
20 import android.util.Log;
21 import android.view.View;
22 import android.view.ViewGroup;
23 import android.view.ViewRootImpl;
24 
25 import androidx.annotation.VisibleForTesting;
26 
27 import com.android.keyguard.KeyguardUpdateMonitor;
28 import com.android.keyguard.KeyguardViewController;
29 import com.android.keyguard.ViewMediatorCallback;
30 import com.android.systemui.R;
31 import com.android.systemui.car.systembar.CarSystemBarController;
32 import com.android.systemui.car.window.OverlayViewController;
33 import com.android.systemui.car.window.OverlayViewGlobalStateController;
34 import com.android.systemui.dagger.SysUISingleton;
35 import com.android.systemui.dagger.qualifiers.Main;
36 import com.android.systemui.statusbar.phone.BiometricUnlockController;
37 import com.android.systemui.statusbar.phone.KeyguardBouncer;
38 import com.android.systemui.statusbar.phone.KeyguardBouncer.Factory;
39 import com.android.systemui.statusbar.phone.KeyguardBypassController;
40 import com.android.systemui.statusbar.phone.NotificationPanelViewController;
41 import com.android.systemui.statusbar.phone.StatusBar;
42 import com.android.systemui.statusbar.policy.KeyguardStateController;
43 import com.android.systemui.util.concurrency.DelayableExecutor;
44 
45 import javax.inject.Inject;
46 
47 import dagger.Lazy;
48 
49 /**
50  * Automotive implementation of the {@link KeyguardViewController}. It controls the Keyguard View
51  * that is mounted to the SystemUIOverlayWindow.
52  */
53 @SysUISingleton
54 public class CarKeyguardViewController extends OverlayViewController implements
55         KeyguardViewController {
56     private static final String TAG = "CarKeyguardViewController";
57     private static final boolean DEBUG = true;
58 
59     private final DelayableExecutor mMainExecutor;
60     private final KeyguardStateController mKeyguardStateController;
61     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
62     private final Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
63     private final ViewMediatorCallback mViewMediatorCallback;
64     private final CarSystemBarController mCarSystemBarController;
65     private final Factory mKeyguardBouncerFactory;
66     // Needed to instantiate mBouncer.
67     private final KeyguardBouncer.BouncerExpansionCallback mExpansionCallback =
68             new KeyguardBouncer.BouncerExpansionCallback() {
69                 @Override
70                 public void onFullyShown() {
71                 }
72 
73                 @Override
74                 public void onStartingToHide() {
75                 }
76 
77                 @Override
78                 public void onStartingToShow() {
79                 }
80 
81                 @Override
82                 public void onFullyHidden() {
83                 }
84             };
85 
86     private KeyguardBouncer mBouncer;
87     private OnKeyguardCancelClickedListener mKeyguardCancelClickedListener;
88     private boolean mShowing;
89     private boolean mIsOccluded;
90 
91     @Inject
CarKeyguardViewController( @ain DelayableExecutor mainExecutor, OverlayViewGlobalStateController overlayViewGlobalStateController, KeyguardStateController keyguardStateController, KeyguardUpdateMonitor keyguardUpdateMonitor, Lazy<BiometricUnlockController> biometricUnlockControllerLazy, ViewMediatorCallback viewMediatorCallback, CarSystemBarController carSystemBarController, KeyguardBouncer.Factory keyguardBouncerFactory)92     public CarKeyguardViewController(
93             @Main DelayableExecutor mainExecutor,
94             OverlayViewGlobalStateController overlayViewGlobalStateController,
95             KeyguardStateController keyguardStateController,
96             KeyguardUpdateMonitor keyguardUpdateMonitor,
97             Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
98             ViewMediatorCallback viewMediatorCallback,
99             CarSystemBarController carSystemBarController,
100             KeyguardBouncer.Factory keyguardBouncerFactory) {
101 
102         super(R.id.keyguard_stub, overlayViewGlobalStateController);
103 
104         mMainExecutor = mainExecutor;
105         mKeyguardStateController = keyguardStateController;
106         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
107         mBiometricUnlockControllerLazy = biometricUnlockControllerLazy;
108         mViewMediatorCallback = viewMediatorCallback;
109         mCarSystemBarController = carSystemBarController;
110         mKeyguardBouncerFactory = keyguardBouncerFactory;
111     }
112 
113     @Override
getFocusAreaViewId()114     protected int getFocusAreaViewId() {
115         return R.id.keyguard_container;
116     }
117 
118     @Override
shouldShowNavigationBarInsets()119     protected boolean shouldShowNavigationBarInsets() {
120         return true;
121     }
122 
123     @Override
onFinishInflate()124     public void onFinishInflate() {
125         mBouncer = mKeyguardBouncerFactory
126                 .create(getLayout().findViewById(R.id.keyguard_container), mExpansionCallback);
127         mBiometricUnlockControllerLazy.get().setKeyguardViewController(this);
128     }
129 
130     @Override
notifyKeyguardAuthenticated(boolean strongAuth)131     public void notifyKeyguardAuthenticated(boolean strongAuth) {
132         if (mBouncer != null) {
133             mBouncer.notifyKeyguardAuthenticated(strongAuth);
134         }
135     }
136 
137     @Override
showBouncer(boolean scrimmed)138     public void showBouncer(boolean scrimmed) {
139         if (mShowing && !mBouncer.isShowing()) {
140             mBouncer.show(/* resetSecuritySelection= */ false);
141         }
142     }
143 
144     @Override
show(Bundle options)145     public void show(Bundle options) {
146         if (mShowing) return;
147 
148         mShowing = true;
149         mKeyguardStateController.notifyKeyguardState(mShowing, /* occluded= */ false);
150         mCarSystemBarController.showAllKeyguardButtons(/* isSetUp= */ true);
151         start();
152         reset(/* hideBouncerWhenShowing= */ false);
153         notifyKeyguardUpdateMonitor();
154     }
155 
156     @Override
hide(long startTime, long fadeoutDuration)157     public void hide(long startTime, long fadeoutDuration) {
158         if (!mShowing) return;
159 
160         mViewMediatorCallback.readyForKeyguardDone();
161         mShowing = false;
162         mKeyguardStateController.notifyKeyguardState(mShowing, /* occluded= */ false);
163         mBouncer.hide(/* destroyView= */ true);
164         mCarSystemBarController.showAllNavigationButtons(/* isSetUp= */ true);
165         stop();
166         mKeyguardStateController.notifyKeyguardDoneFading();
167         mMainExecutor.execute(mViewMediatorCallback::keyguardGone);
168         notifyKeyguardUpdateMonitor();
169     }
170 
171     @Override
reset(boolean hideBouncerWhenShowing)172     public void reset(boolean hideBouncerWhenShowing) {
173         mMainExecutor.execute(() -> {
174             if (mShowing) {
175                 if (mBouncer != null) {
176                     if (!mBouncer.isSecure()) {
177                         dismissAndCollapse();
178                     }
179                     resetBouncer();
180                 }
181                 mKeyguardUpdateMonitor.sendKeyguardReset();
182                 notifyKeyguardUpdateMonitor();
183             } else {
184                 // This is necessary in order to address an inconsistency between the keyguard
185                 // service and the keyguard views.
186                 // TODO: Investigate the source of the inconsistency.
187                 show(/* options= */ null);
188             }
189         });
190     }
191 
192     @Override
onFinishedGoingToSleep()193     public void onFinishedGoingToSleep() {
194         if (mBouncer != null) {
195             mBouncer.onScreenTurnedOff();
196         }
197     }
198 
199     @Override
setOccluded(boolean occluded, boolean animate)200     public void setOccluded(boolean occluded, boolean animate) {
201         mIsOccluded = occluded;
202         getOverlayViewGlobalStateController().setOccluded(occluded);
203         if (occluded) {
204             mCarSystemBarController.showAllOcclusionButtons(/* isSetup= */ true);
205         } else {
206             if (mShowing && mBouncer.isSecure()) {
207                 mCarSystemBarController.showAllKeyguardButtons(/* isSetup= */ true);
208             } else {
209                 mCarSystemBarController.showAllNavigationButtons(/* isSetUp= */ true);
210             }
211         }
212     }
213 
214     @Override
onCancelClicked()215     public void onCancelClicked() {
216         if (mBouncer == null) return;
217 
218         getOverlayViewGlobalStateController().setWindowNeedsInput(/* needsInput= */ false);
219 
220         mBouncer.hide(/* destroyView= */ true);
221         mKeyguardCancelClickedListener.onCancelClicked();
222     }
223 
224     @Override
isShowing()225     public boolean isShowing() {
226         return mShowing;
227     }
228 
229     @Override
dismissAndCollapse()230     public void dismissAndCollapse() {
231         // If dismissing and collapsing Keyguard is requested (e.g. by a Keyguard-dismissing
232         // Activity) while Keyguard is occluded, unocclude Keyguard so the user can authenticate to
233         // dismiss Keyguard.
234         if (mIsOccluded) {
235             setOccluded(/* occluded= */ false, /* animate= */ false);
236         }
237         if (mBouncer != null && !mBouncer.isSecure()) {
238             hide(/* startTime= */ 0, /* fadeoutDuration= */ 0);
239         }
240     }
241 
242     @Override
startPreHideAnimation(Runnable finishRunnable)243     public void startPreHideAnimation(Runnable finishRunnable) {
244         if (mBouncer == null) return;
245 
246         mBouncer.startPreHideAnimation(finishRunnable);
247     }
248 
249     @Override
setNeedsInput(boolean needsInput)250     public void setNeedsInput(boolean needsInput) {
251         getOverlayViewGlobalStateController().setWindowNeedsInput(needsInput);
252     }
253 
254     /**
255      * Add listener for keyguard cancel clicked.
256      */
registerOnKeyguardCancelClickedListener( OnKeyguardCancelClickedListener keyguardCancelClickedListener)257     public void registerOnKeyguardCancelClickedListener(
258             OnKeyguardCancelClickedListener keyguardCancelClickedListener) {
259         mKeyguardCancelClickedListener = keyguardCancelClickedListener;
260     }
261 
262     /**
263      * Remove listener for keyguard cancel clicked.
264      */
unregisterOnKeyguardCancelClickedListener( OnKeyguardCancelClickedListener keyguardCancelClickedListener)265     public void unregisterOnKeyguardCancelClickedListener(
266             OnKeyguardCancelClickedListener keyguardCancelClickedListener) {
267         mKeyguardCancelClickedListener = null;
268     }
269 
270     @Override
getViewRootImpl()271     public ViewRootImpl getViewRootImpl() {
272         return ((View) getLayout().getParent()).getViewRootImpl();
273     }
274 
275     @Override
isBouncerShowing()276     public boolean isBouncerShowing() {
277         return mBouncer != null && mBouncer.isShowing();
278     }
279 
280     @Override
bouncerIsOrWillBeShowing()281     public boolean bouncerIsOrWillBeShowing() {
282         return mBouncer != null && (mBouncer.isShowing() || mBouncer.inTransit());
283     }
284 
285     @Override
keyguardGoingAway()286     public void keyguardGoingAway() {
287         // no-op
288     }
289 
290     @Override
setKeyguardGoingAwayState(boolean isKeyguardGoingAway)291     public void setKeyguardGoingAwayState(boolean isKeyguardGoingAway) {
292         // no-op
293     }
294 
295     @Override
onStartedGoingToSleep()296     public void onStartedGoingToSleep() {
297         // no-op
298     }
299 
300     @Override
onStartedWakingUp()301     public void onStartedWakingUp() {
302         // no-op
303     }
304 
305     @Override
onScreenTurningOn()306     public void onScreenTurningOn() {
307         // no-op
308     }
309 
310     @Override
onScreenTurnedOn()311     public void onScreenTurnedOn() {
312         // no-op
313     }
314 
315     @Override
shouldDisableWindowAnimationsForUnlock()316     public boolean shouldDisableWindowAnimationsForUnlock() {
317         return false;
318     }
319 
320     @Override
isGoingToNotificationShade()321     public boolean isGoingToNotificationShade() {
322         return false;
323     }
324 
325     @Override
isUnlockWithWallpaper()326     public boolean isUnlockWithWallpaper() {
327         return false;
328     }
329 
330     @Override
shouldSubtleWindowAnimationsForUnlock()331     public boolean shouldSubtleWindowAnimationsForUnlock() {
332         return false;
333     }
334 
335     @Override
blockPanelExpansionFromCurrentTouch()336     public void blockPanelExpansionFromCurrentTouch() {
337         // no-op
338     }
339 
340     @Override
registerStatusBar(StatusBar statusBar, ViewGroup container, NotificationPanelViewController notificationPanelViewController, BiometricUnlockController biometricUnlockController, View notificationContainer, KeyguardBypassController bypassController)341     public void registerStatusBar(StatusBar statusBar, ViewGroup container,
342             NotificationPanelViewController notificationPanelViewController,
343             BiometricUnlockController biometricUnlockController,
344             View notificationContainer, KeyguardBypassController bypassController) {
345         // no-op
346     }
347 
348     /**
349      * Hides Keyguard so that the transitioning Bouncer can be hidden until it is prepared. To be
350      * called by {@link com.android.systemui.car.userswitcher.FullscreenUserSwitcherViewMediator}
351      * when a new user is selected.
352      */
hideKeyguardToPrepareBouncer()353     public void hideKeyguardToPrepareBouncer() {
354         getLayout().setVisibility(View.INVISIBLE);
355     }
356 
357     @VisibleForTesting
setKeyguardBouncer(KeyguardBouncer keyguardBouncer)358     void setKeyguardBouncer(KeyguardBouncer keyguardBouncer) {
359         mBouncer = keyguardBouncer;
360     }
361 
revealKeyguardIfBouncerPrepared()362     private void revealKeyguardIfBouncerPrepared() {
363         int reattemptDelayMillis = 50;
364         Runnable revealKeyguard = () -> {
365             if (mBouncer == null) {
366                 if (DEBUG) {
367                     Log.d(TAG, "revealKeyguardIfBouncerPrepared: revealKeyguard request is ignored "
368                             + "since the Bouncer has not been initialized yet.");
369                 }
370                 return;
371             }
372             if (!mBouncer.inTransit() || !mBouncer.isSecure()) {
373                 showInternal();
374             } else {
375                 if (DEBUG) {
376                     Log.d(TAG, "revealKeyguardIfBouncerPrepared: Bouncer is not prepared "
377                             + "yet so reattempting after " + reattemptDelayMillis + "ms.");
378                 }
379                 mMainExecutor.executeDelayed(this::revealKeyguardIfBouncerPrepared,
380                         reattemptDelayMillis);
381             }
382         };
383         mMainExecutor.execute(revealKeyguard);
384     }
385 
notifyKeyguardUpdateMonitor()386     private void notifyKeyguardUpdateMonitor() {
387         mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(mShowing);
388         if (mBouncer != null) {
389             mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(isBouncerShowing());
390         }
391     }
392 
resetBouncer()393     private void resetBouncer() {
394         mMainExecutor.execute(() -> {
395             hideInternal();
396             mBouncer.hide(/* destroyView= */ false);
397             mBouncer.show(/* resetSecuritySelection= */ true);
398             revealKeyguardIfBouncerPrepared();
399         });
400     }
401 
402     /**
403      * Defines a callback for keyguard cancel button clicked listeners.
404      */
405     public interface OnKeyguardCancelClickedListener {
406         /**
407          * Called when keyguard cancel button is clicked.
408          */
onCancelClicked()409         void onCancelClicked();
410     }
411 }
412