Merge "Remove KeyguardHostView" into tm-qpr-dev

This commit is contained in:
Aaron Liu
2023-02-08 16:34:15 +00:00
committed by Android (Google) Code Review
15 changed files with 641 additions and 1059 deletions

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- <!--
** **
** Copyright 2012, The Android Open Source Project ** Copyright 2023, The Android Open Source Project
** **
** Licensed under the Apache License, Version 2.0 (the "License") ** Licensed under the Apache License, Version 2.0 (the "License")
** you may not use this file except in compliance with the License. ** you may not use this file except in compliance with the License.
@@ -17,12 +17,10 @@
*/ */
--> -->
<!-- This is the host view that generally contains two sub views: the widget view <com.android.keyguard.KeyguardSecurityContainer
and the security view. -->
<com.android.keyguard.KeyguardHostView
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/res-auto" xmlns:androidprv="http://schemas.android.com/apk/res-auto"
android:id="@+id/keyguard_host_view" android:id="@+id/keyguard_security_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:clipChildren="false" android:clipChildren="false"
@@ -30,16 +28,6 @@
android:paddingTop="@dimen/keyguard_lock_padding" android:paddingTop="@dimen/keyguard_lock_padding"
android:importantForAccessibility="yes"> <!-- Needed because TYPE_WINDOW_STATE_CHANGED is sent android:importantForAccessibility="yes"> <!-- Needed because TYPE_WINDOW_STATE_CHANGED is sent
from this view when bouncer is shown --> from this view when bouncer is shown -->
<com.android.keyguard.KeyguardSecurityContainer
android:id="@+id/keyguard_security_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false"
android:padding="0dp"
android:fitsSystemWindows="true"
android:layout_gravity="center">
<com.android.keyguard.KeyguardSecurityViewFlipper <com.android.keyguard.KeyguardSecurityViewFlipper
android:id="@+id/view_flipper" android:id="@+id/view_flipper"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@@ -52,5 +40,3 @@
</com.android.keyguard.KeyguardSecurityViewFlipper> </com.android.keyguard.KeyguardSecurityViewFlipper>
</com.android.keyguard.KeyguardSecurityContainer> </com.android.keyguard.KeyguardSecurityContainer>
</com.android.keyguard.KeyguardHostView>

View File

@@ -1,78 +0,0 @@
/*
* Copyright (C) 2007 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.keyguard;
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.FrameLayout;
/**
* Base class for keyguard view. {@link #reset} is where you should
* reset the state of your view. Use the {@link KeyguardViewCallback} via
* {@link #getCallback()} to send information back (such as poking the wake lock,
* or finishing the keyguard).
*
* Handles intercepting of media keys that still work when the keyguard is
* showing.
*/
public class KeyguardHostView extends FrameLayout {
protected ViewMediatorCallback mViewMediatorCallback;
private boolean mIsInteractable;
public KeyguardHostView(Context context) {
this(context, null);
}
public KeyguardHostView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
if (mViewMediatorCallback != null) {
mViewMediatorCallback.keyguardDoneDrawing();
}
}
public void setViewMediatorCallback(ViewMediatorCallback viewMediatorCallback) {
mViewMediatorCallback = viewMediatorCallback;
}
/** Set true if the view can be interacted with */
public void setInteractable(boolean isInteractable) {
mIsInteractable = isInteractable;
}
/**
* Make sure to disallow touches while transitioning the bouncer, otherwise
* it can remain interactable even when barely visible.
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return !mIsInteractable;
}
/** True to consume any events that are sent to it */
@Override
public boolean onTouchEvent(MotionEvent ev) {
return true;
}
}

View File

@@ -1,535 +0,0 @@
/*
* Copyright (C) 2020 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.keyguard;
import android.app.ActivityManager;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.media.AudioManager;
import android.os.SystemClock;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.util.MathUtils;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnKeyListener;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
import android.window.OnBackAnimationCallback;
import androidx.annotation.NonNull;
import com.android.keyguard.KeyguardSecurityContainer.SecurityCallback;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.keyguard.dagger.KeyguardBouncerScope;
import com.android.settingslib.Utils;
import com.android.systemui.R;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.util.ViewController;
import java.io.File;
import javax.inject.Inject;
/** Controller for a {@link KeyguardHostView}. */
@KeyguardBouncerScope
public class KeyguardHostViewController extends ViewController<KeyguardHostView> {
private static final String TAG = "KeyguardViewBase";
public static final boolean DEBUG = KeyguardConstants.DEBUG;
// Whether the volume keys should be handled by keyguard. If true, then
// they will be handled here for specific media types such as music, otherwise
// the audio service will bring up the volume dialog.
private static final boolean KEYGUARD_MANAGES_VOLUME = false;
private static final String ENABLE_MENU_KEY_FILE = "/data/local/enable_menu_key";
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final KeyguardSecurityContainerController mKeyguardSecurityContainerController;
private final TelephonyManager mTelephonyManager;
private final ViewMediatorCallback mViewMediatorCallback;
private final AudioManager mAudioManager;
private ActivityStarter.OnDismissAction mDismissAction;
private Runnable mCancelAction;
private int mTranslationY;
private final KeyguardUpdateMonitorCallback mUpdateCallback =
new KeyguardUpdateMonitorCallback() {
@Override
public void onTrustGrantedForCurrentUser(
boolean dismissKeyguard,
boolean newlyUnlocked,
TrustGrantFlags flags,
String message
) {
if (dismissKeyguard) {
if (!mView.isVisibleToUser()) {
// The trust agent dismissed the keyguard without the user proving
// that they are present (by swiping up to show the bouncer). That's
// fine if the user proved presence via some other way to the trust
// agent.
Log.i(TAG, "TrustAgent dismissed Keyguard.");
}
mSecurityCallback.dismiss(
false /* authenticated */,
KeyguardUpdateMonitor.getCurrentUser(),
/* bypassSecondaryLockScreen */ false,
SecurityMode.Invalid
);
} else {
if (flags.isInitiatedByUser() || flags.dismissKeyguardRequested()) {
mViewMediatorCallback.playTrustedSound();
}
}
}
};
private final SecurityCallback mSecurityCallback = new SecurityCallback() {
@Override
public boolean dismiss(boolean authenticated, int targetUserId,
boolean bypassSecondaryLockScreen, SecurityMode expectedSecurityMode) {
return mKeyguardSecurityContainerController.showNextSecurityScreenOrFinish(
authenticated, targetUserId, bypassSecondaryLockScreen, expectedSecurityMode);
}
@Override
public void userActivity() {
mViewMediatorCallback.userActivity();
}
@Override
public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput) {
mViewMediatorCallback.setNeedsInput(needsInput);
}
/**
* Authentication has happened and it's time to dismiss keyguard. This function
* should clean up and inform KeyguardViewMediator.
*
* @param strongAuth whether the user has authenticated with strong authentication like
* pattern, password or PIN but not by trust agents or fingerprint
* @param targetUserId a user that needs to be the foreground user at the dismissal
* completion.
*/
@Override
public void finish(boolean strongAuth, int targetUserId) {
// If there's a pending runnable because the user interacted with a widget
// and we're leaving keyguard, then run it.
boolean deferKeyguardDone = false;
if (mDismissAction != null) {
deferKeyguardDone = mDismissAction.onDismiss();
mDismissAction = null;
mCancelAction = null;
}
if (mViewMediatorCallback != null) {
if (deferKeyguardDone) {
mViewMediatorCallback.keyguardDonePending(strongAuth, targetUserId);
} else {
mViewMediatorCallback.keyguardDone(strongAuth, targetUserId);
}
}
}
@Override
public void reset() {
mViewMediatorCallback.resetKeyguard();
}
@Override
public void onCancelClicked() {
mViewMediatorCallback.onCancelClicked();
}
};
private OnKeyListener mOnKeyListener = (v, keyCode, event) -> interceptMediaKey(event);
@Inject
public KeyguardHostViewController(KeyguardHostView view,
KeyguardUpdateMonitor keyguardUpdateMonitor,
AudioManager audioManager,
TelephonyManager telephonyManager,
ViewMediatorCallback viewMediatorCallback,
KeyguardSecurityContainerController.Factory
keyguardSecurityContainerControllerFactory) {
super(view);
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mAudioManager = audioManager;
mTelephonyManager = telephonyManager;
mViewMediatorCallback = viewMediatorCallback;
mKeyguardSecurityContainerController = keyguardSecurityContainerControllerFactory.create(
mSecurityCallback);
}
/** Initialize the Controller. */
public void onInit() {
mKeyguardSecurityContainerController.init();
updateResources();
}
@Override
protected void onViewAttached() {
mView.setViewMediatorCallback(mViewMediatorCallback);
// Update ViewMediator with the current input method requirements
mViewMediatorCallback.setNeedsInput(mKeyguardSecurityContainerController.needsInput());
mKeyguardUpdateMonitor.registerCallback(mUpdateCallback);
mView.setOnKeyListener(mOnKeyListener);
mKeyguardSecurityContainerController.showPrimarySecurityScreen(false);
}
@Override
protected void onViewDetached() {
mKeyguardUpdateMonitor.removeCallback(mUpdateCallback);
mView.setOnKeyListener(null);
}
/** Called before this view is being removed. */
public void cleanUp() {
mKeyguardSecurityContainerController.onPause();
}
public void resetSecurityContainer() {
mKeyguardSecurityContainerController.reset();
}
/**
* Dismisses the keyguard by going to the next screen or making it gone.
* @param targetUserId a user that needs to be the foreground user at the dismissal completion.
* @return True if the keyguard is done.
*/
public boolean dismiss(int targetUserId) {
return mSecurityCallback.dismiss(false, targetUserId, false,
getCurrentSecurityMode());
}
/**
* Called when the Keyguard is actively shown on the screen.
*/
public void onResume() {
if (DEBUG) Log.d(TAG, "screen on, instance " + Integer.toHexString(hashCode()));
mKeyguardSecurityContainerController.onResume(KeyguardSecurityView.SCREEN_ON);
mView.requestFocus();
}
public CharSequence getAccessibilityTitleForCurrentMode() {
return mKeyguardSecurityContainerController.getTitle();
}
/**
* Starts the animation when the Keyguard gets shown.
*/
public void appear(int statusBarHeight) {
// We might still be collapsed and the view didn't have time to layout yet or still
// be small, let's wait on the predraw to do the animation in that case.
if (mView.getHeight() != 0 && mView.getHeight() != statusBarHeight) {
mKeyguardSecurityContainerController.startAppearAnimation();
} else {
mView.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
mView.getViewTreeObserver().removeOnPreDrawListener(this);
mKeyguardSecurityContainerController.startAppearAnimation();
return true;
}
});
mView.requestLayout();
}
}
/**
* Show a string explaining why the security view needs to be solved.
*
* @param reason a flag indicating which string should be shown, see
* {@link KeyguardSecurityView#PROMPT_REASON_NONE},
* {@link KeyguardSecurityView#PROMPT_REASON_RESTART},
* {@link KeyguardSecurityView#PROMPT_REASON_TIMEOUT}, and
* {@link KeyguardSecurityView#PROMPT_REASON_PREPARE_FOR_UPDATE}.
*/
public void showPromptReason(int reason) {
mKeyguardSecurityContainerController.showPromptReason(reason);
}
public void showMessage(CharSequence message, ColorStateList colorState) {
mKeyguardSecurityContainerController.showMessage(message, colorState);
}
public void showErrorMessage(CharSequence customMessage) {
showMessage(customMessage, Utils.getColorError(mView.getContext()));
}
/**
* Sets an action to run when keyguard finishes.
*
* @param action
*/
public void setOnDismissAction(ActivityStarter.OnDismissAction action, Runnable cancelAction) {
if (mCancelAction != null) {
mCancelAction.run();
mCancelAction = null;
}
mDismissAction = action;
mCancelAction = cancelAction;
}
public void cancelDismissAction() {
setOnDismissAction(null, null);
}
public void startDisappearAnimation(Runnable finishRunnable) {
if (!mKeyguardSecurityContainerController.startDisappearAnimation(finishRunnable)
&& finishRunnable != null) {
finishRunnable.run();
}
}
/**
* Called when the Keyguard is not actively shown anymore on the screen.
*/
public void onPause() {
if (DEBUG) {
Log.d(TAG, String.format("screen off, instance %s at %s",
Integer.toHexString(hashCode()), SystemClock.uptimeMillis()));
}
mKeyguardSecurityContainerController.showPrimarySecurityScreen(true);
mKeyguardSecurityContainerController.onPause();
mView.clearFocus();
}
/**
* Called when the view needs to be shown.
*/
public void showPrimarySecurityScreen() {
if (DEBUG) Log.d(TAG, "show()");
mKeyguardSecurityContainerController.showPrimarySecurityScreen(false);
}
/**
* Fades and translates in/out the security screen.
* Fades in as expansion approaches 0.
* Animation duration is between 0.33f and 0.67f of panel expansion fraction.
* @param fraction amount of the screen that should show.
*/
public void setExpansion(float fraction) {
float scaledFraction = BouncerPanelExpansionCalculator.showBouncerProgress(fraction);
mView.setAlpha(MathUtils.constrain(1 - scaledFraction, 0f, 1f));
mView.setTranslationY(scaledFraction * mTranslationY);
}
/**
* When bouncer was visible and is starting to become hidden.
*/
public void onStartingToHide() {
mKeyguardSecurityContainerController.onStartingToHide();
}
/** Called when bouncer visibility changes. */
public void onBouncerVisibilityChanged(@View.Visibility int visibility) {
mKeyguardSecurityContainerController.onBouncerVisibilityChanged(visibility);
}
public boolean hasDismissActions() {
return mDismissAction != null || mCancelAction != null;
}
public SecurityMode getCurrentSecurityMode() {
return mKeyguardSecurityContainerController.getCurrentSecurityMode();
}
public int getTop() {
int top = mView.getTop();
// The password view has an extra top padding that should be ignored.
if (getCurrentSecurityMode() == SecurityMode.Password) {
View messageArea = mView.findViewById(R.id.keyguard_message_area);
top += messageArea.getTop();
}
return top;
}
public boolean handleBackKey() {
SecurityMode securityMode = mKeyguardSecurityContainerController.getCurrentSecurityMode();
if (securityMode != SecurityMode.None) {
mKeyguardSecurityContainerController.dismiss(
false, KeyguardUpdateMonitor.getCurrentUser(), securityMode);
return true;
}
return false;
}
/**
* In general, we enable unlocking the insecure keyguard with the menu key. However, there are
* some cases where we wish to disable it, notably when the menu button placement or technology
* is prone to false positives.
*
* @return true if the menu key should be enabled
*/
public boolean shouldEnableMenuKey() {
final Resources res = mView.getResources();
final boolean configDisabled = res.getBoolean(R.bool.config_disableMenuKeyInLockScreen);
final boolean isTestHarness = ActivityManager.isRunningInTestHarness();
final boolean fileOverride = (new File(ENABLE_MENU_KEY_FILE)).exists();
return !configDisabled || isTestHarness || fileOverride;
}
/**
* @return true if the current bouncer is password
*/
public boolean dispatchBackKeyEventPreIme() {
if (mKeyguardSecurityContainerController.getCurrentSecurityMode()
== SecurityMode.Password) {
return true;
}
return false;
}
/**
* @return the {@link OnBackAnimationCallback} to animate this view during a back gesture.
*/
@NonNull
public OnBackAnimationCallback getBackCallback() {
return mKeyguardSecurityContainerController.getBackCallback();
}
/**
* Allows the media keys to work when the keyguard is showing.
* The media keys should be of no interest to the actual keyguard view(s),
* so intercepting them here should not be of any harm.
* @param event The key event
* @return whether the event was consumed as a media key.
*/
public boolean interceptMediaKey(KeyEvent event) {
int keyCode = event.getKeyCode();
if (event.getAction() == KeyEvent.ACTION_DOWN) {
switch (keyCode) {
case KeyEvent.KEYCODE_MEDIA_PLAY:
case KeyEvent.KEYCODE_MEDIA_PAUSE:
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
/* Suppress PLAY/PAUSE toggle when phone is ringing or
* in-call to avoid music playback */
if (mTelephonyManager != null &&
mTelephonyManager.getCallState() != TelephonyManager.CALL_STATE_IDLE) {
return true; // suppress key event
}
case KeyEvent.KEYCODE_MUTE:
case KeyEvent.KEYCODE_HEADSETHOOK:
case KeyEvent.KEYCODE_MEDIA_STOP:
case KeyEvent.KEYCODE_MEDIA_NEXT:
case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
case KeyEvent.KEYCODE_MEDIA_REWIND:
case KeyEvent.KEYCODE_MEDIA_RECORD:
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
handleMediaKeyEvent(event);
return true;
}
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_MUTE: {
if (KEYGUARD_MANAGES_VOLUME) {
// Volume buttons should only function for music (local or remote).
// TODO: Actually handle MUTE.
mAudioManager.adjustSuggestedStreamVolume(
keyCode == KeyEvent.KEYCODE_VOLUME_UP
? AudioManager.ADJUST_RAISE
: AudioManager.ADJUST_LOWER /* direction */,
AudioManager.STREAM_MUSIC /* stream */, 0 /* flags */);
// Don't execute default volume behavior
return true;
} else {
return false;
}
}
}
} else if (event.getAction() == KeyEvent.ACTION_UP) {
switch (keyCode) {
case KeyEvent.KEYCODE_MUTE:
case KeyEvent.KEYCODE_HEADSETHOOK:
case KeyEvent.KEYCODE_MEDIA_PLAY:
case KeyEvent.KEYCODE_MEDIA_PAUSE:
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
case KeyEvent.KEYCODE_MEDIA_STOP:
case KeyEvent.KEYCODE_MEDIA_NEXT:
case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
case KeyEvent.KEYCODE_MEDIA_REWIND:
case KeyEvent.KEYCODE_MEDIA_RECORD:
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
handleMediaKeyEvent(event);
return true;
}
}
}
return false;
}
private void handleMediaKeyEvent(KeyEvent keyEvent) {
mAudioManager.dispatchMediaKeyEvent(keyEvent);
}
public void finish(boolean strongAuth, int currentUser) {
mSecurityCallback.finish(strongAuth, currentUser);
}
/**
* Apply keyguard configuration from the currently active resources. This can be called when the
* device configuration changes, to re-apply some resources that are qualified on the device
* configuration.
*/
public void updateResources() {
int gravity;
Resources resources = mView.getResources();
if (resources.getBoolean(R.bool.can_use_one_handed_bouncer)) {
gravity = resources.getInteger(
R.integer.keyguard_host_view_one_handed_gravity);
} else {
gravity = resources.getInteger(R.integer.keyguard_host_view_gravity);
}
mTranslationY = resources
.getDimensionPixelSize(R.dimen.keyguard_host_view_translation_y);
// Android SysUI uses a FrameLayout as the top-level, but Auto uses RelativeLayout.
// We're just changing the gravity here though (which can't be applied to RelativeLayout),
// so only attempt the update if mView is inside a FrameLayout.
if (mView.getLayoutParams() instanceof FrameLayout.LayoutParams) {
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mView.getLayoutParams();
if (lp.gravity != gravity) {
lp.gravity = gravity;
mView.setLayoutParams(lp);
}
}
if (mKeyguardSecurityContainerController != null) {
mKeyguardSecurityContainerController.updateResources();
}
}
/** Update keyguard position based on a tapped X coordinate. */
public void updateKeyguardPosition(float x) {
if (mKeyguardSecurityContainerController != null) {
mKeyguardSecurityContainerController.updateKeyguardPosition(x);
}
}
/** Set true if the view can be interacted with */
public void setInteractable(boolean isInteractable) {
mView.setInteractable(isInteractable);
}
}

