Merge "[Bouncer] Make bouncer view a ConstraintLayout" into tm-qpr-dev am: 06ab363b77
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20028956 Change-Id: I8e0d43956f310b0ee5c89d5a92f7ff94cf60dc50 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -24,7 +24,6 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
androidprv:layout_maxWidth="@dimen/keyguard_security_width"
|
androidprv:layout_maxWidth="@dimen/keyguard_security_width"
|
||||||
androidprv:layout_maxHeight="@dimen/keyguard_security_height"
|
|
||||||
android:layout_gravity="center_horizontal|bottom"
|
android:layout_gravity="center_horizontal|bottom"
|
||||||
android:gravity="bottom"
|
android:gravity="bottom"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -15,6 +15,12 @@
|
|||||||
*/
|
*/
|
||||||
package com.android.keyguard;
|
package com.android.keyguard;
|
||||||
|
|
||||||
|
import static androidx.constraintlayout.widget.ConstraintSet.BOTTOM;
|
||||||
|
import static androidx.constraintlayout.widget.ConstraintSet.END;
|
||||||
|
import static androidx.constraintlayout.widget.ConstraintSet.PARENT_ID;
|
||||||
|
import static androidx.constraintlayout.widget.ConstraintSet.START;
|
||||||
|
import static androidx.constraintlayout.widget.ConstraintSet.TOP;
|
||||||
|
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
import android.app.admin.IKeyguardCallback;
|
import android.app.admin.IKeyguardCallback;
|
||||||
import android.app.admin.IKeyguardClient;
|
import android.app.admin.IKeyguardClient;
|
||||||
@@ -30,7 +36,10 @@ import android.util.Log;
|
|||||||
import android.view.SurfaceControlViewHost;
|
import android.view.SurfaceControlViewHost;
|
||||||
import android.view.SurfaceHolder;
|
import android.view.SurfaceHolder;
|
||||||
import android.view.SurfaceView;
|
import android.view.SurfaceView;
|
||||||
import android.view.ViewGroup;
|
import android.view.View;
|
||||||
|
|
||||||
|
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||||
|
import androidx.constraintlayout.widget.ConstraintSet;
|
||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
|
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
|
||||||
@@ -49,7 +58,7 @@ public class AdminSecondaryLockScreenController {
|
|||||||
private static final int REMOTE_CONTENT_READY_TIMEOUT_MILLIS = 500;
|
private static final int REMOTE_CONTENT_READY_TIMEOUT_MILLIS = 500;
|
||||||
private final KeyguardUpdateMonitor mUpdateMonitor;
|
private final KeyguardUpdateMonitor mUpdateMonitor;
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
private final ViewGroup mParent;
|
private final ConstraintLayout mParent;
|
||||||
private AdminSecurityView mView;
|
private AdminSecurityView mView;
|
||||||
private Handler mHandler;
|
private Handler mHandler;
|
||||||
private IKeyguardClient mClient;
|
private IKeyguardClient mClient;
|
||||||
@@ -156,6 +165,7 @@ public class AdminSecondaryLockScreenController {
|
|||||||
mUpdateMonitor = updateMonitor;
|
mUpdateMonitor = updateMonitor;
|
||||||
mKeyguardCallback = callback;
|
mKeyguardCallback = callback;
|
||||||
mView = new AdminSecurityView(mContext, mSurfaceHolderCallback);
|
mView = new AdminSecurityView(mContext, mSurfaceHolderCallback);
|
||||||
|
mView.setId(View.generateViewId());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -167,6 +177,15 @@ public class AdminSecondaryLockScreenController {
|
|||||||
}
|
}
|
||||||
if (!mView.isAttachedToWindow()) {
|
if (!mView.isAttachedToWindow()) {
|
||||||
mParent.addView(mView);
|
mParent.addView(mView);
|
||||||
|
ConstraintSet constraintSet = new ConstraintSet();
|
||||||
|
constraintSet.clone(mParent);
|
||||||
|
constraintSet.connect(mView.getId(), TOP, PARENT_ID, TOP);
|
||||||
|
constraintSet.connect(mView.getId(), START, PARENT_ID, START);
|
||||||
|
constraintSet.connect(mView.getId(), END, PARENT_ID, END);
|
||||||
|
constraintSet.connect(mView.getId(), BOTTOM, PARENT_ID, BOTTOM);
|
||||||
|
constraintSet.constrainHeight(mView.getId(), ConstraintSet.MATCH_CONSTRAINT);
|
||||||
|
constraintSet.constrainWidth(mView.getId(), ConstraintSet.MATCH_CONSTRAINT);
|
||||||
|
constraintSet.applyTo(mParent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,15 +21,23 @@ import static android.view.WindowInsets.Type.ime;
|
|||||||
import static android.view.WindowInsets.Type.systemBars;
|
import static android.view.WindowInsets.Type.systemBars;
|
||||||
import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_STOP;
|
import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_STOP;
|
||||||
|
|
||||||
|
import static androidx.constraintlayout.widget.ConstraintSet.BOTTOM;
|
||||||
|
import static androidx.constraintlayout.widget.ConstraintSet.CHAIN_SPREAD;
|
||||||
|
import static androidx.constraintlayout.widget.ConstraintSet.END;
|
||||||
|
import static androidx.constraintlayout.widget.ConstraintSet.LEFT;
|
||||||
|
import static androidx.constraintlayout.widget.ConstraintSet.MATCH_CONSTRAINT;
|
||||||
|
import static androidx.constraintlayout.widget.ConstraintSet.PARENT_ID;
|
||||||
|
import static androidx.constraintlayout.widget.ConstraintSet.RIGHT;
|
||||||
|
import static androidx.constraintlayout.widget.ConstraintSet.START;
|
||||||
|
import static androidx.constraintlayout.widget.ConstraintSet.TOP;
|
||||||
|
import static androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT;
|
||||||
|
|
||||||
import static com.android.systemui.plugins.FalsingManager.LOW_PENALTY;
|
import static com.android.systemui.plugins.FalsingManager.LOW_PENALTY;
|
||||||
|
|
||||||
import static java.lang.Integer.max;
|
import static java.lang.Integer.max;
|
||||||
|
|
||||||
import android.animation.Animator;
|
|
||||||
import android.animation.AnimatorListenerAdapter;
|
|
||||||
import android.animation.AnimatorSet;
|
import android.animation.AnimatorSet;
|
||||||
import android.animation.ObjectAnimator;
|
import android.animation.ObjectAnimator;
|
||||||
import android.animation.ValueAnimator;
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.admin.DevicePolicyManager;
|
import android.app.admin.DevicePolicyManager;
|
||||||
@@ -44,12 +52,12 @@ import android.graphics.drawable.Drawable;
|
|||||||
import android.graphics.drawable.LayerDrawable;
|
import android.graphics.drawable.LayerDrawable;
|
||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
|
import android.transition.TransitionManager;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.MathUtils;
|
import android.util.MathUtils;
|
||||||
import android.util.TypedValue;
|
import android.util.TypedValue;
|
||||||
import android.view.GestureDetector;
|
import android.view.GestureDetector;
|
||||||
import android.view.Gravity;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.VelocityTracker;
|
import android.view.VelocityTracker;
|
||||||
@@ -59,8 +67,6 @@ import android.view.ViewGroup;
|
|||||||
import android.view.WindowInsets;
|
import android.view.WindowInsets;
|
||||||
import android.view.WindowInsetsAnimation;
|
import android.view.WindowInsetsAnimation;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
import android.view.animation.AnimationUtils;
|
|
||||||
import android.view.animation.Interpolator;
|
|
||||||
import android.widget.AdapterView;
|
import android.widget.AdapterView;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
@@ -68,8 +74,9 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import androidx.annotation.IntDef;
|
import androidx.annotation.IntDef;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||||
|
import androidx.constraintlayout.widget.ConstraintSet;
|
||||||
import androidx.dynamicanimation.animation.DynamicAnimation;
|
import androidx.dynamicanimation.animation.DynamicAnimation;
|
||||||
import androidx.dynamicanimation.animation.SpringAnimation;
|
import androidx.dynamicanimation.animation.SpringAnimation;
|
||||||
|
|
||||||
@@ -92,9 +99,9 @@ import com.android.systemui.util.settings.GlobalSettings;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
public class KeyguardSecurityContainer extends FrameLayout {
|
/** Determines how the bouncer is displayed to the user. */
|
||||||
|
public class KeyguardSecurityContainer extends ConstraintLayout {
|
||||||
static final int USER_TYPE_PRIMARY = 1;
|
static final int USER_TYPE_PRIMARY = 1;
|
||||||
static final int USER_TYPE_WORK_PROFILE = 2;
|
static final int USER_TYPE_WORK_PROFILE = 2;
|
||||||
static final int USER_TYPE_SECONDARY_USER = 3;
|
static final int USER_TYPE_SECONDARY_USER = 3;
|
||||||
@@ -125,15 +132,6 @@ public class KeyguardSecurityContainer extends FrameLayout {
|
|||||||
// How much to scale the default slop by, to avoid accidental drags.
|
// How much to scale the default slop by, to avoid accidental drags.
|
||||||
private static final float SLOP_SCALE = 4f;
|
private static final float SLOP_SCALE = 4f;
|
||||||
|
|
||||||
private static final long IME_DISAPPEAR_DURATION_MS = 125;
|
|
||||||
|
|
||||||
// The duration of the animation to switch security sides.
|
|
||||||
private static final long SECURITY_SHIFT_ANIMATION_DURATION_MS = 500;
|
|
||||||
|
|
||||||
// How much of the switch sides animation should be dedicated to fading the security out. The
|
|
||||||
// remainder will fade it back in again.
|
|
||||||
private static final float SECURITY_SHIFT_ANIMATION_FADE_OUT_PROPORTION = 0.2f;
|
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
KeyguardSecurityViewFlipper mSecurityViewFlipper;
|
KeyguardSecurityViewFlipper mSecurityViewFlipper;
|
||||||
private GlobalSettings mGlobalSettings;
|
private GlobalSettings mGlobalSettings;
|
||||||
@@ -648,48 +646,9 @@ public class KeyguardSecurityContainer extends FrameLayout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
|
||||||
int maxHeight = 0;
|
|
||||||
int maxWidth = 0;
|
|
||||||
int childState = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < getChildCount(); i++) {
|
|
||||||
final View view = getChildAt(i);
|
|
||||||
if (view.getVisibility() != GONE) {
|
|
||||||
int updatedWidthMeasureSpec = mViewMode.getChildWidthMeasureSpec(widthMeasureSpec);
|
|
||||||
final LayoutParams lp = (LayoutParams) view.getLayoutParams();
|
|
||||||
|
|
||||||
// When using EXACTLY spec, measure will use the layout width if > 0. Set before
|
|
||||||
// measuring the child
|
|
||||||
lp.width = MeasureSpec.getSize(updatedWidthMeasureSpec);
|
|
||||||
measureChildWithMargins(view, updatedWidthMeasureSpec, 0,
|
|
||||||
heightMeasureSpec, 0);
|
|
||||||
|
|
||||||
maxWidth = Math.max(maxWidth,
|
|
||||||
view.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
|
|
||||||
maxHeight = Math.max(maxHeight,
|
|
||||||
view.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
|
|
||||||
childState = combineMeasuredStates(childState, view.getMeasuredState());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
maxWidth += getPaddingLeft() + getPaddingRight();
|
|
||||||
maxHeight += getPaddingTop() + getPaddingBottom();
|
|
||||||
|
|
||||||
// Check against our minimum height and width
|
|
||||||
maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
|
|
||||||
maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
|
|
||||||
|
|
||||||
setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
|
|
||||||
resolveSizeAndState(maxHeight, heightMeasureSpec,
|
|
||||||
childState << MEASURED_HEIGHT_STATE_SHIFT));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||||
super.onLayout(changed, left, top, right, bottom);
|
super.onLayout(changed, left, top, right, bottom);
|
||||||
|
|
||||||
int width = right - left;
|
int width = right - left;
|
||||||
if (changed && mWidth != width) {
|
if (changed && mWidth != width) {
|
||||||
mWidth = width;
|
mWidth = width;
|
||||||
@@ -761,7 +720,7 @@ public class KeyguardSecurityContainer extends FrameLayout {
|
|||||||
* Enscapsulates the differences between bouncer modes for the container.
|
* Enscapsulates the differences between bouncer modes for the container.
|
||||||
*/
|
*/
|
||||||
interface ViewMode {
|
interface ViewMode {
|
||||||
default void init(@NonNull ViewGroup v, @NonNull GlobalSettings globalSettings,
|
default void init(@NonNull ConstraintLayout v, @NonNull GlobalSettings globalSettings,
|
||||||
@NonNull KeyguardSecurityViewFlipper viewFlipper,
|
@NonNull KeyguardSecurityViewFlipper viewFlipper,
|
||||||
@NonNull FalsingManager falsingManager,
|
@NonNull FalsingManager falsingManager,
|
||||||
@NonNull UserSwitcherController userSwitcherController) {};
|
@NonNull UserSwitcherController userSwitcherController) {};
|
||||||
@@ -787,11 +746,6 @@ public class KeyguardSecurityContainer extends FrameLayout {
|
|||||||
/** On notif tap, this animation will run */
|
/** On notif tap, this animation will run */
|
||||||
default void startAppearAnimation(SecurityMode securityMode) {};
|
default void startAppearAnimation(SecurityMode securityMode) {};
|
||||||
|
|
||||||
/** Override to alter the width measure spec to perhaps limit the ViewFlipper size */
|
|
||||||
default int getChildWidthMeasureSpec(int parentWidthMeasureSpec) {
|
|
||||||
return parentWidthMeasureSpec;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Called when we are setting a new ViewMode */
|
/** Called when we are setting a new ViewMode */
|
||||||
default void onDestroy() {};
|
default void onDestroy() {};
|
||||||
}
|
}
|
||||||
@@ -801,13 +755,12 @@ public class KeyguardSecurityContainer extends FrameLayout {
|
|||||||
* screen devices
|
* screen devices
|
||||||
*/
|
*/
|
||||||
abstract static class SidedSecurityMode implements ViewMode {
|
abstract static class SidedSecurityMode implements ViewMode {
|
||||||
@Nullable private ValueAnimator mRunningSecurityShiftAnimator;
|
|
||||||
private KeyguardSecurityViewFlipper mViewFlipper;
|
private KeyguardSecurityViewFlipper mViewFlipper;
|
||||||
private ViewGroup mView;
|
private ConstraintLayout mView;
|
||||||
private GlobalSettings mGlobalSettings;
|
private GlobalSettings mGlobalSettings;
|
||||||
private int mDefaultSideSetting;
|
private int mDefaultSideSetting;
|
||||||
|
|
||||||
public void init(ViewGroup v, KeyguardSecurityViewFlipper viewFlipper,
|
public void init(ConstraintLayout v, KeyguardSecurityViewFlipper viewFlipper,
|
||||||
GlobalSettings globalSettings, boolean leftAlignedByDefault) {
|
GlobalSettings globalSettings, boolean leftAlignedByDefault) {
|
||||||
mView = v;
|
mView = v;
|
||||||
mViewFlipper = viewFlipper;
|
mViewFlipper = viewFlipper;
|
||||||
@@ -850,127 +803,6 @@ public class KeyguardSecurityContainer extends FrameLayout {
|
|||||||
|
|
||||||
protected abstract void updateSecurityViewLocation(boolean leftAlign, boolean animate);
|
protected abstract void updateSecurityViewLocation(boolean leftAlign, boolean animate);
|
||||||
|
|
||||||
protected void translateSecurityViewLocation(boolean leftAlign, boolean animate) {
|
|
||||||
translateSecurityViewLocation(leftAlign, animate, i -> {});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Moves the inner security view to the correct location with animation. This is triggered
|
|
||||||
* when the user double taps on the side of the screen that is not currently occupied by
|
|
||||||
* the security view.
|
|
||||||
*/
|
|
||||||
protected void translateSecurityViewLocation(boolean leftAlign, boolean animate,
|
|
||||||
Consumer<Float> securityAlphaListener) {
|
|
||||||
if (mRunningSecurityShiftAnimator != null) {
|
|
||||||
mRunningSecurityShiftAnimator.cancel();
|
|
||||||
mRunningSecurityShiftAnimator = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
int targetTranslation = leftAlign
|
|
||||||
? 0 : mView.getMeasuredWidth() - mViewFlipper.getWidth();
|
|
||||||
|
|
||||||
if (animate) {
|
|
||||||
// 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/208250221): Make this animation properly abortable.
|
|
||||||
Interpolator positionInterpolator = AnimationUtils.loadInterpolator(
|
|
||||||
mView.getContext(), android.R.interpolator.fast_out_extra_slow_in);
|
|
||||||
Interpolator fadeOutInterpolator = Interpolators.FAST_OUT_LINEAR_IN;
|
|
||||||
Interpolator fadeInInterpolator = Interpolators.LINEAR_OUT_SLOW_IN;
|
|
||||||
|
|
||||||
mRunningSecurityShiftAnimator = ValueAnimator.ofFloat(0.0f, 1.0f);
|
|
||||||
mRunningSecurityShiftAnimator.setDuration(SECURITY_SHIFT_ANIMATION_DURATION_MS);
|
|
||||||
mRunningSecurityShiftAnimator.setInterpolator(Interpolators.LINEAR);
|
|
||||||
|
|
||||||
int initialTranslation = (int) mViewFlipper.getTranslationX();
|
|
||||||
int totalTranslation = (int) mView.getResources().getDimension(
|
|
||||||
R.dimen.security_shift_animation_translation);
|
|
||||||
|
|
||||||
final boolean shouldRestoreLayerType = mViewFlipper.hasOverlappingRendering()
|
|
||||||
&& mViewFlipper.getLayerType() != View.LAYER_TYPE_HARDWARE;
|
|
||||||
if (shouldRestoreLayerType) {
|
|
||||||
mViewFlipper.setLayerType(View.LAYER_TYPE_HARDWARE, /* paint= */null);
|
|
||||||
}
|
|
||||||
|
|
||||||
float initialAlpha = mViewFlipper.getAlpha();
|
|
||||||
|
|
||||||
mRunningSecurityShiftAnimator.addListener(new AnimatorListenerAdapter() {
|
|
||||||
@Override
|
|
||||||
public void onAnimationEnd(Animator animation) {
|
|
||||||
mRunningSecurityShiftAnimator = null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
mRunningSecurityShiftAnimator.addUpdateListener(animation -> {
|
|
||||||
float switchPoint = SECURITY_SHIFT_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 (leftAlign) {
|
|
||||||
currentTranslation = -currentTranslation;
|
|
||||||
translationRemaining = -translationRemaining;
|
|
||||||
}
|
|
||||||
|
|
||||||
float opacity;
|
|
||||||
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());
|
|
||||||
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%.
|
|
||||||
mViewFlipper.setAlpha(opacity * initialAlpha);
|
|
||||||
|
|
||||||
// Animate away from the source.
|
|
||||||
mViewFlipper.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());
|
|
||||||
|
|
||||||
opacity = fadeInInterpolator.getInterpolation(fadeInFraction);
|
|
||||||
mViewFlipper.setAlpha(opacity);
|
|
||||||
|
|
||||||
// Fading back in, animate towards the destination.
|
|
||||||
mViewFlipper.setTranslationX(targetTranslation - translationRemaining);
|
|
||||||
}
|
|
||||||
securityAlphaListener.accept(opacity);
|
|
||||||
|
|
||||||
if (animation.getAnimatedFraction() == 1.0f && shouldRestoreLayerType) {
|
|
||||||
mViewFlipper.setLayerType(View.LAYER_TYPE_NONE, /* paint= */null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
mRunningSecurityShiftAnimator.start();
|
|
||||||
} else {
|
|
||||||
mViewFlipper.setTranslationX(targetTranslation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
boolean isLeftAligned() {
|
boolean isLeftAligned() {
|
||||||
return mGlobalSettings.getInt(Settings.Global.ONE_HANDED_KEYGUARD_SIDE,
|
return mGlobalSettings.getInt(Settings.Global.ONE_HANDED_KEYGUARD_SIDE,
|
||||||
mDefaultSideSetting)
|
mDefaultSideSetting)
|
||||||
@@ -989,11 +821,11 @@ public class KeyguardSecurityContainer extends FrameLayout {
|
|||||||
* Default bouncer is centered within the space
|
* Default bouncer is centered within the space
|
||||||
*/
|
*/
|
||||||
static class DefaultViewMode implements ViewMode {
|
static class DefaultViewMode implements ViewMode {
|
||||||
private ViewGroup mView;
|
private ConstraintLayout mView;
|
||||||
private KeyguardSecurityViewFlipper mViewFlipper;
|
private KeyguardSecurityViewFlipper mViewFlipper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(@NonNull ViewGroup v, @NonNull GlobalSettings globalSettings,
|
public void init(@NonNull ConstraintLayout v, @NonNull GlobalSettings globalSettings,
|
||||||
@NonNull KeyguardSecurityViewFlipper viewFlipper,
|
@NonNull KeyguardSecurityViewFlipper viewFlipper,
|
||||||
@NonNull FalsingManager falsingManager,
|
@NonNull FalsingManager falsingManager,
|
||||||
@NonNull UserSwitcherController userSwitcherController) {
|
@NonNull UserSwitcherController userSwitcherController) {
|
||||||
@@ -1005,11 +837,14 @@ public class KeyguardSecurityContainer extends FrameLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateSecurityViewGroup() {
|
private void updateSecurityViewGroup() {
|
||||||
FrameLayout.LayoutParams lp =
|
ConstraintSet constraintSet = new ConstraintSet();
|
||||||
(FrameLayout.LayoutParams) mViewFlipper.getLayoutParams();
|
constraintSet.connect(mViewFlipper.getId(), START, PARENT_ID, START);
|
||||||
lp.gravity = Gravity.CENTER_HORIZONTAL;
|
constraintSet.connect(mViewFlipper.getId(), END, PARENT_ID, END);
|
||||||
mViewFlipper.setLayoutParams(lp);
|
constraintSet.connect(mViewFlipper.getId(), BOTTOM, PARENT_ID, BOTTOM);
|
||||||
mViewFlipper.setTranslationX(0);
|
constraintSet.connect(mViewFlipper.getId(), TOP, PARENT_ID, TOP);
|
||||||
|
constraintSet.constrainHeight(mViewFlipper.getId(), MATCH_CONSTRAINT);
|
||||||
|
constraintSet.constrainWidth(mViewFlipper.getId(), MATCH_CONSTRAINT);
|
||||||
|
constraintSet.applyTo(mView);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1018,7 +853,7 @@ public class KeyguardSecurityContainer extends FrameLayout {
|
|||||||
* a user switcher, in both portrait and landscape modes.
|
* a user switcher, in both portrait and landscape modes.
|
||||||
*/
|
*/
|
||||||
static class UserSwitcherViewMode extends SidedSecurityMode {
|
static class UserSwitcherViewMode extends SidedSecurityMode {
|
||||||
private ViewGroup mView;
|
private ConstraintLayout mView;
|
||||||
private ViewGroup mUserSwitcherViewGroup;
|
private ViewGroup mUserSwitcherViewGroup;
|
||||||
private KeyguardSecurityViewFlipper mViewFlipper;
|
private KeyguardSecurityViewFlipper mViewFlipper;
|
||||||
private TextView mUserSwitcher;
|
private TextView mUserSwitcher;
|
||||||
@@ -1029,11 +864,8 @@ public class KeyguardSecurityContainer extends FrameLayout {
|
|||||||
private UserSwitcherController.UserSwitchCallback mUserSwitchCallback =
|
private UserSwitcherController.UserSwitchCallback mUserSwitchCallback =
|
||||||
this::setupUserSwitcher;
|
this::setupUserSwitcher;
|
||||||
|
|
||||||
private float mAnimationLastAlpha = 1f;
|
|
||||||
private boolean mAnimationWaitsToShift = true;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(@NonNull ViewGroup v, @NonNull GlobalSettings globalSettings,
|
public void init(@NonNull ConstraintLayout v, @NonNull GlobalSettings globalSettings,
|
||||||
@NonNull KeyguardSecurityViewFlipper viewFlipper,
|
@NonNull KeyguardSecurityViewFlipper viewFlipper,
|
||||||
@NonNull FalsingManager falsingManager,
|
@NonNull FalsingManager falsingManager,
|
||||||
@NonNull UserSwitcherController userSwitcherController) {
|
@NonNull UserSwitcherController userSwitcherController) {
|
||||||
@@ -1240,88 +1072,55 @@ public class KeyguardSecurityContainer extends FrameLayout {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Each view will get half the width. Yes, it would be easier to use something other than
|
|
||||||
* FrameLayout but it was too disruptive to downstream projects to change.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int getChildWidthMeasureSpec(int parentWidthMeasureSpec) {
|
|
||||||
return MeasureSpec.makeMeasureSpec(
|
|
||||||
MeasureSpec.getSize(parentWidthMeasureSpec) / 2,
|
|
||||||
MeasureSpec.EXACTLY);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateSecurityViewLocation() {
|
public void updateSecurityViewLocation() {
|
||||||
updateSecurityViewLocation(isLeftAligned(), /* animate= */false);
|
updateSecurityViewLocation(isLeftAligned(), /* animate= */false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateSecurityViewLocation(boolean leftAlign, boolean animate) {
|
public void updateSecurityViewLocation(boolean leftAlign, boolean animate) {
|
||||||
setYTranslation();
|
|
||||||
setGravity();
|
|
||||||
setXTranslation(leftAlign, animate);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setXTranslation(boolean leftAlign, boolean animate) {
|
|
||||||
if (mResources.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
|
|
||||||
mUserSwitcherViewGroup.setTranslationX(0);
|
|
||||||
mViewFlipper.setTranslationX(0);
|
|
||||||
} else {
|
|
||||||
int switcherTargetTranslation = leftAlign
|
|
||||||
? mView.getMeasuredWidth() - mViewFlipper.getWidth() : 0;
|
|
||||||
if (animate) {
|
if (animate) {
|
||||||
mAnimationWaitsToShift = true;
|
TransitionManager.beginDelayedTransition(mView,
|
||||||
mAnimationLastAlpha = 1f;
|
new KeyguardSecurityViewTransition());
|
||||||
translateSecurityViewLocation(leftAlign, animate, securityAlpha -> {
|
|
||||||
// During the animation security view fades out - alpha goes from 1 to
|
|
||||||
// (almost) 0 - and then fades in - alpha grows back to 1.
|
|
||||||
// If new alpha is bigger than previous one it means we're at inflection
|
|
||||||
// point and alpha is zero or almost zero. That's when we want to do
|
|
||||||
// translation of user switcher, so that it's not visible to the user.
|
|
||||||
boolean fullyFadeOut = securityAlpha == 0.0f
|
|
||||||
|| securityAlpha > mAnimationLastAlpha;
|
|
||||||
if (fullyFadeOut && mAnimationWaitsToShift) {
|
|
||||||
mUserSwitcherViewGroup.setTranslationX(switcherTargetTranslation);
|
|
||||||
mAnimationWaitsToShift = false;
|
|
||||||
}
|
}
|
||||||
mUserSwitcherViewGroup.setAlpha(securityAlpha);
|
|
||||||
mAnimationLastAlpha = securityAlpha;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
translateSecurityViewLocation(leftAlign, animate);
|
|
||||||
mUserSwitcherViewGroup.setTranslationX(switcherTargetTranslation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setGravity() {
|
|
||||||
if (mResources.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
|
|
||||||
updateViewGravity(mUserSwitcherViewGroup, Gravity.CENTER_HORIZONTAL);
|
|
||||||
updateViewGravity(mViewFlipper, Gravity.CENTER_HORIZONTAL);
|
|
||||||
} else {
|
|
||||||
// horizontal gravity is the same because we translate these views anyway
|
|
||||||
updateViewGravity(mViewFlipper, Gravity.LEFT | Gravity.BOTTOM);
|
|
||||||
updateViewGravity(mUserSwitcherViewGroup, Gravity.LEFT | Gravity.CENTER_VERTICAL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setYTranslation() {
|
|
||||||
int yTrans = mResources.getDimensionPixelSize(R.dimen.bouncer_user_switcher_y_trans);
|
int yTrans = mResources.getDimensionPixelSize(R.dimen.bouncer_user_switcher_y_trans);
|
||||||
if (mResources.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
|
if (mResources.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
|
||||||
mUserSwitcherViewGroup.setTranslationY(yTrans);
|
ConstraintSet constraintSet = new ConstraintSet();
|
||||||
|
constraintSet.connect(mUserSwitcherViewGroup.getId(), TOP, PARENT_ID, TOP, yTrans);
|
||||||
|
constraintSet.connect(mViewFlipper.getId(), TOP, PARENT_ID, TOP);
|
||||||
|
constraintSet.connect(mViewFlipper.getId(), BOTTOM, PARENT_ID, BOTTOM);
|
||||||
|
constraintSet.centerHorizontally(mViewFlipper.getId(), PARENT_ID);
|
||||||
|
constraintSet.centerHorizontally(mUserSwitcherViewGroup.getId(), PARENT_ID);
|
||||||
|
constraintSet.setVerticalChainStyle(mViewFlipper.getId(), CHAIN_SPREAD);
|
||||||
|
constraintSet.setVerticalChainStyle(mUserSwitcherViewGroup.getId(), CHAIN_SPREAD);
|
||||||
|
constraintSet.constrainHeight(mUserSwitcherViewGroup.getId(), WRAP_CONTENT);
|
||||||
|
constraintSet.constrainWidth(mUserSwitcherViewGroup.getId(), WRAP_CONTENT);
|
||||||
|
constraintSet.constrainHeight(mViewFlipper.getId(), MATCH_CONSTRAINT);
|
||||||
|
constraintSet.applyTo(mView);
|
||||||
} else {
|
} else {
|
||||||
// Attempt to reposition a bit higher to make up for this frame being a bit lower
|
int leftElement = leftAlign ? mViewFlipper.getId() : mUserSwitcherViewGroup.getId();
|
||||||
// on the device
|
int rightElement =
|
||||||
mUserSwitcherViewGroup.setTranslationY(-yTrans);
|
leftAlign ? mUserSwitcherViewGroup.getId() : mViewFlipper.getId();
|
||||||
mViewFlipper.setTranslationY(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateViewGravity(View v, int gravity) {
|
ConstraintSet constraintSet = new ConstraintSet();
|
||||||
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) v.getLayoutParams();
|
constraintSet.connect(leftElement, LEFT, PARENT_ID, LEFT);
|
||||||
lp.gravity = gravity;
|
constraintSet.connect(leftElement, RIGHT, rightElement, LEFT);
|
||||||
v.setLayoutParams(lp);
|
constraintSet.connect(rightElement, LEFT, leftElement, RIGHT);
|
||||||
|
constraintSet.connect(rightElement, RIGHT, PARENT_ID, RIGHT);
|
||||||
|
constraintSet.connect(mUserSwitcherViewGroup.getId(), TOP, PARENT_ID, TOP);
|
||||||
|
constraintSet.connect(mUserSwitcherViewGroup.getId(), BOTTOM, PARENT_ID, BOTTOM,
|
||||||
|
yTrans);
|
||||||
|
constraintSet.connect(mViewFlipper.getId(), TOP, PARENT_ID, TOP);
|
||||||
|
constraintSet.connect(mViewFlipper.getId(), BOTTOM, PARENT_ID, BOTTOM);
|
||||||
|
constraintSet.setHorizontalChainStyle(mUserSwitcherViewGroup.getId(), CHAIN_SPREAD);
|
||||||
|
constraintSet.setHorizontalChainStyle(mViewFlipper.getId(), CHAIN_SPREAD);
|
||||||
|
constraintSet.constrainHeight(mUserSwitcherViewGroup.getId(),
|
||||||
|
MATCH_CONSTRAINT);
|
||||||
|
constraintSet.constrainWidth(mUserSwitcherViewGroup.getId(),
|
||||||
|
MATCH_CONSTRAINT);
|
||||||
|
constraintSet.constrainWidth(mViewFlipper.getId(), MATCH_CONSTRAINT);
|
||||||
|
constraintSet.constrainHeight(mViewFlipper.getId(), MATCH_CONSTRAINT);
|
||||||
|
constraintSet.applyTo(mView);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1330,11 +1129,11 @@ public class KeyguardSecurityContainer extends FrameLayout {
|
|||||||
* between alternate sides of the display.
|
* between alternate sides of the display.
|
||||||
*/
|
*/
|
||||||
static class OneHandedViewMode extends SidedSecurityMode {
|
static class OneHandedViewMode extends SidedSecurityMode {
|
||||||
private ViewGroup mView;
|
private ConstraintLayout mView;
|
||||||
private KeyguardSecurityViewFlipper mViewFlipper;
|
private KeyguardSecurityViewFlipper mViewFlipper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(@NonNull ViewGroup v, @NonNull GlobalSettings globalSettings,
|
public void init(@NonNull ConstraintLayout v, @NonNull GlobalSettings globalSettings,
|
||||||
@NonNull KeyguardSecurityViewFlipper viewFlipper,
|
@NonNull KeyguardSecurityViewFlipper viewFlipper,
|
||||||
@NonNull FalsingManager falsingManager,
|
@NonNull FalsingManager falsingManager,
|
||||||
@NonNull UserSwitcherController userSwitcherController) {
|
@NonNull UserSwitcherController userSwitcherController) {
|
||||||
@@ -1342,27 +1141,9 @@ public class KeyguardSecurityContainer extends FrameLayout {
|
|||||||
mView = v;
|
mView = v;
|
||||||
mViewFlipper = viewFlipper;
|
mViewFlipper = viewFlipper;
|
||||||
|
|
||||||
updateSecurityViewGravity();
|
|
||||||
updateSecurityViewLocation(isLeftAligned(), /* animate= */false);
|
updateSecurityViewLocation(isLeftAligned(), /* animate= */false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* One-handed mode contains the child to half of the available space.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int getChildWidthMeasureSpec(int parentWidthMeasureSpec) {
|
|
||||||
return MeasureSpec.makeMeasureSpec(
|
|
||||||
MeasureSpec.getSize(parentWidthMeasureSpec) / 2,
|
|
||||||
MeasureSpec.EXACTLY);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateSecurityViewGravity() {
|
|
||||||
FrameLayout.LayoutParams lp =
|
|
||||||
(FrameLayout.LayoutParams) mViewFlipper.getLayoutParams();
|
|
||||||
lp.gravity = Gravity.LEFT | Gravity.BOTTOM;
|
|
||||||
mViewFlipper.setLayoutParams(lp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Moves the bouncer to align with a tap (most likely in the shade), so the bouncer
|
* Moves the bouncer to align with a tap (most likely in the shade), so the bouncer
|
||||||
* appears on the same side as a touch.
|
* appears on the same side as a touch.
|
||||||
@@ -1380,7 +1161,20 @@ public class KeyguardSecurityContainer extends FrameLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void updateSecurityViewLocation(boolean leftAlign, boolean animate) {
|
protected void updateSecurityViewLocation(boolean leftAlign, boolean animate) {
|
||||||
translateSecurityViewLocation(leftAlign, animate);
|
if (animate) {
|
||||||
|
TransitionManager.beginDelayedTransition(mView,
|
||||||
|
new KeyguardSecurityViewTransition());
|
||||||
|
}
|
||||||
|
ConstraintSet constraintSet = new ConstraintSet();
|
||||||
|
if (leftAlign) {
|
||||||
|
constraintSet.connect(mViewFlipper.getId(), LEFT, PARENT_ID, LEFT);
|
||||||
|
} else {
|
||||||
|
constraintSet.connect(mViewFlipper.getId(), RIGHT, PARENT_ID, RIGHT);
|
||||||
|
}
|
||||||
|
constraintSet.connect(mViewFlipper.getId(), TOP, PARENT_ID, TOP);
|
||||||
|
constraintSet.connect(mViewFlipper.getId(), BOTTOM, PARENT_ID, BOTTOM);
|
||||||
|
constraintSet.constrainPercentWidth(mViewFlipper.getId(), 0.5f);
|
||||||
|
constraintSet.applyTo(mView);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,210 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 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.animation.Animator
|
||||||
|
import android.animation.AnimatorListenerAdapter
|
||||||
|
import android.animation.ValueAnimator
|
||||||
|
import android.graphics.Rect
|
||||||
|
import android.transition.Transition
|
||||||
|
import android.transition.TransitionValues
|
||||||
|
import android.util.MathUtils
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.view.animation.AnimationUtils
|
||||||
|
import com.android.internal.R.interpolator.fast_out_extra_slow_in
|
||||||
|
import com.android.systemui.R
|
||||||
|
import com.android.systemui.animation.Interpolators
|
||||||
|
|
||||||
|
/** Animates constraint layout changes for the security view. */
|
||||||
|
class KeyguardSecurityViewTransition : Transition() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val PROP_BOUNDS = "securityViewLocation:bounds"
|
||||||
|
|
||||||
|
// The duration of the animation to switch security sides.
|
||||||
|
const val SECURITY_SHIFT_ANIMATION_DURATION_MS = 500L
|
||||||
|
|
||||||
|
// How much of the switch sides animation should be dedicated to fading the security out.
|
||||||
|
// The remainder will fade it back in again.
|
||||||
|
const val SECURITY_SHIFT_ANIMATION_FADE_OUT_PROPORTION = 0.2f
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun captureValues(values: TransitionValues) {
|
||||||
|
val boundsRect = Rect()
|
||||||
|
boundsRect.left = values.view.left
|
||||||
|
boundsRect.top = values.view.top
|
||||||
|
boundsRect.right = values.view.right
|
||||||
|
boundsRect.bottom = values.view.bottom
|
||||||
|
values.values[PROP_BOUNDS] = boundsRect
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getTransitionProperties(): Array<String>? {
|
||||||
|
return arrayOf(PROP_BOUNDS)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun captureEndValues(transitionValues: TransitionValues?) {
|
||||||
|
transitionValues?.let { captureValues(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun captureStartValues(transitionValues: TransitionValues?) {
|
||||||
|
transitionValues?.let { captureValues(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createAnimator(
|
||||||
|
sceneRoot: ViewGroup?,
|
||||||
|
startValues: TransitionValues?,
|
||||||
|
endValues: TransitionValues?
|
||||||
|
): Animator? {
|
||||||
|
if (sceneRoot == null || startValues == null || endValues == null) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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/208250221): Make this animation properly abortable.
|
||||||
|
val positionInterpolator =
|
||||||
|
AnimationUtils.loadInterpolator(sceneRoot.context, fast_out_extra_slow_in)
|
||||||
|
val fadeOutInterpolator = Interpolators.FAST_OUT_LINEAR_IN
|
||||||
|
val fadeInInterpolator = Interpolators.LINEAR_OUT_SLOW_IN
|
||||||
|
var runningSecurityShiftAnimator = ValueAnimator.ofFloat(0.0f, 1.0f)
|
||||||
|
runningSecurityShiftAnimator.duration = SECURITY_SHIFT_ANIMATION_DURATION_MS
|
||||||
|
runningSecurityShiftAnimator.interpolator = Interpolators.LINEAR
|
||||||
|
val startRect = startValues.values[PROP_BOUNDS] as Rect
|
||||||
|
val endRect = endValues.values[PROP_BOUNDS] as Rect
|
||||||
|
val v = startValues.view
|
||||||
|
val totalTranslation: Int =
|
||||||
|
sceneRoot.resources.getDimension(R.dimen.security_shift_animation_translation).toInt()
|
||||||
|
val shouldRestoreLayerType =
|
||||||
|
(v.hasOverlappingRendering() && v.layerType != View.LAYER_TYPE_HARDWARE)
|
||||||
|
if (shouldRestoreLayerType) {
|
||||||
|
v.setLayerType(View.LAYER_TYPE_HARDWARE, /* paint= */ null)
|
||||||
|
}
|
||||||
|
val initialAlpha: Float = v.alpha
|
||||||
|
runningSecurityShiftAnimator.addListener(
|
||||||
|
object : AnimatorListenerAdapter() {
|
||||||
|
override fun onAnimationEnd(animation: Animator) {
|
||||||
|
runningSecurityShiftAnimator = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
var finishedFadingOutNonSecurityView = false
|
||||||
|
|
||||||
|
runningSecurityShiftAnimator.addUpdateListener { animation: ValueAnimator ->
|
||||||
|
val switchPoint = SECURITY_SHIFT_ANIMATION_FADE_OUT_PROPORTION
|
||||||
|
val isFadingOut = animation.animatedFraction < switchPoint
|
||||||
|
val opacity: Float
|
||||||
|
var currentTranslation =
|
||||||
|
(positionInterpolator.getInterpolation(animation.animatedFraction) *
|
||||||
|
totalTranslation)
|
||||||
|
.toInt()
|
||||||
|
var translationRemaining = totalTranslation - currentTranslation
|
||||||
|
val leftAlign = endRect.left < startRect.left
|
||||||
|
if (leftAlign) {
|
||||||
|
currentTranslation = -currentTranslation
|
||||||
|
translationRemaining = -translationRemaining
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isFadingOut) {
|
||||||
|
// The bouncer fades out over the first X%.
|
||||||
|
val fadeOutFraction =
|
||||||
|
MathUtils.constrainedMap(
|
||||||
|
/* rangeMin= */ 1.0f,
|
||||||
|
/* rangeMax= */ 0.0f,
|
||||||
|
/* valueMin= */ 0.0f,
|
||||||
|
/* valueMax= */ switchPoint,
|
||||||
|
animation.animatedFraction
|
||||||
|
)
|
||||||
|
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%.
|
||||||
|
v.alpha = opacity * initialAlpha
|
||||||
|
if (v is KeyguardSecurityViewFlipper) {
|
||||||
|
v.setLeftTopRightBottom(
|
||||||
|
startRect.left + currentTranslation,
|
||||||
|
startRect.top,
|
||||||
|
startRect.right + currentTranslation,
|
||||||
|
startRect.bottom
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// And in again over the remaining (100-X)%.
|
||||||
|
val fadeInFraction =
|
||||||
|
MathUtils.constrainedMap(
|
||||||
|
/* rangeMin= */ 0.0f,
|
||||||
|
/* rangeMax= */ 1.0f,
|
||||||
|
/* valueMin= */ switchPoint,
|
||||||
|
/* valueMax= */ 1.0f,
|
||||||
|
animation.animatedFraction
|
||||||
|
)
|
||||||
|
opacity = fadeInInterpolator.getInterpolation(fadeInFraction)
|
||||||
|
v.alpha = opacity
|
||||||
|
|
||||||
|
// Fading back in, animate towards the destination.
|
||||||
|
if (v is KeyguardSecurityViewFlipper) {
|
||||||
|
v.setLeftTopRightBottom(
|
||||||
|
endRect.left - translationRemaining,
|
||||||
|
endRect.top,
|
||||||
|
endRect.right - translationRemaining,
|
||||||
|
endRect.bottom
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (animation.animatedFraction == 1.0f && shouldRestoreLayerType) {
|
||||||
|
v.setLayerType(View.LAYER_TYPE_NONE, /* paint= */ null)
|
||||||
|
}
|
||||||
|
|
||||||
|
// For views that are not the security view flipper, we do not want to apply
|
||||||
|
// an x translation animation. Instead, we want to fade out, move to final position and
|
||||||
|
// then fade in.
|
||||||
|
if (v !is KeyguardSecurityViewFlipper) {
|
||||||
|
// Opacity goes close to 0 but does not fully get to 0.
|
||||||
|
if (opacity - 0.001f < 0f) {
|
||||||
|
v.setLeftTopRightBottom(
|
||||||
|
endRect.left,
|
||||||
|
endRect.top,
|
||||||
|
endRect.right,
|
||||||
|
endRect.bottom
|
||||||
|
)
|
||||||
|
finishedFadingOutNonSecurityView = true
|
||||||
|
} else if (!finishedFadingOutNonSecurityView) {
|
||||||
|
v.setLeftTopRightBottom(
|
||||||
|
startRect.left,
|
||||||
|
startRect.top,
|
||||||
|
startRect.right,
|
||||||
|
startRect.bottom
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
runningSecurityShiftAnimator.start()
|
||||||
|
return runningSecurityShiftAnimator
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -41,6 +41,7 @@ import android.testing.TestableLooper.RunWithLooper;
|
|||||||
import android.testing.ViewUtils;
|
import android.testing.ViewUtils;
|
||||||
import android.view.SurfaceControlViewHost;
|
import android.view.SurfaceControlViewHost;
|
||||||
import android.view.SurfaceView;
|
import android.view.SurfaceView;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
@@ -84,6 +85,7 @@ public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase {
|
|||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
|
|
||||||
mKeyguardSecurityContainer = spy(new KeyguardSecurityContainer(mContext));
|
mKeyguardSecurityContainer = spy(new KeyguardSecurityContainer(mContext));
|
||||||
|
mKeyguardSecurityContainer.setId(View.generateViewId());
|
||||||
ViewUtils.attachView(mKeyguardSecurityContainer);
|
ViewUtils.attachView(mKeyguardSecurityContainer);
|
||||||
|
|
||||||
mTestableLooper = TestableLooper.get(this);
|
mTestableLooper = TestableLooper.get(this);
|
||||||
|
|||||||
@@ -21,10 +21,14 @@ import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
|
|||||||
import static android.provider.Settings.Global.ONE_HANDED_KEYGUARD_SIDE;
|
import static android.provider.Settings.Global.ONE_HANDED_KEYGUARD_SIDE;
|
||||||
import static android.provider.Settings.Global.ONE_HANDED_KEYGUARD_SIDE_LEFT;
|
import static android.provider.Settings.Global.ONE_HANDED_KEYGUARD_SIDE_LEFT;
|
||||||
import static android.provider.Settings.Global.ONE_HANDED_KEYGUARD_SIDE_RIGHT;
|
import static android.provider.Settings.Global.ONE_HANDED_KEYGUARD_SIDE_RIGHT;
|
||||||
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
|
|
||||||
import static android.view.WindowInsets.Type.ime;
|
import static android.view.WindowInsets.Type.ime;
|
||||||
import static android.view.WindowInsets.Type.systemBars;
|
import static android.view.WindowInsets.Type.systemBars;
|
||||||
|
|
||||||
|
import static androidx.constraintlayout.widget.ConstraintSet.CHAIN_SPREAD;
|
||||||
|
import static androidx.constraintlayout.widget.ConstraintSet.MATCH_CONSTRAINT;
|
||||||
|
import static androidx.constraintlayout.widget.ConstraintSet.PARENT_ID;
|
||||||
|
import static androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT;
|
||||||
|
|
||||||
import static com.android.keyguard.KeyguardSecurityContainer.MODE_DEFAULT;
|
import static com.android.keyguard.KeyguardSecurityContainer.MODE_DEFAULT;
|
||||||
import static com.android.keyguard.KeyguardSecurityContainer.MODE_ONE_HANDED;
|
import static com.android.keyguard.KeyguardSecurityContainer.MODE_ONE_HANDED;
|
||||||
|
|
||||||
@@ -32,9 +36,6 @@ import static com.google.common.truth.Truth.assertThat;
|
|||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.anyInt;
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
import static org.mockito.Mockito.atLeastOnce;
|
|
||||||
import static org.mockito.Mockito.never;
|
|
||||||
import static org.mockito.Mockito.reset;
|
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
@@ -43,19 +44,17 @@ import android.content.res.Configuration;
|
|||||||
import android.graphics.Insets;
|
import android.graphics.Insets;
|
||||||
import android.testing.AndroidTestingRunner;
|
import android.testing.AndroidTestingRunner;
|
||||||
import android.testing.TestableLooper;
|
import android.testing.TestableLooper;
|
||||||
import android.view.Gravity;
|
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.WindowInsets;
|
import android.view.WindowInsets;
|
||||||
import android.widget.FrameLayout;
|
|
||||||
|
|
||||||
|
import androidx.constraintlayout.widget.ConstraintSet;
|
||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
import com.android.systemui.R;
|
import com.android.systemui.R;
|
||||||
import com.android.systemui.SysuiTestCase;
|
import com.android.systemui.SysuiTestCase;
|
||||||
import com.android.systemui.plugins.FalsingManager;
|
import com.android.systemui.plugins.FalsingManager;
|
||||||
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
|
||||||
import com.android.systemui.statusbar.policy.UserSwitcherController;
|
import com.android.systemui.statusbar.policy.UserSwitcherController;
|
||||||
import com.android.systemui.user.data.source.UserRecord;
|
import com.android.systemui.user.data.source.UserRecord;
|
||||||
import com.android.systemui.util.settings.GlobalSettings;
|
import com.android.systemui.util.settings.GlobalSettings;
|
||||||
@@ -64,8 +63,6 @@ import org.junit.Before;
|
|||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.ArgumentCaptor;
|
|
||||||
import org.mockito.Captor;
|
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.junit.MockitoJUnit;
|
import org.mockito.junit.MockitoJUnit;
|
||||||
import org.mockito.junit.MockitoRule;
|
import org.mockito.junit.MockitoRule;
|
||||||
@@ -78,14 +75,11 @@ import java.util.ArrayList;
|
|||||||
public class KeyguardSecurityContainerTest extends SysuiTestCase {
|
public class KeyguardSecurityContainerTest extends SysuiTestCase {
|
||||||
|
|
||||||
private static final int VIEW_WIDTH = 1600;
|
private static final int VIEW_WIDTH = 1600;
|
||||||
|
private static final int VIEW_HEIGHT = 900;
|
||||||
private int mScreenWidth;
|
|
||||||
private int mFakeMeasureSpec;
|
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public MockitoRule mRule = MockitoJUnit.rule();
|
public MockitoRule mRule = MockitoJUnit.rule();
|
||||||
|
|
||||||
@Mock
|
|
||||||
private KeyguardSecurityViewFlipper mSecurityViewFlipper;
|
private KeyguardSecurityViewFlipper mSecurityViewFlipper;
|
||||||
@Mock
|
@Mock
|
||||||
private GlobalSettings mGlobalSettings;
|
private GlobalSettings mGlobalSettings;
|
||||||
@@ -93,59 +87,32 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase {
|
|||||||
private FalsingManager mFalsingManager;
|
private FalsingManager mFalsingManager;
|
||||||
@Mock
|
@Mock
|
||||||
private UserSwitcherController mUserSwitcherController;
|
private UserSwitcherController mUserSwitcherController;
|
||||||
@Mock
|
|
||||||
private KeyguardStateController mKeyguardStateController;
|
|
||||||
@Captor
|
|
||||||
private ArgumentCaptor<FrameLayout.LayoutParams> mLayoutCaptor;
|
|
||||||
|
|
||||||
private KeyguardSecurityContainer mKeyguardSecurityContainer;
|
private KeyguardSecurityContainer mKeyguardSecurityContainer;
|
||||||
private FrameLayout.LayoutParams mSecurityViewFlipperLayoutParams;
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
// Needed here, otherwise when mKeyguardSecurityContainer is created below, it'll cache
|
// Needed here, otherwise when mKeyguardSecurityContainer is created below, it'll cache
|
||||||
// the real references (rather than the TestableResources that this call creates).
|
// the real references (rather than the TestableResources that this call creates).
|
||||||
mContext.ensureTestableResources();
|
mContext.ensureTestableResources();
|
||||||
mSecurityViewFlipperLayoutParams = new FrameLayout.LayoutParams(
|
|
||||||
MATCH_PARENT, MATCH_PARENT);
|
|
||||||
|
|
||||||
when(mSecurityViewFlipper.getLayoutParams()).thenReturn(mSecurityViewFlipperLayoutParams);
|
mSecurityViewFlipper = new KeyguardSecurityViewFlipper(getContext());
|
||||||
|
mSecurityViewFlipper.setId(View.generateViewId());
|
||||||
mKeyguardSecurityContainer = new KeyguardSecurityContainer(getContext());
|
mKeyguardSecurityContainer = new KeyguardSecurityContainer(getContext());
|
||||||
|
mKeyguardSecurityContainer.setRight(VIEW_WIDTH);
|
||||||
|
mKeyguardSecurityContainer.setLeft(0);
|
||||||
|
mKeyguardSecurityContainer.setTop(0);
|
||||||
|
mKeyguardSecurityContainer.setBottom(VIEW_HEIGHT);
|
||||||
|
mKeyguardSecurityContainer.setId(View.generateViewId());
|
||||||
mKeyguardSecurityContainer.mSecurityViewFlipper = mSecurityViewFlipper;
|
mKeyguardSecurityContainer.mSecurityViewFlipper = mSecurityViewFlipper;
|
||||||
mKeyguardSecurityContainer.addView(mSecurityViewFlipper, new ViewGroup.LayoutParams(
|
mKeyguardSecurityContainer.addView(mSecurityViewFlipper, new ViewGroup.LayoutParams(
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
|
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||||
|
|
||||||
when(mUserSwitcherController.getCurrentUserName()).thenReturn("Test User");
|
when(mUserSwitcherController.getCurrentUserName()).thenReturn("Test User");
|
||||||
when(mUserSwitcherController.isKeyguardShowing()).thenReturn(true);
|
when(mUserSwitcherController.isKeyguardShowing()).thenReturn(true);
|
||||||
|
|
||||||
mScreenWidth = getUiDevice().getDisplayWidth();
|
|
||||||
mFakeMeasureSpec = View
|
|
||||||
.MeasureSpec.makeMeasureSpec(mScreenWidth, View.MeasureSpec.EXACTLY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onMeasure_usesHalfWidthWithOneHandedModeEnabled() {
|
public void testOnApplyWindowInsets() {
|
||||||
mKeyguardSecurityContainer.initMode(MODE_ONE_HANDED, mGlobalSettings, mFalsingManager,
|
|
||||||
mUserSwitcherController);
|
|
||||||
|
|
||||||
int halfWidthMeasureSpec =
|
|
||||||
View.MeasureSpec.makeMeasureSpec(mScreenWidth / 2, View.MeasureSpec.EXACTLY);
|
|
||||||
mKeyguardSecurityContainer.onMeasure(mFakeMeasureSpec, mFakeMeasureSpec);
|
|
||||||
|
|
||||||
verify(mSecurityViewFlipper).measure(halfWidthMeasureSpec, mFakeMeasureSpec);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void onMeasure_usesFullWidthWithOneHandedModeDisabled() {
|
|
||||||
mKeyguardSecurityContainer.initMode(MODE_DEFAULT, mGlobalSettings, mFalsingManager,
|
|
||||||
mUserSwitcherController);
|
|
||||||
|
|
||||||
mKeyguardSecurityContainer.measure(mFakeMeasureSpec, mFakeMeasureSpec);
|
|
||||||
verify(mSecurityViewFlipper).measure(mFakeMeasureSpec, mFakeMeasureSpec);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void onMeasure_respectsViewInsets() {
|
|
||||||
int paddingBottom = getContext().getResources()
|
int paddingBottom = getContext().getResources()
|
||||||
.getDimensionPixelSize(R.dimen.keyguard_security_view_bottom_margin);
|
.getDimensionPixelSize(R.dimen.keyguard_security_view_bottom_margin);
|
||||||
int imeInsetAmount = paddingBottom + 1;
|
int imeInsetAmount = paddingBottom + 1;
|
||||||
@@ -162,17 +129,12 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase {
|
|||||||
.setInsetsIgnoringVisibility(systemBars(), systemBarInset)
|
.setInsetsIgnoringVisibility(systemBars(), systemBarInset)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// It's reduced by the max of the systembar and IME, so just subtract IME inset.
|
|
||||||
int expectedHeightMeasureSpec = View.MeasureSpec.makeMeasureSpec(
|
|
||||||
mScreenWidth - imeInsetAmount, View.MeasureSpec.EXACTLY);
|
|
||||||
|
|
||||||
mKeyguardSecurityContainer.onApplyWindowInsets(insets);
|
mKeyguardSecurityContainer.onApplyWindowInsets(insets);
|
||||||
mKeyguardSecurityContainer.measure(mFakeMeasureSpec, mFakeMeasureSpec);
|
assertThat(mKeyguardSecurityContainer.getPaddingBottom()).isEqualTo(imeInsetAmount);
|
||||||
verify(mSecurityViewFlipper).measure(mFakeMeasureSpec, expectedHeightMeasureSpec);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onMeasure_respectsViewInsets_largerSystembar() {
|
public void testOnApplyWindowInsets_largerSystembar() {
|
||||||
int imeInsetAmount = 0;
|
int imeInsetAmount = 0;
|
||||||
int paddingBottom = getContext().getResources()
|
int paddingBottom = getContext().getResources()
|
||||||
.getDimensionPixelSize(R.dimen.keyguard_security_view_bottom_margin);
|
.getDimensionPixelSize(R.dimen.keyguard_security_view_bottom_margin);
|
||||||
@@ -189,25 +151,22 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase {
|
|||||||
.setInsetsIgnoringVisibility(systemBars(), systemBarInset)
|
.setInsetsIgnoringVisibility(systemBars(), systemBarInset)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
int expectedHeightMeasureSpec = View.MeasureSpec.makeMeasureSpec(
|
|
||||||
mScreenWidth - systemBarInsetAmount, View.MeasureSpec.EXACTLY);
|
|
||||||
|
|
||||||
mKeyguardSecurityContainer.onApplyWindowInsets(insets);
|
mKeyguardSecurityContainer.onApplyWindowInsets(insets);
|
||||||
mKeyguardSecurityContainer.measure(mFakeMeasureSpec, mFakeMeasureSpec);
|
assertThat(mKeyguardSecurityContainer.getPaddingBottom()).isEqualTo(systemBarInsetAmount);
|
||||||
verify(mSecurityViewFlipper).measure(mFakeMeasureSpec, expectedHeightMeasureSpec);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupForUpdateKeyguardPosition(boolean oneHandedMode) {
|
@Test
|
||||||
int mode = oneHandedMode ? MODE_ONE_HANDED : MODE_DEFAULT;
|
public void testDefaultViewMode() {
|
||||||
mKeyguardSecurityContainer.initMode(mode, mGlobalSettings, mFalsingManager,
|
mKeyguardSecurityContainer.initMode(MODE_ONE_HANDED, mGlobalSettings, mFalsingManager,
|
||||||
mUserSwitcherController);
|
mUserSwitcherController);
|
||||||
|
mKeyguardSecurityContainer.initMode(MODE_DEFAULT, mGlobalSettings, mFalsingManager,
|
||||||
mKeyguardSecurityContainer.measure(mFakeMeasureSpec, mFakeMeasureSpec);
|
mUserSwitcherController);
|
||||||
mKeyguardSecurityContainer.layout(0, 0, mScreenWidth, mScreenWidth);
|
ConstraintSet.Constraint viewFlipperConstraint =
|
||||||
|
getViewConstraint(mSecurityViewFlipper.getId());
|
||||||
// Clear any interactions with the mock so we know the interactions definitely come from the
|
assertThat(viewFlipperConstraint.layout.topToTop).isEqualTo(PARENT_ID);
|
||||||
// below testing.
|
assertThat(viewFlipperConstraint.layout.startToStart).isEqualTo(PARENT_ID);
|
||||||
reset(mSecurityViewFlipper);
|
assertThat(viewFlipperConstraint.layout.endToEnd).isEqualTo(PARENT_ID);
|
||||||
|
assertThat(viewFlipperConstraint.layout.bottomToBottom).isEqualTo(PARENT_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -217,13 +176,22 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase {
|
|||||||
mKeyguardSecurityContainer.getWidth() - 1f);
|
mKeyguardSecurityContainer.getWidth() - 1f);
|
||||||
|
|
||||||
verify(mGlobalSettings).putInt(ONE_HANDED_KEYGUARD_SIDE, ONE_HANDED_KEYGUARD_SIDE_RIGHT);
|
verify(mGlobalSettings).putInt(ONE_HANDED_KEYGUARD_SIDE, ONE_HANDED_KEYGUARD_SIDE_RIGHT);
|
||||||
assertSecurityTranslationX(
|
ConstraintSet.Constraint viewFlipperConstraint =
|
||||||
mKeyguardSecurityContainer.getWidth() - mSecurityViewFlipper.getWidth());
|
getViewConstraint(mSecurityViewFlipper.getId());
|
||||||
|
assertThat(viewFlipperConstraint.layout.widthPercent).isEqualTo(0.5f);
|
||||||
|
assertThat(viewFlipperConstraint.layout.topToTop).isEqualTo(PARENT_ID);
|
||||||
|
assertThat(viewFlipperConstraint.layout.rightToRight).isEqualTo(PARENT_ID);
|
||||||
|
assertThat(viewFlipperConstraint.layout.leftToLeft).isEqualTo(-1);
|
||||||
|
|
||||||
mKeyguardSecurityContainer.updatePositionByTouchX(1f);
|
mKeyguardSecurityContainer.updatePositionByTouchX(1f);
|
||||||
verify(mGlobalSettings).putInt(ONE_HANDED_KEYGUARD_SIDE, ONE_HANDED_KEYGUARD_SIDE_LEFT);
|
verify(mGlobalSettings).putInt(ONE_HANDED_KEYGUARD_SIDE, ONE_HANDED_KEYGUARD_SIDE_LEFT);
|
||||||
|
|
||||||
verify(mSecurityViewFlipper).setTranslationX(0.0f);
|
viewFlipperConstraint =
|
||||||
|
getViewConstraint(mSecurityViewFlipper.getId());
|
||||||
|
assertThat(viewFlipperConstraint.layout.widthPercent).isEqualTo(0.5f);
|
||||||
|
assertThat(viewFlipperConstraint.layout.topToTop).isEqualTo(PARENT_ID);
|
||||||
|
assertThat(viewFlipperConstraint.layout.leftToLeft).isEqualTo(PARENT_ID);
|
||||||
|
assertThat(viewFlipperConstraint.layout.rightToRight).isEqualTo(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -232,10 +200,16 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase {
|
|||||||
|
|
||||||
mKeyguardSecurityContainer.updatePositionByTouchX(
|
mKeyguardSecurityContainer.updatePositionByTouchX(
|
||||||
mKeyguardSecurityContainer.getWidth() - 1f);
|
mKeyguardSecurityContainer.getWidth() - 1f);
|
||||||
verify(mSecurityViewFlipper, never()).setTranslationX(anyInt());
|
ConstraintSet.Constraint viewFlipperConstraint =
|
||||||
|
getViewConstraint(mSecurityViewFlipper.getId());
|
||||||
|
assertThat(viewFlipperConstraint.layout.rightToRight).isEqualTo(-1);
|
||||||
|
assertThat(viewFlipperConstraint.layout.leftToLeft).isEqualTo(-1);
|
||||||
|
|
||||||
mKeyguardSecurityContainer.updatePositionByTouchX(1f);
|
mKeyguardSecurityContainer.updatePositionByTouchX(1f);
|
||||||
verify(mSecurityViewFlipper, never()).setTranslationX(anyInt());
|
viewFlipperConstraint =
|
||||||
|
getViewConstraint(mSecurityViewFlipper.getId());
|
||||||
|
assertThat(viewFlipperConstraint.layout.rightToRight).isEqualTo(-1);
|
||||||
|
assertThat(viewFlipperConstraint.layout.leftToLeft).isEqualTo(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -249,17 +223,31 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase {
|
|||||||
setupUserSwitcher();
|
setupUserSwitcher();
|
||||||
mKeyguardSecurityContainer.onConfigurationChanged(landscapeConfig);
|
mKeyguardSecurityContainer.onConfigurationChanged(landscapeConfig);
|
||||||
|
|
||||||
// THEN views are oriented side by side
|
ConstraintSet.Constraint viewFlipperConstraint =
|
||||||
assertSecurityGravity(Gravity.LEFT | Gravity.BOTTOM);
|
getViewConstraint(mSecurityViewFlipper.getId());
|
||||||
assertUserSwitcherGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
|
ConstraintSet.Constraint userSwitcherConstraint =
|
||||||
assertSecurityTranslationX(
|
getViewConstraint(R.id.keyguard_bouncer_user_switcher);
|
||||||
mKeyguardSecurityContainer.getWidth() - mSecurityViewFlipper.getWidth());
|
assertThat(viewFlipperConstraint.layout.rightToRight).isEqualTo(PARENT_ID);
|
||||||
assertUserSwitcherTranslationX(0f);
|
assertThat(viewFlipperConstraint.layout.leftToRight).isEqualTo(
|
||||||
|
R.id.keyguard_bouncer_user_switcher);
|
||||||
|
assertThat(userSwitcherConstraint.layout.leftToLeft).isEqualTo(PARENT_ID);
|
||||||
|
assertThat(userSwitcherConstraint.layout.rightToLeft).isEqualTo(
|
||||||
|
mSecurityViewFlipper.getId());
|
||||||
|
assertThat(viewFlipperConstraint.layout.topToTop).isEqualTo(PARENT_ID);
|
||||||
|
assertThat(viewFlipperConstraint.layout.bottomToBottom).isEqualTo(PARENT_ID);
|
||||||
|
assertThat(userSwitcherConstraint.layout.topToTop).isEqualTo(PARENT_ID);
|
||||||
|
assertThat(userSwitcherConstraint.layout.bottomToBottom).isEqualTo(PARENT_ID);
|
||||||
|
assertThat(userSwitcherConstraint.layout.bottomMargin).isEqualTo(
|
||||||
|
getContext().getResources().getDimensionPixelSize(
|
||||||
|
R.dimen.bouncer_user_switcher_y_trans));
|
||||||
|
assertThat(viewFlipperConstraint.layout.horizontalChainStyle).isEqualTo(CHAIN_SPREAD);
|
||||||
|
assertThat(userSwitcherConstraint.layout.horizontalChainStyle).isEqualTo(CHAIN_SPREAD);
|
||||||
|
assertThat(viewFlipperConstraint.layout.mHeight).isEqualTo(MATCH_CONSTRAINT);
|
||||||
|
assertThat(userSwitcherConstraint.layout.mHeight).isEqualTo(MATCH_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUserSwitcherModeViewGravityPortrait() {
|
public void testUserSwitcherModeViewPositionPortrait() {
|
||||||
// GIVEN one user has been setup and in landscape
|
// GIVEN one user has been setup and in landscape
|
||||||
when(mUserSwitcherController.getUsers()).thenReturn(buildUserRecords(1));
|
when(mUserSwitcherController.getUsers()).thenReturn(buildUserRecords(1));
|
||||||
Configuration portraitConfig = configuration(ORIENTATION_PORTRAIT);
|
Configuration portraitConfig = configuration(ORIENTATION_PORTRAIT);
|
||||||
@@ -267,15 +255,28 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase {
|
|||||||
|
|
||||||
// WHEN UserSwitcherViewMode is initialized and config has changed
|
// WHEN UserSwitcherViewMode is initialized and config has changed
|
||||||
setupUserSwitcher();
|
setupUserSwitcher();
|
||||||
reset(mSecurityViewFlipper);
|
|
||||||
when(mSecurityViewFlipper.getLayoutParams()).thenReturn(mSecurityViewFlipperLayoutParams);
|
|
||||||
mKeyguardSecurityContainer.onConfigurationChanged(portraitConfig);
|
mKeyguardSecurityContainer.onConfigurationChanged(portraitConfig);
|
||||||
|
|
||||||
// THEN views are both centered horizontally
|
ConstraintSet.Constraint viewFlipperConstraint =
|
||||||
assertSecurityGravity(Gravity.CENTER_HORIZONTAL);
|
getViewConstraint(mSecurityViewFlipper.getId());
|
||||||
assertUserSwitcherGravity(Gravity.CENTER_HORIZONTAL);
|
ConstraintSet.Constraint userSwitcherConstraint =
|
||||||
assertSecurityTranslationX(0);
|
getViewConstraint(R.id.keyguard_bouncer_user_switcher);
|
||||||
assertUserSwitcherTranslationX(0);
|
|
||||||
|
assertThat(viewFlipperConstraint.layout.topToTop).isEqualTo(PARENT_ID);
|
||||||
|
assertThat(viewFlipperConstraint.layout.bottomToBottom).isEqualTo(PARENT_ID);
|
||||||
|
assertThat(userSwitcherConstraint.layout.topToTop).isEqualTo(PARENT_ID);
|
||||||
|
assertThat(userSwitcherConstraint.layout.topMargin).isEqualTo(
|
||||||
|
getContext().getResources().getDimensionPixelSize(
|
||||||
|
R.dimen.bouncer_user_switcher_y_trans));
|
||||||
|
assertThat(viewFlipperConstraint.layout.leftToLeft).isEqualTo(PARENT_ID);
|
||||||
|
assertThat(viewFlipperConstraint.layout.rightToRight).isEqualTo(PARENT_ID);
|
||||||
|
assertThat(userSwitcherConstraint.layout.leftToLeft).isEqualTo(PARENT_ID);
|
||||||
|
assertThat(userSwitcherConstraint.layout.rightToRight).isEqualTo(PARENT_ID);
|
||||||
|
assertThat(viewFlipperConstraint.layout.verticalChainStyle).isEqualTo(CHAIN_SPREAD);
|
||||||
|
assertThat(userSwitcherConstraint.layout.verticalChainStyle).isEqualTo(CHAIN_SPREAD);
|
||||||
|
assertThat(viewFlipperConstraint.layout.mHeight).isEqualTo(MATCH_CONSTRAINT);
|
||||||
|
assertThat(userSwitcherConstraint.layout.mHeight).isEqualTo(WRAP_CONTENT);
|
||||||
|
assertThat(userSwitcherConstraint.layout.mWidth).isEqualTo(WRAP_CONTENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -337,9 +338,9 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase {
|
|||||||
when(mGlobalSettings.getInt(any(), anyInt())).thenReturn(ONE_HANDED_KEYGUARD_SIDE_LEFT);
|
when(mGlobalSettings.getInt(any(), anyInt())).thenReturn(ONE_HANDED_KEYGUARD_SIDE_LEFT);
|
||||||
mKeyguardSecurityContainer.onConfigurationChanged(new Configuration());
|
mKeyguardSecurityContainer.onConfigurationChanged(new Configuration());
|
||||||
|
|
||||||
assertSecurityTranslationX(0);
|
ConstraintSet.Constraint viewFlipperConstraint = getViewConstraint(
|
||||||
assertUserSwitcherTranslationX(
|
mSecurityViewFlipper.getId());
|
||||||
mKeyguardSecurityContainer.getWidth() - mSecurityViewFlipper.getWidth());
|
assertThat(viewFlipperConstraint.layout.leftToLeft).isEqualTo(PARENT_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Configuration configuration(@Configuration.Orientation int orientation) {
|
private Configuration configuration(@Configuration.Orientation int orientation) {
|
||||||
@@ -348,28 +349,6 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase {
|
|||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertSecurityTranslationX(float translation) {
|
|
||||||
verify(mSecurityViewFlipper).setTranslationX(translation);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertUserSwitcherTranslationX(float translation) {
|
|
||||||
ViewGroup userSwitcher = mKeyguardSecurityContainer.findViewById(
|
|
||||||
R.id.keyguard_bouncer_user_switcher);
|
|
||||||
assertThat(userSwitcher.getTranslationX()).isEqualTo(translation);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertUserSwitcherGravity(@Gravity.GravityFlags int gravity) {
|
|
||||||
ViewGroup userSwitcher = mKeyguardSecurityContainer.findViewById(
|
|
||||||
R.id.keyguard_bouncer_user_switcher);
|
|
||||||
assertThat(((FrameLayout.LayoutParams) userSwitcher.getLayoutParams()).gravity)
|
|
||||||
.isEqualTo(gravity);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertSecurityGravity(@Gravity.GravityFlags int gravity) {
|
|
||||||
verify(mSecurityViewFlipper, atLeastOnce()).setLayoutParams(mLayoutCaptor.capture());
|
|
||||||
assertThat(mLayoutCaptor.getValue().gravity).isEqualTo(gravity);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setViewWidth(int width) {
|
private void setViewWidth(int width) {
|
||||||
mKeyguardSecurityContainer.setRight(width);
|
mKeyguardSecurityContainer.setRight(width);
|
||||||
mKeyguardSecurityContainer.setLeft(0);
|
mKeyguardSecurityContainer.setLeft(0);
|
||||||
@@ -399,9 +378,6 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase {
|
|||||||
when(mGlobalSettings.getInt(any(), anyInt())).thenReturn(ONE_HANDED_KEYGUARD_SIDE_RIGHT);
|
when(mGlobalSettings.getInt(any(), anyInt())).thenReturn(ONE_HANDED_KEYGUARD_SIDE_RIGHT);
|
||||||
mKeyguardSecurityContainer.initMode(KeyguardSecurityContainer.MODE_USER_SWITCHER,
|
mKeyguardSecurityContainer.initMode(KeyguardSecurityContainer.MODE_USER_SWITCHER,
|
||||||
mGlobalSettings, mFalsingManager, mUserSwitcherController);
|
mGlobalSettings, mFalsingManager, mUserSwitcherController);
|
||||||
// reset mSecurityViewFlipper so setup doesn't influence test verifications
|
|
||||||
reset(mSecurityViewFlipper);
|
|
||||||
when(mSecurityViewFlipper.getLayoutParams()).thenReturn(mSecurityViewFlipperLayoutParams);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ArrayList<UserRecord> buildUserRecords(int count) {
|
private ArrayList<UserRecord> buildUserRecords(int count) {
|
||||||
@@ -415,4 +391,17 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase {
|
|||||||
}
|
}
|
||||||
return users;
|
return users;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setupForUpdateKeyguardPosition(boolean oneHandedMode) {
|
||||||
|
int mode = oneHandedMode ? MODE_ONE_HANDED : MODE_DEFAULT;
|
||||||
|
mKeyguardSecurityContainer.initMode(mode, mGlobalSettings, mFalsingManager,
|
||||||
|
mUserSwitcherController);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get the ConstraintLayout constraint of the view. */
|
||||||
|
private ConstraintSet.Constraint getViewConstraint(int viewId) {
|
||||||
|
ConstraintSet constraintSet = new ConstraintSet();
|
||||||
|
constraintSet.clone(mKeyguardSecurityContainer);
|
||||||
|
return constraintSet.getConstraint(viewId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user