blob: f4d08e01d5c3233655842ccfc870d7417503a334 [file] [log] [blame]
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.statusbar.policy;
import android.annotation.NonNull;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.biometrics.BiometricSourceType;
import android.os.Build;
import android.os.SystemProperties;
import android.os.Trace;
import androidx.annotation.VisibleForTesting;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.logging.KeyguardUpdateMonitorLogger;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Objects;
import javax.inject.Inject;
import dagger.Lazy;
/**
*/
@SysUISingleton
public class KeyguardStateControllerImpl implements KeyguardStateController, Dumpable {
private static final boolean DEBUG_AUTH_WITH_ADB = false;
private static final String AUTH_BROADCAST_KEY = "debug_trigger_auth";
private final ArrayList<Callback> mCallbacks = new ArrayList<>();
private final Context mContext;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final LockPatternUtils mLockPatternUtils;
private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
new UpdateMonitorCallback();
private final Lazy<KeyguardUnlockAnimationController> mUnlockAnimationControllerLazy;
private final KeyguardUpdateMonitorLogger mLogger;
private boolean mCanDismissLockScreen;
private boolean mShowing;
private boolean mBouncerShowing;
private boolean mSecure;
private boolean mOccluded;
private boolean mKeyguardFadingAway;
private long mKeyguardFadingAwayDelay;
private long mKeyguardFadingAwayDuration;
private boolean mKeyguardGoingAway;
private boolean mLaunchTransitionFadingAway;
private boolean mTrustManaged;
private boolean mTrusted;
private boolean mDebugUnlocked = false;
private boolean mFaceAuthEnabled;
private float mDismissAmount = 0f;
private boolean mDismissingFromTouch = false;
/**
* Whether the panel is currently flinging to a collapsed state, which means we're dismissing
* the keyguard.
*/
private boolean mFlingingToDismissKeyguard = false;
/**
* Whether the panel is currently flinging to a collapsed state, which means we're dismissing
* the keyguard, and the fling started during a swipe gesture. This means that we need to take
* over the gesture and animate the rest of the way dismissed.
*/
private boolean mFlingingToDismissKeyguardDuringSwipeGesture = false;
/**
* Whether the panel is currently flinging to an expanded state, which means we cancelled the
* dismiss gesture and are snapping back to the keyguard state.
*/
private boolean mSnappingKeyguardBackAfterSwipe = false;
/**
*/
@Inject
public KeyguardStateControllerImpl(
Context context,
KeyguardUpdateMonitor keyguardUpdateMonitor,
LockPatternUtils lockPatternUtils,
Lazy<KeyguardUnlockAnimationController> keyguardUnlockAnimationController,
KeyguardUpdateMonitorLogger logger,
DumpManager dumpManager) {
mContext = context;
mLogger = logger;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mLockPatternUtils = lockPatternUtils;
mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
mUnlockAnimationControllerLazy = keyguardUnlockAnimationController;
dumpManager.registerDumpable(getClass().getSimpleName(), this);
update(true /* updateAlways */);
if (Build.IS_DEBUGGABLE && DEBUG_AUTH_WITH_ADB) {
// Watch for interesting updates
final IntentFilter filter = new IntentFilter();
filter.addAction(AUTH_BROADCAST_KEY);
context.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (DEBUG_AUTH_WITH_ADB && AUTH_BROADCAST_KEY.equals(intent.getAction())) {
mDebugUnlocked = !mDebugUnlocked;
update(true /* updateAlways */);
}
}
}, filter, null, null, Context.RECEIVER_EXPORTED_UNAUDITED);
}
}
@Override
public void addCallback(@NonNull Callback callback) {
Objects.requireNonNull(callback, "Callback must not be null. b/128895449");
if (!mCallbacks.contains(callback)) {
mCallbacks.add(callback);
}
}
@Override
public void removeCallback(@NonNull Callback callback) {
Objects.requireNonNull(callback, "Callback must not be null. b/128895449");
mCallbacks.remove(callback);
}
@Override
public boolean isShowing() {
return mShowing;
}
@Override
public boolean isBouncerShowing() {
return mBouncerShowing;
}
@Override
public boolean isMethodSecure() {
return mSecure;
}
@Override
public boolean isOccluded() {
return mOccluded;
}
@Override
public boolean isTrusted() {
return mTrusted;
}
@Override
public void notifyKeyguardState(boolean showing, boolean occluded) {
if (mShowing == showing && mOccluded == occluded) return;
mShowing = showing;
mOccluded = occluded;
Trace.instantForTrack(Trace.TRACE_TAG_APP, "UI Events",
"Keyguard showing: " + showing + " occluded: " + occluded);
notifyKeyguardChanged();
// Update the dismiss amount to the full 0f/1f if we explicitly show or hide the keyguard.
// Otherwise, the dismiss amount could be left at a random value if we show/hide during a
// dismiss gesture, canceling the gesture.
notifyKeyguardDismissAmountChanged(showing ? 0f : 1f, false);
}
private void notifyKeyguardChanged() {
Trace.beginSection("KeyguardStateController#notifyKeyguardChanged");
// Copy the list to allow removal during callback.
new ArrayList<>(mCallbacks).forEach(Callback::onKeyguardShowingChanged);
Trace.endSection();
}
private void notifyUnlockedChanged() {
Trace.beginSection("KeyguardStateController#notifyUnlockedChanged");
// Copy the list to allow removal during callback.
new ArrayList<>(mCallbacks).forEach(Callback::onUnlockedChanged);
Trace.endSection();
}
@Override
public void notifyKeyguardFadingAway(long delay, long fadeoutDuration) {
mKeyguardFadingAwayDelay = delay;
mKeyguardFadingAwayDuration = fadeoutDuration;
setKeyguardFadingAway(true);
}
private void setKeyguardFadingAway(boolean keyguardFadingAway) {
if (mKeyguardFadingAway != keyguardFadingAway) {
Trace.traceCounter(Trace.TRACE_TAG_APP, "keyguardFadingAway",
keyguardFadingAway ? 1 : 0);
mKeyguardFadingAway = keyguardFadingAway;
ArrayList<Callback> callbacks = new ArrayList<>(mCallbacks);
for (int i = 0; i < callbacks.size(); i++) {
callbacks.get(i).onKeyguardFadingAwayChanged();
}
}
}
@Override
public void notifyKeyguardDoneFading() {
notifyKeyguardGoingAway(false);
setKeyguardFadingAway(false);
}
@VisibleForTesting
void update(boolean updateAlways) {
Trace.beginSection("KeyguardStateController#update");
int user = KeyguardUpdateMonitor.getCurrentUser();
boolean secure = mLockPatternUtils.isSecure(user);
boolean canDismissLockScreen = !secure || mKeyguardUpdateMonitor.getUserCanSkipBouncer(user)
|| (Build.IS_DEBUGGABLE && DEBUG_AUTH_WITH_ADB && mDebugUnlocked);
boolean trustManaged = mKeyguardUpdateMonitor.getUserTrustIsManaged(user);
boolean trusted = mKeyguardUpdateMonitor.getUserHasTrust(user);
boolean faceAuthEnabled = mKeyguardUpdateMonitor.isFaceAuthEnabledForUser(user);
boolean changed = secure != mSecure || canDismissLockScreen != mCanDismissLockScreen
|| trustManaged != mTrustManaged || mTrusted != trusted
|| mFaceAuthEnabled != faceAuthEnabled;
if (changed || updateAlways) {
mSecure = secure;
mCanDismissLockScreen = canDismissLockScreen;
mTrusted = trusted;
mTrustManaged = trustManaged;
mFaceAuthEnabled = faceAuthEnabled;
mLogger.logKeyguardStateUpdate(
mSecure, mCanDismissLockScreen, mTrusted, mTrustManaged);
notifyUnlockedChanged();
}
Trace.endSection();
}
@Override
public boolean canDismissLockScreen() {
return mCanDismissLockScreen;
}
@Override
public boolean isKeyguardScreenRotationAllowed() {
return SystemProperties.getBoolean("lockscreen.rot_override", false)
|| mContext.getResources().getBoolean(R.bool.config_enableLockScreenRotation);
}
@Override
public boolean isFaceAuthEnabled() {
return mFaceAuthEnabled;
}
@Override
public boolean isKeyguardFadingAway() {
return mKeyguardFadingAway;
}
@Override
public boolean isKeyguardGoingAway() {
return mKeyguardGoingAway;
}
@Override
public boolean isAnimatingBetweenKeyguardAndSurfaceBehind() {
return mUnlockAnimationControllerLazy.get().isAnimatingBetweenKeyguardAndSurfaceBehind();
}
@Override
public long getKeyguardFadingAwayDelay() {
return mKeyguardFadingAwayDelay;
}
@Override
public long getKeyguardFadingAwayDuration() {
return mKeyguardFadingAwayDuration;
}
@Override
public long calculateGoingToFullShadeDelay() {
return mKeyguardFadingAwayDelay + mKeyguardFadingAwayDuration;
}
@Override
public boolean isFlingingToDismissKeyguard() {
return mFlingingToDismissKeyguard;
}
@Override
public boolean isFlingingToDismissKeyguardDuringSwipeGesture() {
return mFlingingToDismissKeyguardDuringSwipeGesture;
}
@Override
public boolean isSnappingKeyguardBackAfterSwipe() {
return mSnappingKeyguardBackAfterSwipe;
}
@Override
public float getDismissAmount() {
return mDismissAmount;
}
@Override
public boolean isDismissingFromSwipe() {
return mDismissingFromTouch;
}
@Override
public void notifyKeyguardGoingAway(boolean keyguardGoingAway) {
if (mKeyguardGoingAway != keyguardGoingAway) {
Trace.traceCounter(Trace.TRACE_TAG_APP, "keyguardGoingAway",
keyguardGoingAway ? 1 : 0);
mKeyguardGoingAway = keyguardGoingAway;
new ArrayList<>(mCallbacks).forEach(Callback::onKeyguardGoingAwayChanged);
}
}
@Override
public void notifyBouncerShowing(boolean showing) {
if (mBouncerShowing != showing) {
mBouncerShowing = showing;
new ArrayList<>(mCallbacks).forEach(Callback::onBouncerShowingChanged);
}
}
@Override
public void notifyPanelFlingEnd() {
mFlingingToDismissKeyguard = false;
mFlingingToDismissKeyguardDuringSwipeGesture = false;
mSnappingKeyguardBackAfterSwipe = false;
}
@Override
public void notifyPanelFlingStart(boolean flingToDismiss) {
mFlingingToDismissKeyguard = flingToDismiss;
mFlingingToDismissKeyguardDuringSwipeGesture =
flingToDismiss && mDismissingFromTouch;
mSnappingKeyguardBackAfterSwipe = !flingToDismiss;
}
@Override
public void notifyKeyguardDismissAmountChanged(float dismissAmount,
boolean dismissingFromTouch) {
mDismissAmount = dismissAmount;
mDismissingFromTouch = dismissingFromTouch;
new ArrayList<>(mCallbacks).forEach(Callback::onKeyguardDismissAmountChanged);
}
@Override
public void setLaunchTransitionFadingAway(boolean fadingAway) {
mLaunchTransitionFadingAway = fadingAway;
new ArrayList<>(mCallbacks).forEach(Callback::onLaunchTransitionFadingAwayChanged);
}
@Override
public boolean isLaunchTransitionFadingAway() {
return mLaunchTransitionFadingAway;
}
/**
* Dumps internal state for debugging.
* @param pw Where to dump.
*/
@Override
public void dump(PrintWriter pw, String[] args) {
pw.println("KeyguardStateController:");
pw.println(" mSecure: " + mSecure);
pw.println(" mCanDismissLockScreen: " + mCanDismissLockScreen);
pw.println(" mTrustManaged: " + mTrustManaged);
pw.println(" mTrusted: " + mTrusted);
pw.println(" mDebugUnlocked: " + mDebugUnlocked);
pw.println(" mFaceAuthEnabled: " + mFaceAuthEnabled);
pw.println(" isKeyguardFadingAway: " + isKeyguardFadingAway());
pw.println(" isKeyguardGoingAway: " + isKeyguardGoingAway());
}
private class UpdateMonitorCallback extends KeyguardUpdateMonitorCallback {
@Override
public void onUserSwitchComplete(int userId) {
update(false /* updateAlways */);
}
@Override
public void onTrustChanged(int userId) {
update(false /* updateAlways */);
notifyKeyguardChanged();
}
@Override
public void onTrustManagedChanged(int userId) {
update(false /* updateAlways */);
}
@Override
public void onStartedWakingUp() {
update(false /* updateAlways */);
}
@Override
public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType,
boolean isStrongBiometric) {
Trace.beginSection("KeyguardUpdateMonitorCallback#onBiometricAuthenticated");
if (mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(isStrongBiometric)) {
update(false /* updateAlways */);
}
Trace.endSection();
}
@Override
public void onStrongAuthStateChanged(int userId) {
update(false /* updateAlways */);
}
@Override
public void onKeyguardVisibilityChanged(boolean showing) {
update(false /* updateAlways */);
}
@Override
public void onBiometricsCleared() {
update(false /* alwaysUpdate */);
}
}
}