View File

@@ -51,26 +51,7 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView>
// The following is used to ignore callbacks from SecurityViews that are no longer current // The following is used to ignore callbacks from SecurityViews that are no longer current
// (e.g. face unlock). This avoids unwanted asynchronous events from messing with the // (e.g. face unlock). This avoids unwanted asynchronous events from messing with the
// state for the current security method. // state for the current security method.
private KeyguardSecurityCallback mNullCallback = new KeyguardSecurityCallback() { private KeyguardSecurityCallback mNullCallback = new KeyguardSecurityCallback() {};
@Override
public void userActivity() { }
@Override
public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) { }
@Override
public boolean isVerifyUnlockOnly() {
return false;
}
@Override
public void dismiss(boolean securityVerified, int targetUserId,
SecurityMode expectedSecurityMode) { }
@Override
public void dismiss(boolean authenticated, int targetId,
boolean bypassSecondaryLockScreen, SecurityMode expectedSecurityMode) { }
@Override
public void onUserInput() { }
@Override
public void reset() {}
};
protected KeyguardInputViewController(T view, SecurityMode securityMode, protected KeyguardInputViewController(T view, SecurityMode securityMode,
KeyguardSecurityCallback keyguardSecurityCallback, KeyguardSecurityCallback keyguardSecurityCallback,

View File

@@ -25,7 +25,9 @@ public interface KeyguardSecurityCallback {
* @param targetUserId a user that needs to be the foreground user at the dismissal completion. * @param targetUserId a user that needs to be the foreground user at the dismissal completion.
* @param expectedSecurityMode The security mode that is invoking this dismiss. * @param expectedSecurityMode The security mode that is invoking this dismiss.
*/ */
void dismiss(boolean securityVerified, int targetUserId, SecurityMode expectedSecurityMode); default void dismiss(boolean securityVerified, int targetUserId,
SecurityMode expectedSecurityMode) {
}
/** /**
* Dismiss the given security screen. * Dismiss the given security screen.
@@ -35,19 +37,26 @@ public interface KeyguardSecurityCallback {
* if any, during this dismissal. * if any, during this dismissal.
* @param expectedSecurityMode The security mode that is invoking this dismiss. * @param expectedSecurityMode The security mode that is invoking this dismiss.
*/ */
void dismiss(boolean securityVerified, int targetUserId, boolean bypassSecondaryLockScreen, default boolean dismiss(boolean securityVerified, int targetUserId,
SecurityMode expectedSecurityMode); boolean bypassSecondaryLockScreen,
SecurityMode expectedSecurityMode) {
return false;
}
/** /**
* Manually report user activity to keep the device awake. * Manually report user activity to keep the device awake.
*/ */
void userActivity(); default void userActivity() {
}
/** /**
* Checks if keyguard is in "verify credentials" mode. * Checks if keyguard is in "verify credentials" mode.
*
* @return true if user has been asked to verify security. * @return true if user has been asked to verify security.
*/ */
boolean isVerifyUnlockOnly(); default boolean isVerifyUnlockOnly() {
return false;
}
/** /**
* Call to report an unlock attempt. * Call to report an unlock attempt.
@@ -56,12 +65,14 @@ public interface KeyguardSecurityCallback {
* @param timeoutMs timeout in milliseconds to wait before reattempting an unlock. * @param timeoutMs timeout in milliseconds to wait before reattempting an unlock.
* Only nonzero if 'success' is false * Only nonzero if 'success' is false
*/ */
void reportUnlockAttempt(int userId, boolean success, int timeoutMs); default void reportUnlockAttempt(int userId, boolean success, int timeoutMs) {
}
/** /**
* Resets the keyguard view. * Resets the keyguard view.
*/ */
void reset(); default void reset() {
}
/** /**
* Call when cancel button is pressed in bouncer. * Call when cancel button is pressed in bouncer.
@@ -73,5 +84,19 @@ public interface KeyguardSecurityCallback {
/** /**
* Invoked whenever users are typing their password or drawing a pattern. * Invoked whenever users are typing their password or drawing a pattern.
*/ */
void onUserInput(); default void onUserInput() {
}
/**
* Dismisses keyguard and go to unlocked state.
*/
default void finish(boolean strongAuth, int targetUserId) {
}
/**
* Specifies that security mode has changed.
*/
default void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput) {
}
} }

View File

