Merge changes from topic "b166448040-keyguard-message-area"

* changes:
  3/N Use KeyguardSecurityContainerController in KHVC.
  2/N Use KeyguardHostViewController in KeyguardBouncer.
  1/N Add Controllers for most KeyguardBouncer related views.
This commit is contained in:
Dave Mankoff
2020-09-10 14:02:50 +00:00
committed by Android (Google) Code Review
17 changed files with 1096 additions and 596 deletions

View File

@@ -30,7 +30,6 @@ import androidx.annotation.VisibleForTesting;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardViewController;
import com.android.keyguard.ViewMediatorCallback;
import com.android.keyguard.dagger.KeyguardBouncerComponent;
import com.android.systemui.R;
import com.android.systemui.car.CarServiceProvider;
import com.android.systemui.car.navigationbar.CarNavigationBarController;
@@ -40,6 +39,7 @@ import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
import com.android.systemui.statusbar.phone.KeyguardBouncer;
import com.android.systemui.statusbar.phone.KeyguardBouncer.Factory;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationPanelViewController;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -66,7 +66,7 @@ public class CarKeyguardViewController extends OverlayViewController implements
private final Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
private final ViewMediatorCallback mViewMediatorCallback;
private final CarNavigationBarController mCarNavigationBarController;
private final KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory;
private final Factory mKeyguardBouncerFactory;
// Needed to instantiate mBouncer.
private final KeyguardBouncer.BouncerExpansionCallback
mExpansionCallback = new KeyguardBouncer.BouncerExpansionCallback() {
@@ -107,7 +107,7 @@ public class CarKeyguardViewController extends OverlayViewController implements
Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
ViewMediatorCallback viewMediatorCallback,
CarNavigationBarController carNavigationBarController,
KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory) {
KeyguardBouncer.Factory keyguardBouncerFactory) {
super(R.id.keyguard_stub, overlayViewGlobalStateController);
@@ -118,7 +118,7 @@ public class CarKeyguardViewController extends OverlayViewController implements
mBiometricUnlockControllerLazy = biometricUnlockControllerLazy;
mViewMediatorCallback = viewMediatorCallback;
mCarNavigationBarController = carNavigationBarController;
mKeyguardBouncerComponentFactory = keyguardBouncerComponentFactory;
mKeyguardBouncerFactory = keyguardBouncerFactory;
registerUserSwitchedListener();
}
@@ -130,9 +130,8 @@ public class CarKeyguardViewController extends OverlayViewController implements
@Override
public void onFinishInflate() {
mBouncer = mKeyguardBouncerComponentFactory
.build(getLayout().findViewById(R.id.keyguard_container), mExpansionCallback)
.createKeyguardBouncer();
mBouncer = mKeyguardBouncerFactory
.create(getLayout().findViewById(R.id.keyguard_container), mExpansionCallback);
mBiometricUnlockControllerLazy.get().setKeyguardViewController(this);
}

View File

