summaryrefslogtreecommitdiff
path: root/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
diff options
context:
space:
mode:
authorDave Mankoff <mankoff@google.com>2020-08-31 16:59:58 -0400
committerDave Mankoff <mankoff@google.com>2020-09-08 14:47:43 -0400
commit860a2c0343354be81c8b845b1ee3075c0c5ca10e (patch)
treef1d872e09b1b3d6037e5d6822505aeb1143f9f19 /packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
parentf6032e30d71f51d8f5b5c037ec500b4aa589b731 (diff)
3/N Use KeyguardSecurityContainerController in KHVC.
Use the KeyguardSecurityContainerController in the KeyguardHostViewController instead of the view directly. This actually cleans up KeyguardHostView quite a bit, with all lot of its business logic moved over to its view. The KeyguardSecurityContainerController doesn't do much except to proxy through calls to its view for now. Bug: 166448040 Test: atest SystemUITests && manual Change-Id: I96a27b673c4579983bb07b7fb7ef321a022f0f65
Diffstat (limited to 'packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java')
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java298
1 files changed, 264 insertions, 34 deletions
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
index 381071994e7b..7aabb17de90c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
@@ -16,39 +16,60 @@
package com.android.keyguard;
+import android.app.ActivityManager;
import android.content.res.ColorStateList;
+import android.content.res.Resources;
+import android.media.AudioManager;
+import android.os.SystemClock;
import android.service.trust.TrustAgentService;
+import android.telephony.TelephonyManager;
import android.util.Log;
import android.util.MathUtils;
import android.view.KeyEvent;
import android.view.View;
+import android.view.View.OnKeyListener;
import android.view.ViewTreeObserver;
-import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardSecurityContainer.SecurityCallback;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.keyguard.dagger.KeyguardBouncerScope;
+import com.android.settingslib.Utils;
import com.android.systemui.R;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.phone.KeyguardBouncer;
import com.android.systemui.util.ViewController;
+import java.io.File;
+
import javax.inject.Inject;
/** Controller for a {@link KeyguardHostView}. */
@KeyguardBouncerScope
public class KeyguardHostViewController extends ViewController<KeyguardHostView> {
private static final String TAG = "KeyguardViewBase";
+ public static final boolean DEBUG = KeyguardConstants.DEBUG;
+ // Whether the volume keys should be handled by keyguard. If true, then
+ // they will be handled here for specific media types such as music, otherwise
+ // the audio service will bring up the volume dialog.
+ private static final boolean KEYGUARD_MANAGES_VOLUME = false;
+
+ private static final String ENABLE_MENU_KEY_FILE = "/data/local/enable_menu_key";
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final KeyguardSecurityContainerController mKeyguardSecurityContainerController;
- private final LockPatternUtils mLockPatternUtils;
+ private final TelephonyManager mTelephonyManager;
private final ViewMediatorCallback mViewMediatorCallback;
+ private final AudioManager mAudioManager;
+
+ private ActivityStarter.OnDismissAction mDismissAction;
+ private Runnable mCancelAction;
private final KeyguardUpdateMonitorCallback mUpdateCallback =
new KeyguardUpdateMonitorCallback() {
@Override
public void onUserSwitchComplete(int userId) {
- mView.getSecurityContainer().showPrimarySecurityScreen(false /* turning off */);
+ mKeyguardSecurityContainerController.showPrimarySecurityScreen(
+ false /* turning off */);
}
@Override
@@ -70,7 +91,7 @@ public class KeyguardHostViewController extends ViewController<KeyguardHostView>
//agent.
Log.i(TAG, "TrustAgent dismissed Keyguard.");
}
- mView.dismiss(false /* authenticated */, userId,
+ mSecurityCallback.dismiss(false /* authenticated */, userId,
/* bypassSecondaryLockScreen */ false);
} else {
mViewMediatorCallback.playTrustedSound();
@@ -79,35 +100,102 @@ public class KeyguardHostViewController extends ViewController<KeyguardHostView>
}
};
+ private final SecurityCallback mSecurityCallback = new SecurityCallback() {
+
+ @Override
+ public boolean dismiss(boolean authenticated, int targetUserId,
+ boolean bypassSecondaryLockScreen) {
+ return mKeyguardSecurityContainerController.showNextSecurityScreenOrFinish(
+ authenticated, targetUserId, bypassSecondaryLockScreen);
+ }
+
+ @Override
+ public void userActivity() {
+ mViewMediatorCallback.userActivity();
+ }
+
+ @Override
+ public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput) {
+ mViewMediatorCallback.setNeedsInput(needsInput);
+ }
+
+ /**
+ * Authentication has happened and it's time to dismiss keyguard. This function
+ * should clean up and inform KeyguardViewMediator.
+ *
+ * @param strongAuth whether the user has authenticated with strong authentication like
+ * pattern, password or PIN but not by trust agents or fingerprint
+ * @param targetUserId a user that needs to be the foreground user at the dismissal
+ * completion.
+ */
+ @Override
+ public void finish(boolean strongAuth, int targetUserId) {
+ // If there's a pending runnable because the user interacted with a widget
+ // and we're leaving keyguard, then run it.
+ boolean deferKeyguardDone = false;
+ if (mDismissAction != null) {
+ deferKeyguardDone = mDismissAction.onDismiss();
+ mDismissAction = null;
+ mCancelAction = null;
+ }
+ if (mViewMediatorCallback != null) {
+ if (deferKeyguardDone) {
+ mViewMediatorCallback.keyguardDonePending(strongAuth, targetUserId);
+ } else {
+ mViewMediatorCallback.keyguardDone(strongAuth, targetUserId);
+ }
+ }
+ }
+
+ @Override
+ public void reset() {
+ mViewMediatorCallback.resetKeyguard();
+ }
+
+ @Override
+ public void onCancelClicked() {
+ mViewMediatorCallback.onCancelClicked();
+ }
+ };
+
+ private OnKeyListener mOnKeyListener = (v, keyCode, event) -> interceptMediaKey(event);
+
@Inject
public KeyguardHostViewController(KeyguardHostView view,
KeyguardUpdateMonitor keyguardUpdateMonitor,
KeyguardSecurityContainerController keyguardSecurityContainerController,
- LockPatternUtils lockPatternUtils,
+ AudioManager audioManager,
+ TelephonyManager telephonyManager,
ViewMediatorCallback viewMediatorCallback) {
super(view);
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mKeyguardSecurityContainerController = keyguardSecurityContainerController;
- mLockPatternUtils = lockPatternUtils;
+ mAudioManager = audioManager;
+ mTelephonyManager = telephonyManager;
mViewMediatorCallback = viewMediatorCallback;
}
/** Initialize the Controller. */
public void init() {
super.init();
- mView.setLockPatternUtils(mLockPatternUtils);
mView.setViewMediatorCallback(mViewMediatorCallback);
+ // Update ViewMediator with the current input method requirements
+ mViewMediatorCallback.setNeedsInput(mKeyguardSecurityContainerController.needsInput());
mKeyguardSecurityContainerController.init();
+ mKeyguardSecurityContainerController.setSecurityCallback(mSecurityCallback);
+ mKeyguardSecurityContainerController.showPrimarySecurityScreen(false);
}
@Override
protected void onViewAttached() {
mKeyguardUpdateMonitor.registerCallback(mUpdateCallback);
+ mView.setOnKeyListener(mOnKeyListener);
}
@Override
protected void onViewDetached() {
mKeyguardUpdateMonitor.removeCallback(mUpdateCallback);
+ mView.setOnKeyListener(null);
}
/** Called before this view is being removed. */
@@ -116,37 +204,46 @@ public class KeyguardHostViewController extends ViewController<KeyguardHostView>
}
public void resetSecurityContainer() {
- mView.resetSecurityContainer();
+ mKeyguardSecurityContainerController.reset();
}
- public boolean dismiss(int activeUserId) {
- return mView.dismiss(activeUserId);
+ /**
+ * Dismisses the keyguard by going to the next screen or making it gone.
+ * @param targetUserId a user that needs to be the foreground user at the dismissal completion.
+ * @return True if the keyguard is done.
+ */
+ public boolean dismiss(int targetUserId) {
+ return mSecurityCallback.dismiss(false, targetUserId, false);
}
+ /**
+ * Called when the Keyguard is actively shown on the screen.
+ */
public void onResume() {
- mView.onResume();
+ if (DEBUG) Log.d(TAG, "screen on, instance " + Integer.toHexString(hashCode()));
+ mKeyguardSecurityContainerController.onResume(KeyguardSecurityView.SCREEN_ON);
+ mView.requestFocus();
}
public CharSequence getAccessibilityTitleForCurrentMode() {
- return mView.getAccessibilityTitleForCurrentMode();
- }
-
- public void showErrorMessage(CharSequence customMessage) {
- mView.showErrorMessage(customMessage);
+ 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) {
- mView.startAppearAnimation();
+ mKeyguardSecurityContainerController.startAppearAnimation();
} else {
mView.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
mView.getViewTreeObserver().removeOnPreDrawListener(this);
- mView.startAppearAnimation();
+ mKeyguardSecurityContainerController.startAppearAnimation();
return true;
}
});
@@ -154,32 +251,71 @@ public class KeyguardHostViewController extends ViewController<KeyguardHostView>
}
}
+ /**
+ * 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) {
- mView.showPromptReason(reason);
+ mKeyguardSecurityContainerController.showPromptReason(reason);
}
- public void showMessage(String message, ColorStateList colorState) {
- mView.showMessage(message, colorState);
+ 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) {
- mView.setOnDismissAction(action, cancelAction);
+ if (mCancelAction != null) {
+ mCancelAction.run();
+ mCancelAction = null;
+ }
+ mDismissAction = action;
+ mCancelAction = cancelAction;
}
public void cancelDismissAction() {
- mView.cancelDismissAction();
+ setOnDismissAction(null, null);
}
- public void startDisappearAnimation(Runnable runnable) {
- mView.startDisappearAnimation(runnable);
+ 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() {
- mView.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() {
- mView.showPrimarySecurityScreen();
+ if (DEBUG) Log.d(TAG, "show()");
+ mKeyguardSecurityContainerController.showPrimarySecurityScreen(false);
}
public void setExpansion(float fraction) {
@@ -188,16 +324,19 @@ public class KeyguardHostViewController extends ViewController<KeyguardHostView>
mView.setTranslationY(fraction * mView.getHeight());
}
+ /**
+ * When bouncer was visible and is starting to become hidden.
+ */
public void onStartingToHide() {
- mView.onStartingToHide();
+ mKeyguardSecurityContainerController.onStartingToHide();
}
public boolean hasDismissActions() {
- return mView.hasDismissActions();
+ return mDismissAction != null || mCancelAction != null;
}
public SecurityMode getCurrentSecurityMode() {
- return mView.getCurrentSecurityMode();
+ return mKeyguardSecurityContainerController.getCurrentSecurityMode();
}
public int getTop() {
@@ -211,19 +350,110 @@ public class KeyguardHostViewController extends ViewController<KeyguardHostView>
}
public boolean handleBackKey() {
- return mView.handleBackKey();
+ if (mKeyguardSecurityContainerController.getCurrentSecuritySelection()
+ != SecurityMode.None) {
+ mKeyguardSecurityContainerController.dismiss(
+ false, KeyguardUpdateMonitor.getCurrentUser());
+ return true;
+ }
+ return false;
}
+ /**
+ * In general, we enable unlocking the insecure keyguard with the menu key. However, there are
+ * some cases where we wish to disable it, notably when the menu button placement or technology
+ * is prone to false positives.
+ *
+ * @return true if the menu key should be enabled
+ */
public boolean shouldEnableMenuKey() {
- return mView.shouldEnableMenuKey();
+ final Resources res = mView.getResources();
+ final boolean configDisabled = res.getBoolean(R.bool.config_disableMenuKeyInLockScreen);
+ final boolean isTestHarness = ActivityManager.isRunningInTestHarness();
+ final boolean fileOverride = (new File(ENABLE_MENU_KEY_FILE)).exists();
+ return !configDisabled || isTestHarness || fileOverride;
}
+ /**
+ * Allows the media keys to work when the keyguard is showing.
+ * The media keys should be of no interest to the actual keyguard view(s),
+ * so intercepting them here should not be of any harm.
+ * @param event The key event
+ * @return whether the event was consumed as a media key.
+ */
public boolean interceptMediaKey(KeyEvent event) {
- return mView.interceptMediaKey(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) {
- mView.finish(strongAuth, currentUser);
+ mSecurityCallback.finish(strongAuth, currentUser);
}