@@ -50,6 +50,7 @@ import android.content.res.Configuration;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.BlendMode; import android.graphics.BlendMode;
import android.graphics.Canvas;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
@@ -164,6 +165,8 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
private boolean mDisappearAnimRunning; private boolean mDisappearAnimRunning;
private SwipeListener mSwipeListener; private SwipeListener mSwipeListener;
private ViewMode mViewMode = new DefaultViewMode(); private ViewMode mViewMode = new DefaultViewMode();
private boolean mIsInteractable;
protected ViewMediatorCallback mViewMediatorCallback;
/* /*
* Using MODE_UNINITIALIZED to mean the view mode is set to DefaultViewMode, but init() has not * Using MODE_UNINITIALIZED to mean the view mode is set to DefaultViewMode, but init() has not
* yet been called on it. This will happen when the ViewController is initialized. * yet been called on it. This will happen when the ViewController is initialized.
@@ -265,31 +268,6 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
return mBackCallback; return mBackCallback;
} }
// Used to notify the container when something interesting happens.
public interface SecurityCallback {
/**
* Potentially dismiss the current security screen, after validating that all device
* security has been unlocked. Otherwise show the next screen.
*/
boolean dismiss(boolean authenticated, int targetUserId, boolean bypassSecondaryLockScreen,
SecurityMode expectedSecurityMode);
void userActivity();
void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput);
/**
* @param strongAuth wheher the user has authenticated with strong authentication like
* pattern, password or PIN but not by trust agents or fingerprint
* @param targetUserId a user that needs to be the foreground user at the finish completion.
*/
void finish(boolean strongAuth, int targetUserId);
void reset();
void onCancelClicked();
}
public interface SwipeListener { public interface SwipeListener {
void onSwipeUp(); void onSwipeUp();
} }
@@ -342,7 +320,7 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
public KeyguardSecurityContainer(Context context, AttributeSet attrs, int defStyle) { public KeyguardSecurityContainer(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle); super(context, attrs, defStyle);
mSpringAnimation = new SpringAnimation(this, DynamicAnimation.Y); mSpringAnimation = new SpringAnimation(this, DynamicAnimation.TRANSLATION_Y);
mViewConfiguration = ViewConfiguration.get(context); mViewConfiguration = ViewConfiguration.get(context);
mDoubleTapDetector = new GestureDetector(context, new DoubleTapListener()); mDoubleTapDetector = new GestureDetector(context, new DoubleTapListener());
} }
@@ -445,6 +423,11 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
mViewMode.reset(); mViewMode.reset();
} }
/** Set true if the view can be interacted with */
public void setInteractable(boolean isInteractable) {
mIsInteractable = isInteractable;
}
@Override @Override
public boolean shouldDelayChildPressedState() { public boolean shouldDelayChildPressedState() {
return true; return true;
@@ -452,6 +435,10 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
@Override @Override
public boolean onInterceptTouchEvent(MotionEvent event) { public boolean onInterceptTouchEvent(MotionEvent event) {
if (!mIsInteractable) {
return true;
}
boolean result = mMotionEventListeners.stream().anyMatch( boolean result = mMotionEventListeners.stream().anyMatch(
listener -> listener.onInterceptTouchEvent(event)) listener -> listener.onInterceptTouchEvent(event))
|| super.onInterceptTouchEvent(event); || super.onInterceptTouchEvent(event);
@@ -639,6 +626,18 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
return insets.inset(0, 0, 0, inset); return insets.inset(0, 0, 0, inset);
} }
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
if (mViewMediatorCallback != null) {
mViewMediatorCallback.keyguardDoneDrawing();
}
}
public void setViewMediatorCallback(ViewMediatorCallback viewMediatorCallback) {
mViewMediatorCallback = viewMediatorCallback;
}
private void showDialog(String title, String message) { private void showDialog(String title, String message) {
if (mAlertDialog != null) { if (mAlertDialog != null) {
mAlertDialog.dismiss(); mAlertDialog.dismiss();

View File

@@ -29,17 +29,26 @@ import static com.android.keyguard.KeyguardSecurityContainer.USER_TYPE_SECONDARY
import static com.android.keyguard.KeyguardSecurityContainer.USER_TYPE_WORK_PROFILE; import static com.android.keyguard.KeyguardSecurityContainer.USER_TYPE_WORK_PROFILE;
import static com.android.systemui.DejankUtils.whitelistIpcs; import static com.android.systemui.DejankUtils.whitelistIpcs;
import android.app.ActivityManager;
import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManager;
import android.content.Intent; import android.content.Intent;
import android.content.res.ColorStateList; import android.content.res.ColorStateList;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.content.res.Resources;
import android.hardware.biometrics.BiometricSourceType; import android.hardware.biometrics.BiometricSourceType;
import android.media.AudioManager;
import android.metrics.LogMaker; import android.metrics.LogMaker;
import android.os.SystemClock;
import android.os.UserHandle; import android.os.UserHandle;
import android.telephony.TelephonyManager;
import android.util.Log; import android.util.Log;
import android.util.MathUtils;
import android.util.Slog; import android.util.Slog;
import android.view.KeyEvent;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
import android.window.OnBackAnimationCallback; import android.window.OnBackAnimationCallback;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@@ -53,7 +62,6 @@ import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardSecurityContainer.BouncerUiEvent; import com.android.keyguard.KeyguardSecurityContainer.BouncerUiEvent;
import com.android.keyguard.KeyguardSecurityContainer.SecurityCallback;
import com.android.keyguard.KeyguardSecurityContainer.SwipeListener; import com.android.keyguard.KeyguardSecurityContainer.SwipeListener;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.keyguard.dagger.KeyguardBouncerScope; import com.android.keyguard.dagger.KeyguardBouncerScope;
@@ -67,6 +75,7 @@ import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags; import com.android.systemui.flags.Flags;
import com.android.systemui.log.SessionTracker; import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.shared.system.SysUiStatsLog; import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -75,6 +84,7 @@ import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.util.ViewController; import com.android.systemui.util.ViewController;
import com.android.systemui.util.settings.GlobalSettings; import com.android.systemui.util.settings.GlobalSettings;
import java.io.File;
import java.util.Optional; import java.util.Optional;
import javax.inject.Inject; import javax.inject.Inject;
@@ -95,7 +105,6 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
private final UiEventLogger mUiEventLogger; private final UiEventLogger mUiEventLogger;
private final KeyguardStateController mKeyguardStateController; private final KeyguardStateController mKeyguardStateController;
private final KeyguardSecurityViewFlipperController mSecurityViewFlipperController; private final KeyguardSecurityViewFlipperController mSecurityViewFlipperController;
private final SecurityCallback mSecurityCallback;
private final ConfigurationController mConfigurationController; private final ConfigurationController mConfigurationController;
private final FalsingCollector mFalsingCollector; private final FalsingCollector mFalsingCollector;
private final FalsingManager mFalsingManager; private final FalsingManager mFalsingManager;
@@ -105,6 +114,20 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
private final SessionTracker mSessionTracker; private final SessionTracker mSessionTracker;
private final Optional<SideFpsController> mSideFpsController; private final Optional<SideFpsController> mSideFpsController;
private final FalsingA11yDelegate mFalsingA11yDelegate; private final FalsingA11yDelegate mFalsingA11yDelegate;
private int mTranslationY;
// Whether the volume keys should be handled by keyguard. If true, then
// they will be handled here for specific media types such as music, otherwise
// the audio service will bring up the volume dialog.
private static final boolean KEYGUARD_MANAGES_VOLUME = false;
private static final String ENABLE_MENU_KEY_FILE = "/data/local/enable_menu_key";
private final TelephonyManager mTelephonyManager;
private final ViewMediatorCallback mViewMediatorCallback;
private final AudioManager mAudioManager;
private View.OnKeyListener mOnKeyListener = (v, keyCode, event) -> interceptMediaKey(event);
private ActivityStarter.OnDismissAction mDismissAction;
private Runnable mCancelAction;
private int mLastOrientation = Configuration.ORIENTATION_UNDEFINED; private int mLastOrientation = Configuration.ORIENTATION_UNDEFINED;
@@ -149,11 +172,6 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
}; };
private KeyguardSecurityCallback mKeyguardSecurityCallback = new KeyguardSecurityCallback() { private KeyguardSecurityCallback mKeyguardSecurityCallback = new KeyguardSecurityCallback() {
public void userActivity() {
if (mSecurityCallback != null) {
mSecurityCallback.userActivity();
}
}
@Override @Override
public void onUserInput() { public void onUserInput() {
@@ -168,16 +186,23 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
} }
@Override @Override
public void dismiss(boolean authenticated, int targetId, public boolean dismiss(boolean authenticated, int targetId,
boolean bypassSecondaryLockScreen, SecurityMode expectedSecurityMode) { boolean bypassSecondaryLockScreen, SecurityMode expectedSecurityMode) {
mSecurityCallback.dismiss(authenticated, targetId, bypassSecondaryLockScreen, return showNextSecurityScreenOrFinish(
expectedSecurityMode); authenticated, targetId, bypassSecondaryLockScreen, expectedSecurityMode);
} }
@Override
public void userActivity() {
mViewMediatorCallback.userActivity();
}
@Override
public boolean isVerifyUnlockOnly() { public boolean isVerifyUnlockOnly() {
return false; return false;
} }
@Override
public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) { public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) {
int bouncerSide = SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__SIDE__DEFAULT; int bouncerSide = SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__SIDE__DEFAULT;
if (mView.isSidedSecurityMode()) { if (mView.isSidedSecurityMode()) {
@@ -214,12 +239,47 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
: BouncerUiEvent.BOUNCER_PASSWORD_FAILURE, getSessionId()); : BouncerUiEvent.BOUNCER_PASSWORD_FAILURE, getSessionId());
} }
@Override
public void reset() { public void reset() {
mSecurityCallback.reset(); mViewMediatorCallback.resetKeyguard();
} }
@Override
public void onCancelClicked() { public void onCancelClicked() {
mSecurityCallback.onCancelClicked(); mViewMediatorCallback.onCancelClicked();
}
/**
* Authentication has happened and it's time to dismiss keyguard. This function
* should clean up and inform KeyguardViewMediator.
*
* @param strongAuth whether the user has authenticated with strong authentication like
* pattern, password or PIN but not by trust agents or fingerprint
* @param targetUserId a user that needs to be the foreground user at the dismissal
* completion.
*/
@Override
public void finish(boolean strongAuth, int targetUserId) {
// If there's a pending runnable because the user interacted with a widget
// and we're leaving keyguard, then run it.
boolean deferKeyguardDone = false;
if (mDismissAction != null) {
deferKeyguardDone = mDismissAction.onDismiss();
mDismissAction = null;
mCancelAction = null;
}
if (mViewMediatorCallback != null) {
if (deferKeyguardDone) {
mViewMediatorCallback.keyguardDonePending(strongAuth, targetUserId);
} else {
mViewMediatorCallback.keyguardDone(strongAuth, targetUserId);
}
}
}
@Override
public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput) {
mViewMediatorCallback.setNeedsInput(needsInput);
} }
}; };
@@ -262,6 +322,34 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
private boolean mBouncerVisible = false; private boolean mBouncerVisible = false;
private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback = private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
new KeyguardUpdateMonitorCallback() { new KeyguardUpdateMonitorCallback() {
@Override
public void onTrustGrantedForCurrentUser(
boolean dismissKeyguard,
boolean newlyUnlocked,
TrustGrantFlags flags,
String message
) {
if (dismissKeyguard) {
if (!mView.isVisibleToUser()) {
// The trust agent dismissed the keyguard without the user proving
// that they are present (by swiping up to show the bouncer). That's
// fine if the user proved presence via some other way to the trust
// agent.
Log.i(TAG, "TrustAgent dismissed Keyguard.");
}
mKeyguardSecurityCallback.dismiss(
false /* authenticated */,
KeyguardUpdateMonitor.getCurrentUser(),
/* bypassSecondaryLockScreen */ false,
SecurityMode.Invalid
);
} else {
if (flags.isInitiatedByUser() || flags.dismissKeyguardRequested()) {
mViewMediatorCallback.playTrustedSound();
}
}
}
@Override @Override
public void onDevicePolicyManagerStateChanged() { public void onDevicePolicyManagerStateChanged() {
showPrimarySecurityScreen(false); showPrimarySecurityScreen(false);
@@ -281,7 +369,8 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
} }
}; };
private KeyguardSecurityContainerController(KeyguardSecurityContainer view, @Inject
public KeyguardSecurityContainerController(KeyguardSecurityContainer view,
AdminSecondaryLockScreenController.Factory adminSecondaryLockScreenControllerFactory, AdminSecondaryLockScreenController.Factory adminSecondaryLockScreenControllerFactory,
LockPatternUtils lockPatternUtils, LockPatternUtils lockPatternUtils,
KeyguardUpdateMonitor keyguardUpdateMonitor, KeyguardUpdateMonitor keyguardUpdateMonitor,
@@ -289,7 +378,6 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
MetricsLogger metricsLogger, MetricsLogger metricsLogger,
UiEventLogger uiEventLogger, UiEventLogger uiEventLogger,
KeyguardStateController keyguardStateController, KeyguardStateController keyguardStateController,
SecurityCallback securityCallback,
KeyguardSecurityViewFlipperController securityViewFlipperController, KeyguardSecurityViewFlipperController securityViewFlipperController,
ConfigurationController configurationController, ConfigurationController configurationController,
FalsingCollector falsingCollector, FalsingCollector falsingCollector,
@@ -299,7 +387,11 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
GlobalSettings globalSettings, GlobalSettings globalSettings,
SessionTracker sessionTracker, SessionTracker sessionTracker,
Optional<SideFpsController> sideFpsController, Optional<SideFpsController> sideFpsController,
FalsingA11yDelegate falsingA11yDelegate) { FalsingA11yDelegate falsingA11yDelegate,
TelephonyManager telephonyManager,
ViewMediatorCallback viewMediatorCallback,
AudioManager audioManager
) {
super(view); super(view);
mLockPatternUtils = lockPatternUtils; mLockPatternUtils = lockPatternUtils;
mUpdateMonitor = keyguardUpdateMonitor; mUpdateMonitor = keyguardUpdateMonitor;
@@ -307,7 +399,6 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
mMetricsLogger = metricsLogger; mMetricsLogger = metricsLogger;
mUiEventLogger = uiEventLogger; mUiEventLogger = uiEventLogger;
mKeyguardStateController = keyguardStateController; mKeyguardStateController = keyguardStateController;
mSecurityCallback = securityCallback;
mSecurityViewFlipperController = securityViewFlipperController; mSecurityViewFlipperController = securityViewFlipperController;
mAdminSecondaryLockScreenController = adminSecondaryLockScreenControllerFactory.create( mAdminSecondaryLockScreenController = adminSecondaryLockScreenControllerFactory.create(
mKeyguardSecurityCallback); mKeyguardSecurityCallback);
@@ -321,11 +412,15 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
mSessionTracker = sessionTracker; mSessionTracker = sessionTracker;
mSideFpsController = sideFpsController; mSideFpsController = sideFpsController;
mFalsingA11yDelegate = falsingA11yDelegate; mFalsingA11yDelegate = falsingA11yDelegate;
mTelephonyManager = telephonyManager;
mViewMediatorCallback = viewMediatorCallback;
mAudioManager = audioManager;
} }
@Override @Override
public void onInit() { public void onInit() {
mSecurityViewFlipperController.init(); mSecurityViewFlipperController.init();
updateResources();
configureMode(); configureMode();
} }
@@ -336,6 +431,11 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
mView.addMotionEventListener(mGlobalTouchListener); mView.addMotionEventListener(mGlobalTouchListener);
mConfigurationController.addCallback(mConfigurationListener); mConfigurationController.addCallback(mConfigurationListener);
mUserSwitcherController.addUserSwitchCallback(mUserSwitchCallback); mUserSwitcherController.addUserSwitchCallback(mUserSwitchCallback);
mView.setViewMediatorCallback(mViewMediatorCallback);
// Update ViewMediator with the current input method requirements
mViewMediatorCallback.setNeedsInput(needsInput());
mView.setOnKeyListener(mOnKeyListener);
showPrimarySecurityScreen(false);
} }
@Override @Override
@@ -348,6 +448,11 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
/** */ /** */
public void onPause() { public void onPause() {
if (DEBUG) {
Log.d(TAG, String.format("screen off, instance %s at %s",
Integer.toHexString(hashCode()), SystemClock.uptimeMillis()));
}
showPrimarySecurityScreen(true);
mAdminSecondaryLockScreenController.hide(); mAdminSecondaryLockScreenController.hide();
if (mCurrentSecurityMode != SecurityMode.None) { if (mCurrentSecurityMode != SecurityMode.None) {
getCurrentSecurityController().onPause(); getCurrentSecurityController().onPause();
@@ -356,6 +461,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
// It might happen that onStartingToHide is not called when the device is locked while on // It might happen that onStartingToHide is not called when the device is locked while on
// bouncer. // bouncer.
setBouncerVisible(false); setBouncerVisible(false);
mView.clearFocus();
} }
private void updateSideFpsVisibility() { private void updateSideFpsVisibility() {
@@ -391,12 +497,22 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
* @param turningOff true if the device is being turned off * @param turningOff true if the device is being turned off
*/ */
public void showPrimarySecurityScreen(boolean turningOff) { public void showPrimarySecurityScreen(boolean turningOff) {
if (DEBUG) Log.d(TAG, "show()");
SecurityMode securityMode = whitelistIpcs(() -> mSecurityModel.getSecurityMode( SecurityMode securityMode = whitelistIpcs(() -> mSecurityModel.getSecurityMode(
KeyguardUpdateMonitor.getCurrentUser())); KeyguardUpdateMonitor.getCurrentUser()));
if (DEBUG) Log.v(TAG, "showPrimarySecurityScreen(turningOff=" + turningOff + ")"); if (DEBUG) Log.v(TAG, "showPrimarySecurityScreen(turningOff=" + turningOff + ")");
showSecurityScreen(securityMode); showSecurityScreen(securityMode);
} }
/**
* Show a string explaining why the security view needs to be solved.
*
* @param reason a flag indicating which string should be shown, see
* {@link KeyguardSecurityView#PROMPT_REASON_NONE},
* {@link KeyguardSecurityView#PROMPT_REASON_RESTART},
* {@link KeyguardSecurityView#PROMPT_REASON_TIMEOUT}, and
* {@link KeyguardSecurityView#PROMPT_REASON_PREPARE_FOR_UPDATE}.
*/
@Override @Override
public void showPromptReason(int reason) { public void showPromptReason(int reason) {
if (mCurrentSecurityMode != SecurityMode.None) { if (mCurrentSecurityMode != SecurityMode.None) {
@@ -413,8 +529,32 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
} }
} }
public SecurityMode getCurrentSecurityMode() { /**
return mCurrentSecurityMode; * Sets an action to run when keyguard finishes.
*
* @param action callback to be invoked when keyguard disappear animation completes.
*/
public void setOnDismissAction(ActivityStarter.OnDismissAction action, Runnable cancelAction) {
if (mCancelAction != null) {
mCancelAction.run();
mCancelAction = null;
}
mDismissAction = action;
mCancelAction = cancelAction;
}
/**
* @return whether dismiss action or cancel action has been set.
*/
public boolean hasDismissActions() {
return mDismissAction != null || mCancelAction != null;
}
/**
* Remove any dismiss action or cancel action that was set.
*/
public void cancelDismissAction() {
setOnDismissAction(null, null);
} }
/** /**
@@ -426,17 +566,64 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
mKeyguardSecurityCallback.dismiss(authenticated, targetUserId, expectedSecurityMode); mKeyguardSecurityCallback.dismiss(authenticated, targetUserId, expectedSecurityMode);
} }
/**
* Dismisses the keyguard by going to the next screen or making it gone.
* @param targetUserId a user that needs to be the foreground user at the dismissal completion.
* @return True if the keyguard is done.
*/
public boolean dismiss(int targetUserId) {
return mKeyguardSecurityCallback.dismiss(false, targetUserId, false,
getCurrentSecurityMode());
}
public SecurityMode getCurrentSecurityMode() {
return mCurrentSecurityMode;
}
/**
* @return the top of the corresponding view.
*/
public int getTop() {
int top = mView.getTop();
// The password view has an extra top padding that should be ignored.
if (getCurrentSecurityMode() == SecurityMode.Password) {
View messageArea = mView.findViewById(R.id.keyguard_message_area);
top += messageArea.getTop();
}
return top;
}
/** Set true if the view can be interacted with */
public void setInteractable(boolean isInteractable) {
mView.setInteractable(isInteractable);
}
/**
* Dismiss keyguard due to a user unlock event.
*/
public void finish(boolean strongAuth, int currentUser) {
mKeyguardSecurityCallback.finish(strongAuth, currentUser);
}
/**
* @return the text of the KeyguardMessageArea.
*/
public CharSequence getTitle() {
return mView.getTitle();
}
/**
* Resets the state of the views.
*/
public void reset() { public void reset() {
mView.reset(); mView.reset();
mSecurityViewFlipperController.reset(); mSecurityViewFlipperController.reset();
} }
public CharSequence getTitle() {
return mView.getTitle();
}
@Override @Override
public void onResume(int reason) { public void onResume(int reason) {
if (DEBUG) Log.d(TAG, "screen on, instance " + Integer.toHexString(hashCode()));
mView.requestFocus();
if (mCurrentSecurityMode != SecurityMode.None) { if (mCurrentSecurityMode != SecurityMode.None) {
int state = SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED__STATE__SHOWN; int state = SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED__STATE__SHOWN;
if (mView.isSidedSecurityMode()) { if (mView.isSidedSecurityMode()) {
@@ -454,6 +641,30 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
mKeyguardStateController.isFaceAuthEnabled()); mKeyguardStateController.isFaceAuthEnabled());
} }
/**
* Show the bouncer and start appear animations.
*
* @param statusBarHeight
*/
public void appear(int statusBarHeight) {
// We might still be collapsed and the view didn't have time to layout yet or still
// be small, let's wait on the predraw to do the animation in that case.
if (mView.getHeight() != 0 && mView.getHeight() != statusBarHeight) {
startAppearAnimation();
} else {
mView.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
mView.getViewTreeObserver().removeOnPreDrawListener(this);
startAppearAnimation();
return true;
}
});
mView.requestLayout();
}
}
public void startAppearAnimation() { public void startAppearAnimation() {
if (mCurrentSecurityMode != SecurityMode.None) { if (mCurrentSecurityMode != SecurityMode.None) {
mView.setAlpha(1f); mView.setAlpha(1f);
@@ -465,9 +676,13 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
public boolean startDisappearAnimation(Runnable onFinishRunnable) { public boolean startDisappearAnimation(Runnable onFinishRunnable) {
if (mCurrentSecurityMode != SecurityMode.None) { if (mCurrentSecurityMode != SecurityMode.None) {
mView.startDisappearAnimation(mCurrentSecurityMode); mView.startDisappearAnimation(mCurrentSecurityMode);
return getCurrentSecurityController().startDisappearAnimation(onFinishRunnable); boolean animating = getCurrentSecurityController().startDisappearAnimation(
onFinishRunnable);
if (!animating && onFinishRunnable != null) {
onFinishRunnable.run();
}
return animating;
} }
return false; return false;
} }
@@ -583,7 +798,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
mUiEventLogger.log(uiEvent, getSessionId()); mUiEventLogger.log(uiEvent, getSessionId());
} }
if (finish) { if (finish) {
mSecurityCallback.finish(strongAuth, targetUserId); mKeyguardSecurityCallback.finish(strongAuth, targetUserId);
} }
return finish; return finish;
} }
@@ -596,10 +811,113 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
* @return the {@link OnBackAnimationCallback} to animate this view during a back gesture. * @return the {@link OnBackAnimationCallback} to animate this view during a back gesture.
*/ */
@NonNull @NonNull
OnBackAnimationCallback getBackCallback() { public OnBackAnimationCallback getBackCallback() {
return mView.getBackCallback(); return mView.getBackCallback();
} }
/**
* @return whether we should dispatch the back key event before Ime.
*/
public boolean dispatchBackKeyEventPreIme() {
return getCurrentSecurityMode() == SecurityMode.Password;
}
/**
* Allows the media keys to work when the keyguard is showing.
* The media keys should be of no interest to the actual keyguard view(s),
* so intercepting them here should not be of any harm.
* @param event The key event
* @return whether the event was consumed as a media key.
*/
public boolean interceptMediaKey(KeyEvent event) {
int keyCode = event.getKeyCode();
if (event.getAction() == KeyEvent.ACTION_DOWN) {
switch (keyCode) {
case KeyEvent.KEYCODE_MEDIA_PLAY:
case KeyEvent.KEYCODE_MEDIA_PAUSE:
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
/* Suppress PLAY/PAUSE toggle when phone is ringing or
* in-call to avoid music playback */
if (mTelephonyManager != null
&& mTelephonyManager.getCallState()
!= TelephonyManager.CALL_STATE_IDLE) {
return true; // suppress key event
}
return false;
case KeyEvent.KEYCODE_MUTE:
case KeyEvent.KEYCODE_HEADSETHOOK:
case KeyEvent.KEYCODE_MEDIA_STOP:
case KeyEvent.KEYCODE_MEDIA_NEXT:
case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
case KeyEvent.KEYCODE_MEDIA_REWIND:
case KeyEvent.KEYCODE_MEDIA_RECORD:
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
handleMediaKeyEvent(event);
return true;
}
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_MUTE: {
if (KEYGUARD_MANAGES_VOLUME) {
// Volume buttons should only function for music (local or remote).
// TODO: Actually handle MUTE.
mAudioManager.adjustSuggestedStreamVolume(
keyCode == KeyEvent.KEYCODE_VOLUME_UP
? AudioManager.ADJUST_RAISE
: AudioManager.ADJUST_LOWER /* direction */,
AudioManager.STREAM_MUSIC /* stream */, 0 /* flags */);
// Don't execute default volume behavior
return true;
} else {
return false;
}
}
}
} else if (event.getAction() == KeyEvent.ACTION_UP) {
switch (keyCode) {
case KeyEvent.KEYCODE_MUTE:
case KeyEvent.KEYCODE_HEADSETHOOK:
case KeyEvent.KEYCODE_MEDIA_PLAY:
case KeyEvent.KEYCODE_MEDIA_PAUSE:
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
case KeyEvent.KEYCODE_MEDIA_STOP:
case KeyEvent.KEYCODE_MEDIA_NEXT:
case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
case KeyEvent.KEYCODE_MEDIA_REWIND:
case KeyEvent.KEYCODE_MEDIA_RECORD:
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
handleMediaKeyEvent(event);
return true;
}
}
}
return false;
}
private void handleMediaKeyEvent(KeyEvent keyEvent) {
mAudioManager.dispatchMediaKeyEvent(keyEvent);
}
/**
* In general, we enable unlocking the insecure keyguard with the menu key. However, there are
* some cases where we wish to disable it, notably when the menu button placement or technology
* is prone to false positives.
*
* @return true if the menu key should be enabled
*/
public boolean shouldEnableMenuKey() {
final Resources res = mView.getResources();
final boolean configDisabled = res.getBoolean(R.bool.config_disableMenuKeyInLockScreen);
final boolean isTestHarness = ActivityManager.isRunningInTestHarness();
final boolean fileOverride = (new File(ENABLE_MENU_KEY_FILE)).exists();
return !configDisabled || isTestHarness || fileOverride;
}
/** /**
* Switches to the given security view unless it's already being shown, in which case * Switches to the given security view unless it's already being shown, in which case
* this is a no-op. * this is a no-op.
@@ -628,7 +946,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
configureMode(); configureMode();
} }
mSecurityCallback.onSecurityModeChanged( mKeyguardSecurityCallback.onSecurityModeChanged(
securityMode, newView != null && newView.needsInput()); securityMode, newView != null && newView.needsInput());
} }
@@ -726,6 +1044,30 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
* configuration. * configuration.
*/ */
public void updateResources() { public void updateResources() {
int gravity;
Resources resources = mView.getResources();
if (resources.getBoolean(R.bool.can_use_one_handed_bouncer)) {
gravity = resources.getInteger(
R.integer.keyguard_host_view_one_handed_gravity);
} else {
gravity = resources.getInteger(R.integer.keyguard_host_view_gravity);
}
mTranslationY = resources
.getDimensionPixelSize(R.dimen.keyguard_host_view_translation_y);
// Android SysUI uses a FrameLayout as the top-level, but Auto uses RelativeLayout.
// We're just changing the gravity here though (which can't be applied to RelativeLayout),
// so only attempt the update if mView is inside a FrameLayout.
if (mView.getLayoutParams() instanceof FrameLayout.LayoutParams) {
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mView.getLayoutParams();
if (lp.gravity != gravity) {
lp.gravity = gravity;
mView.setLayoutParams(lp);
}
}
int newOrientation = getResources().getConfiguration().orientation; int newOrientation = getResources().getConfiguration().orientation;
if (newOrientation != mLastOrientation) { if (newOrientation != mLastOrientation) {
mLastOrientation = newOrientation; mLastOrientation = newOrientation;
@@ -759,77 +1101,15 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
mKeyguardSecurityCallback); mKeyguardSecurityCallback);
} }
static class Factory { /**
* Fades and translates in/out the security screen.
private final KeyguardSecurityContainer mView; * Fades in as expansion approaches 0.
private final AdminSecondaryLockScreenController.Factory * Animation duration is between 0.33f and 0.67f of panel expansion fraction.
mAdminSecondaryLockScreenControllerFactory; * @param fraction amount of the screen that should show.
private final LockPatternUtils mLockPatternUtils; */
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; public void setExpansion(float fraction) {
private final KeyguardSecurityModel mKeyguardSecurityModel; float scaledFraction = BouncerPanelExpansionCalculator.showBouncerProgress(fraction);
private final MetricsLogger mMetricsLogger; mView.setAlpha(MathUtils.constrain(1 - scaledFraction, 0f, 1f));
private final UiEventLogger mUiEventLogger; mView.setTranslationY(scaledFraction * mTranslationY);
private final KeyguardStateController mKeyguardStateController;
private final KeyguardSecurityViewFlipperController mSecurityViewFlipperController;
private final ConfigurationController mConfigurationController;
private final FalsingCollector mFalsingCollector;
private final FalsingManager mFalsingManager;
private final GlobalSettings mGlobalSettings;
private final FeatureFlags mFeatureFlags;
private final UserSwitcherController mUserSwitcherController;
private final SessionTracker mSessionTracker;
private final Optional<SideFpsController> mSidefpsController;
private final FalsingA11yDelegate mFalsingA11yDelegate;
@Inject
Factory(KeyguardSecurityContainer view,
AdminSecondaryLockScreenController.Factory
adminSecondaryLockScreenControllerFactory,
LockPatternUtils lockPatternUtils,
KeyguardUpdateMonitor keyguardUpdateMonitor,
KeyguardSecurityModel keyguardSecurityModel,
MetricsLogger metricsLogger,
UiEventLogger uiEventLogger,
KeyguardStateController keyguardStateController,
KeyguardSecurityViewFlipperController securityViewFlipperController,
ConfigurationController configurationController,
FalsingCollector falsingCollector,
FalsingManager falsingManager,
UserSwitcherController userSwitcherController,
FeatureFlags featureFlags,
GlobalSettings globalSettings,
SessionTracker sessionTracker,
Optional<SideFpsController> sidefpsController,
FalsingA11yDelegate falsingA11yDelegate) {
mView = view;
mAdminSecondaryLockScreenControllerFactory = adminSecondaryLockScreenControllerFactory;
mLockPatternUtils = lockPatternUtils;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mKeyguardSecurityModel = keyguardSecurityModel;
mMetricsLogger = metricsLogger;
mUiEventLogger = uiEventLogger;
mKeyguardStateController = keyguardStateController;
mSecurityViewFlipperController = securityViewFlipperController;
mConfigurationController = configurationController;
mFalsingCollector = falsingCollector;
mFalsingManager = falsingManager;
mFeatureFlags = featureFlags;
mGlobalSettings = globalSettings;
mUserSwitcherController = userSwitcherController;
mSessionTracker = sessionTracker;
mSidefpsController = sidefpsController;
mFalsingA11yDelegate = falsingA11yDelegate;
}
public KeyguardSecurityContainerController create(
SecurityCallback securityCallback) {
return new KeyguardSecurityContainerController(mView,
mAdminSecondaryLockScreenControllerFactory, mLockPatternUtils,
mKeyguardUpdateMonitor, mKeyguardSecurityModel, mMetricsLogger, mUiEventLogger,
mKeyguardStateController, securityCallback, mSecurityViewFlipperController,
mConfigurationController, mFalsingCollector, mFalsingManager,
mUserSwitcherController, mFeatureFlags, mGlobalSettings, mSessionTracker,
mSidefpsController, mFalsingA11yDelegate);
}
} }
} }

