summaryrefslogtreecommitdiff
path: root/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
diff options
context:
space:
mode:
Diffstat (limited to 'packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java')
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java207
1 files changed, 132 insertions, 75 deletions
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index ca4d73b6de5d..0328b5a62b06 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -23,6 +23,7 @@ import static java.lang.Integer.max;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
@@ -36,10 +37,11 @@ import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
-import android.view.ViewPropertyAnimator;
import android.view.WindowInsets;
import android.view.WindowInsetsAnimation;
import android.view.WindowManager;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
import android.widget.FrameLayout;
import androidx.annotation.Nullable;
@@ -55,7 +57,7 @@ import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
-import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
+import com.android.systemui.shared.system.SysUiStatsLog;
import java.util.ArrayList;
import java.util.List;
@@ -85,6 +87,13 @@ public class KeyguardSecurityContainer extends FrameLayout {
private static final long IME_DISAPPEAR_DURATION_MS = 125;
+ // The duration of the animation to switch bouncer sides.
+ private static final long BOUNCER_HANDEDNESS_ANIMATION_DURATION_MS = 500;
+
+ // How much of the switch sides animation should be dedicated to fading the bouncer out. The
+ // remainder will fade it back in again.
+ private static final float BOUNCER_HANDEDNESS_ANIMATION_FADE_OUT_PROPORTION = 0.2f;
+
@VisibleForTesting
KeyguardSecurityViewFlipper mSecurityViewFlipper;
private AlertDialog mAlertDialog;
@@ -104,8 +113,7 @@ public class KeyguardSecurityContainer extends FrameLayout {
private boolean mIsSecurityViewLeftAligned = true;
private boolean mOneHandedMode = false;
- private SecurityMode mSecurityMode = SecurityMode.Invalid;
- private ViewPropertyAnimator mRunningOneHandedAnimator;
+ @Nullable private ValueAnimator mRunningOneHandedAnimator;
private final WindowInsetsAnimation.Callback mWindowInsetsAnimationCallback =
new WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP) {
@@ -248,66 +256,47 @@ public class KeyguardSecurityContainer extends FrameLayout {
}
void onResume(SecurityMode securityMode, boolean faceAuthEnabled) {
- mSecurityMode = securityMode;
mSecurityViewFlipper.setWindowInsetsAnimationCallback(mWindowInsetsAnimationCallback);
updateBiometricRetry(securityMode, faceAuthEnabled);
-
- updateLayoutForSecurityMode(securityMode);
}
- void updateLayoutForSecurityMode(SecurityMode securityMode) {
- mSecurityMode = securityMode;
- mOneHandedMode = canUseOneHandedBouncer();
-
- if (mOneHandedMode) {
- mIsSecurityViewLeftAligned = isOneHandedKeyguardLeftAligned(mContext);
- }
-
+ /**
+ * Sets whether this security container is in one handed mode. If so, it will measure its
+ * child SecurityViewFlipper in one half of the screen, and move it when tapping on the opposite
+ * side of the screen.
+ */
+ public void setOneHandedMode(boolean oneHandedMode) {
+ mOneHandedMode = oneHandedMode;
updateSecurityViewGravity();
updateSecurityViewLocation(false);
}
- /** Update keyguard position based on a tapped X coordinate. */
- public void updateKeyguardPosition(float x) {
- if (mOneHandedMode) {
- moveBouncerForXCoordinate(x, /* animate= */false);
- }
+ /** Returns whether this security container is in one-handed mode. */
+ public boolean isOneHandedMode() {
+ return mOneHandedMode;
}
- /** Return whether the one-handed keyguard should be enabled. */
- private boolean canUseOneHandedBouncer() {
- // Is it enabled?
- if (!getResources().getBoolean(
- com.android.internal.R.bool.config_enableDynamicKeyguardPositioning)) {
- return false;
- }
-
- if (!KeyguardSecurityModel.isSecurityViewOneHanded(mSecurityMode)) {
- return false;
- }
-
- return getResources().getBoolean(R.bool.can_use_one_handed_bouncer);
+ /**
+ * When in one-handed mode, sets if the inner SecurityViewFlipper should be aligned to the
+ * left-hand side of the screen or not, and whether to animate when moving between the two.
+ */
+ public void setOneHandedModeLeftAligned(boolean leftAligned, boolean animate) {
+ mIsSecurityViewLeftAligned = leftAligned;
+ updateSecurityViewLocation(animate);
}
- /** Read whether the one-handed keyguard should be on the left/right from settings. */
- private boolean isOneHandedKeyguardLeftAligned(Context context) {
- try {
- return Settings.Global.getInt(context.getContentResolver(),
- Settings.Global.ONE_HANDED_KEYGUARD_SIDE)
- == Settings.Global.ONE_HANDED_KEYGUARD_SIDE_LEFT;
- } catch (Settings.SettingNotFoundException ex) {
- return true;
- }
+ /** Returns whether the inner SecurityViewFlipper is left-aligned when in one-handed mode. */
+ public boolean isOneHandedModeLeftAligned() {
+ return mIsSecurityViewLeftAligned;
}
private void updateSecurityViewGravity() {
- View securityView = findKeyguardSecurityView();
-
- if (securityView == null) {
+ if (mSecurityViewFlipper == null) {
return;
}
- FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) securityView.getLayoutParams();
+ FrameLayout.LayoutParams lp =
+ (FrameLayout.LayoutParams) mSecurityViewFlipper.getLayoutParams();
if (mOneHandedMode) {
lp.gravity = Gravity.LEFT | Gravity.BOTTOM;
@@ -315,7 +304,7 @@ public class KeyguardSecurityContainer extends FrameLayout {
lp.gravity = Gravity.CENTER_HORIZONTAL;
}
- securityView.setLayoutParams(lp);
+ mSecurityViewFlipper.setLayoutParams(lp);
}
/**
@@ -324,14 +313,12 @@ public class KeyguardSecurityContainer extends FrameLayout {
* by the security view .
*/
private void updateSecurityViewLocation(boolean animate) {
- View securityView = findKeyguardSecurityView();
-
- if (securityView == null) {
+ if (mSecurityViewFlipper == null) {
return;
}
if (!mOneHandedMode) {
- securityView.setTranslationX(0);
+ mSecurityViewFlipper.setTranslationX(0);
return;
}
@@ -340,40 +327,105 @@ public class KeyguardSecurityContainer extends FrameLayout {
mRunningOneHandedAnimator = null;
}
- int targetTranslation = mIsSecurityViewLeftAligned ? 0 : (int) (getMeasuredWidth() / 2f);
+ int targetTranslation = mIsSecurityViewLeftAligned
+ ? 0 : (int) (getMeasuredWidth() - mSecurityViewFlipper.getWidth());
if (animate) {
- mRunningOneHandedAnimator = securityView.animate().translationX(targetTranslation);
- mRunningOneHandedAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
- mRunningOneHandedAnimator.setListener(new AnimatorListenerAdapter() {
+ // This animation is a bit fun to implement. The bouncer needs to move, and fade in/out
+ // at the same time. The issue is, the bouncer should only move a short amount (120dp or
+ // so), but obviously needs to go from one side of the screen to the other. This needs a
+ // pretty custom animation.
+ //
+ // This works as follows. It uses a ValueAnimation to simply drive the animation
+ // progress. This animator is responsible for both the translation of the bouncer, and
+ // the current fade. It will fade the bouncer out while also moving it along the 120dp
+ // path. Once the bouncer is fully faded out though, it will "snap" the bouncer closer
+ // to its destination, then fade it back in again. The effect is that the bouncer will
+ // move from 0 -> X while fading out, then (destination - X) -> destination while fading
+ // back in again.
+ // TODO(b/195012405): Make this animation properly abortable.
+ Interpolator positionInterpolator = AnimationUtils.loadInterpolator(
+ mContext, android.R.interpolator.fast_out_extra_slow_in);
+ Interpolator fadeOutInterpolator = Interpolators.FAST_OUT_LINEAR_IN;
+ Interpolator fadeInInterpolator = Interpolators.LINEAR_OUT_SLOW_IN;
+
+ mRunningOneHandedAnimator = ValueAnimator.ofFloat(0.0f, 1.0f);
+ mRunningOneHandedAnimator.setDuration(BOUNCER_HANDEDNESS_ANIMATION_DURATION_MS);
+ mRunningOneHandedAnimator.setInterpolator(Interpolators.LINEAR);
+
+ int initialTranslation = (int) mSecurityViewFlipper.getTranslationX();
+ int totalTranslation = (int) getResources().getDimension(
+ R.dimen.one_handed_bouncer_move_animation_translation);
+
+ final boolean shouldRestoreLayerType = mSecurityViewFlipper.hasOverlappingRendering()
+ && mSecurityViewFlipper.getLayerType() != View.LAYER_TYPE_HARDWARE;
+ if (shouldRestoreLayerType) {
+ mSecurityViewFlipper.setLayerType(View.LAYER_TYPE_HARDWARE, /* paint= */null);
+ }
+
+ float initialAlpha = mSecurityViewFlipper.getAlpha();
+
+ mRunningOneHandedAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mRunningOneHandedAnimator = null;
}
});
+ mRunningOneHandedAnimator.addUpdateListener(animation -> {
+ float switchPoint = BOUNCER_HANDEDNESS_ANIMATION_FADE_OUT_PROPORTION;
+ boolean isFadingOut = animation.getAnimatedFraction() < switchPoint;
+
+ int currentTranslation = (int) (positionInterpolator.getInterpolation(
+ animation.getAnimatedFraction()) * totalTranslation);
+ int translationRemaining = totalTranslation - currentTranslation;
+
+ // Flip the sign if we're going from right to left.
+ if (mIsSecurityViewLeftAligned) {
+ currentTranslation = -currentTranslation;
+ translationRemaining = -translationRemaining;
+ }
- mRunningOneHandedAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
- mRunningOneHandedAnimator.start();
- } else {
- securityView.setTranslationX(targetTranslation);
- }
- }
+ if (isFadingOut) {
+ // The bouncer fades out over the first X%.
+ float fadeOutFraction = MathUtils.constrainedMap(
+ /* rangeMin= */1.0f,
+ /* rangeMax= */0.0f,
+ /* valueMin= */0.0f,
+ /* valueMax= */switchPoint,
+ animation.getAnimatedFraction());
+ float opacity = fadeOutInterpolator.getInterpolation(fadeOutFraction);
+
+ // When fading out, the alpha needs to start from the initial opacity of the
+ // view flipper, otherwise we get a weird bit of jank as it ramps back to 100%.
+ mSecurityViewFlipper.setAlpha(opacity * initialAlpha);
+
+ // Animate away from the source.
+ mSecurityViewFlipper.setTranslationX(initialTranslation + currentTranslation);
+ } else {
+ // And in again over the remaining (100-X)%.
+ float fadeInFraction = MathUtils.constrainedMap(
+ /* rangeMin= */0.0f,
+ /* rangeMax= */1.0f,
+ /* valueMin= */switchPoint,
+ /* valueMax= */1.0f,
+ animation.getAnimatedFraction());
+
+ float opacity = fadeInInterpolator.getInterpolation(fadeInFraction);
+ mSecurityViewFlipper.setAlpha(opacity);
+
+ // Fading back in, animate towards the destination.
+ mSecurityViewFlipper.setTranslationX(targetTranslation - translationRemaining);
+ }
- @Nullable
- private KeyguardSecurityViewFlipper findKeyguardSecurityView() {
- for (int i = 0; i < getChildCount(); i++) {
- View child = getChildAt(i);
+ if (animation.getAnimatedFraction() == 1.0f && shouldRestoreLayerType) {
+ mSecurityViewFlipper.setLayerType(View.LAYER_TYPE_NONE, /* paint= */null);
+ }
+ });
- if (isKeyguardSecurityView(child)) {
- return (KeyguardSecurityViewFlipper) child;
- }
+ mRunningOneHandedAnimator.start();
+ } else {
+ mSecurityViewFlipper.setTranslationX(targetTranslation);
}
-
- return null;
- }
-
- private boolean isKeyguardSecurityView(View view) {
- return view instanceof KeyguardSecurityViewFlipper;
}
public void onPause() {
@@ -510,6 +562,11 @@ public class KeyguardSecurityContainer extends FrameLayout {
mIsSecurityViewLeftAligned ? Settings.Global.ONE_HANDED_KEYGUARD_SIDE_LEFT
: Settings.Global.ONE_HANDED_KEYGUARD_SIDE_RIGHT);
+ int keyguardState = mIsSecurityViewLeftAligned
+ ? SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED__STATE__SWITCH_LEFT
+ : SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED__STATE__SWITCH_RIGHT;
+ SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED, keyguardState);
+
updateSecurityViewLocation(animate);
}
}
@@ -635,7 +692,7 @@ public class KeyguardSecurityContainer extends FrameLayout {
for (int i = 0; i < getChildCount(); i++) {
final View view = getChildAt(i);
if (view.getVisibility() != GONE) {
- if (mOneHandedMode && isKeyguardSecurityView(view)) {
+ if (mOneHandedMode && view == mSecurityViewFlipper) {
measureChildWithMargins(view, halfWidthMeasureSpec, 0,
heightMeasureSpec, 0);
} else {