1 /*
2  * Copyright (C) 2014 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.statusbar.policy;
18 
19 import static android.hardware.biometrics.BiometricSourceType.FACE;
20 
21 import static com.android.systemui.flags.Flags.LOCKSCREEN_ENABLE_LANDSCAPE;
22 
23 import android.annotation.NonNull;
24 import android.content.BroadcastReceiver;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.content.IntentFilter;
28 import android.hardware.biometrics.BiometricSourceType;
29 import android.os.Build;
30 import android.os.SystemProperties;
31 import android.os.Trace;
32 
33 import androidx.annotation.VisibleForTesting;
34 
35 import com.android.internal.widget.LockPatternUtils;
36 import com.android.keyguard.KeyguardUpdateMonitor;
37 import com.android.keyguard.KeyguardUpdateMonitorCallback;
38 import com.android.keyguard.logging.KeyguardUpdateMonitorLogger;
39 import com.android.systemui.Dumpable;
40 import com.android.systemui.R;
41 import com.android.systemui.dagger.SysUISingleton;
42 import com.android.systemui.dump.DumpManager;
43 import com.android.systemui.flags.FeatureFlags;
44 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
45 
46 import dagger.Lazy;
47 
48 import java.io.PrintWriter;
49 import java.util.ArrayList;
50 import java.util.Objects;
51 
52 import javax.inject.Inject;
53 
54 /**
55  *
56  */
57 @SysUISingleton
58 public class KeyguardStateControllerImpl implements KeyguardStateController, Dumpable {
59 
60     private static final boolean DEBUG_AUTH_WITH_ADB = false;
61     private static final String AUTH_BROADCAST_KEY = "debug_trigger_auth";
62 
63     private final ArrayList<Callback> mCallbacks = new ArrayList<>();
64     private final Context mContext;
65     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
66     private final LockPatternUtils mLockPatternUtils;
67     private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
68             new UpdateMonitorCallback();
69     private final Lazy<KeyguardUnlockAnimationController> mUnlockAnimationControllerLazy;
70     private final KeyguardUpdateMonitorLogger mLogger;
71 
72     private boolean mCanDismissLockScreen;
73     private boolean mShowing;
74     private boolean mPrimaryBouncerShowing;
75     private boolean mSecure;
76     private boolean mOccluded;
77 
78     private boolean mKeyguardFadingAway;
79     private long mKeyguardFadingAwayDelay;
80     private long mKeyguardFadingAwayDuration;
81     private boolean mKeyguardGoingAway;
82     private boolean mLaunchTransitionFadingAway;
83     private boolean mTrustManaged;
84     private boolean mTrusted;
85     private boolean mDebugUnlocked = false;
86     private boolean mFaceAuthEnabled;
87 
88     private float mDismissAmount = 0f;
89     private boolean mDismissingFromTouch = false;
90 
91     /**
92      * Whether the panel is currently flinging to a collapsed state, which means we're dismissing
93      * the keyguard.
94      */
95     private boolean mFlingingToDismissKeyguard = false;
96 
97     /**
98      * Whether the panel is currently flinging to a collapsed state, which means we're dismissing
99      * the keyguard, and the fling started during a swipe gesture. This means that we need to take
100      * over the gesture and animate the rest of the way dismissed.
101      */
102     private boolean mFlingingToDismissKeyguardDuringSwipeGesture = false;
103 
104     /**
105      * Whether the panel is currently flinging to an expanded state, which means we cancelled the
106      * dismiss gesture and are snapping back to the keyguard state.
107      */
108     private boolean mSnappingKeyguardBackAfterSwipe = false;
109 
110     private FeatureFlags mFeatureFlags;
111 
112     /**
113      *
114      */
115     @Inject
KeyguardStateControllerImpl( Context context, KeyguardUpdateMonitor keyguardUpdateMonitor, LockPatternUtils lockPatternUtils, Lazy<KeyguardUnlockAnimationController> keyguardUnlockAnimationController, KeyguardUpdateMonitorLogger logger, DumpManager dumpManager, FeatureFlags featureFlags)116     public KeyguardStateControllerImpl(
117             Context context,
118             KeyguardUpdateMonitor keyguardUpdateMonitor,
119             LockPatternUtils lockPatternUtils,
120             Lazy<KeyguardUnlockAnimationController> keyguardUnlockAnimationController,
121             KeyguardUpdateMonitorLogger logger,
122             DumpManager dumpManager,
123             FeatureFlags featureFlags) {
124         mContext = context;
125         mLogger = logger;
126         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
127         mLockPatternUtils = lockPatternUtils;
128         mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
129         mUnlockAnimationControllerLazy = keyguardUnlockAnimationController;
130         mFeatureFlags = featureFlags;
131 
132         dumpManager.registerDumpable(getClass().getSimpleName(), this);
133 
134         update(true /* updateAlways */);
135         if (Build.IS_DEBUGGABLE && DEBUG_AUTH_WITH_ADB) {
136             // Watch for interesting updates
137             final IntentFilter filter = new IntentFilter();
138             filter.addAction(AUTH_BROADCAST_KEY);
139             context.registerReceiver(new BroadcastReceiver() {
140                 @Override
141                 public void onReceive(Context context, Intent intent) {
142                     if (DEBUG_AUTH_WITH_ADB && AUTH_BROADCAST_KEY.equals(intent.getAction())) {
143                         mDebugUnlocked = !mDebugUnlocked;
144                         update(true /* updateAlways */);
145                     }
146                 }
147             }, filter, null, null, Context.RECEIVER_EXPORTED_UNAUDITED);
148         }
149     }
150 
151     @Override
addCallback(@onNull Callback callback)152     public void addCallback(@NonNull Callback callback) {
153         Objects.requireNonNull(callback, "Callback must not be null. b/128895449");
154         if (!mCallbacks.contains(callback)) {
155             mCallbacks.add(callback);
156         }
157     }
158 
159     @Override
removeCallback(@onNull Callback callback)160     public void removeCallback(@NonNull Callback callback) {
161         Objects.requireNonNull(callback, "Callback must not be null. b/128895449");
162         mCallbacks.remove(callback);
163     }
164 
165     @Override
isShowing()166     public boolean isShowing() {
167         return mShowing;
168     }
169 
170     @Override
isPrimaryBouncerShowing()171     public boolean isPrimaryBouncerShowing() {
172         return mPrimaryBouncerShowing;
173     }
174 
175     @Override
isMethodSecure()176     public boolean isMethodSecure() {
177         return mSecure;
178     }
179 
180     @Override
isOccluded()181     public boolean isOccluded() {
182         return mOccluded;
183     }
184 
185     @Override
isTrusted()186     public boolean isTrusted() {
187         return mTrusted;
188     }
189 
190     @Override
notifyKeyguardState(boolean showing, boolean occluded)191     public void notifyKeyguardState(boolean showing, boolean occluded) {
192         if (mShowing == showing && mOccluded == occluded) return;
193         mShowing = showing;
194         mOccluded = occluded;
195         mKeyguardUpdateMonitor.setKeyguardShowing(showing, occluded);
196         Trace.instantForTrack(Trace.TRACE_TAG_APP, "UI Events",
197                 "Keyguard showing: " + showing + " occluded: " + occluded);
198         notifyKeyguardChanged();
199 
200         // Update the dismiss amount to the full 0f/1f if we explicitly show or hide the keyguard.
201         // Otherwise, the dismiss amount could be left at a random value if we show/hide during a
202         // dismiss gesture, canceling the gesture.
203         notifyKeyguardDismissAmountChanged(showing ? 0f : 1f, false);
204     }
205 
notifyKeyguardChanged()206     private void notifyKeyguardChanged() {
207         Trace.beginSection("KeyguardStateController#notifyKeyguardChanged");
208         // Copy the list to allow removal during callback.
209         new ArrayList<>(mCallbacks).forEach(Callback::onKeyguardShowingChanged);
210         Trace.endSection();
211     }
212 
notifyKeyguardFaceAuthEnabledChanged()213     private void notifyKeyguardFaceAuthEnabledChanged() {
214         // Copy the list to allow removal during callback.
215         new ArrayList<>(mCallbacks).forEach(Callback::onFaceAuthEnabledChanged);
216     }
217 
notifyUnlockedChanged()218     private void notifyUnlockedChanged() {
219         Trace.beginSection("KeyguardStateController#notifyUnlockedChanged");
220         // Copy the list to allow removal during callback.
221         new ArrayList<>(mCallbacks).forEach(Callback::onUnlockedChanged);
222         Trace.endSection();
223     }
224 
225     @Override
notifyKeyguardFadingAway(long delay, long fadeoutDuration)226     public void notifyKeyguardFadingAway(long delay, long fadeoutDuration) {
227         mKeyguardFadingAwayDelay = delay;
228         mKeyguardFadingAwayDuration = fadeoutDuration;
229         setKeyguardFadingAway(true);
230     }
231 
setKeyguardFadingAway(boolean keyguardFadingAway)232     private void setKeyguardFadingAway(boolean keyguardFadingAway) {
233         if (mKeyguardFadingAway != keyguardFadingAway) {
234             Trace.traceCounter(Trace.TRACE_TAG_APP, "keyguardFadingAway",
235                     keyguardFadingAway ? 1 : 0);
236             mKeyguardFadingAway = keyguardFadingAway;
237             ArrayList<Callback> callbacks = new ArrayList<>(mCallbacks);
238             for (int i = 0; i < callbacks.size(); i++) {
239                 callbacks.get(i).onKeyguardFadingAwayChanged();
240             }
241         }
242     }
243 
244     @Override
notifyKeyguardDoneFading()245     public void notifyKeyguardDoneFading() {
246         notifyKeyguardGoingAway(false);
247         setKeyguardFadingAway(false);
248     }
249 
250     @VisibleForTesting
update(boolean updateAlways)251     void update(boolean updateAlways) {
252         Trace.beginSection("KeyguardStateController#update");
253         int user = KeyguardUpdateMonitor.getCurrentUser();
254         boolean secure = mLockPatternUtils.isSecure(user);
255         boolean canDismissLockScreen = !secure || mKeyguardUpdateMonitor.getUserCanSkipBouncer(user)
256                 || (Build.IS_DEBUGGABLE && DEBUG_AUTH_WITH_ADB && mDebugUnlocked);
257         boolean trustManaged = mKeyguardUpdateMonitor.getUserTrustIsManaged(user);
258         boolean trusted = mKeyguardUpdateMonitor.getUserHasTrust(user);
259         boolean faceAuthEnabled = mKeyguardUpdateMonitor.isFaceAuthEnabledForUser(user);
260         boolean changed = secure != mSecure || canDismissLockScreen != mCanDismissLockScreen
261                 || trustManaged != mTrustManaged || mTrusted != trusted
262                 || mFaceAuthEnabled != faceAuthEnabled;
263         if (changed || updateAlways) {
264             mSecure = secure;
265             mCanDismissLockScreen = canDismissLockScreen;
266             mTrusted = trusted;
267             mTrustManaged = trustManaged;
268             mFaceAuthEnabled = faceAuthEnabled;
269             mLogger.logKeyguardStateUpdate(
270                     mSecure, mCanDismissLockScreen, mTrusted, mTrustManaged);
271             notifyUnlockedChanged();
272         }
273         Trace.endSection();
274     }
275 
276     @Override
canDismissLockScreen()277     public boolean canDismissLockScreen() {
278         return mCanDismissLockScreen;
279     }
280 
281     @Override
isKeyguardScreenRotationAllowed()282     public boolean isKeyguardScreenRotationAllowed() {
283         return SystemProperties.getBoolean("lockscreen.rot_override", false)
284                 || mContext.getResources().getBoolean(R.bool.config_enableLockScreenRotation)
285                 || mFeatureFlags.isEnabled(LOCKSCREEN_ENABLE_LANDSCAPE);
286     }
287 
288     @Override
isFaceAuthEnabled()289     public boolean isFaceAuthEnabled() {
290         return mFaceAuthEnabled;
291     }
292 
293     @Override
isKeyguardFadingAway()294     public boolean isKeyguardFadingAway() {
295         return mKeyguardFadingAway;
296     }
297 
298     @Override
isKeyguardGoingAway()299     public boolean isKeyguardGoingAway() {
300         return mKeyguardGoingAway;
301     }
302 
303     @Override
isAnimatingBetweenKeyguardAndSurfaceBehind()304     public boolean isAnimatingBetweenKeyguardAndSurfaceBehind() {
305         return mUnlockAnimationControllerLazy.get().isAnimatingBetweenKeyguardAndSurfaceBehind();
306     }
307 
308     @Override
getKeyguardFadingAwayDelay()309     public long getKeyguardFadingAwayDelay() {
310         return mKeyguardFadingAwayDelay;
311     }
312 
313     @Override
getKeyguardFadingAwayDuration()314     public long getKeyguardFadingAwayDuration() {
315         return mKeyguardFadingAwayDuration;
316     }
317 
318     @Override
calculateGoingToFullShadeDelay()319     public long calculateGoingToFullShadeDelay() {
320         return mKeyguardFadingAwayDelay + mKeyguardFadingAwayDuration;
321     }
322 
323     @Override
isFlingingToDismissKeyguard()324     public boolean isFlingingToDismissKeyguard() {
325         return mFlingingToDismissKeyguard;
326     }
327 
328     @Override
isFlingingToDismissKeyguardDuringSwipeGesture()329     public boolean isFlingingToDismissKeyguardDuringSwipeGesture() {
330         return mFlingingToDismissKeyguardDuringSwipeGesture;
331     }
332 
333     @Override
isSnappingKeyguardBackAfterSwipe()334     public boolean isSnappingKeyguardBackAfterSwipe() {
335         return mSnappingKeyguardBackAfterSwipe;
336     }
337 
338     @Override
getDismissAmount()339     public float getDismissAmount() {
340         return mDismissAmount;
341     }
342 
343     @Override
isDismissingFromSwipe()344     public boolean isDismissingFromSwipe() {
345         return mDismissingFromTouch;
346     }
347 
348     @Override
notifyKeyguardGoingAway(boolean keyguardGoingAway)349     public void notifyKeyguardGoingAway(boolean keyguardGoingAway) {
350         if (mKeyguardGoingAway != keyguardGoingAway) {
351             Trace.traceCounter(Trace.TRACE_TAG_APP, "keyguardGoingAway",
352                     keyguardGoingAway ? 1 : 0);
353             mKeyguardGoingAway = keyguardGoingAway;
354             new ArrayList<>(mCallbacks).forEach(Callback::onKeyguardGoingAwayChanged);
355         }
356     }
357 
358     @Override
notifyPrimaryBouncerShowing(boolean showing)359     public void notifyPrimaryBouncerShowing(boolean showing) {
360         if (mPrimaryBouncerShowing != showing) {
361             mPrimaryBouncerShowing = showing;
362 
363             new ArrayList<>(mCallbacks).forEach(Callback::onPrimaryBouncerShowingChanged);
364         }
365     }
366 
367     @Override
notifyPanelFlingEnd()368     public void notifyPanelFlingEnd() {
369         mFlingingToDismissKeyguard = false;
370         mFlingingToDismissKeyguardDuringSwipeGesture = false;
371         mSnappingKeyguardBackAfterSwipe = false;
372     }
373 
374     @Override
notifyPanelFlingStart(boolean flingToDismiss)375     public void notifyPanelFlingStart(boolean flingToDismiss) {
376         mFlingingToDismissKeyguard = flingToDismiss;
377         mFlingingToDismissKeyguardDuringSwipeGesture =
378                 flingToDismiss && mDismissingFromTouch;
379         mSnappingKeyguardBackAfterSwipe = !flingToDismiss;
380     }
381 
382     @Override
notifyKeyguardDismissAmountChanged(float dismissAmount, boolean dismissingFromTouch)383     public void notifyKeyguardDismissAmountChanged(float dismissAmount,
384             boolean dismissingFromTouch) {
385         mDismissAmount = dismissAmount;
386         mDismissingFromTouch = dismissingFromTouch;
387         new ArrayList<>(mCallbacks).forEach(Callback::onKeyguardDismissAmountChanged);
388     }
389 
390     @Override
setLaunchTransitionFadingAway(boolean fadingAway)391     public void setLaunchTransitionFadingAway(boolean fadingAway) {
392         mLaunchTransitionFadingAway = fadingAway;
393         new ArrayList<>(mCallbacks).forEach(Callback::onLaunchTransitionFadingAwayChanged);
394     }
395 
396     @Override
isLaunchTransitionFadingAway()397     public boolean isLaunchTransitionFadingAway() {
398         return mLaunchTransitionFadingAway;
399     }
400 
401     /**
402      * Dumps internal state for debugging.
403      * @param pw Where to dump.
404      */
405     @Override
dump(PrintWriter pw, String[] args)406     public void dump(PrintWriter pw, String[] args) {
407         pw.println("KeyguardStateController:");
408         pw.println("  mShowing: " + mShowing);
409         pw.println("  mOccluded: " + mOccluded);
410         pw.println("  mSecure: " + mSecure);
411         pw.println("  mCanDismissLockScreen: " + mCanDismissLockScreen);
412         pw.println("  mTrustManaged: " + mTrustManaged);
413         pw.println("  mTrusted: " + mTrusted);
414         pw.println("  mDebugUnlocked: " + mDebugUnlocked);
415         pw.println("  mFaceAuthEnabled: " + mFaceAuthEnabled);
416         pw.println("  isKeyguardFadingAway: " + isKeyguardFadingAway());
417         pw.println("  isKeyguardGoingAway: " + isKeyguardGoingAway());
418         pw.println("  isLaunchTransitionFadingAway: " + isLaunchTransitionFadingAway());
419     }
420 
421     private class UpdateMonitorCallback extends KeyguardUpdateMonitorCallback {
422         @Override
onUserSwitchComplete(int userId)423         public void onUserSwitchComplete(int userId) {
424             update(false /* updateAlways */);
425         }
426 
427         @Override
onTrustChanged(int userId)428         public void onTrustChanged(int userId) {
429             update(false /* updateAlways */);
430             notifyKeyguardChanged();
431         }
432 
433         @Override
onTrustManagedChanged(int userId)434         public void onTrustManagedChanged(int userId) {
435             update(false /* updateAlways */);
436         }
437 
438         @Override
onBiometricEnrollmentStateChanged(BiometricSourceType biometricSourceType)439         public void onBiometricEnrollmentStateChanged(BiometricSourceType biometricSourceType) {
440             if (biometricSourceType == FACE) {
441                 // We only care about enrollment state here. Keyguard face auth enabled is just
442                 // same as face auth enrolled
443                 update(false);
444                 notifyKeyguardFaceAuthEnabledChanged();
445             }
446         }
447 
448         @Override
onStartedWakingUp()449         public void onStartedWakingUp() {
450             update(false /* updateAlways */);
451         }
452 
453         @Override
onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType, boolean isStrongBiometric)454         public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType,
455                 boolean isStrongBiometric) {
456             Trace.beginSection("KeyguardUpdateMonitorCallback#onBiometricAuthenticated");
457             if (mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(isStrongBiometric)) {
458                 update(false /* updateAlways */);
459             }
460             Trace.endSection();
461         }
462 
463         @Override
onStrongAuthStateChanged(int userId)464         public void onStrongAuthStateChanged(int userId) {
465             update(false /* updateAlways */);
466         }
467 
468         @Override
onLockedOutStateChanged(BiometricSourceType biometricSourceType)469         public void onLockedOutStateChanged(BiometricSourceType biometricSourceType) {
470             update(false /* updateAlways */);
471         }
472 
473         @Override
onKeyguardVisibilityChanged(boolean visible)474         public void onKeyguardVisibilityChanged(boolean visible) {
475             update(false /* updateAlways */);
476         }
477 
478         @Override
onBiometricsCleared()479         public void onBiometricsCleared() {
480             update(false /* alwaysUpdate */);
481         }
482 
483         @Override
onEnabledTrustAgentsChanged(int userId)484         public void onEnabledTrustAgentsChanged(int userId) {
485             update(false /* updateAlways */);
486         }
487     }
488 }
489