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:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -26,5 +26,5 @@ import javax.inject.Qualifier;
|
||||
@Qualifier
|
||||
@Documented
|
||||
@Retention(RUNTIME)
|
||||
public @interface ContainerView {
|
||||
public @interface RootView {
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user