View File

@@ -3747,7 +3747,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
} }
// TODO: use these callbacks elsewhere in place of the existing notifyScreen*() // TODO: use these callbacks elsewhere in place of the existing notifyScreen*()
// (KeyguardViewMediator, KeyguardHostView) // (KeyguardViewMediator, KeyguardSecurityContainer)
/** /**
* Dispatch wakeup events to: * Dispatch wakeup events to:
* - update biometric listening states * - update biometric listening states

View File

@@ -18,7 +18,7 @@ package com.android.keyguard.dagger;
import android.view.ViewGroup; import android.view.ViewGroup;
import com.android.keyguard.KeyguardHostViewController; import com.android.keyguard.KeyguardSecurityContainerController;
import com.android.systemui.dagger.qualifiers.RootView; import com.android.systemui.dagger.qualifiers.RootView;
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor; import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor;
@@ -37,6 +37,6 @@ public interface KeyguardBouncerComponent {
KeyguardBouncerComponent create(@BindsInstance @RootView ViewGroup bouncerContainer); KeyguardBouncerComponent create(@BindsInstance @RootView ViewGroup bouncerContainer);
} }
/** Returns a {@link KeyguardHostViewController}. */ /** Returns a {@link KeyguardSecurityContainerController}. */
KeyguardHostViewController getKeyguardHostViewController(); KeyguardSecurityContainerController getSecurityContainerController();
} }

