Merge "[Bouncer] Make bouncer view a ConstraintLayout" into tm-qpr-dev
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml
index 5486adb..6ec65ce 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml
@@ -24,7 +24,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
androidprv:layout_maxWidth="@dimen/keyguard_security_width"
- androidprv:layout_maxHeight="@dimen/keyguard_security_height"
android:layout_gravity="center_horizontal|bottom"
android:gravity="bottom"
>
diff --git a/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java b/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java
index 00f1c01..207f344 100644
--- a/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java
+++ b/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java
@@ -15,6 +15,12 @@
*/
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.app.admin.IKeyguardCallback;
import android.app.admin.IKeyguardClient;
@@ -30,7 +36,10 @@
import android.view.SurfaceControlViewHost;
import android.view.SurfaceHolder;
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.keyguard.KeyguardSecurityModel.SecurityMode;
@@ -49,7 +58,7 @@
private static final int REMOTE_CONTENT_READY_TIMEOUT_MILLIS = 500;
private final KeyguardUpdateMonitor mUpdateMonitor;
private final Context mContext;
- private final ViewGroup mParent;
+ private final ConstraintLayout mParent;
private AdminSecurityView mView;
private Handler mHandler;
private IKeyguardClient mClient;
@@ -156,6 +165,7 @@
mUpdateMonitor = updateMonitor;
mKeyguardCallback = callback;
mView = new AdminSecurityView(mContext, mSurfaceHolderCallback);
+ mView.setId(View.generateViewId());
}
/**
@@ -167,6 +177,15 @@
}
if (!mView.isAttachedToWindow()) {
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);
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 353c369..c34db15 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -21,15 +21,23 @@
import static android.view.WindowInsets.Type.systemBars;
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 java.lang.Integer.max;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.admin.DevicePolicyManager;
@@ -44,12 +52,12 @@
import android.graphics.drawable.LayerDrawable;
import android.os.UserManager;
import android.provider.Settings;
+import android.transition.TransitionManager;
import android.util.AttributeSet;
import android.util.Log;
import android.util.MathUtils;
import android.util.TypedValue;
import android.view.GestureDetector;
-import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.VelocityTracker;
@@ -59,8 +67,6 @@
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.AdapterView;
import android.widget.FrameLayout;
import android.widget.ImageView;
@@ -68,8 +74,9 @@
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
+import androidx.constraintlayout.widget.ConstraintLayout;
+import androidx.constraintlayout.widget.ConstraintSet;
import androidx.dynamicanimation.animation.DynamicAnimation;
import androidx.dynamicanimation.animation.SpringAnimation;
@@ -92,9 +99,9 @@
import java.util.ArrayList;
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_WORK_PROFILE = 2;
static final int USER_TYPE_SECONDARY_USER = 3;
@@ -125,15 +132,6 @@
// How much to scale the default slop by, to avoid accidental drags.
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
KeyguardSecurityViewFlipper mSecurityViewFlipper;
private GlobalSettings mGlobalSettings;
@@ -649,47 +647,8 @@
}
@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
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
-
int width = right - left;
if (changed && mWidth != width) {
mWidth = width;
@@ -761,7 +720,7 @@
* Enscapsulates the differences between bouncer modes for the container.
*/
interface ViewMode {
- default void init(@NonNull ViewGroup v, @NonNull GlobalSettings globalSettings,
+ default void init(@NonNull ConstraintLayout v, @NonNull GlobalSettings globalSettings,
@NonNull KeyguardSecurityViewFlipper viewFlipper,
@NonNull FalsingManager falsingManager,
@NonNull UserSwitcherController userSwitcherController) {};
@@ -787,11 +746,6 @@
/** On notif tap, this animation will run */
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 */
default void onDestroy() {};
}
@@ -801,13 +755,12 @@
* screen devices
*/
abstract static class SidedSecurityMode implements ViewMode {
- @Nullable private ValueAnimator mRunningSecurityShiftAnimator;
private KeyguardSecurityViewFlipper mViewFlipper;
- private ViewGroup mView;
+ private ConstraintLayout mView;
private GlobalSettings mGlobalSettings;
private int mDefaultSideSetting;
- public void init(ViewGroup v, KeyguardSecurityViewFlipper viewFlipper,
+ public void init(ConstraintLayout v, KeyguardSecurityViewFlipper viewFlipper,
GlobalSettings globalSettings, boolean leftAlignedByDefault) {
mView = v;
mViewFlipper = viewFlipper;
@@ -850,127 +803,6 @@
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() {
return mGlobalSettings.getInt(Settings.Global.ONE_HANDED_KEYGUARD_SIDE,
mDefaultSideSetting)
@@ -989,11 +821,11 @@
* Default bouncer is centered within the space
*/
static class DefaultViewMode implements ViewMode {
- private ViewGroup mView;
+ private ConstraintLayout mView;
private KeyguardSecurityViewFlipper mViewFlipper;
@Override
- public void init(@NonNull ViewGroup v, @NonNull GlobalSettings globalSettings,
+ public void init(@NonNull ConstraintLayout v, @NonNull GlobalSettings globalSettings,
@NonNull KeyguardSecurityViewFlipper viewFlipper,
@NonNull FalsingManager falsingManager,
@NonNull UserSwitcherController userSwitcherController) {
@@ -1005,11 +837,14 @@
}
private void updateSecurityViewGroup() {
- FrameLayout.LayoutParams lp =
- (FrameLayout.LayoutParams) mViewFlipper.getLayoutParams();
- lp.gravity = Gravity.CENTER_HORIZONTAL;
- mViewFlipper.setLayoutParams(lp);
- mViewFlipper.setTranslationX(0);
+ ConstraintSet constraintSet = new ConstraintSet();
+ constraintSet.connect(mViewFlipper.getId(), START, PARENT_ID, START);
+ constraintSet.connect(mViewFlipper.getId(), END, PARENT_ID, END);
+ constraintSet.connect(mViewFlipper.getId(), BOTTOM, PARENT_ID, BOTTOM);
+ 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 @@
* a user switcher, in both portrait and landscape modes.
*/
static class UserSwitcherViewMode extends SidedSecurityMode {
- private ViewGroup mView;
+ private ConstraintLayout mView;
private ViewGroup mUserSwitcherViewGroup;
private KeyguardSecurityViewFlipper mViewFlipper;
private TextView mUserSwitcher;
@@ -1029,11 +864,8 @@
private UserSwitcherController.UserSwitchCallback mUserSwitchCallback =
this::setupUserSwitcher;
- private float mAnimationLastAlpha = 1f;
- private boolean mAnimationWaitsToShift = true;
-
@Override
- public void init(@NonNull ViewGroup v, @NonNull GlobalSettings globalSettings,
+ public void init(@NonNull ConstraintLayout v, @NonNull GlobalSettings globalSettings,
@NonNull KeyguardSecurityViewFlipper viewFlipper,
@NonNull FalsingManager falsingManager,
@NonNull UserSwitcherController userSwitcherController) {
@@ -1240,88 +1072,55 @@
});
}
- /**
- * 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
public void updateSecurityViewLocation() {
updateSecurityViewLocation(isLeftAligned(), /* animate= */false);
}
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) {
- mAnimationWaitsToShift = true;
- mAnimationLastAlpha = 1f;
- 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);
- }
+ if (animate) {
+ TransitionManager.beginDelayedTransition(mView,
+ new KeyguardSecurityViewTransition());
}
-
- }
-
- 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);
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 {
- // Attempt to reposition a bit higher to make up for this frame being a bit lower
- // on the device
- mUserSwitcherViewGroup.setTranslationY(-yTrans);
- mViewFlipper.setTranslationY(0);
- }
- }
+ int leftElement = leftAlign ? mViewFlipper.getId() : mUserSwitcherViewGroup.getId();
+ int rightElement =
+ leftAlign ? mUserSwitcherViewGroup.getId() : mViewFlipper.getId();
- private void updateViewGravity(View v, int gravity) {
- FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) v.getLayoutParams();
- lp.gravity = gravity;
- v.setLayoutParams(lp);
+ ConstraintSet constraintSet = new ConstraintSet();
+ constraintSet.connect(leftElement, LEFT, PARENT_ID, LEFT);
+ constraintSet.connect(leftElement, RIGHT, rightElement, LEFT);
+ 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 @@
* between alternate sides of the display.
*/
static class OneHandedViewMode extends SidedSecurityMode {
- private ViewGroup mView;
+ private ConstraintLayout mView;
private KeyguardSecurityViewFlipper mViewFlipper;
@Override
- public void init(@NonNull ViewGroup v, @NonNull GlobalSettings globalSettings,
+ public void init(@NonNull ConstraintLayout v, @NonNull GlobalSettings globalSettings,
@NonNull KeyguardSecurityViewFlipper viewFlipper,
@NonNull FalsingManager falsingManager,
@NonNull UserSwitcherController userSwitcherController) {
@@ -1342,28 +1141,10 @@
mView = v;
mViewFlipper = viewFlipper;
- updateSecurityViewGravity();
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
* appears on the same side as a touch.
*/
@@ -1380,7 +1161,20 @@
}
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);
}
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewTransition.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewTransition.kt
new file mode 100644
index 0000000..9eb2c11
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewTransition.kt
@@ -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
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java
index 80385e6..f5cd0ca 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java
@@ -41,6 +41,7 @@
import android.testing.ViewUtils;
import android.view.SurfaceControlViewHost;
import android.view.SurfaceView;
+import android.view.View;
import androidx.test.filters.SmallTest;
@@ -84,6 +85,7 @@
MockitoAnnotations.initMocks(this);
mKeyguardSecurityContainer = spy(new KeyguardSecurityContainer(mContext));
+ mKeyguardSecurityContainer.setId(View.generateViewId());
ViewUtils.attachView(mKeyguardSecurityContainer);
mTestableLooper = TestableLooper.get(this);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
index c1036e3..52f8825 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
@@ -21,10 +21,14 @@
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_RIGHT;
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.WindowInsets.Type.ime;
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_ONE_HANDED;
@@ -32,9 +36,6 @@
import static org.mockito.ArgumentMatchers.any;
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.when;
@@ -43,19 +44,17 @@
import android.graphics.Insets;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
-import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets;
-import android.widget.FrameLayout;
+import androidx.constraintlayout.widget.ConstraintSet;
import androidx.test.filters.SmallTest;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.user.data.source.UserRecord;
import com.android.systemui.util.settings.GlobalSettings;
@@ -64,8 +63,6 @@
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
@@ -78,14 +75,11 @@
public class KeyguardSecurityContainerTest extends SysuiTestCase {
private static final int VIEW_WIDTH = 1600;
-
- private int mScreenWidth;
- private int mFakeMeasureSpec;
+ private static final int VIEW_HEIGHT = 900;
@Rule
public MockitoRule mRule = MockitoJUnit.rule();
- @Mock
private KeyguardSecurityViewFlipper mSecurityViewFlipper;
@Mock
private GlobalSettings mGlobalSettings;
@@ -93,59 +87,32 @@
private FalsingManager mFalsingManager;
@Mock
private UserSwitcherController mUserSwitcherController;
- @Mock
- private KeyguardStateController mKeyguardStateController;
- @Captor
- private ArgumentCaptor<FrameLayout.LayoutParams> mLayoutCaptor;
private KeyguardSecurityContainer mKeyguardSecurityContainer;
- private FrameLayout.LayoutParams mSecurityViewFlipperLayoutParams;
@Before
public void setup() {
// Needed here, otherwise when mKeyguardSecurityContainer is created below, it'll cache
// the real references (rather than the TestableResources that this call creates).
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.setRight(VIEW_WIDTH);
+ mKeyguardSecurityContainer.setLeft(0);
+ mKeyguardSecurityContainer.setTop(0);
+ mKeyguardSecurityContainer.setBottom(VIEW_HEIGHT);
+ mKeyguardSecurityContainer.setId(View.generateViewId());
mKeyguardSecurityContainer.mSecurityViewFlipper = mSecurityViewFlipper;
mKeyguardSecurityContainer.addView(mSecurityViewFlipper, new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
when(mUserSwitcherController.getCurrentUserName()).thenReturn("Test User");
when(mUserSwitcherController.isKeyguardShowing()).thenReturn(true);
-
- mScreenWidth = getUiDevice().getDisplayWidth();
- mFakeMeasureSpec = View
- .MeasureSpec.makeMeasureSpec(mScreenWidth, View.MeasureSpec.EXACTLY);
}
-
@Test
- public void onMeasure_usesHalfWidthWithOneHandedModeEnabled() {
- 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() {
+ public void testOnApplyWindowInsets() {
int paddingBottom = getContext().getResources()
.getDimensionPixelSize(R.dimen.keyguard_security_view_bottom_margin);
int imeInsetAmount = paddingBottom + 1;
@@ -162,17 +129,12 @@
.setInsetsIgnoringVisibility(systemBars(), systemBarInset)
.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.measure(mFakeMeasureSpec, mFakeMeasureSpec);
- verify(mSecurityViewFlipper).measure(mFakeMeasureSpec, expectedHeightMeasureSpec);
+ assertThat(mKeyguardSecurityContainer.getPaddingBottom()).isEqualTo(imeInsetAmount);
}
@Test
- public void onMeasure_respectsViewInsets_largerSystembar() {
+ public void testOnApplyWindowInsets_largerSystembar() {
int imeInsetAmount = 0;
int paddingBottom = getContext().getResources()
.getDimensionPixelSize(R.dimen.keyguard_security_view_bottom_margin);
@@ -189,25 +151,22 @@
.setInsetsIgnoringVisibility(systemBars(), systemBarInset)
.build();
- int expectedHeightMeasureSpec = View.MeasureSpec.makeMeasureSpec(
- mScreenWidth - systemBarInsetAmount, View.MeasureSpec.EXACTLY);
-
mKeyguardSecurityContainer.onApplyWindowInsets(insets);
- mKeyguardSecurityContainer.measure(mFakeMeasureSpec, mFakeMeasureSpec);
- verify(mSecurityViewFlipper).measure(mFakeMeasureSpec, expectedHeightMeasureSpec);
+ assertThat(mKeyguardSecurityContainer.getPaddingBottom()).isEqualTo(systemBarInsetAmount);
}
- private void setupForUpdateKeyguardPosition(boolean oneHandedMode) {
- int mode = oneHandedMode ? MODE_ONE_HANDED : MODE_DEFAULT;
- mKeyguardSecurityContainer.initMode(mode, mGlobalSettings, mFalsingManager,
+ @Test
+ public void testDefaultViewMode() {
+ mKeyguardSecurityContainer.initMode(MODE_ONE_HANDED, mGlobalSettings, mFalsingManager,
mUserSwitcherController);
-
- mKeyguardSecurityContainer.measure(mFakeMeasureSpec, mFakeMeasureSpec);
- mKeyguardSecurityContainer.layout(0, 0, mScreenWidth, mScreenWidth);
-
- // Clear any interactions with the mock so we know the interactions definitely come from the
- // below testing.
- reset(mSecurityViewFlipper);
+ mKeyguardSecurityContainer.initMode(MODE_DEFAULT, mGlobalSettings, mFalsingManager,
+ mUserSwitcherController);
+ ConstraintSet.Constraint viewFlipperConstraint =
+ getViewConstraint(mSecurityViewFlipper.getId());
+ assertThat(viewFlipperConstraint.layout.topToTop).isEqualTo(PARENT_ID);
+ assertThat(viewFlipperConstraint.layout.startToStart).isEqualTo(PARENT_ID);
+ assertThat(viewFlipperConstraint.layout.endToEnd).isEqualTo(PARENT_ID);
+ assertThat(viewFlipperConstraint.layout.bottomToBottom).isEqualTo(PARENT_ID);
}
@Test
@@ -217,13 +176,22 @@
mKeyguardSecurityContainer.getWidth() - 1f);
verify(mGlobalSettings).putInt(ONE_HANDED_KEYGUARD_SIDE, ONE_HANDED_KEYGUARD_SIDE_RIGHT);
- assertSecurityTranslationX(
- mKeyguardSecurityContainer.getWidth() - mSecurityViewFlipper.getWidth());
+ ConstraintSet.Constraint viewFlipperConstraint =
+ 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);
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
@@ -232,10 +200,16 @@
mKeyguardSecurityContainer.updatePositionByTouchX(
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);
- verify(mSecurityViewFlipper, never()).setTranslationX(anyInt());
+ viewFlipperConstraint =
+ getViewConstraint(mSecurityViewFlipper.getId());
+ assertThat(viewFlipperConstraint.layout.rightToRight).isEqualTo(-1);
+ assertThat(viewFlipperConstraint.layout.leftToLeft).isEqualTo(-1);
}
@Test
@@ -249,17 +223,31 @@
setupUserSwitcher();
mKeyguardSecurityContainer.onConfigurationChanged(landscapeConfig);
- // THEN views are oriented side by side
- assertSecurityGravity(Gravity.LEFT | Gravity.BOTTOM);
- assertUserSwitcherGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
- assertSecurityTranslationX(
- mKeyguardSecurityContainer.getWidth() - mSecurityViewFlipper.getWidth());
- assertUserSwitcherTranslationX(0f);
-
+ ConstraintSet.Constraint viewFlipperConstraint =
+ getViewConstraint(mSecurityViewFlipper.getId());
+ ConstraintSet.Constraint userSwitcherConstraint =
+ getViewConstraint(R.id.keyguard_bouncer_user_switcher);
+ assertThat(viewFlipperConstraint.layout.rightToRight).isEqualTo(PARENT_ID);
+ 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
- public void testUserSwitcherModeViewGravityPortrait() {
+ public void testUserSwitcherModeViewPositionPortrait() {
// GIVEN one user has been setup and in landscape
when(mUserSwitcherController.getUsers()).thenReturn(buildUserRecords(1));
Configuration portraitConfig = configuration(ORIENTATION_PORTRAIT);
@@ -267,15 +255,28 @@
// WHEN UserSwitcherViewMode is initialized and config has changed
setupUserSwitcher();
- reset(mSecurityViewFlipper);
- when(mSecurityViewFlipper.getLayoutParams()).thenReturn(mSecurityViewFlipperLayoutParams);
mKeyguardSecurityContainer.onConfigurationChanged(portraitConfig);
- // THEN views are both centered horizontally
- assertSecurityGravity(Gravity.CENTER_HORIZONTAL);
- assertUserSwitcherGravity(Gravity.CENTER_HORIZONTAL);
- assertSecurityTranslationX(0);
- assertUserSwitcherTranslationX(0);
+ ConstraintSet.Constraint viewFlipperConstraint =
+ getViewConstraint(mSecurityViewFlipper.getId());
+ ConstraintSet.Constraint userSwitcherConstraint =
+ getViewConstraint(R.id.keyguard_bouncer_user_switcher);
+
+ 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
@@ -337,9 +338,9 @@
when(mGlobalSettings.getInt(any(), anyInt())).thenReturn(ONE_HANDED_KEYGUARD_SIDE_LEFT);
mKeyguardSecurityContainer.onConfigurationChanged(new Configuration());
- assertSecurityTranslationX(0);
- assertUserSwitcherTranslationX(
- mKeyguardSecurityContainer.getWidth() - mSecurityViewFlipper.getWidth());
+ ConstraintSet.Constraint viewFlipperConstraint = getViewConstraint(
+ mSecurityViewFlipper.getId());
+ assertThat(viewFlipperConstraint.layout.leftToLeft).isEqualTo(PARENT_ID);
}
private Configuration configuration(@Configuration.Orientation int orientation) {
@@ -348,28 +349,6 @@
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) {
mKeyguardSecurityContainer.setRight(width);
mKeyguardSecurityContainer.setLeft(0);
@@ -399,9 +378,6 @@
when(mGlobalSettings.getInt(any(), anyInt())).thenReturn(ONE_HANDED_KEYGUARD_SIDE_RIGHT);
mKeyguardSecurityContainer.initMode(KeyguardSecurityContainer.MODE_USER_SWITCHER,
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) {
@@ -415,4 +391,17 @@
}
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);
+ }
}