Merge "Revert "Remove KeyguardHostView"" into tm-qpr-dev
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
**
|
||||
** Copyright 2023, The Android Open Source Project
|
||||
** Copyright 2012, 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.
|
||||
@@ -17,10 +17,12 @@
|
||||
*/
|
||||
-->
|
||||
|
||||
<com.android.keyguard.KeyguardSecurityContainer
|
||||
<!-- This is the host view that generally contains two sub views: the widget view
|
||||
and the security view. -->
|
||||
<com.android.keyguard.KeyguardHostView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:androidprv="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/keyguard_security_container"
|
||||
android:id="@+id/keyguard_host_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipChildren="false"
|
||||
@@ -28,15 +30,27 @@
|
||||
android:paddingTop="@dimen/keyguard_lock_padding"
|
||||
android:importantForAccessibility="yes"> <!-- Needed because TYPE_WINDOW_STATE_CHANGED is sent
|
||||
from this view when bouncer is shown -->
|
||||
<com.android.keyguard.KeyguardSecurityViewFlipper
|
||||
android:id="@+id/view_flipper"
|
||||
android:layout_width="wrap_content"
|
||||
|
||||
<com.android.keyguard.KeyguardSecurityContainer
|
||||
android:id="@+id/keyguard_security_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:paddingTop="@dimen/keyguard_security_view_top_margin"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center">
|
||||
</com.android.keyguard.KeyguardSecurityViewFlipper>
|
||||
</com.android.keyguard.KeyguardSecurityContainer>
|
||||
android:padding="0dp"
|
||||
android:fitsSystemWindows="true"
|
||||
android:layout_gravity="center">
|
||||
<com.android.keyguard.KeyguardSecurityViewFlipper
|
||||
android:id="@+id/view_flipper"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:paddingTop="@dimen/keyguard_security_view_top_margin"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center">
|
||||
</com.android.keyguard.KeyguardSecurityViewFlipper>
|
||||
</com.android.keyguard.KeyguardSecurityContainer>
|
||||
|
||||
</com.android.keyguard.KeyguardHostView>
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) 2007 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.keyguard;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
/**
|
||||
* Base class for keyguard view. {@link #reset} is where you should
|
||||
* reset the state of your view. Use the {@link KeyguardViewCallback} via
|
||||
* {@link #getCallback()} to send information back (such as poking the wake lock,
|
||||
* or finishing the keyguard).
|
||||
*
|
||||
* Handles intercepting of media keys that still work when the keyguard is
|
||||
* showing.
|
||||
*/
|
||||
public class KeyguardHostView extends FrameLayout {
|
||||
|
||||
protected ViewMediatorCallback mViewMediatorCallback;
|
||||
private boolean mIsInteractable;
|
||||
|
||||
public KeyguardHostView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public KeyguardHostView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dispatchDraw(Canvas canvas) {
|
||||
super.dispatchDraw(canvas);
|
||||
if (mViewMediatorCallback != null) {
|
||||
mViewMediatorCallback.keyguardDoneDrawing();
|
||||
}
|
||||
}
|
||||
|
||||
public void setViewMediatorCallback(ViewMediatorCallback viewMediatorCallback) {
|
||||
mViewMediatorCallback = viewMediatorCallback;
|
||||
}
|
||||
|
||||
/** Set true if the view can be interacted with */
|
||||
public void setInteractable(boolean isInteractable) {
|
||||
mIsInteractable = isInteractable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure to disallow touches while transitioning the bouncer, otherwise
|
||||
* it can remain interactable even when barely visible.
|
||||
*/
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
return !mIsInteractable;
|
||||
}
|
||||
|
||||
/** True to consume any events that are sent to it */
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent ev) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,535 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.keyguard;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.Resources;
|
||||
import android.media.AudioManager;
|
||||
import android.os.SystemClock;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.Log;
|
||||
import android.util.MathUtils;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.View.OnKeyListener;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.widget.FrameLayout;
|
||||
import android.window.OnBackAnimationCallback;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.keyguard.KeyguardSecurityContainer.SecurityCallback;
|
||||
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
|
||||
import com.android.keyguard.dagger.KeyguardBouncerScope;
|
||||
import com.android.settingslib.Utils;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.plugins.ActivityStarter;
|
||||
import com.android.systemui.util.ViewController;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
/** Controller for a {@link KeyguardHostView}. */
|
||||
@KeyguardBouncerScope
|
||||
public class KeyguardHostViewController extends ViewController<KeyguardHostView> {
|
||||
private static final String TAG = "KeyguardViewBase";
|
||||
public static final boolean DEBUG = KeyguardConstants.DEBUG;
|
||||
// Whether the volume keys should be handled by keyguard. If true, then
|
||||
// they will be handled here for specific media types such as music, otherwise
|
||||
// the audio service will bring up the volume dialog.
|
||||
private static final boolean KEYGUARD_MANAGES_VOLUME = false;
|
||||
|
||||
private static final String ENABLE_MENU_KEY_FILE = "/data/local/enable_menu_key";
|
||||
|
||||
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
|
||||
private final KeyguardSecurityContainerController mKeyguardSecurityContainerController;
|
||||
private final TelephonyManager mTelephonyManager;
|
||||
private final ViewMediatorCallback mViewMediatorCallback;
|
||||
private final AudioManager mAudioManager;
|
||||
|
||||
private ActivityStarter.OnDismissAction mDismissAction;
|
||||
private Runnable mCancelAction;
|
||||
private int mTranslationY;
|
||||
|
||||
private final KeyguardUpdateMonitorCallback mUpdateCallback =
|
||||
new KeyguardUpdateMonitorCallback() {
|
||||
@Override
|
||||
public void onTrustGrantedForCurrentUser(
|
||||
boolean dismissKeyguard,
|
||||
boolean newlyUnlocked,
|
||||
TrustGrantFlags flags,
|
||||
String message
|
||||
) {
|
||||
if (dismissKeyguard) {
|
||||
if (!mView.isVisibleToUser()) {
|
||||
// The trust agent dismissed the keyguard without the user proving
|
||||
// that they are present (by swiping up to show the bouncer). That's
|
||||
// fine if the user proved presence via some other way to the trust
|
||||
// agent.
|
||||
Log.i(TAG, "TrustAgent dismissed Keyguard.");
|
||||
}
|
||||
mSecurityCallback.dismiss(
|
||||
false /* authenticated */,
|
||||
KeyguardUpdateMonitor.getCurrentUser(),
|
||||
/* bypassSecondaryLockScreen */ false,
|
||||
SecurityMode.Invalid
|
||||
);
|
||||
} else {
|
||||
if (flags.isInitiatedByUser() || flags.dismissKeyguardRequested()) {
|
||||
mViewMediatorCallback.playTrustedSound();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private final SecurityCallback mSecurityCallback = new SecurityCallback() {
|
||||
|
||||
@Override
|
||||
public boolean dismiss(boolean authenticated, int targetUserId,
|
||||
boolean bypassSecondaryLockScreen, SecurityMode expectedSecurityMode) {
|
||||
return mKeyguardSecurityContainerController.showNextSecurityScreenOrFinish(
|
||||
authenticated, targetUserId, bypassSecondaryLockScreen, expectedSecurityMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void userActivity() {
|
||||
mViewMediatorCallback.userActivity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput) {
|
||||
mViewMediatorCallback.setNeedsInput(needsInput);
|
||||
}
|
||||
|
||||
/**
|
||||
* Authentication has happened and it's time to dismiss keyguard. This function
|
||||
* should clean up and inform KeyguardViewMediator.
|
||||
*
|
||||
* @param strongAuth whether the user has authenticated with strong authentication like
|
||||
* pattern, password or PIN but not by trust agents or fingerprint
|
||||
* @param targetUserId a user that needs to be the foreground user at the dismissal
|
||||
* completion.
|
||||
*/
|
||||
@Override
|
||||
public void finish(boolean strongAuth, int targetUserId) {
|
||||
// If there's a pending runnable because the user interacted with a widget
|
||||
// and we're leaving keyguard, then run it.
|
||||
boolean deferKeyguardDone = false;
|
||||
if (mDismissAction != null) {
|
||||
deferKeyguardDone = mDismissAction.onDismiss();
|
||||
mDismissAction = null;
|
||||
mCancelAction = null;
|
||||
}
|
||||
if (mViewMediatorCallback != null) {
|
||||
if (deferKeyguardDone) {
|
||||
mViewMediatorCallback.keyguardDonePending(strongAuth, targetUserId);
|
||||
} else {
|
||||
mViewMediatorCallback.keyguardDone(strongAuth, targetUserId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
mViewMediatorCallback.resetKeyguard();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancelClicked() {
|
||||
mViewMediatorCallback.onCancelClicked();
|
||||
}
|
||||
};
|
||||
|
||||
private OnKeyListener mOnKeyListener = (v, keyCode, event) -> interceptMediaKey(event);
|
||||
|
||||
@Inject
|
||||
public KeyguardHostViewController(KeyguardHostView view,
|
||||
KeyguardUpdateMonitor keyguardUpdateMonitor,
|
||||
AudioManager audioManager,
|
||||
TelephonyManager telephonyManager,
|
||||
ViewMediatorCallback viewMediatorCallback,
|
||||
KeyguardSecurityContainerController.Factory
|
||||
keyguardSecurityContainerControllerFactory) {
|
||||
super(view);
|
||||
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
|
||||
mAudioManager = audioManager;
|
||||
mTelephonyManager = telephonyManager;
|
||||
mViewMediatorCallback = viewMediatorCallback;
|
||||
mKeyguardSecurityContainerController = keyguardSecurityContainerControllerFactory.create(
|
||||
mSecurityCallback);
|
||||
}
|
||||
|
||||
/** Initialize the Controller. */
|
||||
public void onInit() {
|
||||
mKeyguardSecurityContainerController.init();
|
||||
updateResources();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onViewAttached() {
|
||||
mView.setViewMediatorCallback(mViewMediatorCallback);
|
||||
// Update ViewMediator with the current input method requirements
|
||||
mViewMediatorCallback.setNeedsInput(mKeyguardSecurityContainerController.needsInput());
|
||||
mKeyguardUpdateMonitor.registerCallback(mUpdateCallback);
|
||||
mView.setOnKeyListener(mOnKeyListener);
|
||||
mKeyguardSecurityContainerController.showPrimarySecurityScreen(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onViewDetached() {
|
||||
mKeyguardUpdateMonitor.removeCallback(mUpdateCallback);
|
||||
mView.setOnKeyListener(null);
|
||||
}
|
||||
|
||||
/** Called before this view is being removed. */
|
||||
public void cleanUp() {
|
||||
mKeyguardSecurityContainerController.onPause();
|
||||
}
|
||||
|
||||
public void resetSecurityContainer() {
|
||||
mKeyguardSecurityContainerController.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dismisses the keyguard by going to the next screen or making it gone.
|
||||
* @param targetUserId a user that needs to be the foreground user at the dismissal completion.
|
||||
* @return True if the keyguard is done.
|
||||
*/
|
||||
public boolean dismiss(int targetUserId) {
|
||||
return mSecurityCallback.dismiss(false, targetUserId, false,
|
||||
getCurrentSecurityMode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the Keyguard is actively shown on the screen.
|
||||
*/
|
||||
public void onResume() {
|
||||
if (DEBUG) Log.d(TAG, "screen on, instance " + Integer.toHexString(hashCode()));
|
||||
mKeyguardSecurityContainerController.onResume(KeyguardSecurityView.SCREEN_ON);
|
||||
mView.requestFocus();
|
||||
}
|
||||
|
||||
public CharSequence getAccessibilityTitleForCurrentMode() {
|
||||
return mKeyguardSecurityContainerController.getTitle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the animation when the Keyguard gets shown.
|
||||
*/
|
||||
public void appear(int statusBarHeight) {
|
||||
// We might still be collapsed and the view didn't have time to layout yet or still
|
||||
// be small, let's wait on the predraw to do the animation in that case.
|
||||
if (mView.getHeight() != 0 && mView.getHeight() != statusBarHeight) {
|
||||
mKeyguardSecurityContainerController.startAppearAnimation();
|
||||
} else {
|
||||
mView.getViewTreeObserver().addOnPreDrawListener(
|
||||
new ViewTreeObserver.OnPreDrawListener() {
|
||||
@Override
|
||||
public boolean onPreDraw() {
|
||||
mView.getViewTreeObserver().removeOnPreDrawListener(this);
|
||||
mKeyguardSecurityContainerController.startAppearAnimation();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
mView.requestLayout();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a string explaining why the security view needs to be solved.
|
||||
*
|
||||
* @param reason a flag indicating which string should be shown, see
|
||||
* {@link KeyguardSecurityView#PROMPT_REASON_NONE},
|
||||
* {@link KeyguardSecurityView#PROMPT_REASON_RESTART},
|
||||
* {@link KeyguardSecurityView#PROMPT_REASON_TIMEOUT}, and
|
||||
* {@link KeyguardSecurityView#PROMPT_REASON_PREPARE_FOR_UPDATE}.
|
||||
*/
|
||||
public void showPromptReason(int reason) {
|
||||
mKeyguardSecurityContainerController.showPromptReason(reason);
|
||||
}
|
||||
|
||||
public void showMessage(CharSequence message, ColorStateList colorState) {
|
||||
mKeyguardSecurityContainerController.showMessage(message, colorState);
|
||||
}
|
||||
|
||||
public void showErrorMessage(CharSequence customMessage) {
|
||||
showMessage(customMessage, Utils.getColorError(mView.getContext()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an action to run when keyguard finishes.
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
public void setOnDismissAction(ActivityStarter.OnDismissAction action, Runnable cancelAction) {
|
||||
if (mCancelAction != null) {
|
||||
mCancelAction.run();
|
||||
mCancelAction = null;
|
||||
}
|
||||
mDismissAction = action;
|
||||
mCancelAction = cancelAction;
|
||||
}
|
||||
|
||||
public void cancelDismissAction() {
|
||||
setOnDismissAction(null, null);
|
||||
}
|
||||
|
||||
public void startDisappearAnimation(Runnable finishRunnable) {
|
||||
if (!mKeyguardSecurityContainerController.startDisappearAnimation(finishRunnable)
|
||||
&& finishRunnable != null) {
|
||||
finishRunnable.run();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the Keyguard is not actively shown anymore on the screen.
|
||||
*/
|
||||
public void onPause() {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, String.format("screen off, instance %s at %s",
|
||||
Integer.toHexString(hashCode()), SystemClock.uptimeMillis()));
|
||||
}
|
||||
mKeyguardSecurityContainerController.showPrimarySecurityScreen(true);
|
||||
mKeyguardSecurityContainerController.onPause();
|
||||
mView.clearFocus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the view needs to be shown.
|
||||
*/
|
||||
public void showPrimarySecurityScreen() {
|
||||
if (DEBUG) Log.d(TAG, "show()");
|
||||
mKeyguardSecurityContainerController.showPrimarySecurityScreen(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fades and translates in/out the security screen.
|
||||
* Fades in as expansion approaches 0.
|
||||
* Animation duration is between 0.33f and 0.67f of panel expansion fraction.
|
||||
* @param fraction amount of the screen that should show.
|
||||
*/
|
||||
public void setExpansion(float fraction) {
|
||||
float scaledFraction = BouncerPanelExpansionCalculator.showBouncerProgress(fraction);
|
||||
mView.setAlpha(MathUtils.constrain(1 - scaledFraction, 0f, 1f));
|
||||
mView.setTranslationY(scaledFraction * mTranslationY);
|
||||
}
|
||||
|
||||
/**
|
||||
* When bouncer was visible and is starting to become hidden.
|
||||
*/
|
||||
public void onStartingToHide() {
|
||||
mKeyguardSecurityContainerController.onStartingToHide();
|
||||
}
|
||||
|
||||
/** Called when bouncer visibility changes. */
|
||||
public void onBouncerVisibilityChanged(@View.Visibility int visibility) {
|
||||
mKeyguardSecurityContainerController.onBouncerVisibilityChanged(visibility);
|
||||
}
|
||||
|
||||
public boolean hasDismissActions() {
|
||||
return mDismissAction != null || mCancelAction != null;
|
||||
}
|
||||
|
||||
public SecurityMode getCurrentSecurityMode() {
|
||||
return mKeyguardSecurityContainerController.getCurrentSecurityMode();
|
||||
}
|
||||
|
||||
public int getTop() {
|
||||
int top = mView.getTop();
|
||||
// The password view has an extra top padding that should be ignored.
|
||||
if (getCurrentSecurityMode() == SecurityMode.Password) {
|
||||
View messageArea = mView.findViewById(R.id.keyguard_message_area);
|
||||
top += messageArea.getTop();
|
||||
}
|
||||
return top;
|
||||
}
|
||||
|
||||
public boolean handleBackKey() {
|
||||
SecurityMode securityMode = mKeyguardSecurityContainerController.getCurrentSecurityMode();
|
||||
if (securityMode != SecurityMode.None) {
|
||||
mKeyguardSecurityContainerController.dismiss(
|
||||
false, KeyguardUpdateMonitor.getCurrentUser(), securityMode);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* In general, we enable unlocking the insecure keyguard with the menu key. However, there are
|
||||
* some cases where we wish to disable it, notably when the menu button placement or technology
|
||||
* is prone to false positives.
|
||||
*
|
||||
* @return true if the menu key should be enabled
|
||||
*/
|
||||
public boolean shouldEnableMenuKey() {
|
||||
final Resources res = mView.getResources();
|
||||
final boolean configDisabled = res.getBoolean(R.bool.config_disableMenuKeyInLockScreen);
|
||||
final boolean isTestHarness = ActivityManager.isRunningInTestHarness();
|
||||
final boolean fileOverride = (new File(ENABLE_MENU_KEY_FILE)).exists();
|
||||
return !configDisabled || isTestHarness || fileOverride;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the current bouncer is password
|
||||
*/
|
||||
public boolean dispatchBackKeyEventPreIme() {
|
||||
if (mKeyguardSecurityContainerController.getCurrentSecurityMode()
|
||||
== SecurityMode.Password) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link OnBackAnimationCallback} to animate this view during a back gesture.
|
||||
*/
|
||||
@NonNull
|
||||
public OnBackAnimationCallback getBackCallback() {
|
||||
return mKeyguardSecurityContainerController.getBackCallback();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows the media keys to work when the keyguard is showing.
|
||||
* The media keys should be of no interest to the actual keyguard view(s),
|
||||
* so intercepting them here should not be of any harm.
|
||||
* @param event The key event
|
||||
* @return whether the event was consumed as a media key.
|
||||
*/
|
||||
public boolean interceptMediaKey(KeyEvent event) {
|
||||
int keyCode = event.getKeyCode();
|
||||
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||
switch (keyCode) {
|
||||
case KeyEvent.KEYCODE_MEDIA_PLAY:
|
||||
case KeyEvent.KEYCODE_MEDIA_PAUSE:
|
||||
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
|
||||
/* Suppress PLAY/PAUSE toggle when phone is ringing or
|
||||
* in-call to avoid music playback */
|
||||
if (mTelephonyManager != null &&
|
||||
mTelephonyManager.getCallState() != TelephonyManager.CALL_STATE_IDLE) {
|
||||
return true; // suppress key event
|
||||
}
|
||||
case KeyEvent.KEYCODE_MUTE:
|
||||
case KeyEvent.KEYCODE_HEADSETHOOK:
|
||||
case KeyEvent.KEYCODE_MEDIA_STOP:
|
||||
case KeyEvent.KEYCODE_MEDIA_NEXT:
|
||||
case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
|
||||
case KeyEvent.KEYCODE_MEDIA_REWIND:
|
||||
case KeyEvent.KEYCODE_MEDIA_RECORD:
|
||||
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
|
||||
case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
|
||||
handleMediaKeyEvent(event);
|
||||
return true;
|
||||
}
|
||||
|
||||
case KeyEvent.KEYCODE_VOLUME_UP:
|
||||
case KeyEvent.KEYCODE_VOLUME_DOWN:
|
||||
case KeyEvent.KEYCODE_VOLUME_MUTE: {
|
||||
if (KEYGUARD_MANAGES_VOLUME) {
|
||||
// Volume buttons should only function for music (local or remote).
|
||||
// TODO: Actually handle MUTE.
|
||||
mAudioManager.adjustSuggestedStreamVolume(
|
||||
keyCode == KeyEvent.KEYCODE_VOLUME_UP
|
||||
? AudioManager.ADJUST_RAISE
|
||||
: AudioManager.ADJUST_LOWER /* direction */,
|
||||
AudioManager.STREAM_MUSIC /* stream */, 0 /* flags */);
|
||||
// Don't execute default volume behavior
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (event.getAction() == KeyEvent.ACTION_UP) {
|
||||
switch (keyCode) {
|
||||
case KeyEvent.KEYCODE_MUTE:
|
||||
case KeyEvent.KEYCODE_HEADSETHOOK:
|
||||
case KeyEvent.KEYCODE_MEDIA_PLAY:
|
||||
case KeyEvent.KEYCODE_MEDIA_PAUSE:
|
||||
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
|
||||
case KeyEvent.KEYCODE_MEDIA_STOP:
|
||||
case KeyEvent.KEYCODE_MEDIA_NEXT:
|
||||
case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
|
||||
case KeyEvent.KEYCODE_MEDIA_REWIND:
|
||||
case KeyEvent.KEYCODE_MEDIA_RECORD:
|
||||
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
|
||||
case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
|
||||
handleMediaKeyEvent(event);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private void handleMediaKeyEvent(KeyEvent keyEvent) {
|
||||
mAudioManager.dispatchMediaKeyEvent(keyEvent);
|
||||
}
|
||||
|
||||
public void finish(boolean strongAuth, int currentUser) {
|
||||
mSecurityCallback.finish(strongAuth, currentUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply keyguard configuration from the currently active resources. This can be called when the
|
||||
* device configuration changes, to re-apply some resources that are qualified on the device
|
||||
* configuration.
|
||||
*/
|
||||
public void updateResources() {
|
||||
int gravity;
|
||||
|
||||
Resources resources = mView.getResources();
|
||||
|
||||
if (resources.getBoolean(R.bool.can_use_one_handed_bouncer)) {
|
||||
gravity = resources.getInteger(
|
||||
R.integer.keyguard_host_view_one_handed_gravity);
|
||||
} else {
|
||||
gravity = resources.getInteger(R.integer.keyguard_host_view_gravity);
|
||||
}
|
||||
|
||||
mTranslationY = resources
|
||||
.getDimensionPixelSize(R.dimen.keyguard_host_view_translation_y);
|
||||
// Android SysUI uses a FrameLayout as the top-level, but Auto uses RelativeLayout.
|
||||
// We're just changing the gravity here though (which can't be applied to RelativeLayout),
|
||||
// so only attempt the update if mView is inside a FrameLayout.
|
||||
if (mView.getLayoutParams() instanceof FrameLayout.LayoutParams) {
|
||||
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mView.getLayoutParams();
|
||||
if (lp.gravity != gravity) {
|
||||
lp.gravity = gravity;
|
||||
mView.setLayoutParams(lp);
|
||||
}
|
||||
}
|
||||
|
||||
if (mKeyguardSecurityContainerController != null) {
|
||||
mKeyguardSecurityContainerController.updateResources();
|
||||
}
|
||||
}
|
||||
|
||||
/** Update keyguard position based on a tapped X coordinate. */
|
||||
public void updateKeyguardPosition(float x) {
|
||||
if (mKeyguardSecurityContainerController != null) {
|
||||
mKeyguardSecurityContainerController.updateKeyguardPosition(x);
|
||||
}
|
||||
}
|
||||
|
||||
/** Set true if the view can be interacted with */
|
||||
public void setInteractable(boolean isInteractable) {
|
||||
mView.setInteractable(isInteractable);
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,26 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView>
|
||||
// The following is used to ignore callbacks from SecurityViews that are no longer current
|
||||
// (e.g. face unlock). This avoids unwanted asynchronous events from messing with the
|
||||
// state for the current security method.
|
||||
private KeyguardSecurityCallback mNullCallback = new KeyguardSecurityCallback() {};
|
||||
private KeyguardSecurityCallback mNullCallback = new KeyguardSecurityCallback() {
|
||||
@Override
|
||||
public void userActivity() { }
|
||||
@Override
|
||||
public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) { }
|
||||
@Override
|
||||
public boolean isVerifyUnlockOnly() {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public void dismiss(boolean securityVerified, int targetUserId,
|
||||
SecurityMode expectedSecurityMode) { }
|
||||
@Override
|
||||
public void dismiss(boolean authenticated, int targetId,
|
||||
boolean bypassSecondaryLockScreen, SecurityMode expectedSecurityMode) { }
|
||||
@Override
|
||||
public void onUserInput() { }
|
||||
@Override
|
||||
public void reset() {}
|
||||
};
|
||||
|
||||
protected KeyguardInputViewController(T view, SecurityMode securityMode,
|
||||
KeyguardSecurityCallback keyguardSecurityCallback,
|
||||
|
||||
@@ -25,9 +25,7 @@ public interface KeyguardSecurityCallback {
|
||||
* @param targetUserId a user that needs to be the foreground user at the dismissal completion.
|
||||
* @param expectedSecurityMode The security mode that is invoking this dismiss.
|
||||
*/
|
||||
default void dismiss(boolean securityVerified, int targetUserId,
|
||||
SecurityMode expectedSecurityMode) {
|
||||
}
|
||||
void dismiss(boolean securityVerified, int targetUserId, SecurityMode expectedSecurityMode);
|
||||
|
||||
/**
|
||||
* Dismiss the given security screen.
|
||||
@@ -37,26 +35,19 @@ public interface KeyguardSecurityCallback {
|
||||
* if any, during this dismissal.
|
||||
* @param expectedSecurityMode The security mode that is invoking this dismiss.
|
||||
*/
|
||||
default boolean dismiss(boolean securityVerified, int targetUserId,
|
||||
boolean bypassSecondaryLockScreen,
|
||||
SecurityMode expectedSecurityMode) {
|
||||
return false;
|
||||
}
|
||||
void dismiss(boolean securityVerified, int targetUserId, boolean bypassSecondaryLockScreen,
|
||||
SecurityMode expectedSecurityMode);
|
||||
|
||||
/**
|
||||
* Manually report user activity to keep the device awake.
|
||||
*/
|
||||
default void userActivity() {
|
||||
}
|
||||
void userActivity();
|
||||
|
||||
/**
|
||||
* Checks if keyguard is in "verify credentials" mode.
|
||||
*
|
||||
* @return true if user has been asked to verify security.
|
||||
*/
|
||||
default boolean isVerifyUnlockOnly() {
|
||||
return false;
|
||||
}
|
||||
boolean isVerifyUnlockOnly();
|
||||
|
||||
/**
|
||||
* Call to report an unlock attempt.
|
||||
@@ -65,14 +56,12 @@ public interface KeyguardSecurityCallback {
|
||||
* @param timeoutMs timeout in milliseconds to wait before reattempting an unlock.
|
||||
* Only nonzero if 'success' is false
|
||||
*/
|
||||
default void reportUnlockAttempt(int userId, boolean success, int timeoutMs) {
|
||||
}
|
||||
void reportUnlockAttempt(int userId, boolean success, int timeoutMs);
|
||||
|
||||
/**
|
||||
* Resets the keyguard view.
|
||||
*/
|
||||
default void reset() {
|
||||
}
|
||||
void reset();
|
||||
|
||||
/**
|
||||
* Call when cancel button is pressed in bouncer.
|
||||
@@ -84,19 +73,5 @@ public interface KeyguardSecurityCallback {
|
||||
/**
|
||||
* Invoked whenever users are typing their password or drawing a pattern.
|
||||
*/
|
||||
default void onUserInput() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Dismisses keyguard and go to unlocked state.
|
||||
*/
|
||||
default void finish(boolean strongAuth, int targetUserId) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies that security mode has changed.
|
||||
*/
|
||||
default void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput) {
|
||||
}
|
||||
void onUserInput();
|
||||
}
|
||||
|
||||
@@ -50,7 +50,6 @@ import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BlendMode;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
@@ -165,8 +164,6 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
|
||||
private boolean mDisappearAnimRunning;
|
||||
private SwipeListener mSwipeListener;
|
||||
private ViewMode mViewMode = new DefaultViewMode();
|
||||
private boolean mIsInteractable;
|
||||
protected ViewMediatorCallback mViewMediatorCallback;
|
||||
/*
|
||||
* Using MODE_UNINITIALIZED to mean the view mode is set to DefaultViewMode, but init() has not
|
||||
* yet been called on it. This will happen when the ViewController is initialized.
|
||||
@@ -268,6 +265,31 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
|
||||
return mBackCallback;
|
||||
}
|
||||
|
||||
// Used to notify the container when something interesting happens.
|
||||
public interface SecurityCallback {
|
||||
/**
|
||||
* Potentially dismiss the current security screen, after validating that all device
|
||||
* security has been unlocked. Otherwise show the next screen.
|
||||
*/
|
||||
boolean dismiss(boolean authenticated, int targetUserId, boolean bypassSecondaryLockScreen,
|
||||
SecurityMode expectedSecurityMode);
|
||||
|
||||
void userActivity();
|
||||
|
||||
void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput);
|
||||
|
||||
/**
|
||||
* @param strongAuth wheher the user has authenticated with strong authentication like
|
||||
* pattern, password or PIN but not by trust agents or fingerprint
|
||||
* @param targetUserId a user that needs to be the foreground user at the finish completion.
|
||||
*/
|
||||
void finish(boolean strongAuth, int targetUserId);
|
||||
|
||||
void reset();
|
||||
|
||||
void onCancelClicked();
|
||||
}
|
||||
|
||||
public interface SwipeListener {
|
||||
void onSwipeUp();
|
||||
}
|
||||
@@ -320,7 +342,7 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
|
||||
|
||||
public KeyguardSecurityContainer(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
mSpringAnimation = new SpringAnimation(this, DynamicAnimation.TRANSLATION_Y);
|
||||
mSpringAnimation = new SpringAnimation(this, DynamicAnimation.Y);
|
||||
mViewConfiguration = ViewConfiguration.get(context);
|
||||
mDoubleTapDetector = new GestureDetector(context, new DoubleTapListener());
|
||||
}
|
||||
@@ -423,11 +445,6 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
|
||||
mViewMode.reset();
|
||||
}
|
||||
|
||||
/** Set true if the view can be interacted with */
|
||||
public void setInteractable(boolean isInteractable) {
|
||||
mIsInteractable = isInteractable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldDelayChildPressedState() {
|
||||
return true;
|
||||
@@ -435,10 +452,6 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent event) {
|
||||
if (!mIsInteractable) {
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean result = mMotionEventListeners.stream().anyMatch(
|
||||
listener -> listener.onInterceptTouchEvent(event))
|
||||
|| super.onInterceptTouchEvent(event);
|
||||
@@ -626,18 +639,6 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
|
||||
return insets.inset(0, 0, 0, inset);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dispatchDraw(Canvas canvas) {
|
||||
super.dispatchDraw(canvas);
|
||||
if (mViewMediatorCallback != null) {
|
||||
mViewMediatorCallback.keyguardDoneDrawing();
|
||||
}
|
||||
}
|
||||
|
||||
public void setViewMediatorCallback(ViewMediatorCallback viewMediatorCallback) {
|
||||
mViewMediatorCallback = viewMediatorCallback;
|
||||
}
|
||||
|
||||
private void showDialog(String title, String message) {
|
||||
if (mAlertDialog != null) {
|
||||
mAlertDialog.dismiss();
|
||||
|
||||
@@ -29,26 +29,17 @@ import static com.android.keyguard.KeyguardSecurityContainer.USER_TYPE_SECONDARY
|
||||
import static com.android.keyguard.KeyguardSecurityContainer.USER_TYPE_WORK_PROFILE;
|
||||
import static com.android.systemui.DejankUtils.whitelistIpcs;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.content.Intent;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.hardware.biometrics.BiometricSourceType;
|
||||
import android.media.AudioManager;
|
||||
import android.metrics.LogMaker;
|
||||
import android.os.SystemClock;
|
||||
import android.os.UserHandle;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.Log;
|
||||
import android.util.MathUtils;
|
||||
import android.util.Slog;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.widget.FrameLayout;
|
||||
import android.window.OnBackAnimationCallback;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -62,6 +53,7 @@ import com.android.internal.logging.nano.MetricsProto;
|
||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.keyguard.KeyguardSecurityContainer.BouncerUiEvent;
|
||||
import com.android.keyguard.KeyguardSecurityContainer.SecurityCallback;
|
||||
import com.android.keyguard.KeyguardSecurityContainer.SwipeListener;
|
||||
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
|
||||
import com.android.keyguard.dagger.KeyguardBouncerScope;
|
||||
@@ -75,7 +67,6 @@ import com.android.systemui.classifier.FalsingCollector;
|
||||
import com.android.systemui.flags.FeatureFlags;
|
||||
import com.android.systemui.flags.Flags;
|
||||
import com.android.systemui.log.SessionTracker;
|
||||
import com.android.systemui.plugins.ActivityStarter;
|
||||
import com.android.systemui.plugins.FalsingManager;
|
||||
import com.android.systemui.shared.system.SysUiStatsLog;
|
||||
import com.android.systemui.statusbar.policy.ConfigurationController;
|
||||
@@ -84,7 +75,6 @@ import com.android.systemui.statusbar.policy.UserSwitcherController;
|
||||
import com.android.systemui.util.ViewController;
|
||||
import com.android.systemui.util.settings.GlobalSettings;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@@ -105,6 +95,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
|
||||
private final UiEventLogger mUiEventLogger;
|
||||
private final KeyguardStateController mKeyguardStateController;
|
||||
private final KeyguardSecurityViewFlipperController mSecurityViewFlipperController;
|
||||
private final SecurityCallback mSecurityCallback;
|
||||
private final ConfigurationController mConfigurationController;
|
||||
private final FalsingCollector mFalsingCollector;
|
||||
private final FalsingManager mFalsingManager;
|
||||
@@ -114,20 +105,6 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
|
||||
private final SessionTracker mSessionTracker;
|
||||
private final Optional<SideFpsController> mSideFpsController;
|
||||
private final FalsingA11yDelegate mFalsingA11yDelegate;
|
||||
private int mTranslationY;
|
||||
// Whether the volume keys should be handled by keyguard. If true, then
|
||||
// they will be handled here for specific media types such as music, otherwise
|
||||
// the audio service will bring up the volume dialog.
|
||||
private static final boolean KEYGUARD_MANAGES_VOLUME = false;
|
||||
|
||||
private static final String ENABLE_MENU_KEY_FILE = "/data/local/enable_menu_key";
|
||||
|
||||
private final TelephonyManager mTelephonyManager;
|
||||
private final ViewMediatorCallback mViewMediatorCallback;
|
||||
private final AudioManager mAudioManager;
|
||||
private View.OnKeyListener mOnKeyListener = (v, keyCode, event) -> interceptMediaKey(event);
|
||||
private ActivityStarter.OnDismissAction mDismissAction;
|
||||
private Runnable mCancelAction;
|
||||
|
||||
private int mLastOrientation = Configuration.ORIENTATION_UNDEFINED;
|
||||
|
||||
@@ -172,6 +149,11 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
|
||||
};
|
||||
|
||||
private KeyguardSecurityCallback mKeyguardSecurityCallback = new KeyguardSecurityCallback() {
|
||||
public void userActivity() {
|
||||
if (mSecurityCallback != null) {
|
||||
mSecurityCallback.userActivity();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserInput() {
|
||||
@@ -186,23 +168,16 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dismiss(boolean authenticated, int targetId,
|
||||
public void dismiss(boolean authenticated, int targetId,
|
||||
boolean bypassSecondaryLockScreen, SecurityMode expectedSecurityMode) {
|
||||
return showNextSecurityScreenOrFinish(
|
||||
authenticated, targetId, bypassSecondaryLockScreen, expectedSecurityMode);
|
||||
mSecurityCallback.dismiss(authenticated, targetId, bypassSecondaryLockScreen,
|
||||
expectedSecurityMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void userActivity() {
|
||||
mViewMediatorCallback.userActivity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVerifyUnlockOnly() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) {
|
||||
int bouncerSide = SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__SIDE__DEFAULT;
|
||||
if (mView.isSidedSecurityMode()) {
|
||||
@@ -239,47 +214,12 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
|
||||
: BouncerUiEvent.BOUNCER_PASSWORD_FAILURE, getSessionId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
mViewMediatorCallback.resetKeyguard();
|
||||
mSecurityCallback.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancelClicked() {
|
||||
mViewMediatorCallback.onCancelClicked();
|
||||
}
|
||||
|
||||
/**
|
||||
* Authentication has happened and it's time to dismiss keyguard. This function
|
||||
* should clean up and inform KeyguardViewMediator.
|
||||
*
|
||||
* @param strongAuth whether the user has authenticated with strong authentication like
|
||||
* pattern, password or PIN but not by trust agents or fingerprint
|
||||
* @param targetUserId a user that needs to be the foreground user at the dismissal
|
||||
* completion.
|
||||
*/
|
||||
@Override
|
||||
public void finish(boolean strongAuth, int targetUserId) {
|
||||
// If there's a pending runnable because the user interacted with a widget
|
||||
// and we're leaving keyguard, then run it.
|
||||
boolean deferKeyguardDone = false;
|
||||
if (mDismissAction != null) {
|
||||
deferKeyguardDone = mDismissAction.onDismiss();
|
||||
mDismissAction = null;
|
||||
mCancelAction = null;
|
||||
}
|
||||
if (mViewMediatorCallback != null) {
|
||||
if (deferKeyguardDone) {
|
||||
mViewMediatorCallback.keyguardDonePending(strongAuth, targetUserId);
|
||||
} else {
|
||||
mViewMediatorCallback.keyguardDone(strongAuth, targetUserId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput) {
|
||||
mViewMediatorCallback.setNeedsInput(needsInput);
|
||||
mSecurityCallback.onCancelClicked();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -322,34 +262,6 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
|
||||
private boolean mBouncerVisible = false;
|
||||
private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
|
||||
new KeyguardUpdateMonitorCallback() {
|
||||
@Override
|
||||
public void onTrustGrantedForCurrentUser(
|
||||
boolean dismissKeyguard,
|
||||
boolean newlyUnlocked,
|
||||
TrustGrantFlags flags,
|
||||
String message
|
||||
) {
|
||||
if (dismissKeyguard) {
|
||||
if (!mView.isVisibleToUser()) {
|
||||
// The trust agent dismissed the keyguard without the user proving
|
||||
// that they are present (by swiping up to show the bouncer). That's
|
||||
// fine if the user proved presence via some other way to the trust
|
||||
// agent.
|
||||
Log.i(TAG, "TrustAgent dismissed Keyguard.");
|
||||
}
|
||||
mKeyguardSecurityCallback.dismiss(
|
||||
false /* authenticated */,
|
||||
KeyguardUpdateMonitor.getCurrentUser(),
|
||||
/* bypassSecondaryLockScreen */ false,
|
||||
SecurityMode.Invalid
|
||||
);
|
||||
} else {
|
||||
if (flags.isInitiatedByUser() || flags.dismissKeyguardRequested()) {
|
||||
mViewMediatorCallback.playTrustedSound();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDevicePolicyManagerStateChanged() {
|
||||
showPrimarySecurityScreen(false);
|
||||
@@ -369,8 +281,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
|
||||
}
|
||||
};
|
||||
|
||||
@Inject
|
||||
public KeyguardSecurityContainerController(KeyguardSecurityContainer view,
|
||||
private KeyguardSecurityContainerController(KeyguardSecurityContainer view,
|
||||
AdminSecondaryLockScreenController.Factory adminSecondaryLockScreenControllerFactory,
|
||||
LockPatternUtils lockPatternUtils,
|
||||
KeyguardUpdateMonitor keyguardUpdateMonitor,
|
||||
@@ -378,6 +289,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
|
||||
MetricsLogger metricsLogger,
|
||||
UiEventLogger uiEventLogger,
|
||||
KeyguardStateController keyguardStateController,
|
||||
SecurityCallback securityCallback,
|
||||
KeyguardSecurityViewFlipperController securityViewFlipperController,
|
||||
ConfigurationController configurationController,
|
||||
FalsingCollector falsingCollector,
|
||||
@@ -387,11 +299,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
|
||||
GlobalSettings globalSettings,
|
||||
SessionTracker sessionTracker,
|
||||
Optional<SideFpsController> sideFpsController,
|
||||
FalsingA11yDelegate falsingA11yDelegate,
|
||||
TelephonyManager telephonyManager,
|
||||
ViewMediatorCallback viewMediatorCallback,
|
||||
AudioManager audioManager
|
||||
) {
|
||||
FalsingA11yDelegate falsingA11yDelegate) {
|
||||
super(view);
|
||||
mLockPatternUtils = lockPatternUtils;
|
||||
mUpdateMonitor = keyguardUpdateMonitor;
|
||||
@@ -399,6 +307,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
|
||||
mMetricsLogger = metricsLogger;
|
||||
mUiEventLogger = uiEventLogger;
|
||||
mKeyguardStateController = keyguardStateController;
|
||||
mSecurityCallback = securityCallback;
|
||||
mSecurityViewFlipperController = securityViewFlipperController;
|
||||
mAdminSecondaryLockScreenController = adminSecondaryLockScreenControllerFactory.create(
|
||||
mKeyguardSecurityCallback);
|
||||
@@ -412,15 +321,11 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
|
||||
mSessionTracker = sessionTracker;
|
||||
mSideFpsController = sideFpsController;
|
||||
mFalsingA11yDelegate = falsingA11yDelegate;
|
||||
mTelephonyManager = telephonyManager;
|
||||
mViewMediatorCallback = viewMediatorCallback;
|
||||
mAudioManager = audioManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInit() {
|
||||
mSecurityViewFlipperController.init();
|
||||
updateResources();
|
||||
configureMode();
|
||||
}
|
||||
|
||||
@@ -431,11 +336,6 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
|
||||
mView.addMotionEventListener(mGlobalTouchListener);
|
||||
mConfigurationController.addCallback(mConfigurationListener);
|
||||
mUserSwitcherController.addUserSwitchCallback(mUserSwitchCallback);
|
||||
mView.setViewMediatorCallback(mViewMediatorCallback);
|
||||
// Update ViewMediator with the current input method requirements
|
||||
mViewMediatorCallback.setNeedsInput(needsInput());
|
||||
mView.setOnKeyListener(mOnKeyListener);
|
||||
showPrimarySecurityScreen(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -448,11 +348,6 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
|
||||
|
||||
/** */
|
||||
public void onPause() {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, String.format("screen off, instance %s at %s",
|
||||
Integer.toHexString(hashCode()), SystemClock.uptimeMillis()));
|
||||
}
|
||||
showPrimarySecurityScreen(true);
|
||||
mAdminSecondaryLockScreenController.hide();
|
||||
if (mCurrentSecurityMode != SecurityMode.None) {
|
||||
getCurrentSecurityController().onPause();
|
||||
@@ -461,7 +356,6 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
|
||||
// It might happen that onStartingToHide is not called when the device is locked while on
|
||||
// bouncer.
|
||||
setBouncerVisible(false);
|
||||
mView.clearFocus();
|
||||
}
|
||||
|
||||
private void updateSideFpsVisibility() {
|
||||
@@ -497,22 +391,12 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
|
||||
* @param turningOff true if the device is being turned off
|
||||
*/
|
||||
public void showPrimarySecurityScreen(boolean turningOff) {
|
||||
if (DEBUG) Log.d(TAG, "show()");
|
||||
SecurityMode securityMode = whitelistIpcs(() -> mSecurityModel.getSecurityMode(
|
||||
KeyguardUpdateMonitor.getCurrentUser()));
|
||||
if (DEBUG) Log.v(TAG, "showPrimarySecurityScreen(turningOff=" + turningOff + ")");
|
||||
showSecurityScreen(securityMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a string explaining why the security view needs to be solved.
|
||||
*
|
||||
* @param reason a flag indicating which string should be shown, see
|
||||
* {@link KeyguardSecurityView#PROMPT_REASON_NONE},
|
||||
* {@link KeyguardSecurityView#PROMPT_REASON_RESTART},
|
||||
* {@link KeyguardSecurityView#PROMPT_REASON_TIMEOUT}, and
|
||||
* {@link KeyguardSecurityView#PROMPT_REASON_PREPARE_FOR_UPDATE}.
|
||||
*/
|
||||
@Override
|
||||
public void showPromptReason(int reason) {
|
||||
if (mCurrentSecurityMode != SecurityMode.None) {
|
||||
@@ -529,32 +413,8 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an action to run when keyguard finishes.
|
||||
*
|
||||
* @param action callback to be invoked when keyguard disappear animation completes.
|
||||
*/
|
||||
public void setOnDismissAction(ActivityStarter.OnDismissAction action, Runnable cancelAction) {
|
||||
if (mCancelAction != null) {
|
||||
mCancelAction.run();
|
||||
mCancelAction = null;
|
||||
}
|
||||
mDismissAction = action;
|
||||
mCancelAction = cancelAction;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether dismiss action or cancel action has been set.
|
||||
*/
|
||||
public boolean hasDismissActions() {
|
||||
return mDismissAction != null || mCancelAction != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove any dismiss action or cancel action that was set.
|
||||
*/
|
||||
public void cancelDismissAction() {
|
||||
setOnDismissAction(null, null);
|
||||
public SecurityMode getCurrentSecurityMode() {
|
||||
return mCurrentSecurityMode;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -566,64 +426,17 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
|
||||
mKeyguardSecurityCallback.dismiss(authenticated, targetUserId, expectedSecurityMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dismisses the keyguard by going to the next screen or making it gone.
|
||||
* @param targetUserId a user that needs to be the foreground user at the dismissal completion.
|
||||
* @return True if the keyguard is done.
|
||||
*/
|
||||
public boolean dismiss(int targetUserId) {
|
||||
return mKeyguardSecurityCallback.dismiss(false, targetUserId, false,
|
||||
getCurrentSecurityMode());
|
||||
}
|
||||
|
||||
public SecurityMode getCurrentSecurityMode() {
|
||||
return mCurrentSecurityMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the top of the corresponding view.
|
||||
*/
|
||||
public int getTop() {
|
||||
int top = mView.getTop();
|
||||
// The password view has an extra top padding that should be ignored.
|
||||
if (getCurrentSecurityMode() == SecurityMode.Password) {
|
||||
View messageArea = mView.findViewById(R.id.keyguard_message_area);
|
||||
top += messageArea.getTop();
|
||||
}
|
||||
return top;
|
||||
}
|
||||
|
||||
/** Set true if the view can be interacted with */
|
||||
public void setInteractable(boolean isInteractable) {
|
||||
mView.setInteractable(isInteractable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dismiss keyguard due to a user unlock event.
|
||||
*/
|
||||
public void finish(boolean strongAuth, int currentUser) {
|
||||
mKeyguardSecurityCallback.finish(strongAuth, currentUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the text of the KeyguardMessageArea.
|
||||
*/
|
||||
public CharSequence getTitle() {
|
||||
return mView.getTitle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the state of the views.
|
||||
*/
|
||||
public void reset() {
|
||||
mView.reset();
|
||||
mSecurityViewFlipperController.reset();
|
||||
}
|
||||
|
||||
public CharSequence getTitle() {
|
||||
return mView.getTitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume(int reason) {
|
||||
if (DEBUG) Log.d(TAG, "screen on, instance " + Integer.toHexString(hashCode()));
|
||||
mView.requestFocus();
|
||||
if (mCurrentSecurityMode != SecurityMode.None) {
|
||||
int state = SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED__STATE__SHOWN;
|
||||
if (mView.isSidedSecurityMode()) {
|
||||
@@ -641,30 +454,6 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
|
||||
mKeyguardStateController.isFaceAuthEnabled());
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the bouncer and start appear animations.
|
||||
*
|
||||
* @param statusBarHeight
|
||||
*/
|
||||
public void appear(int statusBarHeight) {
|
||||
// We might still be collapsed and the view didn't have time to layout yet or still
|
||||
// be small, let's wait on the predraw to do the animation in that case.
|
||||
if (mView.getHeight() != 0 && mView.getHeight() != statusBarHeight) {
|
||||
startAppearAnimation();
|
||||
} else {
|
||||
mView.getViewTreeObserver().addOnPreDrawListener(
|
||||
new ViewTreeObserver.OnPreDrawListener() {
|
||||
@Override
|
||||
public boolean onPreDraw() {
|
||||
mView.getViewTreeObserver().removeOnPreDrawListener(this);
|
||||
startAppearAnimation();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
mView.requestLayout();
|
||||
}
|
||||
}
|
||||
|
||||
public void startAppearAnimation() {
|
||||
if (mCurrentSecurityMode != SecurityMode.None) {
|
||||
mView.setAlpha(1f);
|
||||
@@ -676,13 +465,9 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
|
||||
public boolean startDisappearAnimation(Runnable onFinishRunnable) {
|
||||
if (mCurrentSecurityMode != SecurityMode.None) {
|
||||
mView.startDisappearAnimation(mCurrentSecurityMode);
|
||||
boolean animating = getCurrentSecurityController().startDisappearAnimation(
|
||||
onFinishRunnable);
|
||||
if (!animating && onFinishRunnable != null) {
|
||||
onFinishRunnable.run();
|
||||
}
|
||||
return animating;
|
||||
return getCurrentSecurityController().startDisappearAnimation(onFinishRunnable);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -798,7 +583,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
|
||||
mUiEventLogger.log(uiEvent, getSessionId());
|
||||
}
|
||||
if (finish) {
|
||||
mKeyguardSecurityCallback.finish(strongAuth, targetUserId);
|
||||
mSecurityCallback.finish(strongAuth, targetUserId);
|
||||
}
|
||||
return finish;
|
||||
}
|
||||
@@ -811,113 +596,10 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
|
||||
* @return the {@link OnBackAnimationCallback} to animate this view during a back gesture.
|
||||
*/
|
||||
@NonNull
|
||||
public OnBackAnimationCallback getBackCallback() {
|
||||
OnBackAnimationCallback getBackCallback() {
|
||||
return mView.getBackCallback();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether we should dispatch the back key event before Ime.
|
||||
*/
|
||||
public boolean dispatchBackKeyEventPreIme() {
|
||||
return getCurrentSecurityMode() == SecurityMode.Password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows the media keys to work when the keyguard is showing.
|
||||
* The media keys should be of no interest to the actual keyguard view(s),
|
||||
* so intercepting them here should not be of any harm.
|
||||
* @param event The key event
|
||||
* @return whether the event was consumed as a media key.
|
||||
*/
|
||||
public boolean interceptMediaKey(KeyEvent event) {
|
||||
int keyCode = event.getKeyCode();
|
||||
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||
switch (keyCode) {
|
||||
case KeyEvent.KEYCODE_MEDIA_PLAY:
|
||||
case KeyEvent.KEYCODE_MEDIA_PAUSE:
|
||||
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
|
||||
/* Suppress PLAY/PAUSE toggle when phone is ringing or
|
||||
* in-call to avoid music playback */
|
||||
if (mTelephonyManager != null
|
||||
&& mTelephonyManager.getCallState()
|
||||
!= TelephonyManager.CALL_STATE_IDLE) {
|
||||
return true; // suppress key event
|
||||
}
|
||||
return false;
|
||||
case KeyEvent.KEYCODE_MUTE:
|
||||
case KeyEvent.KEYCODE_HEADSETHOOK:
|
||||
case KeyEvent.KEYCODE_MEDIA_STOP:
|
||||
case KeyEvent.KEYCODE_MEDIA_NEXT:
|
||||
case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
|
||||
case KeyEvent.KEYCODE_MEDIA_REWIND:
|
||||
case KeyEvent.KEYCODE_MEDIA_RECORD:
|
||||
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
|
||||
case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
|
||||
handleMediaKeyEvent(event);
|
||||
return true;
|
||||
}
|
||||
|
||||
case KeyEvent.KEYCODE_VOLUME_UP:
|
||||
case KeyEvent.KEYCODE_VOLUME_DOWN:
|
||||
case KeyEvent.KEYCODE_VOLUME_MUTE: {
|
||||
if (KEYGUARD_MANAGES_VOLUME) {
|
||||
// Volume buttons should only function for music (local or remote).
|
||||
// TODO: Actually handle MUTE.
|
||||
mAudioManager.adjustSuggestedStreamVolume(
|
||||
keyCode == KeyEvent.KEYCODE_VOLUME_UP
|
||||
? AudioManager.ADJUST_RAISE
|
||||
: AudioManager.ADJUST_LOWER /* direction */,
|
||||
AudioManager.STREAM_MUSIC /* stream */, 0 /* flags */);
|
||||
// Don't execute default volume behavior
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (event.getAction() == KeyEvent.ACTION_UP) {
|
||||
switch (keyCode) {
|
||||
case KeyEvent.KEYCODE_MUTE:
|
||||
case KeyEvent.KEYCODE_HEADSETHOOK:
|
||||
case KeyEvent.KEYCODE_MEDIA_PLAY:
|
||||
case KeyEvent.KEYCODE_MEDIA_PAUSE:
|
||||
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
|
||||
case KeyEvent.KEYCODE_MEDIA_STOP:
|
||||
case KeyEvent.KEYCODE_MEDIA_NEXT:
|
||||
case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
|
||||
case KeyEvent.KEYCODE_MEDIA_REWIND:
|
||||
case KeyEvent.KEYCODE_MEDIA_RECORD:
|
||||
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
|
||||
case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
|
||||
handleMediaKeyEvent(event);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private void handleMediaKeyEvent(KeyEvent keyEvent) {
|
||||
mAudioManager.dispatchMediaKeyEvent(keyEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* In general, we enable unlocking the insecure keyguard with the menu key. However, there are
|
||||
* some cases where we wish to disable it, notably when the menu button placement or technology
|
||||
* is prone to false positives.
|
||||
*
|
||||
* @return true if the menu key should be enabled
|
||||
*/
|
||||
public boolean shouldEnableMenuKey() {
|
||||
final Resources res = mView.getResources();
|
||||
final boolean configDisabled = res.getBoolean(R.bool.config_disableMenuKeyInLockScreen);
|
||||
final boolean isTestHarness = ActivityManager.isRunningInTestHarness();
|
||||
final boolean fileOverride = (new File(ENABLE_MENU_KEY_FILE)).exists();
|
||||
return !configDisabled || isTestHarness || fileOverride;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Switches to the given security view unless it's already being shown, in which case
|
||||
* this is a no-op.
|
||||
@@ -946,7 +628,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
|
||||
configureMode();
|
||||
}
|
||||
|
||||
mKeyguardSecurityCallback.onSecurityModeChanged(
|
||||
mSecurityCallback.onSecurityModeChanged(
|
||||
securityMode, newView != null && newView.needsInput());
|
||||
}
|
||||
|
||||
@@ -1044,30 +726,6 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
|
||||
* configuration.
|
||||
*/
|
||||
public void updateResources() {
|
||||
int gravity;
|
||||
|
||||
Resources resources = mView.getResources();
|
||||
|
||||
if (resources.getBoolean(R.bool.can_use_one_handed_bouncer)) {
|
||||
gravity = resources.getInteger(
|
||||
R.integer.keyguard_host_view_one_handed_gravity);
|
||||
} else {
|
||||
gravity = resources.getInteger(R.integer.keyguard_host_view_gravity);
|
||||
}
|
||||
|
||||
mTranslationY = resources
|
||||
.getDimensionPixelSize(R.dimen.keyguard_host_view_translation_y);
|
||||
// Android SysUI uses a FrameLayout as the top-level, but Auto uses RelativeLayout.
|
||||
// We're just changing the gravity here though (which can't be applied to RelativeLayout),
|
||||
// so only attempt the update if mView is inside a FrameLayout.
|
||||
if (mView.getLayoutParams() instanceof FrameLayout.LayoutParams) {
|
||||
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mView.getLayoutParams();
|
||||
if (lp.gravity != gravity) {
|
||||
lp.gravity = gravity;
|
||||
mView.setLayoutParams(lp);
|
||||
}
|
||||
}
|
||||
|
||||
int newOrientation = getResources().getConfiguration().orientation;
|
||||
if (newOrientation != mLastOrientation) {
|
||||
mLastOrientation = newOrientation;
|
||||
@@ -1101,15 +759,77 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
|
||||
mKeyguardSecurityCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fades and translates in/out the security screen.
|
||||
* Fades in as expansion approaches 0.
|
||||
* Animation duration is between 0.33f and 0.67f of panel expansion fraction.
|
||||
* @param fraction amount of the screen that should show.
|
||||
*/
|
||||
public void setExpansion(float fraction) {
|
||||
float scaledFraction = BouncerPanelExpansionCalculator.showBouncerProgress(fraction);
|
||||
mView.setAlpha(MathUtils.constrain(1 - scaledFraction, 0f, 1f));
|
||||
mView.setTranslationY(scaledFraction * mTranslationY);
|
||||
static class Factory {
|
||||
|
||||
private final KeyguardSecurityContainer mView;
|
||||
private final AdminSecondaryLockScreenController.Factory
|
||||
mAdminSecondaryLockScreenControllerFactory;
|
||||
private final LockPatternUtils mLockPatternUtils;
|
||||
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
|
||||
private final KeyguardSecurityModel mKeyguardSecurityModel;
|
||||
private final MetricsLogger mMetricsLogger;
|
||||
private final UiEventLogger mUiEventLogger;
|
||||
private final KeyguardStateController mKeyguardStateController;
|
||||
private final KeyguardSecurityViewFlipperController mSecurityViewFlipperController;
|
||||
private final ConfigurationController mConfigurationController;
|
||||
private final FalsingCollector mFalsingCollector;
|
||||
private final FalsingManager mFalsingManager;
|
||||
private final GlobalSettings mGlobalSettings;
|
||||
private final FeatureFlags mFeatureFlags;
|
||||
private final UserSwitcherController mUserSwitcherController;
|
||||
private final SessionTracker mSessionTracker;
|
||||
private final Optional<SideFpsController> mSidefpsController;
|
||||
private final FalsingA11yDelegate mFalsingA11yDelegate;
|
||||
|
||||
@Inject
|
||||
Factory(KeyguardSecurityContainer view,
|
||||
AdminSecondaryLockScreenController.Factory
|
||||
adminSecondaryLockScreenControllerFactory,
|
||||
LockPatternUtils lockPatternUtils,
|
||||
KeyguardUpdateMonitor keyguardUpdateMonitor,
|
||||
KeyguardSecurityModel keyguardSecurityModel,
|
||||
MetricsLogger metricsLogger,
|
||||
UiEventLogger uiEventLogger,
|
||||
KeyguardStateController keyguardStateController,
|
||||
KeyguardSecurityViewFlipperController securityViewFlipperController,
|
||||
ConfigurationController configurationController,
|
||||
FalsingCollector falsingCollector,
|
||||
FalsingManager falsingManager,
|
||||
UserSwitcherController userSwitcherController,
|
||||
FeatureFlags featureFlags,
|
||||
GlobalSettings globalSettings,
|
||||
SessionTracker sessionTracker,
|
||||
Optional<SideFpsController> sidefpsController,
|
||||
FalsingA11yDelegate falsingA11yDelegate) {
|
||||
mView = view;
|
||||
mAdminSecondaryLockScreenControllerFactory = adminSecondaryLockScreenControllerFactory;
|
||||
mLockPatternUtils = lockPatternUtils;
|
||||
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
|
||||
mKeyguardSecurityModel = keyguardSecurityModel;
|
||||
mMetricsLogger = metricsLogger;
|
||||
mUiEventLogger = uiEventLogger;
|
||||
mKeyguardStateController = keyguardStateController;
|
||||
mSecurityViewFlipperController = securityViewFlipperController;
|
||||
mConfigurationController = configurationController;
|
||||
mFalsingCollector = falsingCollector;
|
||||
mFalsingManager = falsingManager;
|
||||
mFeatureFlags = featureFlags;
|
||||
mGlobalSettings = globalSettings;
|
||||
mUserSwitcherController = userSwitcherController;
|
||||
mSessionTracker = sessionTracker;
|
||||
mSidefpsController = sidefpsController;
|
||||
mFalsingA11yDelegate = falsingA11yDelegate;
|
||||
}
|
||||
|
||||
public KeyguardSecurityContainerController create(
|
||||
SecurityCallback securityCallback) {
|
||||
return new KeyguardSecurityContainerController(mView,
|
||||
mAdminSecondaryLockScreenControllerFactory, mLockPatternUtils,
|
||||
mKeyguardUpdateMonitor, mKeyguardSecurityModel, mMetricsLogger, mUiEventLogger,
|
||||
mKeyguardStateController, securityCallback, mSecurityViewFlipperController,
|
||||
mConfigurationController, mFalsingCollector, mFalsingManager,
|
||||
mUserSwitcherController, mFeatureFlags, mGlobalSettings, mSessionTracker,
|
||||
mSidefpsController, mFalsingA11yDelegate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3747,7 +3747,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
|
||||
}
|
||||
|
||||
// TODO: use these callbacks elsewhere in place of the existing notifyScreen*()
|
||||
// (KeyguardViewMediator, KeyguardSecurityContainer)
|
||||
// (KeyguardViewMediator, KeyguardHostView)
|
||||
/**
|
||||
* Dispatch wakeup events to:
|
||||
* - update biometric listening states
|
||||
|
||||
@@ -18,7 +18,7 @@ package com.android.keyguard.dagger;
|
||||
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.android.keyguard.KeyguardSecurityContainerController;
|
||||
import com.android.keyguard.KeyguardHostViewController;
|
||||
import com.android.systemui.dagger.qualifiers.RootView;
|
||||
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor;
|
||||
|
||||
@@ -37,6 +37,6 @@ public interface KeyguardBouncerComponent {
|
||||
KeyguardBouncerComponent create(@BindsInstance @RootView ViewGroup bouncerContainer);
|
||||
}
|
||||
|
||||
/** Returns a {@link KeyguardSecurityContainerController}. */
|
||||
KeyguardSecurityContainerController getSecurityContainerController();
|
||||
/** Returns a {@link KeyguardHostViewController}. */
|
||||
KeyguardHostViewController getKeyguardHostViewController();
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.android.keyguard.KeyguardHostView;
|
||||
import com.android.keyguard.KeyguardSecurityContainer;
|
||||
import com.android.keyguard.KeyguardSecurityViewFlipper;
|
||||
import com.android.systemui.R;
|
||||
@@ -46,13 +47,19 @@ public interface KeyguardBouncerModule {
|
||||
/** */
|
||||
@Provides
|
||||
@KeyguardBouncerScope
|
||||
static KeyguardSecurityContainer providesKeyguardSecurityContainer(@RootView ViewGroup rootView,
|
||||
static KeyguardHostView providesKeyguardHostView(@RootView ViewGroup rootView,
|
||||
LayoutInflater layoutInflater) {
|
||||
KeyguardSecurityContainer securityContainer =
|
||||
(KeyguardSecurityContainer) layoutInflater.inflate(
|
||||
R.layout.keyguard_security_container_view, rootView, false);
|
||||
rootView.addView(securityContainer);
|
||||
return securityContainer;
|
||||
KeyguardHostView hostView = (KeyguardHostView) layoutInflater.inflate(
|
||||
R.layout.keyguard_host_view, rootView, false);
|
||||
rootView.addView(hostView);
|
||||
return hostView;
|
||||
}
|
||||
|
||||
/** */
|
||||
@Provides
|
||||
@KeyguardBouncerScope
|
||||
static KeyguardSecurityContainer providesKeyguardSecurityContainer(KeyguardHostView hostView) {
|
||||
return hostView.findViewById(R.id.keyguard_security_container);
|
||||
}
|
||||
|
||||
/** */
|
||||
|
||||
@@ -23,12 +23,10 @@ import android.window.OnBackAnimationCallback
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import com.android.internal.policy.SystemBarUtils
|
||||
import com.android.keyguard.KeyguardSecurityContainerController
|
||||
import com.android.keyguard.KeyguardHostViewController
|
||||
import com.android.keyguard.KeyguardSecurityModel
|
||||
import com.android.keyguard.KeyguardSecurityView
|
||||
import com.android.keyguard.KeyguardUpdateMonitor
|
||||
import com.android.keyguard.dagger.KeyguardBouncerComponent
|
||||
import com.android.settingslib.Utils
|
||||
import com.android.systemui.keyguard.data.BouncerViewDelegate
|
||||
import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE
|
||||
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel
|
||||
@@ -46,54 +44,52 @@ object KeyguardBouncerViewBinder {
|
||||
viewModel: KeyguardBouncerViewModel,
|
||||
componentFactory: KeyguardBouncerComponent.Factory
|
||||
) {
|
||||
// Builds the KeyguardSecurityContainerController from bouncer view group.
|
||||
val securityContainerController: KeyguardSecurityContainerController =
|
||||
componentFactory.create(view).securityContainerController
|
||||
securityContainerController.init()
|
||||
// Builds the KeyguardHostViewController from bouncer view group.
|
||||
val hostViewController: KeyguardHostViewController =
|
||||
componentFactory.create(view).keyguardHostViewController
|
||||
hostViewController.init()
|
||||
val delegate =
|
||||
object : BouncerViewDelegate {
|
||||
override fun isFullScreenBouncer(): Boolean {
|
||||
val mode = securityContainerController.currentSecurityMode
|
||||
val mode = hostViewController.currentSecurityMode
|
||||
return mode == KeyguardSecurityModel.SecurityMode.SimPin ||
|
||||
mode == KeyguardSecurityModel.SecurityMode.SimPuk
|
||||
}
|
||||
|
||||
override fun getBackCallback(): OnBackAnimationCallback {
|
||||
return securityContainerController.backCallback
|
||||
return hostViewController.backCallback
|
||||
}
|
||||
|
||||
override fun shouldDismissOnMenuPressed(): Boolean {
|
||||
return securityContainerController.shouldEnableMenuKey()
|
||||
return hostViewController.shouldEnableMenuKey()
|
||||
}
|
||||
|
||||
override fun interceptMediaKey(event: KeyEvent?): Boolean {
|
||||
return securityContainerController.interceptMediaKey(event)
|
||||
return hostViewController.interceptMediaKey(event)
|
||||
}
|
||||
|
||||
override fun dispatchBackKeyEventPreIme(): Boolean {
|
||||
return securityContainerController.dispatchBackKeyEventPreIme()
|
||||
return hostViewController.dispatchBackKeyEventPreIme()
|
||||
}
|
||||
|
||||
override fun showNextSecurityScreenOrFinish(): Boolean {
|
||||
return securityContainerController.dismiss(
|
||||
KeyguardUpdateMonitor.getCurrentUser()
|
||||
)
|
||||
return hostViewController.dismiss(KeyguardUpdateMonitor.getCurrentUser())
|
||||
}
|
||||
|
||||
override fun resume() {
|
||||
securityContainerController.showPrimarySecurityScreen(/* isTurningOff= */ false)
|
||||
securityContainerController.onResume(KeyguardSecurityView.SCREEN_ON)
|
||||
hostViewController.showPrimarySecurityScreen()
|
||||
hostViewController.onResume()
|
||||
}
|
||||
|
||||
override fun setDismissAction(
|
||||
onDismissAction: ActivityStarter.OnDismissAction?,
|
||||
cancelAction: Runnable?
|
||||
) {
|
||||
securityContainerController.setOnDismissAction(onDismissAction, cancelAction)
|
||||
hostViewController.setOnDismissAction(onDismissAction, cancelAction)
|
||||
}
|
||||
|
||||
override fun willDismissWithActions(): Boolean {
|
||||
return securityContainerController.hasDismissActions()
|
||||
return hostViewController.hasDismissActions()
|
||||
}
|
||||
}
|
||||
view.repeatWhenAttached {
|
||||
@@ -102,46 +98,39 @@ object KeyguardBouncerViewBinder {
|
||||
viewModel.setBouncerViewDelegate(delegate)
|
||||
launch {
|
||||
viewModel.show.collect {
|
||||
securityContainerController.showPromptReason(it.promptReason)
|
||||
hostViewController.showPromptReason(it.promptReason)
|
||||
it.errorMessage?.let { errorMessage ->
|
||||
securityContainerController.showMessage(
|
||||
errorMessage,
|
||||
Utils.getColorError(view.context)
|
||||
)
|
||||
hostViewController.showErrorMessage(errorMessage)
|
||||
}
|
||||
securityContainerController.showPrimarySecurityScreen(
|
||||
/* turningOff= */ false
|
||||
)
|
||||
securityContainerController.appear(
|
||||
hostViewController.showPrimarySecurityScreen()
|
||||
hostViewController.appear(
|
||||
SystemBarUtils.getStatusBarHeight(view.context)
|
||||
)
|
||||
securityContainerController.onResume(KeyguardSecurityView.SCREEN_ON)
|
||||
hostViewController.onResume()
|
||||
}
|
||||
}
|
||||
|
||||
launch {
|
||||
viewModel.hide.collect {
|
||||
securityContainerController.cancelDismissAction()
|
||||
securityContainerController.onPause()
|
||||
securityContainerController.reset()
|
||||
hostViewController.cancelDismissAction()
|
||||
hostViewController.cleanUp()
|
||||
hostViewController.resetSecurityContainer()
|
||||
}
|
||||
}
|
||||
|
||||
launch {
|
||||
viewModel.startingToHide.collect {
|
||||
securityContainerController.onStartingToHide()
|
||||
}
|
||||
viewModel.startingToHide.collect { hostViewController.onStartingToHide() }
|
||||
}
|
||||
|
||||
launch {
|
||||
viewModel.startDisappearAnimation.collect {
|
||||
securityContainerController.startDisappearAnimation(it)
|
||||
hostViewController.startDisappearAnimation(it)
|
||||
}
|
||||
}
|
||||
|
||||
launch {
|
||||
viewModel.bouncerExpansionAmount.collect { expansion ->
|
||||
securityContainerController.setExpansion(expansion)
|
||||
hostViewController.setExpansion(expansion)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,8 +138,10 @@ object KeyguardBouncerViewBinder {
|
||||
viewModel.bouncerExpansionAmount
|
||||
.filter { it == EXPANSION_VISIBLE }
|
||||
.collect {
|
||||
securityContainerController.onResume(KeyguardSecurityView.SCREEN_ON)
|
||||
view.announceForAccessibility(securityContainerController.title)
|
||||
hostViewController.onResume()
|
||||
view.announceForAccessibility(
|
||||
hostViewController.accessibilityTitleForCurrentMode
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,13 +149,13 @@ object KeyguardBouncerViewBinder {
|
||||
viewModel.isBouncerVisible.collect { isVisible ->
|
||||
val visibility = if (isVisible) View.VISIBLE else View.INVISIBLE
|
||||
view.visibility = visibility
|
||||
securityContainerController.onBouncerVisibilityChanged(visibility)
|
||||
hostViewController.onBouncerVisibilityChanged(visibility)
|
||||
}
|
||||
}
|
||||
|
||||
launch {
|
||||
viewModel.isInteractable.collect { isInteractable ->
|
||||
securityContainerController.setInteractable(isInteractable)
|
||||
hostViewController.setInteractable(isInteractable)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,36 +164,33 @@ object KeyguardBouncerViewBinder {
|
||||
.filter { !it }
|
||||
.collect {
|
||||
// Remove existing input for security reasons.
|
||||
securityContainerController.reset()
|
||||
hostViewController.resetSecurityContainer()
|
||||
}
|
||||
}
|
||||
|
||||
launch {
|
||||
viewModel.keyguardPosition.collect { position ->
|
||||
securityContainerController.updateKeyguardPosition(position)
|
||||
hostViewController.updateKeyguardPosition(position)
|
||||
}
|
||||
}
|
||||
|
||||
launch {
|
||||
viewModel.updateResources.collect {
|
||||
securityContainerController.updateResources()
|
||||
hostViewController.updateResources()
|
||||
viewModel.notifyUpdateResources()
|
||||
}
|
||||
}
|
||||
|
||||
launch {
|
||||
viewModel.bouncerShowMessage.collect {
|
||||
securityContainerController.showMessage(it.message, it.colorStateList)
|
||||
hostViewController.showMessage(it.message, it.colorStateList)
|
||||
viewModel.onMessageShown()
|
||||
}
|
||||
}
|
||||
|
||||
launch {
|
||||
viewModel.keyguardAuthenticated.collect {
|
||||
securityContainerController.finish(
|
||||
it,
|
||||
KeyguardUpdateMonitor.getCurrentUser()
|
||||
)
|
||||
hostViewController.finish(it, KeyguardUpdateMonitor.getCurrentUser())
|
||||
viewModel.notifyKeyguardAuthenticated()
|
||||
}
|
||||
}
|
||||
@@ -216,7 +204,7 @@ object KeyguardBouncerViewBinder {
|
||||
launch {
|
||||
viewModel.screenTurnedOff.collect {
|
||||
if (view.visibility == View.VISIBLE) {
|
||||
securityContainerController.onPause()
|
||||
hostViewController.onPause()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.keyguard;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.inOrder;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.media.AudioManager;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
import android.testing.TestableResources;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InOrder;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnit;
|
||||
import org.mockito.junit.MockitoRule;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@TestableLooper.RunWithLooper
|
||||
public class KeyguardHostViewControllerTest extends SysuiTestCase {
|
||||
@Mock
|
||||
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
|
||||
|
||||
private KeyguardHostView mKeyguardHostView;
|
||||
@Mock
|
||||
private AudioManager mAudioManager;
|
||||
@Mock
|
||||
private TelephonyManager mTelephonyManager;
|
||||
@Mock
|
||||
private ViewMediatorCallback mViewMediatorCallback;
|
||||
@Mock
|
||||
KeyguardSecurityContainerController.Factory mKeyguardSecurityContainerControllerFactory;
|
||||
@Mock
|
||||
private KeyguardSecurityContainerController mKeyguardSecurityContainerController;
|
||||
|
||||
@Rule
|
||||
public MockitoRule mMockitoRule = MockitoJUnit.rule();
|
||||
|
||||
private TestableResources mTestableResources;
|
||||
private KeyguardHostViewController mKeyguardHostViewController;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
mTestableResources = mContext.getOrCreateTestableResources();
|
||||
|
||||
mKeyguardHostView = new KeyguardHostView(mContext);
|
||||
|
||||
// Explicitly disable one handed keyguard.
|
||||
mTestableResources.addOverride(
|
||||
R.bool.can_use_one_handed_bouncer, false);
|
||||
|
||||
when(mKeyguardSecurityContainerControllerFactory.create(any(
|
||||
KeyguardSecurityContainer.SecurityCallback.class)))
|
||||
.thenReturn(mKeyguardSecurityContainerController);
|
||||
mKeyguardHostViewController = new KeyguardHostViewController(
|
||||
mKeyguardHostView, mKeyguardUpdateMonitor, mAudioManager, mTelephonyManager,
|
||||
mViewMediatorCallback, mKeyguardSecurityContainerControllerFactory);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHasDismissActions() {
|
||||
assertFalse("Action not set yet", mKeyguardHostViewController.hasDismissActions());
|
||||
mKeyguardHostViewController.setOnDismissAction(mock(OnDismissAction.class),
|
||||
null /* cancelAction */);
|
||||
assertTrue("Action should exist", mKeyguardHostViewController.hasDismissActions());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnStartingToHide() {
|
||||
mKeyguardHostViewController.onStartingToHide();
|
||||
verify(mKeyguardSecurityContainerController).onStartingToHide();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onBouncerVisible_propagatesToKeyguardSecurityContainerController() {
|
||||
mKeyguardHostViewController.onBouncerVisibilityChanged(ViewGroup.VISIBLE);
|
||||
mKeyguardHostViewController.onBouncerVisibilityChanged(ViewGroup.INVISIBLE);
|
||||
|
||||
InOrder order = inOrder(mKeyguardSecurityContainerController);
|
||||
order.verify(mKeyguardSecurityContainerController).onBouncerVisibilityChanged(View.VISIBLE);
|
||||
order.verify(mKeyguardSecurityContainerController).onBouncerVisibilityChanged(
|
||||
View.INVISIBLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGravityReappliedOnConfigurationChange() {
|
||||
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT);
|
||||
mKeyguardHostView.setLayoutParams(lp);
|
||||
|
||||
// Set initial gravity
|
||||
mTestableResources.addOverride(R.integer.keyguard_host_view_gravity,
|
||||
Gravity.CENTER);
|
||||
|
||||
// Kick off the initial pass...
|
||||
mKeyguardHostViewController.init();
|
||||
assertEquals(
|
||||
((FrameLayout.LayoutParams) mKeyguardHostView.getLayoutParams()).gravity,
|
||||
Gravity.CENTER);
|
||||
|
||||
// Now simulate a config change
|
||||
mTestableResources.addOverride(R.integer.keyguard_host_view_gravity,
|
||||
Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
|
||||
|
||||
mKeyguardHostViewController.updateResources();
|
||||
assertEquals(
|
||||
((FrameLayout.LayoutParams) mKeyguardHostView.getLayoutParams()).gravity,
|
||||
Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGravityUsesOneHandGravityWhenApplicable() {
|
||||
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT);
|
||||
mKeyguardHostView.setLayoutParams(lp);
|
||||
|
||||
mTestableResources.addOverride(
|
||||
R.integer.keyguard_host_view_gravity,
|
||||
Gravity.CENTER);
|
||||
mTestableResources.addOverride(
|
||||
R.integer.keyguard_host_view_one_handed_gravity,
|
||||
Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
|
||||
|
||||
// Start disabled.
|
||||
mTestableResources.addOverride(
|
||||
R.bool.can_use_one_handed_bouncer, false);
|
||||
|
||||
mKeyguardHostViewController.init();
|
||||
assertEquals(
|
||||
((FrameLayout.LayoutParams) mKeyguardHostView.getLayoutParams()).gravity,
|
||||
Gravity.CENTER);
|
||||
|
||||
// And enable
|
||||
mTestableResources.addOverride(
|
||||
R.bool.can_use_one_handed_bouncer, true);
|
||||
|
||||
mKeyguardHostViewController.updateResources();
|
||||
assertEquals(
|
||||
((FrameLayout.LayoutParams) mKeyguardHostView.getLayoutParams()).gravity,
|
||||
Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateKeyguardPositionDelegatesToSecurityContainer() {
|
||||
mKeyguardHostViewController.updateKeyguardPosition(1.0f);
|
||||
|
||||
verify(mKeyguardSecurityContainerController).updateKeyguardPosition(1.0f);
|
||||
}
|
||||
}
|
||||
@@ -23,17 +23,12 @@ import static com.android.keyguard.KeyguardSecurityContainer.MODE_ONE_HANDED;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static junit.framework.Assert.assertFalse;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.clearInvocations;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.reset;
|
||||
@@ -44,17 +39,12 @@ import static org.mockito.Mockito.when;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.hardware.biometrics.BiometricSourceType;
|
||||
import android.media.AudioManager;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
import android.testing.TestableResources;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.WindowInsetsController;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
@@ -70,7 +60,6 @@ import com.android.systemui.classifier.FalsingA11yDelegate;
|
||||
import com.android.systemui.classifier.FalsingCollector;
|
||||
import com.android.systemui.flags.FeatureFlags;
|
||||
import com.android.systemui.log.SessionTracker;
|
||||
import com.android.systemui.plugins.ActivityStarter;
|
||||
import com.android.systemui.plugins.FalsingManager;
|
||||
import com.android.systemui.statusbar.policy.ConfigurationController;
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||
@@ -82,7 +71,6 @@ import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.ArgumentMatcher;
|
||||
import org.mockito.Captor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnit;
|
||||
@@ -120,6 +108,8 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
|
||||
@Mock
|
||||
private KeyguardInputViewController mInputViewController;
|
||||
@Mock
|
||||
private KeyguardSecurityContainer.SecurityCallback mSecurityCallback;
|
||||
@Mock
|
||||
private WindowInsetsController mWindowInsetsController;
|
||||
@Mock
|
||||
private KeyguardSecurityViewFlipper mSecurityViewFlipper;
|
||||
@@ -136,6 +126,8 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
|
||||
@Mock
|
||||
private EmergencyButtonController mEmergencyButtonController;
|
||||
@Mock
|
||||
private Resources mResources;
|
||||
@Mock
|
||||
private FalsingCollector mFalsingCollector;
|
||||
@Mock
|
||||
private FalsingManager mFalsingManager;
|
||||
@@ -155,12 +147,6 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
|
||||
private KeyguardPasswordViewController mKeyguardPasswordViewControllerMock;
|
||||
@Mock
|
||||
private FalsingA11yDelegate mFalsingA11yDelegate;
|
||||
@Mock
|
||||
private TelephonyManager mTelephonyManager;
|
||||
@Mock
|
||||
private ViewMediatorCallback mViewMediatorCallback;
|
||||
@Mock
|
||||
private AudioManager mAudioManager;
|
||||
|
||||
@Captor
|
||||
private ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardUpdateMonitorCallback;
|
||||
@@ -172,25 +158,18 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
|
||||
private KeyguardSecurityContainerController mKeyguardSecurityContainerController;
|
||||
private KeyguardPasswordViewController mKeyguardPasswordViewController;
|
||||
private KeyguardPasswordView mKeyguardPasswordView;
|
||||
private TestableResources mTestableResources;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
mConfiguration = new Configuration();
|
||||
mConfiguration.setToDefaults(); // Defaults to ORIENTATION_UNDEFINED.
|
||||
mTestableResources = mContext.getOrCreateTestableResources();
|
||||
|
||||
when(mResources.getConfiguration()).thenReturn(mConfiguration);
|
||||
when(mView.getContext()).thenReturn(mContext);
|
||||
when(mView.getResources()).thenReturn(mContext.getResources());
|
||||
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(/* width= */ 0, /* height= */
|
||||
0);
|
||||
lp.gravity = 0;
|
||||
when(mView.getLayoutParams()).thenReturn(lp);
|
||||
when(mView.getResources()).thenReturn(mResources);
|
||||
when(mAdminSecondaryLockScreenControllerFactory.create(any(KeyguardSecurityCallback.class)))
|
||||
.thenReturn(mAdminSecondaryLockScreenController);
|
||||
when(mSecurityViewFlipper.getWindowInsetsController()).thenReturn(mWindowInsetsController);
|
||||
when(mKeyguardSecurityViewFlipperController.getSecurityView(any(SecurityMode.class),
|
||||
any(KeyguardSecurityCallback.class))).thenReturn(mInputViewController);
|
||||
mKeyguardPasswordView = spy((KeyguardPasswordView) LayoutInflater.from(mContext).inflate(
|
||||
R.layout.keyguard_password_view, null));
|
||||
when(mKeyguardPasswordView.getRootView()).thenReturn(mSecurityViewFlipper);
|
||||
@@ -199,21 +178,20 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
|
||||
when(mKeyguardMessageAreaControllerFactory.create(any(KeyguardMessageArea.class)))
|
||||
.thenReturn(mKeyguardMessageAreaController);
|
||||
when(mKeyguardPasswordView.getWindowInsetsController()).thenReturn(mWindowInsetsController);
|
||||
when(mKeyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(SecurityMode.PIN);
|
||||
mKeyguardPasswordViewController = new KeyguardPasswordViewController(
|
||||
(KeyguardPasswordView) mKeyguardPasswordView, mKeyguardUpdateMonitor,
|
||||
SecurityMode.Password, mLockPatternUtils, null,
|
||||
mKeyguardMessageAreaControllerFactory, null, null, mEmergencyButtonController,
|
||||
null, mock(Resources.class), null, mKeyguardViewController);
|
||||
|
||||
mKeyguardSecurityContainerController = new KeyguardSecurityContainerController(
|
||||
mKeyguardSecurityContainerController = new KeyguardSecurityContainerController.Factory(
|
||||
mView, mAdminSecondaryLockScreenControllerFactory, mLockPatternUtils,
|
||||
mKeyguardUpdateMonitor, mKeyguardSecurityModel, mMetricsLogger, mUiEventLogger,
|
||||
mKeyguardStateController, mKeyguardSecurityViewFlipperController,
|
||||
mConfigurationController, mFalsingCollector, mFalsingManager,
|
||||
mUserSwitcherController, mFeatureFlags, mGlobalSettings,
|
||||
mSessionTracker, Optional.of(mSideFpsController), mFalsingA11yDelegate,
|
||||
mTelephonyManager, mViewMediatorCallback, mAudioManager);
|
||||
mSessionTracker, Optional.of(mSideFpsController), mFalsingA11yDelegate).create(
|
||||
mSecurityCallback);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -265,8 +243,7 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
|
||||
eq(mFalsingA11yDelegate));
|
||||
|
||||
// Update rotation. Should trigger update
|
||||
mTestableResources.getResources().getConfiguration().orientation =
|
||||
Configuration.ORIENTATION_LANDSCAPE;
|
||||
mConfiguration.orientation = Configuration.ORIENTATION_LANDSCAPE;
|
||||
|
||||
mKeyguardSecurityContainerController.updateResources();
|
||||
verify(mView).initMode(eq(MODE_DEFAULT), eq(mGlobalSettings), eq(mFalsingManager),
|
||||
@@ -300,7 +277,7 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void showSecurityScreen_oneHandedMode_flagDisabled_noOneHandedMode() {
|
||||
mTestableResources.addOverride(R.bool.can_use_one_handed_bouncer, false);
|
||||
when(mResources.getBoolean(R.bool.can_use_one_handed_bouncer)).thenReturn(false);
|
||||
when(mKeyguardSecurityViewFlipperController.getSecurityView(
|
||||
eq(SecurityMode.Pattern), any(KeyguardSecurityCallback.class)))
|
||||
.thenReturn((KeyguardInputViewController) mKeyguardPasswordViewController);
|
||||
@@ -314,7 +291,7 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void showSecurityScreen_oneHandedMode_flagEnabled_oneHandedMode() {
|
||||
mTestableResources.addOverride(R.bool.can_use_one_handed_bouncer, true);
|
||||
when(mResources.getBoolean(R.bool.can_use_one_handed_bouncer)).thenReturn(true);
|
||||
when(mKeyguardSecurityViewFlipperController.getSecurityView(
|
||||
eq(SecurityMode.Pattern), any(KeyguardSecurityCallback.class)))
|
||||
.thenReturn((KeyguardInputViewController) mKeyguardPasswordViewController);
|
||||
@@ -328,7 +305,7 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void showSecurityScreen_twoHandedMode_flagEnabled_noOneHandedMode() {
|
||||
mTestableResources.addOverride(R.bool.can_use_one_handed_bouncer, true);
|
||||
when(mResources.getBoolean(R.bool.can_use_one_handed_bouncer)).thenReturn(true);
|
||||
setupGetSecurityView();
|
||||
|
||||
mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Password);
|
||||
@@ -505,9 +482,7 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
|
||||
SecurityMode.SimPin);
|
||||
|
||||
// THEN the next security method of PIN is set, and the keyguard is not marked as done
|
||||
|
||||
verify(mViewMediatorCallback, never()).keyguardDonePending(anyBoolean(), anyInt());
|
||||
verify(mViewMediatorCallback, never()).keyguardDone(anyBoolean(), anyInt());
|
||||
verify(mSecurityCallback, never()).finish(anyBoolean(), anyInt());
|
||||
assertThat(mKeyguardSecurityContainerController.getCurrentSecurityMode())
|
||||
.isEqualTo(SecurityMode.PIN);
|
||||
}
|
||||
@@ -581,19 +556,17 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDensityOrFontScaleChanged() {
|
||||
public void onDensityorFontScaleChanged() {
|
||||
ArgumentCaptor<ConfigurationController.ConfigurationListener>
|
||||
configurationListenerArgumentCaptor = ArgumentCaptor.forClass(
|
||||
ConfigurationController.ConfigurationListener.class);
|
||||
mKeyguardSecurityContainerController.onViewAttached();
|
||||
verify(mConfigurationController).addCallback(configurationListenerArgumentCaptor.capture());
|
||||
clearInvocations(mKeyguardSecurityViewFlipperController);
|
||||
|
||||
configurationListenerArgumentCaptor.getValue().onDensityOrFontScaleChanged();
|
||||
|
||||
verify(mView).onDensityOrFontScaleChanged();
|
||||
verify(mKeyguardSecurityViewFlipperController).clearViews();
|
||||
verify(mKeyguardSecurityViewFlipperController).getSecurityView(eq(SecurityMode.PIN),
|
||||
verify(mKeyguardSecurityViewFlipperController).getSecurityView(any(SecurityMode.class),
|
||||
any(KeyguardSecurityCallback.class));
|
||||
}
|
||||
|
||||
@@ -604,13 +577,11 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
|
||||
ConfigurationController.ConfigurationListener.class);
|
||||
mKeyguardSecurityContainerController.onViewAttached();
|
||||
verify(mConfigurationController).addCallback(configurationListenerArgumentCaptor.capture());
|
||||
clearInvocations(mKeyguardSecurityViewFlipperController);
|
||||
|
||||
configurationListenerArgumentCaptor.getValue().onThemeChanged();
|
||||
|
||||
verify(mView).reloadColors();
|
||||
verify(mKeyguardSecurityViewFlipperController).clearViews();
|
||||
verify(mKeyguardSecurityViewFlipperController).getSecurityView(eq(SecurityMode.PIN),
|
||||
verify(mKeyguardSecurityViewFlipperController).getSecurityView(any(SecurityMode.class),
|
||||
any(KeyguardSecurityCallback.class));
|
||||
}
|
||||
|
||||
@@ -621,90 +592,14 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
|
||||
ConfigurationController.ConfigurationListener.class);
|
||||
mKeyguardSecurityContainerController.onViewAttached();
|
||||
verify(mConfigurationController).addCallback(configurationListenerArgumentCaptor.capture());
|
||||
clearInvocations(mKeyguardSecurityViewFlipperController);
|
||||
|
||||
configurationListenerArgumentCaptor.getValue().onUiModeChanged();
|
||||
|
||||
verify(mView).reloadColors();
|
||||
verify(mKeyguardSecurityViewFlipperController).clearViews();
|
||||
verify(mKeyguardSecurityViewFlipperController).getSecurityView(eq(SecurityMode.PIN),
|
||||
verify(mKeyguardSecurityViewFlipperController).getSecurityView(any(SecurityMode.class),
|
||||
any(KeyguardSecurityCallback.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHasDismissActions() {
|
||||
assertFalse("Action not set yet", mKeyguardSecurityContainerController.hasDismissActions());
|
||||
mKeyguardSecurityContainerController.setOnDismissAction(mock(
|
||||
ActivityStarter.OnDismissAction.class),
|
||||
null /* cancelAction */);
|
||||
assertTrue("Action should exist", mKeyguardSecurityContainerController.hasDismissActions());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnStartingToHide() {
|
||||
mKeyguardSecurityContainerController.onStartingToHide();
|
||||
verify(mInputViewController).onStartingToHide();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGravityReappliedOnConfigurationChange() {
|
||||
// Set initial gravity
|
||||
mTestableResources.addOverride(R.integer.keyguard_host_view_gravity,
|
||||
Gravity.CENTER);
|
||||
|
||||
// Kick off the initial pass...
|
||||
mKeyguardSecurityContainerController.onInit();
|
||||
verify(mView).setLayoutParams(argThat(
|
||||
(ArgumentMatcher<FrameLayout.LayoutParams>) argument ->
|
||||
argument.gravity == Gravity.CENTER));
|
||||
clearInvocations(mView);
|
||||
|
||||
// Now simulate a config change
|
||||
mTestableResources.addOverride(R.integer.keyguard_host_view_gravity,
|
||||
Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
|
||||
|
||||
mKeyguardSecurityContainerController.updateResources();
|
||||
verify(mView).setLayoutParams(argThat(
|
||||
(ArgumentMatcher<FrameLayout.LayoutParams>) argument ->
|
||||
argument.gravity == (Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGravityUsesOneHandGravityWhenApplicable() {
|
||||
mTestableResources.addOverride(
|
||||
R.integer.keyguard_host_view_gravity,
|
||||
Gravity.CENTER);
|
||||
mTestableResources.addOverride(
|
||||
R.integer.keyguard_host_view_one_handed_gravity,
|
||||
Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
|
||||
|
||||
// Start disabled.
|
||||
mTestableResources.addOverride(
|
||||
R.bool.can_use_one_handed_bouncer, false);
|
||||
|
||||
mKeyguardSecurityContainerController.onInit();
|
||||
verify(mView).setLayoutParams(argThat(
|
||||
(ArgumentMatcher<FrameLayout.LayoutParams>) argument ->
|
||||
argument.gravity == Gravity.CENTER));
|
||||
clearInvocations(mView);
|
||||
|
||||
// And enable
|
||||
mTestableResources.addOverride(
|
||||
R.bool.can_use_one_handed_bouncer, true);
|
||||
|
||||
mKeyguardSecurityContainerController.updateResources();
|
||||
verify(mView).setLayoutParams(argThat(
|
||||
(ArgumentMatcher<FrameLayout.LayoutParams>) argument ->
|
||||
argument.gravity == (Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateKeyguardPositionDelegatesToSecurityContainer() {
|
||||
mKeyguardSecurityContainerController.updateKeyguardPosition(1.0f);
|
||||
verify(mView).updatePositionByTouchX(1.0f);
|
||||
}
|
||||
|
||||
|
||||
private KeyguardSecurityContainer.SwipeListener getRegisteredSwipeListener() {
|
||||
mKeyguardSecurityContainerController.onViewAttached();
|
||||
verify(mView).setSwipeListener(mSwipeListenerArgumentCaptor.capture());
|
||||
@@ -730,7 +625,7 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
|
||||
}
|
||||
|
||||
private void setSideFpsHintEnabledFromResources(boolean enabled) {
|
||||
mTestableResources.addOverride(R.bool.config_show_sidefps_hint_on_bouncer,
|
||||
when(mResources.getBoolean(R.bool.config_show_sidefps_hint_on_bouncer)).thenReturn(
|
||||
enabled);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ import android.testing.TestableLooper.RunWithLooper
|
||||
import android.view.MotionEvent
|
||||
import android.view.ViewGroup
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.keyguard.KeyguardSecurityContainerController
|
||||
import com.android.keyguard.KeyguardHostViewController
|
||||
import com.android.keyguard.LockIconViewController
|
||||
import com.android.keyguard.dagger.KeyguardBouncerComponent
|
||||
import com.android.systemui.R
|
||||
@@ -106,7 +106,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
|
||||
private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
|
||||
@Mock lateinit var keyguardBouncerComponentFactory: KeyguardBouncerComponent.Factory
|
||||
@Mock lateinit var keyguardBouncerComponent: KeyguardBouncerComponent
|
||||
@Mock lateinit var keyguardSecurityContainerController: KeyguardSecurityContainerController
|
||||
@Mock lateinit var keyguardHostViewController: KeyguardHostViewController
|
||||
@Mock lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
|
||||
|
||||
private lateinit var interactionEventHandlerCaptor: ArgumentCaptor<InteractionEventHandler>
|
||||
@@ -122,8 +122,8 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
|
||||
.thenReturn(mock(ViewGroup::class.java))
|
||||
whenever(keyguardBouncerComponentFactory.create(any(ViewGroup::class.java)))
|
||||
.thenReturn(keyguardBouncerComponent)
|
||||
whenever(keyguardBouncerComponent.securityContainerController)
|
||||
.thenReturn(keyguardSecurityContainerController)
|
||||
whenever(keyguardBouncerComponent.keyguardHostViewController)
|
||||
.thenReturn(keyguardHostViewController)
|
||||
underTest = NotificationShadeWindowViewController(
|
||||
lockscreenShadeTransitionController,
|
||||
FalsingCollectorFake(),
|
||||
|
||||
@@ -33,7 +33,7 @@ import android.view.ViewGroup;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.keyguard.KeyguardSecurityContainerController;
|
||||
import com.android.keyguard.KeyguardHostViewController;
|
||||
import com.android.keyguard.LockIconViewController;
|
||||
import com.android.keyguard.dagger.KeyguardBouncerComponent;
|
||||
import com.android.systemui.R;
|
||||
@@ -97,7 +97,7 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase {
|
||||
@Mock private KeyguardBouncerViewModel mKeyguardBouncerViewModel;
|
||||
@Mock private KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory;
|
||||
@Mock private KeyguardBouncerComponent mKeyguardBouncerComponent;
|
||||
@Mock private KeyguardSecurityContainerController mKeyguardSecurityContainerController;
|
||||
@Mock private KeyguardHostViewController mKeyguardHostViewController;
|
||||
@Mock private NotificationInsetsController mNotificationInsetsController;
|
||||
@Mock private AlternateBouncerInteractor mAlternateBouncerInteractor;
|
||||
@Mock private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
|
||||
@@ -117,8 +117,8 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase {
|
||||
when(mView.findViewById(R.id.keyguard_bouncer_container)).thenReturn(mock(ViewGroup.class));
|
||||
when(mKeyguardBouncerComponentFactory.create(any(ViewGroup.class))).thenReturn(
|
||||
mKeyguardBouncerComponent);
|
||||
when(mKeyguardBouncerComponent.getSecurityContainerController()).thenReturn(
|
||||
mKeyguardSecurityContainerController);
|
||||
when(mKeyguardBouncerComponent.getKeyguardHostViewController()).thenReturn(
|
||||
mKeyguardHostViewController);
|
||||
|
||||
when(mStatusBarStateController.isDozing()).thenReturn(false);
|
||||
mDependency.injectTestDependency(ShadeController.class, mShadeController);
|
||||
|
||||
Reference in New Issue
Block a user