View File

@@ -23,7 +23,6 @@ import android.hardware.fingerprint.FingerprintManager;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.ViewGroup; import android.view.ViewGroup;
import com.android.keyguard.KeyguardHostView;
import com.android.keyguard.KeyguardSecurityContainer; import com.android.keyguard.KeyguardSecurityContainer;
import com.android.keyguard.KeyguardSecurityViewFlipper; import com.android.keyguard.KeyguardSecurityViewFlipper;
import com.android.systemui.R; import com.android.systemui.R;
@@ -47,19 +46,13 @@ public interface KeyguardBouncerModule {
/** */ /** */
@Provides @Provides
@KeyguardBouncerScope @KeyguardBouncerScope
static KeyguardHostView providesKeyguardHostView(@RootView ViewGroup rootView, static KeyguardSecurityContainer providesKeyguardSecurityContainer(@RootView ViewGroup rootView,
LayoutInflater layoutInflater) { LayoutInflater layoutInflater) {
KeyguardHostView hostView = (KeyguardHostView) layoutInflater.inflate( KeyguardSecurityContainer securityContainer =
R.layout.keyguard_host_view, rootView, false); (KeyguardSecurityContainer) layoutInflater.inflate(
rootView.addView(hostView); R.layout.keyguard_security_container_view, rootView, false);
return hostView; rootView.addView(securityContainer);
} return securityContainer;
/** */
@Provides
@KeyguardBouncerScope
static KeyguardSecurityContainer providesKeyguardSecurityContainer(KeyguardHostView hostView) {
return hostView.findViewById(R.id.keyguard_security_container);
} }
/** */ /** */

View File

@@ -23,10 +23,12 @@ import android.window.OnBackAnimationCallback
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle import androidx.lifecycle.repeatOnLifecycle
import com.android.internal.policy.SystemBarUtils import com.android.internal.policy.SystemBarUtils
import com.android.keyguard.KeyguardHostViewController import com.android.keyguard.KeyguardSecurityContainerController
import com.android.keyguard.KeyguardSecurityModel import com.android.keyguard.KeyguardSecurityModel
import com.android.keyguard.KeyguardSecurityView
import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.dagger.KeyguardBouncerComponent import com.android.keyguard.dagger.KeyguardBouncerComponent
import com.android.settingslib.Utils
import com.android.systemui.keyguard.data.BouncerViewDelegate import com.android.systemui.keyguard.data.BouncerViewDelegate
import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel
@@ -44,52 +46,54 @@ object KeyguardBouncerViewBinder {
viewModel: KeyguardBouncerViewModel, viewModel: KeyguardBouncerViewModel,
componentFactory: KeyguardBouncerComponent.Factory componentFactory: KeyguardBouncerComponent.Factory
) { ) {
// Builds the KeyguardHostViewController from bouncer view group. // Builds the KeyguardSecurityContainerController from bouncer view group.
val hostViewController: KeyguardHostViewController = val securityContainerController: KeyguardSecurityContainerController =
componentFactory.create(view).keyguardHostViewController componentFactory.create(view).securityContainerController
hostViewController.init() securityContainerController.init()
val delegate = val delegate =
object : BouncerViewDelegate { object : BouncerViewDelegate {
override fun isFullScreenBouncer(): Boolean { override fun isFullScreenBouncer(): Boolean {
val mode = hostViewController.currentSecurityMode val mode = securityContainerController.currentSecurityMode
return mode == KeyguardSecurityModel.SecurityMode.SimPin || return mode == KeyguardSecurityModel.SecurityMode.SimPin ||
mode == KeyguardSecurityModel.SecurityMode.SimPuk mode == KeyguardSecurityModel.SecurityMode.SimPuk
} }
override fun getBackCallback(): OnBackAnimationCallback { override fun getBackCallback(): OnBackAnimationCallback {
return hostViewController.backCallback return securityContainerController.backCallback
} }
override fun shouldDismissOnMenuPressed(): Boolean { override fun shouldDismissOnMenuPressed(): Boolean {
return hostViewController.shouldEnableMenuKey() return securityContainerController.shouldEnableMenuKey()
} }
override fun interceptMediaKey(event: KeyEvent?): Boolean { override fun interceptMediaKey(event: KeyEvent?): Boolean {
return hostViewController.interceptMediaKey(event) return securityContainerController.interceptMediaKey(event)
} }
override fun dispatchBackKeyEventPreIme(): Boolean { override fun dispatchBackKeyEventPreIme(): Boolean {
return hostViewController.dispatchBackKeyEventPreIme() return securityContainerController.dispatchBackKeyEventPreIme()
} }
override fun showNextSecurityScreenOrFinish(): Boolean { override fun showNextSecurityScreenOrFinish(): Boolean {
return hostViewController.dismiss(KeyguardUpdateMonitor.getCurrentUser()) return securityContainerController.dismiss(
KeyguardUpdateMonitor.getCurrentUser()
)
} }
override fun resume() { override fun resume() {
hostViewController.showPrimarySecurityScreen() securityContainerController.showPrimarySecurityScreen(/* isTurningOff= */ false)
hostViewController.onResume() securityContainerController.onResume(KeyguardSecurityView.SCREEN_ON)
} }
override fun setDismissAction( override fun setDismissAction(
onDismissAction: ActivityStarter.OnDismissAction?, onDismissAction: ActivityStarter.OnDismissAction?,
cancelAction: Runnable? cancelAction: Runnable?
) { ) {
hostViewController.setOnDismissAction(onDismissAction, cancelAction) securityContainerController.setOnDismissAction(onDismissAction, cancelAction)
} }
override fun willDismissWithActions(): Boolean { override fun willDismissWithActions(): Boolean {
return hostViewController.hasDismissActions() return securityContainerController.hasDismissActions()
} }
} }
view.repeatWhenAttached { view.repeatWhenAttached {
@@ -98,39 +102,46 @@ object KeyguardBouncerViewBinder {
viewModel.setBouncerViewDelegate(delegate) viewModel.setBouncerViewDelegate(delegate)
launch { launch {
viewModel.show.collect { viewModel.show.collect {
hostViewController.showPromptReason(it.promptReason) securityContainerController.showPromptReason(it.promptReason)
it.errorMessage?.let { errorMessage -> it.errorMessage?.let { errorMessage ->
hostViewController.showErrorMessage(errorMessage) securityContainerController.showMessage(
errorMessage,
Utils.getColorError(view.context)
)
} }
hostViewController.showPrimarySecurityScreen() securityContainerController.showPrimarySecurityScreen(
hostViewController.appear( /* turningOff= */ false
)
securityContainerController.appear(
SystemBarUtils.getStatusBarHeight(view.context) SystemBarUtils.getStatusBarHeight(view.context)
) )
hostViewController.onResume() securityContainerController.onResume(KeyguardSecurityView.SCREEN_ON)
} }
} }
launch { launch {
viewModel.hide.collect { viewModel.hide.collect {
hostViewController.cancelDismissAction() securityContainerController.cancelDismissAction()
hostViewController.cleanUp() securityContainerController.onPause()
hostViewController.resetSecurityContainer() securityContainerController.reset()
} }
} }
launch { launch {
viewModel.startingToHide.collect { hostViewController.onStartingToHide() } viewModel.startingToHide.collect {
securityContainerController.onStartingToHide()
}
} }
launch { launch {
viewModel.startDisappearAnimation.collect { viewModel.startDisappearAnimation.collect {
hostViewController.startDisappearAnimation(it) securityContainerController.startDisappearAnimation(it)
} }
} }
launch { launch {
viewModel.bouncerExpansionAmount.collect { expansion -> viewModel.bouncerExpansionAmount.collect { expansion ->
hostViewController.setExpansion(expansion) securityContainerController.setExpansion(expansion)
} }
} }
@@ -138,10 +149,8 @@ object KeyguardBouncerViewBinder {
viewModel.bouncerExpansionAmount viewModel.bouncerExpansionAmount
.filter { it == EXPANSION_VISIBLE } .filter { it == EXPANSION_VISIBLE }
.collect { .collect {
hostViewController.onResume() securityContainerController.onResume(KeyguardSecurityView.SCREEN_ON)
view.announceForAccessibility( view.announceForAccessibility(securityContainerController.title)
hostViewController.accessibilityTitleForCurrentMode
)
} }
} }
@@ -149,13 +158,13 @@ object KeyguardBouncerViewBinder {
viewModel.isBouncerVisible.collect { isVisible -> viewModel.isBouncerVisible.collect { isVisible ->
val visibility = if (isVisible) View.VISIBLE else View.INVISIBLE val visibility = if (isVisible) View.VISIBLE else View.INVISIBLE
view.visibility = visibility view.visibility = visibility
hostViewController.onBouncerVisibilityChanged(visibility) securityContainerController.onBouncerVisibilityChanged(visibility)
} }
} }
launch { launch {
viewModel.isInteractable.collect { isInteractable -> viewModel.isInteractable.collect { isInteractable ->
hostViewController.setInteractable(isInteractable) securityContainerController.setInteractable(isInteractable)
} }
} }
@@ -164,33 +173,36 @@ object KeyguardBouncerViewBinder {
.filter { !it } .filter { !it }
.collect { .collect {
// Remove existing input for security reasons. // Remove existing input for security reasons.
hostViewController.resetSecurityContainer() securityContainerController.reset()
} }
} }
launch { launch {
viewModel.keyguardPosition.collect { position -> viewModel.keyguardPosition.collect { position ->
hostViewController.updateKeyguardPosition(position) securityContainerController.updateKeyguardPosition(position)
} }
} }
launch { launch {
viewModel.updateResources.collect { viewModel.updateResources.collect {
hostViewController.updateResources() securityContainerController.updateResources()
viewModel.notifyUpdateResources() viewModel.notifyUpdateResources()
} }
} }
launch { launch {
viewModel.bouncerShowMessage.collect { viewModel.bouncerShowMessage.collect {
hostViewController.showMessage(it.message, it.colorStateList) securityContainerController.showMessage(it.message, it.colorStateList)
viewModel.onMessageShown() viewModel.onMessageShown()
} }
} }
launch { launch {
viewModel.keyguardAuthenticated.collect { viewModel.keyguardAuthenticated.collect {
hostViewController.finish(it, KeyguardUpdateMonitor.getCurrentUser()) securityContainerController.finish(
it,
KeyguardUpdateMonitor.getCurrentUser()
)
viewModel.notifyKeyguardAuthenticated() viewModel.notifyKeyguardAuthenticated()
} }
} }
@@ -204,7 +216,7 @@ object KeyguardBouncerViewBinder {
launch { launch {
viewModel.screenTurnedOff.collect { viewModel.screenTurnedOff.collect {
if (view.visibility == View.VISIBLE) { if (view.visibility == View.VISIBLE) {
hostViewController.onPause() securityContainerController.onPause()
} }
} }
} }

View File

@@ -1,186 +0,0 @@
/*
* Copyright (C) 2018 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.keyguard;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.media.AudioManager;
import android.telephony.TelephonyManager;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableResources;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class KeyguardHostViewControllerTest extends SysuiTestCase {
@Mock
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private KeyguardHostView mKeyguardHostView;
@Mock
private AudioManager mAudioManager;
@Mock
private TelephonyManager mTelephonyManager;
@Mock
private ViewMediatorCallback mViewMediatorCallback;
@Mock
KeyguardSecurityContainerController.Factory mKeyguardSecurityContainerControllerFactory;
@Mock
private KeyguardSecurityContainerController mKeyguardSecurityContainerController;
@Rule
public MockitoRule mMockitoRule = MockitoJUnit.rule();
private TestableResources mTestableResources;
private KeyguardHostViewController mKeyguardHostViewController;
@Before
public void setup() {
mTestableResources = mContext.getOrCreateTestableResources();
mKeyguardHostView = new KeyguardHostView(mContext);
// Explicitly disable one handed keyguard.
mTestableResources.addOverride(
R.bool.can_use_one_handed_bouncer, false);
when(mKeyguardSecurityContainerControllerFactory.create(any(
KeyguardSecurityContainer.SecurityCallback.class)))
.thenReturn(mKeyguardSecurityContainerController);
mKeyguardHostViewController = new KeyguardHostViewController(
mKeyguardHostView, mKeyguardUpdateMonitor, mAudioManager, mTelephonyManager,
mViewMediatorCallback, mKeyguardSecurityContainerControllerFactory);
}
@Test
public void testHasDismissActions() {
assertFalse("Action not set yet", mKeyguardHostViewController.hasDismissActions());
mKeyguardHostViewController.setOnDismissAction(mock(OnDismissAction.class),
null /* cancelAction */);
assertTrue("Action should exist", mKeyguardHostViewController.hasDismissActions());
}
@Test
public void testOnStartingToHide() {
mKeyguardHostViewController.onStartingToHide();
verify(mKeyguardSecurityContainerController).onStartingToHide();
}
@Test
public void onBouncerVisible_propagatesToKeyguardSecurityContainerController() {
mKeyguardHostViewController.onBouncerVisibilityChanged(ViewGroup.VISIBLE);
mKeyguardHostViewController.onBouncerVisibilityChanged(ViewGroup.INVISIBLE);
InOrder order = inOrder(mKeyguardSecurityContainerController);
order.verify(mKeyguardSecurityContainerController).onBouncerVisibilityChanged(View.VISIBLE);
order.verify(mKeyguardSecurityContainerController).onBouncerVisibilityChanged(
View.INVISIBLE);
}
@Test
public void testGravityReappliedOnConfigurationChange() {
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
mKeyguardHostView.setLayoutParams(lp);
// Set initial gravity
mTestableResources.addOverride(R.integer.keyguard_host_view_gravity,
Gravity.CENTER);
// Kick off the initial pass...
mKeyguardHostViewController.init();
assertEquals(
((FrameLayout.LayoutParams) mKeyguardHostView.getLayoutParams()).gravity,
Gravity.CENTER);
// Now simulate a config change
mTestableResources.addOverride(R.integer.keyguard_host_view_gravity,
Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
mKeyguardHostViewController.updateResources();
assertEquals(
((FrameLayout.LayoutParams) mKeyguardHostView.getLayoutParams()).gravity,
Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
}
@Test
public void testGravityUsesOneHandGravityWhenApplicable() {
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
mKeyguardHostView.setLayoutParams(lp);
mTestableResources.addOverride(
R.integer.keyguard_host_view_gravity,
Gravity.CENTER);
mTestableResources.addOverride(
R.integer.keyguard_host_view_one_handed_gravity,
Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
// Start disabled.
mTestableResources.addOverride(
R.bool.can_use_one_handed_bouncer, false);
mKeyguardHostViewController.init();
assertEquals(
((FrameLayout.LayoutParams) mKeyguardHostView.getLayoutParams()).gravity,
Gravity.CENTER);
// And enable
mTestableResources.addOverride(
R.bool.can_use_one_handed_bouncer, true);
mKeyguardHostViewController.updateResources();
assertEquals(
((FrameLayout.LayoutParams) mKeyguardHostView.getLayoutParams()).gravity,
Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
}
@Test
public void testUpdateKeyguardPositionDelegatesToSecurityContainer() {
mKeyguardHostViewController.updateKeyguardPosition(1.0f);
verify(mKeyguardSecurityContainerController).updateKeyguardPosition(1.0f);
}
}

View File

@@ -23,12 +23,17 @@ import static com.android.keyguard.KeyguardSecurityContainer.MODE_ONE_HANDED;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset; import static org.mockito.Mockito.reset;
@@ -39,12 +44,17 @@ import static org.mockito.Mockito.when;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.content.res.Resources; import android.content.res.Resources;
import android.hardware.biometrics.BiometricSourceType; import android.hardware.biometrics.BiometricSourceType;
import android.media.AudioManager;
import android.telephony.TelephonyManager;
import android.testing.AndroidTestingRunner; import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper; import android.testing.TestableLooper;
import android.testing.TestableResources;
import android.view.Gravity;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.WindowInsetsController; import android.view.WindowInsetsController;
import android.widget.FrameLayout;
import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest;
@@ -60,6 +70,7 @@ import com.android.systemui.classifier.FalsingA11yDelegate;
import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.log.SessionTracker; import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -71,6 +82,7 @@ import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatcher;
import org.mockito.Captor; import org.mockito.Captor;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoJUnit;
@@ -108,8 +120,6 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
@Mock @Mock
private KeyguardInputViewController mInputViewController; private KeyguardInputViewController mInputViewController;
@Mock @Mock
private KeyguardSecurityContainer.SecurityCallback mSecurityCallback;
@Mock
private WindowInsetsController mWindowInsetsController; private WindowInsetsController mWindowInsetsController;
@Mock @Mock
private KeyguardSecurityViewFlipper mSecurityViewFlipper; private KeyguardSecurityViewFlipper mSecurityViewFlipper;
@@ -126,8 +136,6 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
@Mock @Mock
private EmergencyButtonController mEmergencyButtonController; private EmergencyButtonController mEmergencyButtonController;
@Mock @Mock
private Resources mResources;
@Mock
private FalsingCollector mFalsingCollector; private FalsingCollector mFalsingCollector;
@Mock @Mock
private FalsingManager mFalsingManager; private FalsingManager mFalsingManager;
@@ -147,6 +155,12 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
private KeyguardPasswordViewController mKeyguardPasswordViewControllerMock; private KeyguardPasswordViewController mKeyguardPasswordViewControllerMock;
@Mock @Mock
private FalsingA11yDelegate mFalsingA11yDelegate; private FalsingA11yDelegate mFalsingA11yDelegate;
@Mock
private TelephonyManager mTelephonyManager;
@Mock
private ViewMediatorCallback mViewMediatorCallback;
@Mock
private AudioManager mAudioManager;
@Captor @Captor
private ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardUpdateMonitorCallback; private ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardUpdateMonitorCallback;
@@ -158,18 +172,25 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
private KeyguardSecurityContainerController mKeyguardSecurityContainerController; private KeyguardSecurityContainerController mKeyguardSecurityContainerController;
private KeyguardPasswordViewController mKeyguardPasswordViewController; private KeyguardPasswordViewController mKeyguardPasswordViewController;
private KeyguardPasswordView mKeyguardPasswordView; private KeyguardPasswordView mKeyguardPasswordView;
private TestableResources mTestableResources;
@Before @Before
public void setup() { public void setup() {
mConfiguration = new Configuration(); mConfiguration = new Configuration();
mConfiguration.setToDefaults(); // Defaults to ORIENTATION_UNDEFINED. mConfiguration.setToDefaults(); // Defaults to ORIENTATION_UNDEFINED.
mTestableResources = mContext.getOrCreateTestableResources();
when(mResources.getConfiguration()).thenReturn(mConfiguration);
when(mView.getContext()).thenReturn(mContext); when(mView.getContext()).thenReturn(mContext);
when(mView.getResources()).thenReturn(mResources); when(mView.getResources()).thenReturn(mContext.getResources());
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(/* width= */ 0, /* height= */
0);
lp.gravity = 0;
when(mView.getLayoutParams()).thenReturn(lp);
when(mAdminSecondaryLockScreenControllerFactory.create(any(KeyguardSecurityCallback.class))) when(mAdminSecondaryLockScreenControllerFactory.create(any(KeyguardSecurityCallback.class)))
.thenReturn(mAdminSecondaryLockScreenController); .thenReturn(mAdminSecondaryLockScreenController);
when(mSecurityViewFlipper.getWindowInsetsController()).thenReturn(mWindowInsetsController); when(mSecurityViewFlipper.getWindowInsetsController()).thenReturn(mWindowInsetsController);
when(mKeyguardSecurityViewFlipperController.getSecurityView(any(SecurityMode.class),
any(KeyguardSecurityCallback.class))).thenReturn(mInputViewController);
mKeyguardPasswordView = spy((KeyguardPasswordView) LayoutInflater.from(mContext).inflate( mKeyguardPasswordView = spy((KeyguardPasswordView) LayoutInflater.from(mContext).inflate(
R.layout.keyguard_password_view, null)); R.layout.keyguard_password_view, null));
when(mKeyguardPasswordView.getRootView()).thenReturn(mSecurityViewFlipper); when(mKeyguardPasswordView.getRootView()).thenReturn(mSecurityViewFlipper);
@@ -178,20 +199,21 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
when(mKeyguardMessageAreaControllerFactory.create(any(KeyguardMessageArea.class))) when(mKeyguardMessageAreaControllerFactory.create(any(KeyguardMessageArea.class)))
.thenReturn(mKeyguardMessageAreaController); .thenReturn(mKeyguardMessageAreaController);
when(mKeyguardPasswordView.getWindowInsetsController()).thenReturn(mWindowInsetsController); when(mKeyguardPasswordView.getWindowInsetsController()).thenReturn(mWindowInsetsController);
when(mKeyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(SecurityMode.PIN);
mKeyguardPasswordViewController = new KeyguardPasswordViewController( mKeyguardPasswordViewController = new KeyguardPasswordViewController(
(KeyguardPasswordView) mKeyguardPasswordView, mKeyguardUpdateMonitor, (KeyguardPasswordView) mKeyguardPasswordView, mKeyguardUpdateMonitor,
SecurityMode.Password, mLockPatternUtils, null, SecurityMode.Password, mLockPatternUtils, null,
mKeyguardMessageAreaControllerFactory, null, null, mEmergencyButtonController, mKeyguardMessageAreaControllerFactory, null, null, mEmergencyButtonController,
null, mock(Resources.class), null, mKeyguardViewController); null, mock(Resources.class), null, mKeyguardViewController);
mKeyguardSecurityContainerController = new KeyguardSecurityContainerController.Factory( mKeyguardSecurityContainerController = new KeyguardSecurityContainerController(
mView, mAdminSecondaryLockScreenControllerFactory, mLockPatternUtils, mView, mAdminSecondaryLockScreenControllerFactory, mLockPatternUtils,
mKeyguardUpdateMonitor, mKeyguardSecurityModel, mMetricsLogger, mUiEventLogger, mKeyguardUpdateMonitor, mKeyguardSecurityModel, mMetricsLogger, mUiEventLogger,
mKeyguardStateController, mKeyguardSecurityViewFlipperController, mKeyguardStateController, mKeyguardSecurityViewFlipperController,
mConfigurationController, mFalsingCollector, mFalsingManager, mConfigurationController, mFalsingCollector, mFalsingManager,
mUserSwitcherController, mFeatureFlags, mGlobalSettings, mUserSwitcherController, mFeatureFlags, mGlobalSettings,
mSessionTracker, Optional.of(mSideFpsController), mFalsingA11yDelegate).create( mSessionTracker, Optional.of(mSideFpsController), mFalsingA11yDelegate,
mSecurityCallback); mTelephonyManager, mViewMediatorCallback, mAudioManager);
} }
@Test @Test
@@ -243,7 +265,8 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
eq(mFalsingA11yDelegate)); eq(mFalsingA11yDelegate));
// Update rotation. Should trigger update // Update rotation. Should trigger update
mConfiguration.orientation = Configuration.ORIENTATION_LANDSCAPE; mTestableResources.getResources().getConfiguration().orientation =
Configuration.ORIENTATION_LANDSCAPE;
mKeyguardSecurityContainerController.updateResources(); mKeyguardSecurityContainerController.updateResources();
verify(mView).initMode(eq(MODE_DEFAULT), eq(mGlobalSettings), eq(mFalsingManager), verify(mView).initMode(eq(MODE_DEFAULT), eq(mGlobalSettings), eq(mFalsingManager),
@@ -277,7 +300,7 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
@Test @Test
public void showSecurityScreen_oneHandedMode_flagDisabled_noOneHandedMode() { public void showSecurityScreen_oneHandedMode_flagDisabled_noOneHandedMode() {
when(mResources.getBoolean(R.bool.can_use_one_handed_bouncer)).thenReturn(false); mTestableResources.addOverride(R.bool.can_use_one_handed_bouncer, false);
when(mKeyguardSecurityViewFlipperController.getSecurityView( when(mKeyguardSecurityViewFlipperController.getSecurityView(
eq(SecurityMode.Pattern), any(KeyguardSecurityCallback.class))) eq(SecurityMode.Pattern), any(KeyguardSecurityCallback.class)))
.thenReturn((KeyguardInputViewController) mKeyguardPasswordViewController); .thenReturn((KeyguardInputViewController) mKeyguardPasswordViewController);
@@ -291,7 +314,7 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
@Test @Test
public void showSecurityScreen_oneHandedMode_flagEnabled_oneHandedMode() { public void showSecurityScreen_oneHandedMode_flagEnabled_oneHandedMode() {
when(mResources.getBoolean(R.bool.can_use_one_handed_bouncer)).thenReturn(true); mTestableResources.addOverride(R.bool.can_use_one_handed_bouncer, true);
when(mKeyguardSecurityViewFlipperController.getSecurityView( when(mKeyguardSecurityViewFlipperController.getSecurityView(
eq(SecurityMode.Pattern), any(KeyguardSecurityCallback.class))) eq(SecurityMode.Pattern), any(KeyguardSecurityCallback.class)))
.thenReturn((KeyguardInputViewController) mKeyguardPasswordViewController); .thenReturn((KeyguardInputViewController) mKeyguardPasswordViewController);
@@ -305,7 +328,7 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
@Test @Test
public void showSecurityScreen_twoHandedMode_flagEnabled_noOneHandedMode() { public void showSecurityScreen_twoHandedMode_flagEnabled_noOneHandedMode() {
when(mResources.getBoolean(R.bool.can_use_one_handed_bouncer)).thenReturn(true); mTestableResources.addOverride(R.bool.can_use_one_handed_bouncer, true);
setupGetSecurityView(); setupGetSecurityView();
mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Password); mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Password);
@@ -482,7 +505,9 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
SecurityMode.SimPin); SecurityMode.SimPin);
// THEN the next security method of PIN is set, and the keyguard is not marked as done // THEN the next security method of PIN is set, and the keyguard is not marked as done
verify(mSecurityCallback, never()).finish(anyBoolean(), anyInt());
verify(mViewMediatorCallback, never()).keyguardDonePending(anyBoolean(), anyInt());
verify(mViewMediatorCallback, never()).keyguardDone(anyBoolean(), anyInt());
assertThat(mKeyguardSecurityContainerController.getCurrentSecurityMode()) assertThat(mKeyguardSecurityContainerController.getCurrentSecurityMode())
.isEqualTo(SecurityMode.PIN); .isEqualTo(SecurityMode.PIN);
} }
@@ -556,17 +581,19 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
} }
@Test @Test
public void onDensityorFontScaleChanged() { public void onDensityOrFontScaleChanged() {
ArgumentCaptor<ConfigurationController.ConfigurationListener> ArgumentCaptor<ConfigurationController.ConfigurationListener>
configurationListenerArgumentCaptor = ArgumentCaptor.forClass( configurationListenerArgumentCaptor = ArgumentCaptor.forClass(
ConfigurationController.ConfigurationListener.class); ConfigurationController.ConfigurationListener.class);
mKeyguardSecurityContainerController.onViewAttached(); mKeyguardSecurityContainerController.onViewAttached();
verify(mConfigurationController).addCallback(configurationListenerArgumentCaptor.capture()); verify(mConfigurationController).addCallback(configurationListenerArgumentCaptor.capture());
clearInvocations(mKeyguardSecurityViewFlipperController);
configurationListenerArgumentCaptor.getValue().onDensityOrFontScaleChanged(); configurationListenerArgumentCaptor.getValue().onDensityOrFontScaleChanged();
verify(mView).onDensityOrFontScaleChanged(); verify(mView).onDensityOrFontScaleChanged();
verify(mKeyguardSecurityViewFlipperController).clearViews(); verify(mKeyguardSecurityViewFlipperController).clearViews();
verify(mKeyguardSecurityViewFlipperController).getSecurityView(any(SecurityMode.class), verify(mKeyguardSecurityViewFlipperController).getSecurityView(eq(SecurityMode.PIN),
any(KeyguardSecurityCallback.class)); any(KeyguardSecurityCallback.class));
} }
@@ -577,11 +604,13 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
ConfigurationController.ConfigurationListener.class); ConfigurationController.ConfigurationListener.class);
mKeyguardSecurityContainerController.onViewAttached(); mKeyguardSecurityContainerController.onViewAttached();
verify(mConfigurationController).addCallback(configurationListenerArgumentCaptor.capture()); verify(mConfigurationController).addCallback(configurationListenerArgumentCaptor.capture());
clearInvocations(mKeyguardSecurityViewFlipperController);
configurationListenerArgumentCaptor.getValue().onThemeChanged(); configurationListenerArgumentCaptor.getValue().onThemeChanged();
verify(mView).reloadColors(); verify(mView).reloadColors();
verify(mKeyguardSecurityViewFlipperController).clearViews(); verify(mKeyguardSecurityViewFlipperController).clearViews();
verify(mKeyguardSecurityViewFlipperController).getSecurityView(any(SecurityMode.class), verify(mKeyguardSecurityViewFlipperController).getSecurityView(eq(SecurityMode.PIN),
any(KeyguardSecurityCallback.class)); any(KeyguardSecurityCallback.class));
} }
@@ -592,14 +621,90 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
ConfigurationController.ConfigurationListener.class); ConfigurationController.ConfigurationListener.class);
mKeyguardSecurityContainerController.onViewAttached(); mKeyguardSecurityContainerController.onViewAttached();
verify(mConfigurationController).addCallback(configurationListenerArgumentCaptor.capture()); verify(mConfigurationController).addCallback(configurationListenerArgumentCaptor.capture());
clearInvocations(mKeyguardSecurityViewFlipperController);
configurationListenerArgumentCaptor.getValue().onUiModeChanged(); configurationListenerArgumentCaptor.getValue().onUiModeChanged();
verify(mView).reloadColors(); verify(mView).reloadColors();
verify(mKeyguardSecurityViewFlipperController).clearViews(); verify(mKeyguardSecurityViewFlipperController).clearViews();
verify(mKeyguardSecurityViewFlipperController).getSecurityView(any(SecurityMode.class), verify(mKeyguardSecurityViewFlipperController).getSecurityView(eq(SecurityMode.PIN),
any(KeyguardSecurityCallback.class)); any(KeyguardSecurityCallback.class));
} }
@Test
public void testHasDismissActions() {
assertFalse("Action not set yet", mKeyguardSecurityContainerController.hasDismissActions());
mKeyguardSecurityContainerController.setOnDismissAction(mock(
ActivityStarter.OnDismissAction.class),
null /* cancelAction */);
assertTrue("Action should exist", mKeyguardSecurityContainerController.hasDismissActions());
}
@Test
public void testOnStartingToHide() {
mKeyguardSecurityContainerController.onStartingToHide();
verify(mInputViewController).onStartingToHide();
}
@Test
public void testGravityReappliedOnConfigurationChange() {
// Set initial gravity
mTestableResources.addOverride(R.integer.keyguard_host_view_gravity,
Gravity.CENTER);
// Kick off the initial pass...
mKeyguardSecurityContainerController.onInit();
verify(mView).setLayoutParams(argThat(
(ArgumentMatcher<FrameLayout.LayoutParams>) argument ->
argument.gravity == Gravity.CENTER));
clearInvocations(mView);
// Now simulate a config change
mTestableResources.addOverride(R.integer.keyguard_host_view_gravity,
Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
mKeyguardSecurityContainerController.updateResources();
verify(mView).setLayoutParams(argThat(
(ArgumentMatcher<FrameLayout.LayoutParams>) argument ->
argument.gravity == (Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM)));
}
@Test
public void testGravityUsesOneHandGravityWhenApplicable() {
mTestableResources.addOverride(
R.integer.keyguard_host_view_gravity,
Gravity.CENTER);
mTestableResources.addOverride(
R.integer.keyguard_host_view_one_handed_gravity,
Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
// Start disabled.
mTestableResources.addOverride(
R.bool.can_use_one_handed_bouncer, false);
mKeyguardSecurityContainerController.onInit();
verify(mView).setLayoutParams(argThat(
(ArgumentMatcher<FrameLayout.LayoutParams>) argument ->
argument.gravity == Gravity.CENTER));
clearInvocations(mView);
// And enable
mTestableResources.addOverride(
R.bool.can_use_one_handed_bouncer, true);
mKeyguardSecurityContainerController.updateResources();
verify(mView).setLayoutParams(argThat(
(ArgumentMatcher<FrameLayout.LayoutParams>) argument ->
argument.gravity == (Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM)));
}
@Test
public void testUpdateKeyguardPositionDelegatesToSecurityContainer() {
mKeyguardSecurityContainerController.updateKeyguardPosition(1.0f);
verify(mView).updatePositionByTouchX(1.0f);
}
private KeyguardSecurityContainer.SwipeListener getRegisteredSwipeListener() { private KeyguardSecurityContainer.SwipeListener getRegisteredSwipeListener() {
mKeyguardSecurityContainerController.onViewAttached(); mKeyguardSecurityContainerController.onViewAttached();
verify(mView).setSwipeListener(mSwipeListenerArgumentCaptor.capture()); verify(mView).setSwipeListener(mSwipeListenerArgumentCaptor.capture());
@@ -625,7 +730,7 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
} }
private void setSideFpsHintEnabledFromResources(boolean enabled) { private void setSideFpsHintEnabledFromResources(boolean enabled) {
when(mResources.getBoolean(R.bool.config_show_sidefps_hint_on_bouncer)).thenReturn( mTestableResources.addOverride(R.bool.config_show_sidefps_hint_on_bouncer,
enabled); enabled);
} }

View File

@@ -21,7 +21,7 @@ import android.testing.TestableLooper.RunWithLooper
import android.view.MotionEvent import android.view.MotionEvent
import android.view.ViewGroup import android.view.ViewGroup
import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardHostViewController import com.android.keyguard.KeyguardSecurityContainerController
import com.android.keyguard.LockIconViewController import com.android.keyguard.LockIconViewController
import com.android.keyguard.dagger.KeyguardBouncerComponent import com.android.keyguard.dagger.KeyguardBouncerComponent
import com.android.systemui.R import com.android.systemui.R
@@ -106,7 +106,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
@Mock lateinit var keyguardBouncerComponentFactory: KeyguardBouncerComponent.Factory @Mock lateinit var keyguardBouncerComponentFactory: KeyguardBouncerComponent.Factory
@Mock lateinit var keyguardBouncerComponent: KeyguardBouncerComponent @Mock lateinit var keyguardBouncerComponent: KeyguardBouncerComponent
@Mock lateinit var keyguardHostViewController: KeyguardHostViewController @Mock lateinit var keyguardSecurityContainerController: KeyguardSecurityContainerController
@Mock lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor @Mock lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
private lateinit var interactionEventHandlerCaptor: ArgumentCaptor<InteractionEventHandler> private lateinit var interactionEventHandlerCaptor: ArgumentCaptor<InteractionEventHandler>
@@ -122,8 +122,8 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
.thenReturn(mock(ViewGroup::class.java)) .thenReturn(mock(ViewGroup::class.java))
whenever(keyguardBouncerComponentFactory.create(any(ViewGroup::class.java))) whenever(keyguardBouncerComponentFactory.create(any(ViewGroup::class.java)))
.thenReturn(keyguardBouncerComponent) .thenReturn(keyguardBouncerComponent)
whenever(keyguardBouncerComponent.keyguardHostViewController) whenever(keyguardBouncerComponent.securityContainerController)
.thenReturn(keyguardHostViewController) .thenReturn(keyguardSecurityContainerController)
underTest = NotificationShadeWindowViewController( underTest = NotificationShadeWindowViewController(
lockscreenShadeTransitionController, lockscreenShadeTransitionController,
FalsingCollectorFake(), FalsingCollectorFake(),

View File

@@ -33,7 +33,7 @@ import android.view.ViewGroup;
import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest;
import com.android.keyguard.KeyguardHostViewController; import com.android.keyguard.KeyguardSecurityContainerController;
import com.android.keyguard.LockIconViewController; import com.android.keyguard.LockIconViewController;
import com.android.keyguard.dagger.KeyguardBouncerComponent; import com.android.keyguard.dagger.KeyguardBouncerComponent;
import com.android.systemui.R; import com.android.systemui.R;
@@ -97,7 +97,7 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase {
@Mock private KeyguardBouncerViewModel mKeyguardBouncerViewModel; @Mock private KeyguardBouncerViewModel mKeyguardBouncerViewModel;
@Mock private KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory; @Mock private KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory;
@Mock private KeyguardBouncerComponent mKeyguardBouncerComponent; @Mock private KeyguardBouncerComponent mKeyguardBouncerComponent;
@Mock private KeyguardHostViewController mKeyguardHostViewController; @Mock private KeyguardSecurityContainerController mKeyguardSecurityContainerController;
@Mock private NotificationInsetsController mNotificationInsetsController; @Mock private NotificationInsetsController mNotificationInsetsController;
@Mock private AlternateBouncerInteractor mAlternateBouncerInteractor; @Mock private AlternateBouncerInteractor mAlternateBouncerInteractor;
@Mock private KeyguardTransitionInteractor mKeyguardTransitionInteractor; @Mock private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
@@ -117,8 +117,8 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase {
when(mView.findViewById(R.id.keyguard_bouncer_container)).thenReturn(mock(ViewGroup.class)); when(mView.findViewById(R.id.keyguard_bouncer_container)).thenReturn(mock(ViewGroup.class));
when(mKeyguardBouncerComponentFactory.create(any(ViewGroup.class))).thenReturn( when(mKeyguardBouncerComponentFactory.create(any(ViewGroup.class))).thenReturn(
mKeyguardBouncerComponent); mKeyguardBouncerComponent);
when(mKeyguardBouncerComponent.getKeyguardHostViewController()).thenReturn( when(mKeyguardBouncerComponent.getSecurityContainerController()).thenReturn(
mKeyguardHostViewController); mKeyguardSecurityContainerController);
when(mStatusBarStateController.isDozing()).thenReturn(false); when(mStatusBarStateController.isDozing()).thenReturn(false);
mDependency.injectTestDependency(ShadeController.class, mShadeController); mDependency.injectTestDependency(ShadeController.class, mShadeController);