@@ -36,7 +36,6 @@ import androidx.test.filters.SmallTest;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.ViewMediatorCallback;
import com.android.keyguard.dagger.KeyguardBouncerComponent;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.car.CarServiceProvider;
@@ -67,9 +66,7 @@ public class CarKeyguardViewControllerTest extends SysuiTestCase {
@Mock
private CarKeyguardViewController.OnKeyguardCancelClickedListener mCancelClickedListener;
@Mock
private KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory;
@Mock
private KeyguardBouncerComponent mKeyguardBouncerComponent;
private KeyguardBouncer.Factory mKeyguardBouncerFactory;
@Mock
private KeyguardBouncer mBouncer;
@@ -77,11 +74,10 @@ public class CarKeyguardViewControllerTest extends SysuiTestCase {
public void setUp() {
MockitoAnnotations.initMocks(this);
when(mKeyguardBouncerComponentFactory.build(
when(mKeyguardBouncerFactory.create(
any(ViewGroup.class),
any(KeyguardBouncer.BouncerExpansionCallback.class)))
.thenReturn(mKeyguardBouncerComponent);
when(mKeyguardBouncerComponent.createKeyguardBouncer()).thenReturn(mBouncer);
.thenReturn(mBouncer);
mCarKeyguardViewController = new CarKeyguardViewController(
Handler.getMain(),
@@ -92,7 +88,7 @@ public class CarKeyguardViewControllerTest extends SysuiTestCase {
() -> mock(BiometricUnlockController.class),
mock(ViewMediatorCallback.class),
mock(CarNavigationBarController.class),
mKeyguardBouncerComponentFactory
mKeyguardBouncerFactory
);
mCarKeyguardViewController.inflate((ViewGroup) LayoutInflater.from(mContext).inflate(
R.layout.sysui_overlay_window, /* root= */ null));

View File

@@ -16,32 +16,11 @@
package com.android.keyguard;
import android.app.ActivityManager;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.media.AudioManager;
import android.os.SystemClock;
import android.service.trust.TrustAgentService;
import android.telephony.TelephonyManager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.widget.FrameLayout;
import androidx.annotation.VisibleForTesting;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardSecurityContainer.SecurityCallback;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import java.io.File;
/**
* Base class for keyguard view. {@link #reset} is where you should
* reset the state of your view. Use the {@link KeyguardViewCallback} via
@@ -51,59 +30,10 @@ import java.io.File;
* Handles intercepting of media keys that still work when the keyguard is
* showing.
*/
public class KeyguardHostView extends FrameLayout implements SecurityCallback {
public class KeyguardHostView extends FrameLayout {
private AudioManager mAudioManager;
private TelephonyManager mTelephonyManager = null;
protected ViewMediatorCallback mViewMediatorCallback;
protected LockPatternUtils mLockPatternUtils;
private OnDismissAction mDismissAction;
private Runnable mCancelAction;
private final KeyguardUpdateMonitorCallback mUpdateCallback =
new KeyguardUpdateMonitorCallback() {
@Override
public void onUserSwitchComplete(int userId) {
getSecurityContainer().showPrimarySecurityScreen(false /* turning off */);
}
@Override
public void onTrustGrantedWithFlags(int flags, int userId) {
if (userId != KeyguardUpdateMonitor.getCurrentUser()) return;
if (!isAttachedToWindow()) return;
boolean bouncerVisible = isVisibleToUser();
boolean initiatedByUser =
(flags & TrustAgentService.FLAG_GRANT_TRUST_INITIATED_BY_USER) != 0;
boolean dismissKeyguard =
(flags & TrustAgentService.FLAG_GRANT_TRUST_DISMISS_KEYGUARD) != 0;
if (initiatedByUser || dismissKeyguard) {
if (mViewMediatorCallback.isScreenOn() && (bouncerVisible || dismissKeyguard)) {
if (!bouncerVisible) {
// 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.");
}
dismiss(false /* authenticated */, userId,
/* bypassSecondaryLockScreen */ false);
} else {
mViewMediatorCallback.playTrustedSound();
}
}
}
};
// 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;
public static final boolean DEBUG = KeyguardConstants.DEBUG;
private static final String TAG = "KeyguardViewBase";
@VisibleForTesting
protected KeyguardSecurityContainer mSecurityContainer;
public KeyguardHostView(Context context) {
this(context, null);
@@ -111,7 +41,6 @@ public class KeyguardHostView extends FrameLayout implements SecurityCallback {
public KeyguardHostView(Context context, AttributeSet attrs) {
super(context, attrs);
Dependency.get(KeyguardUpdateMonitor.class).registerCallback(mUpdateCallback);
}
@Override
@@ -122,337 +51,7 @@ public class KeyguardHostView extends FrameLayout implements SecurityCallback {
}
}
/**
* Sets an action to run when keyguard finishes.
*
* @param action
*/
public void setOnDismissAction(OnDismissAction action, Runnable cancelAction) {
if (mCancelAction != null) {
mCancelAction.run();
mCancelAction = null;
}
mDismissAction = action;
mCancelAction = cancelAction;
}
public boolean hasDismissActions() {
return mDismissAction != null || mCancelAction != null;
}
public void cancelDismissAction() {
setOnDismissAction(null, null);
}
@Override
protected void onFinishInflate() {
mSecurityContainer =
findViewById(R.id.keyguard_security_container);
mLockPatternUtils = new LockPatternUtils(mContext);
mSecurityContainer.setLockPatternUtils(mLockPatternUtils);
mSecurityContainer.setSecurityCallback(this);
mSecurityContainer.showPrimarySecurityScreen(false);
}
/**
* Called when the view needs to be shown.
*/
public void showPrimarySecurityScreen() {
if (DEBUG) Log.d(TAG, "show()");
mSecurityContainer.showPrimarySecurityScreen(false);
}
public KeyguardSecurityView getCurrentSecurityView() {
return mSecurityContainer != null ? mSecurityContainer.getCurrentSecurityView() : null;
}
/**
* 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) {
mSecurityContainer.showPromptReason(reason);
}
public void showMessage(CharSequence message, ColorStateList colorState) {
mSecurityContainer.showMessage(message, colorState);
}
public void showErrorMessage(CharSequence message) {
showMessage(message, Utils.getColorError(mContext));
}
/**
* 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 dismiss(false, targetUserId, false);
}
public boolean handleBackKey() {
if (mSecurityContainer.getCurrentSecuritySelection() != SecurityMode.None) {
mSecurityContainer.dismiss(false, KeyguardUpdateMonitor.getCurrentUser());
return true;
}
return false;
}
protected KeyguardSecurityContainer getSecurityContainer() {
return mSecurityContainer;
}
@Override
public boolean dismiss(boolean authenticated, int targetUserId,
boolean bypassSecondaryLockScreen) {
return mSecurityContainer.showNextSecurityScreenOrFinish(authenticated, targetUserId,
bypassSecondaryLockScreen);
}
/**
* 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();
}
public void resetSecurityContainer() {
mSecurityContainer.reset();
}
@Override
public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput) {
if (mViewMediatorCallback != null) {
mViewMediatorCallback.setNeedsInput(needsInput);
}
}
public CharSequence getAccessibilityTitleForCurrentMode() {
return mSecurityContainer.getTitle();
}
public void userActivity() {
if (mViewMediatorCallback != null) {
mViewMediatorCallback.userActivity();
}
}
/**
* 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()));
mSecurityContainer.showPrimarySecurityScreen(true);
mSecurityContainer.onPause();
clearFocus();
}
/**
* Called when the Keyguard is actively shown on the screen.
*/
public void onResume() {
if (DEBUG) Log.d(TAG, "screen on, instance " + Integer.toHexString(hashCode()));
mSecurityContainer.onResume(KeyguardSecurityView.SCREEN_ON);
requestFocus();
}
/**
* Starts the animation when the Keyguard gets shown.
*/
public void startAppearAnimation() {
mSecurityContainer.startAppearAnimation();
}
public void startDisappearAnimation(Runnable finishRunnable) {
if (!mSecurityContainer.startDisappearAnimation(finishRunnable) && finishRunnable != null) {
finishRunnable.run();
}
}
/**
* Called before this view is being removed.
*/
public void cleanUp() {
getSecurityContainer().onPause();
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (interceptMediaKey(event)) {
return true;
}
return super.dispatchKeyEvent(event);
}
/**
* 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) {
final 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 = (TelephonyManager) getContext().getSystemService(
Context.TELEPHONY_SERVICE);
}
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) {
synchronized (this) {
if (mAudioManager == null) {
mAudioManager = (AudioManager) getContext().getSystemService(
Context.AUDIO_SERVICE);
}
}
// 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) {
synchronized (this) {
if (mAudioManager == null) {
mAudioManager = (AudioManager) getContext().getSystemService(
Context.AUDIO_SERVICE);
}
}
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
*/
private static final String ENABLE_MENU_KEY_FILE = "/data/local/enable_menu_key";
public boolean shouldEnableMenuKey() {
final Resources res = 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;
}
public void setViewMediatorCallback(ViewMediatorCallback viewMediatorCallback) {
mViewMediatorCallback = viewMediatorCallback;
// Update ViewMediator with the current input method requirements
mViewMediatorCallback.setNeedsInput(mSecurityContainer.needsInput());
}
public void setLockPatternUtils(LockPatternUtils utils) {
mLockPatternUtils = utils;
mSecurityContainer.setLockPatternUtils(utils);
}
public SecurityMode getSecurityMode() {
return mSecurityContainer.getSecurityMode();
}
public SecurityMode getCurrentSecurityMode() {
return mSecurityContainer.getCurrentSecurityMode();
}
/**
* When bouncer was visible and is starting to become hidden.
*/
public void onStartingToHide() {
mSecurityContainer.onStartingToHide();
}
}

View File

@@ -0,0 +1,460 @@
/*
* 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.service.trust.TrustAgentService;
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 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.statusbar.phone.KeyguardBouncer;
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 final KeyguardUpdateMonitorCallback mUpdateCallback =
new KeyguardUpdateMonitorCallback() {
@Override
public void onUserSwitchComplete(int userId) {
mKeyguardSecurityContainerController.showPrimarySecurityScreen(
false /* turning off */);
}
@Override
public void onTrustGrantedWithFlags(int flags, int userId) {
if (userId != KeyguardUpdateMonitor.getCurrentUser()) return;
boolean bouncerVisible = mView.isVisibleToUser();
boolean initiatedByUser =
(flags & TrustAgentService.FLAG_GRANT_TRUST_INITIATED_BY_USER) != 0;
boolean dismissKeyguard =
(flags & TrustAgentService.FLAG_GRANT_TRUST_DISMISS_KEYGUARD) != 0;
if (initiatedByUser || dismissKeyguard) {
if (mViewMediatorCallback.isScreenOn()
&& (bouncerVisible || dismissKeyguard)) {
if (!bouncerVisible) {
// 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 */, userId,
/* bypassSecondaryLockScreen */ false);
} else {
mViewMediatorCallback.playTrustedSound();
}
}
}
};
private final SecurityCallback mSecurityCallback = new SecurityCallback() {
@Override
public boolean dismiss(boolean authenticated, int targetUserId,
boolean bypassSecondaryLockScreen) {
return mKeyguardSecurityContainerController.showNextSecurityScreenOrFinish(
authenticated, targetUserId, bypassSecondaryLockScreen);
}
@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,
KeyguardSecurityContainerController keyguardSecurityContainerController,
AudioManager audioManager,
TelephonyManager telephonyManager,
ViewMediatorCallback viewMediatorCallback) {
super(view);
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mKeyguardSecurityContainerController = keyguardSecurityContainerController;
mAudioManager = audioManager;
mTelephonyManager = telephonyManager;
mViewMediatorCallback = viewMediatorCallback;
}
/** Initialize the Controller. */
public void init() {
super.init();
mView.setViewMediatorCallback(mViewMediatorCallback);
// Update ViewMediator with the current input method requirements
mViewMediatorCallback.setNeedsInput(mKeyguardSecurityContainerController.needsInput());
mKeyguardSecurityContainerController.init();
mKeyguardSecurityContainerController.setSecurityCallback(mSecurityCallback);
mKeyguardSecurityContainerController.showPrimarySecurityScreen(false);
}
@Override
protected void onViewAttached() {
mKeyguardUpdateMonitor.registerCallback(mUpdateCallback);
mView.setOnKeyListener(mOnKeyListener);
}
@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);
}
/**
* 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);
}
public void setExpansion(float fraction) {
float alpha = MathUtils.map(KeyguardBouncer.ALPHA_EXPANSION_THRESHOLD, 1, 1, 0, fraction);
mView.setAlpha(MathUtils.constrain(alpha, 0f, 1f));
mView.setTranslationY(fraction * mView.getHeight());
}
/**
* When bouncer was visible and is starting to become hidden.
*/
public void onStartingToHide() {
mKeyguardSecurityContainerController.onStartingToHide();
}
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() {
if (mKeyguardSecurityContainerController.getCurrentSecuritySelection()
!= SecurityMode.None) {
mKeyguardSecurityContainerController.dismiss(
false, KeyguardUpdateMonitor.getCurrentUser());
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;
}
/**
* 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);
}
}

View File

@@ -0,0 +1,68 @@
/*
* 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 com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.util.ViewController;
import javax.inject.Inject;
/** Controller for a {@link KeyguardMessageAreaController}. */
public class KeyguardMessageAreaController extends ViewController<KeyguardMessageArea> {
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final ConfigurationController mConfigurationController;
private KeyguardMessageAreaController(KeyguardMessageArea view,
KeyguardUpdateMonitor keyguardUpdateMonitor,
ConfigurationController configurationController) {
super(view);
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mConfigurationController = configurationController;
}
@Override
protected void onViewAttached() {
//mConfigurationController.addCallback();
//mKeyguardUpdateMonitor.registerCallback();
}
@Override
protected void onViewDetached() {
//mConfigurationController.removeCallback();
//mKeyguardUpdateMonitor.removeCallback();
}
/** Factory for createing {@link com.android.keyguard.KeyguardMessageAreaController}. */
public static class Factory {
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final ConfigurationController mConfigurationController;
@Inject
public Factory(KeyguardUpdateMonitor keyguardUpdateMonitor,
ConfigurationController configurationController) {
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mConfigurationController = configurationController;
}
/** Build a new {@link KeyguardMessageAreaController}. */
public KeyguardMessageAreaController create(KeyguardMessageArea view) {
return new KeyguardMessageAreaController(
view, mKeyguardUpdateMonitor, mConfigurationController);
}
}
}

View File

@@ -0,0 +1,48 @@
/*
* 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.view.ViewGroup;
import com.android.keyguard.dagger.KeyguardBouncerScope;
import com.android.keyguard.dagger.RootView;
import com.android.systemui.statusbar.phone.KeyguardBouncer;
import com.android.systemui.util.ViewController;
import javax.inject.Inject;
/** Controller for a {@link KeyguardBouncer}'s Root view. */
@KeyguardBouncerScope
public class KeyguardRootViewController extends ViewController<ViewGroup> {
@Inject
public KeyguardRootViewController(@RootView ViewGroup view) {
super(view);
}
public ViewGroup getView() {
return mView;
}
@Override
protected void onViewAttached() {
}
@Override
protected void onViewDetached() {
}
}

View File

@@ -0,0 +1,118 @@
/*
* 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.content.res.ColorStateList;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardSecurityContainer.SecurityCallback;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.systemui.util.ViewController;
import javax.inject.Inject;
/** Controller for {@link KeyguardSecurityContainer} */
public class KeyguardSecurityContainerController extends ViewController<KeyguardSecurityContainer> {
private final LockPatternUtils mLockPatternUtils;
private final KeyguardSecurityViewController.Factory mKeyguardSecurityViewControllerFactory;
@Inject
KeyguardSecurityContainerController(KeyguardSecurityContainer view,
LockPatternUtils lockPatternUtils,
KeyguardSecurityViewController.Factory keyguardSecurityViewControllerFactory) {
super(view);
mLockPatternUtils = lockPatternUtils;
view.setLockPatternUtils(mLockPatternUtils);
mKeyguardSecurityViewControllerFactory = keyguardSecurityViewControllerFactory;
}
@Override
protected void onViewAttached() {
}
@Override
protected void onViewDetached() {
}
/** */
public void onPause() {
mView.onPause();
}
public void showPrimarySecurityScreen(boolean turningOff) {
mView.showPrimarySecurityScreen(turningOff);
}
public void showPromptReason(int reason) {
mView.showPromptReason(reason);
}
public void showMessage(CharSequence message, ColorStateList colorState) {
mView.showMessage(message, colorState);
}
public SecurityMode getCurrentSecuritySelection() {
return mView.getCurrentSecuritySelection();
}
public void dismiss(boolean authenticated, int targetUserId) {
mView.dismiss(authenticated, targetUserId);
}
public void reset() {
mView.reset();
}
public CharSequence getTitle() {
return mView.getTitle();
}
public void onResume(int screenOn) {
mView.onResume(screenOn);
}
public void startAppearAnimation() {
mView.startAppearAnimation();
}
public boolean startDisappearAnimation(Runnable onFinishRunnable) {
return mView.startDisappearAnimation(onFinishRunnable);
}
public void onStartingToHide() {
mView.onStartingToHide();
}
public void setSecurityCallback(SecurityCallback securityCallback) {
mView.setSecurityCallback(securityCallback);
}
public boolean showNextSecurityScreenOrFinish(boolean authenticated, int targetUserId,
boolean bypassSecondaryLockScreen) {
return mView.showNextSecurityScreenOrFinish(
authenticated, targetUserId, bypassSecondaryLockScreen);
}
public boolean needsInput() {
return mView.needsInput();
}
public SecurityMode getCurrentSecurityMode() {
return mView.getCurrentSecurityMode();
}
}

View File

@@ -0,0 +1,58 @@
/*
* 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.view.View;
import com.android.systemui.util.ViewController;
import javax.inject.Inject;
/** Controller for a {@link KeyguardSecurityView}. */
public class KeyguardSecurityViewController extends ViewController<View> {
private final KeyguardSecurityView mView;
private KeyguardSecurityViewController(KeyguardSecurityView view) {
super((View) view);
// KeyguardSecurityView isn't actually a View, so we need to track it ourselves.
mView = view;
}
@Override
protected void onViewAttached() {
}
@Override
protected void onViewDetached() {
}
/** Factory for a {@link KeyguardSecurityViewController}. */
public static class Factory {
@Inject
public Factory() {
}
/** Create a new {@link KeyguardSecurityViewController}. */
public KeyguardSecurityViewController create(KeyguardSecurityView view) {
return new KeyguardSecurityViewController(view);
}
}
}

View File

@@ -16,27 +16,27 @@
package com.android.keyguard.dagger;
import android.view.ViewGroup;
import com.android.keyguard.KeyguardHostViewController;
import com.android.keyguard.KeyguardRootViewController;
import com.android.systemui.statusbar.phone.KeyguardBouncer;
import dagger.BindsInstance;
import dagger.Subcomponent;
/**
* Dagger Subcomponent for the {@link KeyguardBouncer}.
*/
@Subcomponent
@Subcomponent(modules = {KeyguardBouncerModule.class})
@KeyguardBouncerScope
public interface KeyguardBouncerComponent {
/** Simple factory for {@link KeyguardBouncerComponent}. */
@Subcomponent.Factory
interface Factory {
KeyguardBouncerComponent build(
@BindsInstance @ContainerView ViewGroup container,
@BindsInstance KeyguardBouncer.BouncerExpansionCallback bouncerExpansionCallback);
KeyguardBouncerComponent create();
}
/** */
KeyguardBouncer createKeyguardBouncer();
/** Returns a {@link KeyguardRootViewController}. */
KeyguardRootViewController getKeyguardRootViewController();
/** Returns a {@link KeyguardHostViewController}. */
KeyguardHostViewController getKeyguardHostViewController();
}

View File

@@ -0,0 +1,64 @@
/*
* 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.dagger;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import com.android.keyguard.KeyguardHostView;
import com.android.keyguard.KeyguardMessageArea;
import com.android.keyguard.KeyguardSecurityContainer;
import com.android.systemui.R;
import com.android.systemui.statusbar.phone.KeyguardBouncer;
import dagger.Module;
import dagger.Provides;
/**
* Module to create and access view related to the {@link KeyguardBouncer}.
*/
@Module
public interface KeyguardBouncerModule {
/** */
@Provides
@KeyguardBouncerScope
@RootView
static ViewGroup providesRootView(LayoutInflater layoutInflater) {
return (ViewGroup) layoutInflater.inflate(R.layout.keyguard_bouncer, null);
}
/** */
@Provides
@KeyguardBouncerScope
static KeyguardMessageArea providesKeyguardMessageArea(@RootView ViewGroup viewGroup) {
return viewGroup.findViewById(R.id.keyguard_message_area);
}
/** */
@Provides
@KeyguardBouncerScope
static KeyguardHostView providesKeyguardHostView(@RootView ViewGroup rootView) {
return rootView.findViewById(R.id.keyguard_host_view);
}
/** */
@Provides
@KeyguardBouncerScope
static KeyguardSecurityContainer preovidesKeyguardSecurityContainer(KeyguardHostView hostView) {
return hostView.findViewById(R.id.keyguard_security_container);
}
}

View File

@@ -26,5 +26,5 @@ import javax.inject.Qualifier;
@Qualifier
@Documented
@Retention(RUNTIME)
public @interface ContainerView {
public @interface RootView {
}

View File

@@ -25,26 +25,21 @@ import android.os.Handler;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
import android.util.MathUtils;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.WindowInsets;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardHostView;
import com.android.keyguard.KeyguardHostViewController;
import com.android.keyguard.KeyguardRootViewController;
import com.android.keyguard.KeyguardSecurityModel;
import com.android.keyguard.KeyguardSecurityView;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.ViewMediatorCallback;
import com.android.keyguard.dagger.ContainerView;
import com.android.keyguard.dagger.KeyguardBouncerScope;
import com.android.keyguard.dagger.KeyguardBouncerComponent;
import com.android.keyguard.dagger.RootView;
import com.android.systemui.DejankUtils;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.shared.system.SysUiStatsLog;
@@ -57,18 +52,16 @@ import javax.inject.Inject;
/**
* A class which manages the bouncer on the lockscreen.
*/
@KeyguardBouncerScope
public class KeyguardBouncer {
private static final String TAG = "KeyguardBouncer";
static final long BOUNCER_FACE_DELAY = 1200;
static final float ALPHA_EXPANSION_THRESHOLD = 0.95f;
public static final float ALPHA_EXPANSION_THRESHOLD = 0.95f;
static final float EXPANSION_HIDDEN = 1f;
static final float EXPANSION_VISIBLE = 0f;
protected final Context mContext;
protected final ViewMediatorCallback mCallback;
protected final LockPatternUtils mLockPatternUtils;
protected final ViewGroup mContainer;
private final FalsingManager mFalsingManager;
private final DismissCallbackRegistry mDismissCallbackRegistry;
@@ -76,6 +69,8 @@ public class KeyguardBouncer {
private final BouncerExpansionCallback mExpansionCallback;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final KeyguardStateController mKeyguardStateController;
private final KeyguardSecurityModel mKeyguardSecurityModel;
private final KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory;
private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
new KeyguardUpdateMonitorCallback() {
@Override
@@ -85,32 +80,33 @@ public class KeyguardBouncer {
};
private final Runnable mRemoveViewRunnable = this::removeView;
private final KeyguardBypassController mKeyguardBypassController;
protected KeyguardHostView mKeyguardView;
private KeyguardHostViewController mKeyguardViewController;
private final Runnable mResetRunnable = ()-> {
if (mKeyguardView != null) {
mKeyguardView.resetSecurityContainer();
if (mKeyguardViewController != null) {
mKeyguardViewController.resetSecurityContainer();
}
};
private int mStatusBarHeight;
private float mExpansion = EXPANSION_HIDDEN;
protected ViewGroup mRoot;
private KeyguardRootViewController mRootViewController;
private boolean mShowingSoon;
private int mBouncerPromptReason;
private boolean mIsAnimatingAway;
private boolean mIsScrimmed;
@Inject
public KeyguardBouncer(Context context, ViewMediatorCallback callback,
LockPatternUtils lockPatternUtils, @ContainerView ViewGroup container,
private KeyguardBouncer(Context context, ViewMediatorCallback callback,
ViewGroup container,
DismissCallbackRegistry dismissCallbackRegistry, FalsingManager falsingManager,
BouncerExpansionCallback expansionCallback,
KeyguardStateController keyguardStateController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
KeyguardBypassController keyguardBypassController, Handler handler) {
KeyguardBypassController keyguardBypassController, Handler handler,
KeyguardSecurityModel keyguardSecurityModel,
KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory) {
mContext = context;
mCallback = callback;
mLockPatternUtils = lockPatternUtils;
mContainer = container;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mFalsingManager = falsingManager;
@@ -118,6 +114,8 @@ public class KeyguardBouncer {
mExpansionCallback = expansionCallback;
mHandler = handler;
mKeyguardStateController = keyguardStateController;
mKeyguardSecurityModel = keyguardSecurityModel;
mKeyguardBouncerComponentFactory = keyguardBouncerComponentFactory;
mKeyguardUpdateMonitor.registerCallback(mUpdateMonitorCallback);
mKeyguardBypassController = keyguardBypassController;
}
@@ -168,7 +166,7 @@ public class KeyguardBouncer {
// If allowed, try to dismiss the Keyguard. If no security auth (password/pin/pattern) is
// set, this will dismiss the whole Keyguard. Otherwise, show the bouncer.
if (allowDismissKeyguard && mKeyguardView.dismiss(activeUserId)) {
if (allowDismissKeyguard && mKeyguardViewController.dismiss(activeUserId)) {
return;
}
@@ -204,12 +202,13 @@ public class KeyguardBouncer {
*/
private void onFullyShown() {
mFalsingManager.onBouncerShown();
if (mKeyguardView == null) {
if (mKeyguardViewController == null) {
Log.wtf(TAG, "onFullyShown when view was null");
} else {
mKeyguardView.onResume();
mKeyguardViewController.onResume();
if (mRoot != null) {
mRoot.announceForAccessibility(mKeyguardView.getAccessibilityTitleForCurrentMode());
mRoot.announceForAccessibility(
mKeyguardViewController.getAccessibilityTitleForCurrentMode());
}
}
}
@@ -233,28 +232,13 @@ public class KeyguardBouncer {
showPromptReason(mBouncerPromptReason);
final CharSequence customMessage = mCallback.consumeCustomMessage();
if (customMessage != null) {
mKeyguardView.showErrorMessage(customMessage);
}
// 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 (mKeyguardView.getHeight() != 0 && mKeyguardView.getHeight() != mStatusBarHeight) {
mKeyguardView.startAppearAnimation();
} else {
mKeyguardView.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
mKeyguardView.getViewTreeObserver().removeOnPreDrawListener(this);
mKeyguardView.startAppearAnimation();
return true;
}
});
mKeyguardView.requestLayout();
mKeyguardViewController.showErrorMessage(customMessage);
}
mKeyguardViewController.appear(mStatusBarHeight);
mShowingSoon = false;
if (mExpansion == EXPANSION_VISIBLE) {
mKeyguardView.onResume();
mKeyguardView.resetSecurityContainer();
mKeyguardViewController.onResume();
mKeyguardViewController.resetSecurityContainer();
showPromptReason(mBouncerPromptReason);
}
SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED,
@@ -270,16 +254,16 @@ public class KeyguardBouncer {
* and {@link KeyguardSecurityView#PROMPT_REASON_RESTART}
*/
public void showPromptReason(int reason) {
if (mKeyguardView != null) {
mKeyguardView.showPromptReason(reason);
if (mKeyguardViewController != null) {
mKeyguardViewController.showPromptReason(reason);
} else {
Log.w(TAG, "Trying to show prompt reason on empty bouncer");
}
}
public void showMessage(String message, ColorStateList colorState) {
if (mKeyguardView != null) {
mKeyguardView.showMessage(message, colorState);
if (mKeyguardViewController != null) {
mKeyguardViewController.showMessage(message, colorState);
} else {
Log.w(TAG, "Trying to show message on empty bouncer");
}
@@ -293,7 +277,7 @@ public class KeyguardBouncer {
public void showWithDismissAction(OnDismissAction r, Runnable cancelAction) {
ensureView();
mKeyguardView.setOnDismissAction(r, cancelAction);
mKeyguardViewController.setOnDismissAction(r, cancelAction);
show(false /* resetSecuritySelection */);
}
@@ -307,9 +291,9 @@ public class KeyguardBouncer {
mFalsingManager.onBouncerHidden();
mCallback.onBouncerVisiblityChanged(false /* shown */);
cancelShowRunnable();
if (mKeyguardView != null) {
mKeyguardView.cancelDismissAction();
mKeyguardView.cleanUp();
if (mKeyguardViewController != null) {
mKeyguardViewController.cancelDismissAction();
mKeyguardViewController.cleanUp();
}
mIsAnimatingAway = false;
if (mRoot != null) {
@@ -328,8 +312,8 @@ public class KeyguardBouncer {
*/
public void startPreHideAnimation(Runnable runnable) {
mIsAnimatingAway = true;
if (mKeyguardView != null) {
mKeyguardView.startDisappearAnimation(runnable);
if (mKeyguardViewController != null) {
mKeyguardViewController.startDisappearAnimation(runnable);
} else if (runnable != null) {
runnable.run();
}
@@ -345,8 +329,9 @@ public class KeyguardBouncer {
}
public void onScreenTurnedOff() {
if (mKeyguardView != null && mRoot != null && mRoot.getVisibility() == View.VISIBLE) {
mKeyguardView.onPause();
if (mKeyguardViewController != null
&& mRoot != null && mRoot.getVisibility() == View.VISIBLE) {
mKeyguardViewController.onPause();
}
}
@@ -380,7 +365,7 @@ public class KeyguardBouncer {
}
private void showPrimarySecurityScreen() {
mKeyguardView.showPrimarySecurityScreen();
mKeyguardViewController.showPrimarySecurityScreen();
}
/**
@@ -391,10 +376,8 @@ public class KeyguardBouncer {
public void setExpansion(float fraction) {
float oldExpansion = mExpansion;
mExpansion = fraction;
if (mKeyguardView != null && !mIsAnimatingAway) {
float alpha = MathUtils.map(ALPHA_EXPANSION_THRESHOLD, 1, 1, 0, fraction);
mKeyguardView.setAlpha(MathUtils.constrain(alpha, 0f, 1f));
mKeyguardView.setTranslationY(fraction * mKeyguardView.getHeight());
if (mKeyguardViewController != null && !mIsAnimatingAway) {
mKeyguardViewController.setExpansion(fraction);
}
if (fraction == EXPANSION_VISIBLE && oldExpansion != EXPANSION_VISIBLE) {
@@ -405,28 +388,22 @@ public class KeyguardBouncer {
mExpansionCallback.onFullyHidden();
} else if (fraction != EXPANSION_VISIBLE && oldExpansion == EXPANSION_VISIBLE) {
mExpansionCallback.onStartingToHide();
if (mKeyguardView != null) {
mKeyguardView.onStartingToHide();
if (mKeyguardViewController != null) {
mKeyguardViewController.onStartingToHide();
}
}
}
public boolean willDismissWithAction() {
return mKeyguardView != null && mKeyguardView.hasDismissActions();
return mKeyguardViewController != null && mKeyguardViewController.hasDismissActions();
}
public int getTop() {
if (mKeyguardView == null) {
if (mKeyguardViewController == null) {
return 0;
}
int top = mKeyguardView.getTop();
// The password view has an extra top padding that should be ignored.
if (mKeyguardView.getCurrentSecurityMode() == SecurityMode.Password) {
View messageArea = mKeyguardView.findViewById(R.id.keyguard_message_area);
top += messageArea.getTop();
}
return top;
return mKeyguardViewController.getTop();
}
protected void ensureView() {
@@ -442,10 +419,13 @@ public class KeyguardBouncer {
protected void inflateView() {
removeView();
mHandler.removeCallbacks(mRemoveViewRunnable);
mRoot = (ViewGroup) LayoutInflater.from(mContext).inflate(R.layout.keyguard_bouncer, null);
mKeyguardView = mRoot.findViewById(R.id.keyguard_host_view);
mKeyguardView.setLockPatternUtils(mLockPatternUtils);
mKeyguardView.setViewMediatorCallback(mCallback);
KeyguardBouncerComponent component = mKeyguardBouncerComponentFactory.create();
mRootViewController = component.getKeyguardRootViewController();
mRootViewController.init();
mRoot = mRootViewController.getView(); // TODO(b/166448040): Don't access root view here.
mKeyguardViewController = component.getKeyguardHostViewController();
mKeyguardViewController.init();
mContainer.addView(mRoot, mContainer.getChildCount());
mStatusBarHeight = mRoot.getResources().getDimensionPixelOffset(
com.android.systemui.R.dimen.status_bar_height);
@@ -465,7 +445,7 @@ public class KeyguardBouncer {
}
public boolean onBackPressed() {
return mKeyguardView != null && mKeyguardView.handleBackKey();
return mKeyguardViewController != null && mKeyguardViewController.handleBackKey();
}
/**
@@ -473,7 +453,7 @@ public class KeyguardBouncer {
* notifications on Keyguard, like SIM PIN/PUK.
*/
public boolean needsFullscreenBouncer() {
SecurityMode mode = Dependency.get(KeyguardSecurityModel.class).getSecurityMode(
SecurityMode mode = mKeyguardSecurityModel.getSecurityMode(
KeyguardUpdateMonitor.getCurrentUser());
return mode == SecurityMode.SimPin || mode == SecurityMode.SimPuk;
}
@@ -483,8 +463,8 @@ public class KeyguardBouncer {
* makes this method much faster.
*/
public boolean isFullscreenBouncer() {
if (mKeyguardView != null) {
SecurityMode mode = mKeyguardView.getCurrentSecurityMode();
if (mKeyguardViewController != null) {
SecurityMode mode = mKeyguardViewController.getCurrentSecurityMode();
return mode == SecurityMode.SimPin || mode == SecurityMode.SimPuk;
}
return false;
@@ -494,21 +474,22 @@ public class KeyguardBouncer {
* WARNING: This method might cause Binder calls.
*/
public boolean isSecure() {
return mKeyguardView == null || mKeyguardView.getSecurityMode() != SecurityMode.None;
return mKeyguardSecurityModel.getSecurityMode(
KeyguardUpdateMonitor.getCurrentUser()) != SecurityMode.None;
}
public boolean shouldDismissOnMenuPressed() {
return mKeyguardView.shouldEnableMenuKey();
return mKeyguardViewController.shouldEnableMenuKey();
}
public boolean interceptMediaKey(KeyEvent event) {
ensureView();
return mKeyguardView.interceptMediaKey(event);
return mKeyguardViewController.interceptMediaKey(event);
}
public void notifyKeyguardAuthenticated(boolean strongAuth) {
ensureView();
mKeyguardView.finish(strongAuth, KeyguardUpdateMonitor.getCurrentUser());
mKeyguardViewController.finish(strongAuth, KeyguardUpdateMonitor.getCurrentUser());
}
public void dump(PrintWriter pw) {
@@ -516,8 +497,8 @@ public class KeyguardBouncer {
pw.println(" isShowing(): " + isShowing());
pw.println(" mStatusBarHeight: " + mStatusBarHeight);
pw.println(" mExpansion: " + mExpansion);
pw.println(" mKeyguardView; " + mKeyguardView);
pw.println(" mShowingSoon: " + mKeyguardView);
pw.println(" mKeyguardViewController; " + mKeyguardViewController);
pw.println(" mShowingSoon: " + mShowingSoon);
pw.println(" mBouncerPromptReason: " + mBouncerPromptReason);
pw.println(" mIsAnimatingAway: " + mIsAnimatingAway);
}
@@ -528,4 +509,46 @@ public class KeyguardBouncer {
void onStartingToShow();
void onFullyHidden();
}
/** Create a {@link KeyguardBouncer} once a container and bouncer callback are available. */
public static class Factory {
private final Context mContext;
private final ViewMediatorCallback mCallback;
private final DismissCallbackRegistry mDismissCallbackRegistry;
private final FalsingManager mFalsingManager;
private final KeyguardStateController mKeyguardStateController;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final KeyguardBypassController mKeyguardBypassController;
private final Handler mHandler;
private final KeyguardSecurityModel mKeyguardSecurityModel;
private final KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory;
@Inject
public Factory(Context context, ViewMediatorCallback callback,
DismissCallbackRegistry dismissCallbackRegistry, FalsingManager falsingManager,
KeyguardStateController keyguardStateController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
KeyguardBypassController keyguardBypassController, Handler handler,
KeyguardSecurityModel keyguardSecurityModel,
KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory) {
mContext = context;
mCallback = callback;
mDismissCallbackRegistry = dismissCallbackRegistry;
mFalsingManager = falsingManager;
mKeyguardStateController = keyguardStateController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mKeyguardBypassController = keyguardBypassController;
mHandler = handler;
mKeyguardSecurityModel = keyguardSecurityModel;
mKeyguardBouncerComponentFactory = keyguardBouncerComponentFactory;
}
public KeyguardBouncer create(@RootView ViewGroup container,
BouncerExpansionCallback expansionCallback) {
return new KeyguardBouncer(mContext, mCallback, container,
mDismissCallbackRegistry, mFalsingManager, expansionCallback,
mKeyguardStateController, mKeyguardUpdateMonitor, mKeyguardBypassController,
mHandler, mKeyguardSecurityModel, mKeyguardBouncerComponentFactory);
}
}
}

View File

@@ -44,7 +44,6 @@ import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.KeyguardViewController;
import com.android.keyguard.ViewMediatorCallback;
import com.android.keyguard.dagger.KeyguardBouncerComponent;
import com.android.settingslib.animation.AppearAnimationUtils;
import com.android.systemui.DejankUtils;
import com.android.systemui.dagger.SysUISingleton;
@@ -104,7 +103,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
private final NavigationModeController mNavigationModeController;
private final NotificationShadeWindowController mNotificationShadeWindowController;
private final Optional<FaceAuthScreenBrightnessController> mFaceAuthScreenBrightnessController;
private final KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory;
private final KeyguardBouncer.Factory mKeyguardBouncerFactory;
private final BouncerExpansionCallback mExpansionCallback = new BouncerExpansionCallback() {
@Override
public void onFullyShown() {
@@ -216,7 +215,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
KeyguardStateController keyguardStateController,
Optional<FaceAuthScreenBrightnessController> faceAuthScreenBrightnessController,
NotificationMediaManager notificationMediaManager,
KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory) {
KeyguardBouncer.Factory keyguardBouncerFactory) {
mContext = context;
mViewMediatorCallback = callback;
mLockPatternUtils = lockPatternUtils;
@@ -229,7 +228,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mStatusBarStateController = sysuiStatusBarStateController;
mDockManager = dockManager;
mFaceAuthScreenBrightnessController = faceAuthScreenBrightnessController;
mKeyguardBouncerComponentFactory = keyguardBouncerComponentFactory;
mKeyguardBouncerFactory = keyguardBouncerFactory;
}
@Override
@@ -246,9 +245,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mLastLockVisible = mLockIconContainer.getVisibility() == View.VISIBLE;
}
mBiometricUnlockController = biometricUnlockController;
mBouncer = mKeyguardBouncerComponentFactory
.build(container, mExpansionCallback)
.createKeyguardBouncer();
mBouncer = mKeyguardBouncerFactory.create(container, mExpansionCallback);
mNotificationPanelViewController = notificationPanelViewController;
notificationPanelViewController.addExpansionListener(this);
mBypassController = bypassController;

View File

@@ -0,0 +1,72 @@
/*
* 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.systemui.util;
import android.view.View;
import android.view.View.OnAttachStateChangeListener;
/**
* Utility class that handles view lifecycle events for View Controllers.
*
* Implementations should handle setup and teardown related activities inside of
* {@link #onViewAttached()} and {@link #onViewDetached()}.
*
* @param <T> View class that this ViewController is for.
*/
public abstract class ViewController<T extends View> {
protected final T mView;
private boolean mInited;
private OnAttachStateChangeListener mOnAttachStateListener = new OnAttachStateChangeListener() {
@Override
public void onViewAttachedToWindow(View v) {
ViewController.this.onViewAttached();
}
@Override
public void onViewDetachedFromWindow(View v) {
ViewController.this.onViewDetached();
}
};
protected ViewController(T view) {
mView = view;
}
/** Call immediately after constructing Controller in order to handle view lifecycle events. */
public void init() {
if (mInited) {
return;
}
mInited = true;
if (mView.isAttachedToWindow()) {
mOnAttachStateListener.onViewAttachedToWindow(mView);
}
mView.addOnAttachStateChangeListener(mOnAttachStateListener);
}
/**
* Called when the view is attached and a call to {@link #init()} has been made in either order.
*/
protected abstract void onViewAttached();
/**
* Called when the view is detached.
*/
protected abstract void onViewDetached();
}

View File

@@ -11,7 +11,7 @@
* 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
* limitations under the License.
*/
package com.android.keyguard;
@@ -19,11 +19,12 @@ package com.android.keyguard;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import android.media.AudioManager;
import android.telephony.TelephonyManager;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
@@ -39,41 +40,44 @@ import org.mockito.junit.MockitoRule;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class KeyguardHostViewTest extends SysuiTestCase {
public class KeyguardHostViewControllerTest extends SysuiTestCase {
@Mock
private KeyguardSecurityContainer mSecurityContainer;
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock
private LockPatternUtils mLockPatternUtils;
private KeyguardHostView mKeyguardHostView;
@Mock
private KeyguardSecurityContainerController mKeyguardSecurityContainerController;
@Mock
private AudioManager mAudioManager;
@Mock
private TelephonyManager mTelephonyManager;
@Mock
private ViewMediatorCallback mViewMediatorCallback;
@Rule
public MockitoRule mMockitoRule = MockitoJUnit.rule();
private KeyguardHostView mKeyguardHostView;
private KeyguardHostViewController mKeyguardHostViewController;
@Before
public void setup() {
mDependency.injectMockDependency(KeyguardUpdateMonitor.class);
mKeyguardHostView = new KeyguardHostView(getContext()) {
@Override
protected void onFinishInflate() {
mSecurityContainer = KeyguardHostViewTest.this.mSecurityContainer;
mLockPatternUtils = KeyguardHostViewTest.this.mLockPatternUtils;
}
};
mKeyguardHostView.onFinishInflate();
mKeyguardHostViewController = new KeyguardHostViewController(
mKeyguardHostView, mKeyguardUpdateMonitor, mKeyguardSecurityContainerController,
mAudioManager, mTelephonyManager, mViewMediatorCallback);
}
@Test
public void testHasDismissActions() {
Assert.assertFalse("Action not set yet", mKeyguardHostView.hasDismissActions());
mKeyguardHostView.setOnDismissAction(mock(OnDismissAction.class),
Assert.assertFalse("Action not set yet", mKeyguardHostViewController.hasDismissActions());
mKeyguardHostViewController.setOnDismissAction(mock(OnDismissAction.class),
null /* cancelAction */);
Assert.assertTrue("Action should exist", mKeyguardHostView.hasDismissActions());
Assert.assertTrue("Action should exist", mKeyguardHostViewController.hasDismissActions());
}
@Test
public void testOnStartingToHide() {
mKeyguardHostView.onStartingToHide();
verify(mSecurityContainer).onStartingToHide();
mKeyguardHostViewController.onStartingToHide();
verify(mKeyguardSecurityContainerController).onStartingToHide();
}
}

View File

@@ -38,16 +38,16 @@ import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
import androidx.test.filters.SmallTest;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardHostView;
import com.android.keyguard.KeyguardHostViewController;
import com.android.keyguard.KeyguardRootViewController;
import com.android.keyguard.KeyguardSecurityModel;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.ViewMediatorCallback;
import com.android.keyguard.dagger.KeyguardBouncerComponent;
import com.android.systemui.DejankUtils;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.keyguard.DismissCallbackRegistry;
@@ -76,13 +76,9 @@ public class KeyguardBouncerTest extends SysuiTestCase {
@Mock
private ViewMediatorCallback mViewMediatorCallback;
@Mock
private LockPatternUtils mLockPatternUtils;
@Mock
private DismissCallbackRegistry mDismissCallbackRegistry;
@Mock
private KeyguardHostView mKeyguardHostView;
@Mock
private ViewTreeObserver mViewTreeObserver;
private KeyguardHostViewController mKeyguardHostViewController;
@Mock
private KeyguardBouncer.BouncerExpansionCallback mExpansionCallback;
@Mock
@@ -96,7 +92,13 @@ public class KeyguardBouncerTest extends SysuiTestCase {
@Mock
private KeyguardSecurityModel mKeyguardSecurityModel;
@Mock
private KeyguardRootViewController mRootViewController;
@Mock
private ViewGroup mRootView;
@Mock
private KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory;
@Mock
private KeyguardBouncerComponent mKeyguardBouncerComponent;
@Rule
public MockitoRule mRule = MockitoJUnit.rule();
private Integer mRootVisibility = View.INVISIBLE;
@@ -106,7 +108,6 @@ public class KeyguardBouncerTest extends SysuiTestCase {
public void setup() {
allowTestableLooperAsMainThread();
mDependency.injectTestDependency(KeyguardUpdateMonitor.class, mKeyguardUpdateMonitor);
mDependency.injectTestDependency(KeyguardSecurityModel.class, mKeyguardSecurityModel);
mDependency.injectMockDependency(KeyguardStateController.class);
when(mRootView.getVisibility()).thenAnswer((Answer<Integer>) invocation -> mRootVisibility);
doAnswer(invocation -> {
@@ -116,19 +117,22 @@ public class KeyguardBouncerTest extends SysuiTestCase {
when(mKeyguardSecurityModel.getSecurityMode(anyInt()))
.thenReturn(KeyguardSecurityModel.SecurityMode.None);
DejankUtils.setImmediate(true);
when(mKeyguardBouncerComponentFactory.create()).thenReturn(mKeyguardBouncerComponent);
when(mKeyguardBouncerComponent.getKeyguardHostViewController())
.thenReturn(mKeyguardHostViewController);
when(mKeyguardBouncerComponent.getKeyguardRootViewController())
.thenReturn(mRootViewController);
when(mRootViewController.getView()).thenReturn(mRootView);
when(mRootView.getResources()).thenReturn(mContext.getResources());
final ViewGroup container = new FrameLayout(getContext());
when(mKeyguardHostView.getViewTreeObserver()).thenReturn(mViewTreeObserver);
when(mKeyguardHostView.getHeight()).thenReturn(500);
mBouncer = new KeyguardBouncer(getContext(), mViewMediatorCallback,
mLockPatternUtils, container, mDismissCallbackRegistry, mFalsingManager,
mExpansionCallback, mKeyguardStateController, mKeyguardUpdateMonitor,
mKeyguardBypassController, mHandler) {
@Override
protected void inflateView() {
mKeyguardView = mKeyguardHostView;
mRoot = mRootView;
}
};
mBouncer = new KeyguardBouncer.Factory(getContext(), mViewMediatorCallback,
mDismissCallbackRegistry, mFalsingManager,
mKeyguardStateController, mKeyguardUpdateMonitor,
mKeyguardBypassController, mHandler, mKeyguardSecurityModel,
mKeyguardBouncerComponentFactory)
.create(container, mExpansionCallback);
}
@Test
@@ -154,12 +158,10 @@ public class KeyguardBouncerTest extends SysuiTestCase {
mBouncer.ensureView();
mBouncer.setExpansion(1);
reset(mKeyguardHostView);
when(mKeyguardHostView.getHeight()).thenReturn(500);
reset(mKeyguardHostViewController);
mBouncer.show(true);
verify(mKeyguardHostView).setAlpha(eq(1f));
verify(mKeyguardHostView).setTranslationY(eq(0f));
verify(mKeyguardHostViewController).setExpansion(0);
}
@Test
@@ -177,23 +179,23 @@ public class KeyguardBouncerTest extends SysuiTestCase {
@Test
public void testShow_triesToDismissKeyguard() {
mBouncer.show(true);
verify(mKeyguardHostView).dismiss(anyInt());
verify(mKeyguardHostViewController).dismiss(anyInt());
}
@Test
public void testShow_resetsSecuritySelection() {
mBouncer.show(false);
verify(mKeyguardHostView, never()).showPrimarySecurityScreen();
verify(mKeyguardHostViewController, never()).showPrimarySecurityScreen();
mBouncer.hide(false);
mBouncer.show(true);
verify(mKeyguardHostView).showPrimarySecurityScreen();
verify(mKeyguardHostViewController).showPrimarySecurityScreen();
}
@Test
public void testShow_animatesKeyguardView() {
mBouncer.show(true);
verify(mKeyguardHostView).startAppearAnimation();
verify(mKeyguardHostViewController).appear(anyInt());
}
@Test
@@ -201,7 +203,7 @@ public class KeyguardBouncerTest extends SysuiTestCase {
final String errorMessage = "an error message";
when(mViewMediatorCallback.consumeCustomMessage()).thenReturn(errorMessage);
mBouncer.show(true);
verify(mKeyguardHostView).showErrorMessage(eq(errorMessage));
verify(mKeyguardHostViewController).showErrorMessage(eq(errorMessage));
}
@Test
@@ -218,10 +220,10 @@ public class KeyguardBouncerTest extends SysuiTestCase {
verify(mExpansionCallback).onFullyShown();
verify(mExpansionCallback, never()).onStartingToHide();
verify(mKeyguardHostView, never()).onStartingToHide();
verify(mKeyguardHostViewController, never()).onStartingToHide();
mBouncer.setExpansion(0.9f);
verify(mExpansionCallback).onStartingToHide();
verify(mKeyguardHostView).onStartingToHide();
verify(mKeyguardHostViewController).onStartingToHide();
}
@Test
@@ -230,7 +232,7 @@ public class KeyguardBouncerTest extends SysuiTestCase {
mBouncer.setExpansion(0.1f);
mBouncer.setExpansion(0);
verify(mKeyguardHostView).onResume();
verify(mKeyguardHostViewController).onResume();
verify(mRootView).announceForAccessibility(any());
}
@@ -267,7 +269,7 @@ public class KeyguardBouncerTest extends SysuiTestCase {
public void testShowPromptReason_propagates() {
mBouncer.ensureView();
mBouncer.showPromptReason(1);
verify(mKeyguardHostView).showPromptReason(eq(1));
verify(mKeyguardHostViewController).showPromptReason(eq(1));
}
@Test
@@ -275,7 +277,8 @@ public class KeyguardBouncerTest extends SysuiTestCase {
final String message = "a message";
mBouncer.ensureView();
mBouncer.showMessage(message, ColorStateList.valueOf(Color.GREEN));
verify(mKeyguardHostView).showMessage(eq(message), eq(ColorStateList.valueOf(Color.GREEN)));
verify(mKeyguardHostViewController).showMessage(
eq(message), eq(ColorStateList.valueOf(Color.GREEN)));
}
@Test
@@ -283,7 +286,7 @@ public class KeyguardBouncerTest extends SysuiTestCase {
final OnDismissAction dismissAction = () -> false;
final Runnable cancelAction = () -> {};
mBouncer.showWithDismissAction(dismissAction, cancelAction);
verify(mKeyguardHostView).setOnDismissAction(dismissAction, cancelAction);
verify(mKeyguardHostViewController).setOnDismissAction(dismissAction, cancelAction);
Assert.assertTrue("Should be showing", mBouncer.isShowing());
}
@@ -297,7 +300,7 @@ public class KeyguardBouncerTest extends SysuiTestCase {
ran[0] = false;
mBouncer.ensureView();
mBouncer.startPreHideAnimation(r);
verify(mKeyguardHostView).startDisappearAnimation(r);
verify(mKeyguardHostViewController).startDisappearAnimation(r);
Assert.assertFalse("Callback should have been deferred", ran[0]);
}
@@ -322,16 +325,14 @@ public class KeyguardBouncerTest extends SysuiTestCase {
public void testSetExpansion() {
mBouncer.ensureView();
mBouncer.setExpansion(0.5f);
verify(mKeyguardHostView).setAlpha(anyFloat());
verify(mKeyguardHostView).setTranslationY(anyFloat());
verify(mKeyguardHostViewController).setExpansion(0.5f);
}
@Test
public void testIsFullscreenBouncer_asksKeyguardView() {
mBouncer.ensureView();
mBouncer.isFullscreenBouncer();
verify(mKeyguardHostView).getCurrentSecurityMode();
verify(mKeyguardHostView, never()).getSecurityMode();
verify(mKeyguardHostViewController).getCurrentSecurityMode();
}
@Test
@@ -346,21 +347,18 @@ public class KeyguardBouncerTest extends SysuiTestCase {
@Test
public void testIsHiding_skipsTranslation() {
mBouncer.show(false /* reset */);
reset(mKeyguardHostView);
reset(mKeyguardHostViewController);
mBouncer.startPreHideAnimation(null /* runnable */);
mBouncer.setExpansion(0.5f);
verify(mKeyguardHostView, never()).setTranslationY(anyFloat());
verify(mKeyguardHostView, never()).setAlpha(anyFloat());
verify(mKeyguardHostViewController, never()).setExpansion(anyFloat());
}
@Test
public void testIsSecure() {
Assert.assertTrue("Bouncer is secure before inflating views", mBouncer.isSecure());
mBouncer.ensureView();
for (KeyguardSecurityModel.SecurityMode mode : KeyguardSecurityModel.SecurityMode.values()){
reset(mKeyguardHostView);
when(mKeyguardHostView.getSecurityMode()).thenReturn(mode);
reset(mKeyguardSecurityModel);
when(mKeyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(mode);
Assert.assertEquals("Security doesn't match for mode: " + mode,
mBouncer.isSecure(), mode != KeyguardSecurityModel.SecurityMode.None);
}
@@ -392,7 +390,7 @@ public class KeyguardBouncerTest extends SysuiTestCase {
public void testWillDismissWithAction() {
mBouncer.ensureView();
Assert.assertFalse("Action not set yet", mBouncer.willDismissWithAction());
when(mKeyguardHostView.hasDismissActions()).thenReturn(true);
when(mKeyguardHostViewController.hasDismissActions()).thenReturn(true);
Assert.assertTrue("Action should exist", mBouncer.willDismissWithAction());
}

View File

@@ -39,7 +39,6 @@ import androidx.test.filters.SmallTest;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.ViewMediatorCallback;
import com.android.keyguard.dagger.KeyguardBouncerComponent;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dock.DockManager;
import com.android.systemui.keyguard.DismissCallbackRegistry;
@@ -92,9 +91,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
@Mock
private FaceAuthScreenBrightnessController mFaceAuthScreenBrightnessController;
@Mock
private KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory;
@Mock
private KeyguardBouncerComponent mKeyguardBouncerComponent;
private KeyguardBouncer.Factory mKeyguardBouncerFactory;
@Mock
private KeyguardBouncer mBouncer;
@@ -107,11 +104,10 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
when(mLockIconContainer.animate()).thenReturn(mock(ViewPropertyAnimator.class,
RETURNS_DEEP_STUBS));
when(mKeyguardBouncerComponentFactory.build(
when(mKeyguardBouncerFactory.create(
any(ViewGroup.class),
any(KeyguardBouncer.BouncerExpansionCallback.class)))
.thenReturn(mKeyguardBouncerComponent);
when(mKeyguardBouncerComponent.createKeyguardBouncer()).thenReturn(mBouncer);
.thenReturn(mBouncer);
mStatusBarKeyguardViewManager = new StatusBarKeyguardViewManager(
getContext(),
@@ -126,7 +122,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
mKeyguardStateController,
Optional.of(mFaceAuthScreenBrightnessController),
mock(NotificationMediaManager.class),
mKeyguardBouncerComponentFactory);
mKeyguardBouncerFactory);
mStatusBarKeyguardViewManager.registerStatusBar(mStatusBar, mContainer,
mNotificationPanelView, mBiometrucUnlockController,
mLockIconContainer, mNotificationContainer, mBypassController);