blob: 4557b3418e19f8c771397b85551743064868a987 [file] [log] [blame]
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.keyguard;
import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.ColorId.PIN_SHAPES;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Rect;
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.Drawable;
import android.transition.Transition;
import android.transition.TransitionManager;
import android.transition.TransitionValues;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import androidx.core.graphics.drawable.DrawableCompat;
import com.android.app.animation.Interpolators;
import com.android.settingslib.Utils;
import com.android.systemui.R;
/**
* This class contains implementation for methods that will be used when user has set a
* non six digit pin on their device
*/
public class PinShapeNonHintingView extends LinearLayout implements PinShapeInput {
private int mColor = Utils.getColorAttr(getContext(), PIN_SHAPES).getDefaultColor();
private int mPosition = 0;
private final PinShapeAdapter mPinShapeAdapter;
private ValueAnimator mValueAnimator = ValueAnimator.ofFloat(1f, 0f);
public PinShapeNonHintingView(Context context, AttributeSet attrs) {
super(context, attrs);
mPinShapeAdapter = new PinShapeAdapter(context);
}
@Override
public void append() {
int size = getResources().getDimensionPixelSize(R.dimen.password_shape_size);
ImageView pinDot = new ImageView(getContext());
pinDot.setLayoutParams(new LayoutParams(size, size));
pinDot.setImageResource(mPinShapeAdapter.getShape(mPosition));
if (pinDot.getDrawable() != null) {
Drawable wrappedDrawable = DrawableCompat.wrap(pinDot.getDrawable());
DrawableCompat.setTint(wrappedDrawable, mColor);
}
if (pinDot.getDrawable() instanceof AnimatedVectorDrawable) {
((AnimatedVectorDrawable) pinDot.getDrawable()).start();
}
TransitionManager.beginDelayedTransition(this, new PinShapeViewTransition());
addView(pinDot);
mPosition++;
}
@Override
public void delete() {
if (mPosition == 0) {
Log.e(getClass().getName(), "Trying to delete a non-existent char");
return;
}
if (mValueAnimator.isRunning()) {
mValueAnimator.end();
}
mPosition--;
ImageView pinDot = (ImageView) getChildAt(mPosition);
mValueAnimator.addUpdateListener(valueAnimator -> {
float value = (float) valueAnimator.getAnimatedValue();
pinDot.setScaleX(value);
pinDot.setScaleY(value);
});
mValueAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
TransitionManager.beginDelayedTransition(
PinShapeNonHintingView.this,
new PinShapeViewTransition());
removeView(pinDot);
}
});
mValueAnimator.setDuration(PasswordTextView.DISAPPEAR_DURATION);
mValueAnimator.start();
}
@Override
public void setDrawColor(int color) {
this.mColor = color;
}
@Override
public void reset() {
final int position = mPosition;
for (int i = 0; i < position; i++) {
delete();
}
}
@Override
public View getView() {
return this;
}
class PinShapeViewTransition extends Transition {
private static final String PROP_BOUNDS = "PinShapeViewTransition:bounds";
@Override
public void captureEndValues(TransitionValues transitionValues) {
if (transitionValues != null) {
captureValues(transitionValues);
}
}
@Override
public void captureStartValues(TransitionValues transitionValues) {
if (transitionValues != null) {
captureValues(transitionValues);
}
}
private void captureValues(TransitionValues values) {
Rect boundsRect = new Rect();
boundsRect.left = values.view.getLeft();
boundsRect.top = values.view.getTop();
boundsRect.right = values.view.getRight();
boundsRect.bottom = values.view.getBottom();
values.values.put(PROP_BOUNDS, boundsRect);
}
@Override
public String[] getTransitionProperties() {
return new String[] { PROP_BOUNDS };
}
@Override
public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
TransitionValues endValues) {
if (sceneRoot == null || startValues == null || endValues == null) {
return null;
}
Rect startRect = (Rect) startValues.values.get(PROP_BOUNDS);
Rect endRect = (Rect) endValues.values.get(PROP_BOUNDS);
View v = startValues.view;
ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
animator.setDuration(PasswordTextView.APPEAR_DURATION);
animator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
animator.addUpdateListener(valueAnimator -> {
float value = (float) valueAnimator.getAnimatedValue();
int diff = startRect.left - endRect.left;
int currentTranslation = (int) ((diff) * value);
v.setLeftTopRightBottom(
startRect.left - currentTranslation,
startRect.top,
startRect.right - currentTranslation,
startRect.bottom
);
});
animator.start();
return animator;
}
}
}