Use a shared password text view for PIN lock
This new library will be shared with external.
Bug: 270108982
Test: Manual test by building and flashing on local
Test: Tested both hinting and non-hinting pin view. Tested append, delete, full delete, reset, lockout and talkback
Change-Id: I0ddc7c46848c5430d08d2b39ffa0a524e695ebc0
diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp
index ca30e15..a6517c1 100644
--- a/packages/SystemUI/shared/Android.bp
+++ b/packages/SystemUI/shared/Android.bp
@@ -50,6 +50,7 @@
"SystemUIAnimationLib",
"SystemUIPluginLib",
"SystemUIUnfoldLib",
+ "SystemUISharedLib-Keyguard",
"androidx.dynamicanimation_dynamicanimation",
"androidx.concurrent_concurrent-futures",
"androidx.lifecycle_lifecycle-runtime-ktx",
diff --git a/packages/SystemUI/shared/keyguard/Android.bp b/packages/SystemUI/shared/keyguard/Android.bp
new file mode 100644
index 0000000..2181439
--- /dev/null
+++ b/packages/SystemUI/shared/keyguard/Android.bp
@@ -0,0 +1,16 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_packages_SystemUI_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+}
+
+android_library {
+ name: "SystemUISharedLib-Keyguard",
+ srcs: [
+ "src/**/*.java",
+ ],
+ min_sdk_version: "current",
+}
diff --git a/packages/SystemUI/shared/keyguard/AndroidManifest.xml b/packages/SystemUI/shared/keyguard/AndroidManifest.xml
new file mode 100644
index 0000000..49bee08
--- /dev/null
+++ b/packages/SystemUI/shared/keyguard/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.systemui.shared.keyguard">
+</manifest>
\ No newline at end of file
diff --git a/packages/SystemUI/shared/keyguard/src/com/android/keyguard/BasePasswordTextView.java b/packages/SystemUI/shared/keyguard/src/com/android/keyguard/BasePasswordTextView.java
new file mode 100644
index 0000000..fe12134
--- /dev/null
+++ b/packages/SystemUI/shared/keyguard/src/com/android/keyguard/BasePasswordTextView.java
@@ -0,0 +1,239 @@
+/*
+ * 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 android.annotation.CallSuper;
+import android.content.Context;
+import android.text.InputType;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.EditText;
+import android.widget.FrameLayout;
+
+/**
+ * A View similar to a textView which contains password text and can animate when the text is
+ * changed
+ */
+public abstract class BasePasswordTextView extends FrameLayout {
+ private String mText = "";
+ private UserActivityListener mUserActivityListener;
+ protected boolean mIsPinHinting;
+ protected PinShapeInput mPinShapeInput;
+ protected boolean mShowPassword = true;
+ protected boolean mUsePinShapes = false;
+ protected static final char DOT = '\u2022';
+
+ /** Listens to user activities like appending, deleting and resetting PIN text */
+ public interface UserActivityListener {
+
+ /** Listens to user activities. */
+ void onUserActivity();
+ }
+
+ public BasePasswordTextView(Context context) {
+ this(context, null);
+ }
+
+ public BasePasswordTextView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public BasePasswordTextView(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public BasePasswordTextView(
+ Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ protected abstract PinShapeInput inflatePinShapeInput(boolean isPinHinting);
+
+ protected abstract boolean shouldSendAccessibilityEvent();
+
+ protected void onAppend(char c, int newLength) {}
+
+ protected void onDelete(int index) {}
+
+ protected void onReset(boolean animated) {}
+
+ @CallSuper
+ protected void onUserActivity() {
+ if (mUserActivityListener != null) {
+ mUserActivityListener.onUserActivity();
+ }
+ }
+
+ @Override
+ public boolean hasOverlappingRendering() {
+ return false;
+ }
+
+ /** Appends a PIN text */
+ public void append(char c) {
+ CharSequence textbefore = getTransformedText();
+
+ mText = mText + c;
+ int newLength = mText.length();
+ onAppend(c, newLength);
+
+ if (mPinShapeInput != null) {
+ mPinShapeInput.append();
+ }
+
+ onUserActivity();
+
+ sendAccessibilityEventTypeViewTextChanged(textbefore, textbefore.length(), 0, 1);
+ }
+
+ /** Sets a listener who is notified on user activity */
+ public void setUserActivityListener(UserActivityListener userActivityListener) {
+ mUserActivityListener = userActivityListener;
+ }
+
+ /** Deletes the last PIN text */
+ public void deleteLastChar() {
+ int length = mText.length();
+ if (length > 0) {
+ CharSequence textbefore = getTransformedText();
+
+ mText = mText.substring(0, length - 1);
+ onDelete(length - 1);
+
+ if (mPinShapeInput != null) {
+ mPinShapeInput.delete();
+ }
+
+ sendAccessibilityEventTypeViewTextChanged(textbefore, textbefore.length() - 1, 1, 0);
+ }
+ onUserActivity();
+ }
+
+ /** Gets entered PIN text */
+ public String getText() {
+ return mText;
+ }
+
+ /** Gets a transformed text for accessibility event. Called before text changed. */
+ protected CharSequence getTransformedText() {
+ return String.valueOf(DOT).repeat(mText.length());
+ }
+
+ /** Gets a transformed text for accessibility event. Called after text changed. */
+ protected CharSequence getTransformedText(int fromIndex, int removedCount, int addedCount) {
+ return getTransformedText();
+ }
+
+ /** Reset PIN text without error */
+ public void reset(boolean animated, boolean announce) {
+ reset(false /* error */, animated, announce);
+ }
+
+ /** Reset PIN text */
+ public void reset(boolean error, boolean animated, boolean announce) {
+ CharSequence textbefore = getTransformedText();
+
+ mText = "";
+
+ onReset(animated);
+ if (animated) {
+ onUserActivity();
+ }
+
+ if (mPinShapeInput != null) {
+ if (error) {
+ mPinShapeInput.resetWithError();
+ } else {
+ mPinShapeInput.reset();
+ }
+ }
+
+ if (announce) {
+ sendAccessibilityEventTypeViewTextChanged(textbefore, 0, textbefore.length(), 0);
+ }
+ }
+
+ void sendAccessibilityEventTypeViewTextChanged(
+ CharSequence beforeText, int fromIndex, int removedCount, int addedCount) {
+ if (AccessibilityManager.getInstance(mContext).isEnabled()
+ && shouldSendAccessibilityEvent()) {
+ AccessibilityEvent event =
+ AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);
+ event.setFromIndex(fromIndex);
+ event.setRemovedCount(removedCount);
+ event.setAddedCount(addedCount);
+ event.setBeforeText(beforeText);
+ CharSequence transformedText = getTransformedText(fromIndex, removedCount, addedCount);
+ if (!TextUtils.isEmpty(transformedText)) {
+ event.getText().add(transformedText);
+ }
+ event.setPassword(true);
+ sendAccessibilityEventUnchecked(event);
+ }
+ }
+
+ /** Sets whether to use pin shapes. */
+ public void setUsePinShapes(boolean usePinShapes) {
+ mUsePinShapes = usePinShapes;
+ }
+
+ /** Determines whether AutoConfirmation feature is on. */
+ public void setIsPinHinting(boolean isPinHinting) {
+ // Do not reinflate the view if we are using the same one.
+ if (mPinShapeInput != null && mIsPinHinting == isPinHinting) {
+ return;
+ }
+ mIsPinHinting = isPinHinting;
+
+ if (mPinShapeInput != null) {
+ removeView(mPinShapeInput.getView());
+ mPinShapeInput = null;
+ }
+
+ mPinShapeInput = inflatePinShapeInput(isPinHinting);
+ addView(mPinShapeInput.getView());
+ }
+
+ /** Controls whether the last entered digit is briefly shown after being entered */
+ public void setShowPassword(boolean enabled) {
+ mShowPassword = enabled;
+ }
+
+ @Override
+ public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
+ super.onInitializeAccessibilityEvent(event);
+
+ event.setClassName(EditText.class.getName());
+ event.setPassword(true);
+ }
+
+ @Override
+ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(info);
+
+ info.setClassName(EditText.class.getName());
+ info.setPassword(true);
+ info.setText(getTransformedText());
+
+ info.setEditable(true);
+
+ info.setInputType(InputType.TYPE_NUMBER_VARIATION_PASSWORD);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/PinShapeInput.java b/packages/SystemUI/shared/keyguard/src/com/android/keyguard/PinShapeInput.java
similarity index 85%
rename from packages/SystemUI/src/com/android/keyguard/PinShapeInput.java
rename to packages/SystemUI/shared/keyguard/src/com/android/keyguard/PinShapeInput.java
index 52ae6ba..d2b4066 100644
--- a/packages/SystemUI/src/com/android/keyguard/PinShapeInput.java
+++ b/packages/SystemUI/shared/keyguard/src/com/android/keyguard/PinShapeInput.java
@@ -44,6 +44,14 @@
void reset();
/**
+ * This is the method that is triggered for resetting the view with error If it doesn't have to
+ * show something regarding error, just reset
+ */
+ default void resetWithError() {
+ reset();
+ }
+
+ /**
* This is the method that is triggered for getting the view
*/
View getView();
diff --git a/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java b/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java
index 8e8ee48..9a2ffe0 100644
--- a/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java
+++ b/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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.
@@ -11,7 +11,7 @@
* 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
+ * limitations under the License.
*/
package com.android.keyguard;
@@ -30,18 +30,11 @@
import android.graphics.Typeface;
import android.os.PowerManager;
import android.os.SystemClock;
-import android.text.InputType;
-import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.LayoutInflater;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
-import android.widget.EditText;
-import android.widget.FrameLayout;
import com.android.settingslib.Utils;
import com.android.systemui.R;
@@ -52,12 +45,11 @@
* A View similar to a textView which contains password text and can animate when the text is
* changed
*/
-public class PasswordTextView extends FrameLayout {
-
- private static final float DOT_OVERSHOOT_FACTOR = 1.5f;
- private static final long DOT_APPEAR_DURATION_OVERSHOOT = 320;
+public class PasswordTextView extends BasePasswordTextView {
public static final long APPEAR_DURATION = 160;
public static final long DISAPPEAR_DURATION = 160;
+ private static final float DOT_OVERSHOOT_FACTOR = 1.5f;
+ private static final long DOT_APPEAR_DURATION_OVERSHOOT = 320;
private static final long RESET_DELAY_PER_ELEMENT = 40;
private static final long RESET_MAX_DELAY = 200;
@@ -82,15 +74,12 @@
*/
private static final float OVERSHOOT_TIME_POSITION = 0.5f;
- private static char DOT = '\u2022';
-
/**
* The raw text size, will be multiplied by the scaled density when drawn
*/
private int mTextHeightRaw;
private final int mGravity;
private ArrayList<CharState> mTextChars = new ArrayList<>();
- private String mText = "";
private int mDotSize;
private PowerManager mPM;
private int mCharPadding;
@@ -99,15 +88,6 @@
private Interpolator mAppearInterpolator;
private Interpolator mDisappearInterpolator;
private Interpolator mFastOutSlowInInterpolator;
- private boolean mShowPassword = true;
- private UserActivityListener mUserActivityListener;
- private boolean mIsPinHinting;
- private PinShapeInput mPinShapeInput;
- private boolean mUsePinShapes = false;
-
- public interface UserActivityListener {
- void onUserActivity();
- }
public PasswordTextView(Context context) {
this(context, null);
@@ -145,8 +125,7 @@
mCharPadding = a.getDimensionPixelSize(R.styleable.PasswordTextView_charPadding,
getContext().getResources().getDimensionPixelSize(
R.dimen.password_char_padding));
- mDrawColor = a.getColor(R.styleable.PasswordTextView_android_textColor,
- Color.WHITE);
+ mDrawColor = a.getColor(R.styleable.PasswordTextView_android_textColor, Color.WHITE);
mDrawPaint.setColor(mDrawColor);
} finally {
@@ -156,8 +135,7 @@
mDrawPaint.setFlags(Paint.SUBPIXEL_TEXT_FLAG | Paint.ANTI_ALIAS_FLAG);
mDrawPaint.setTextAlign(Paint.Align.CENTER);
mDrawPaint.setTypeface(Typeface.create(
- context.getString(com.android.internal.R.string.config_headlineFontFamily),
- 0));
+ context.getString(com.android.internal.R.string.config_headlineFontFamily), 0));
mAppearInterpolator = AnimationUtils.loadInterpolator(mContext,
android.R.interpolator.linear_out_slow_in);
mDisappearInterpolator = AnimationUtils.loadInterpolator(mContext,
@@ -169,9 +147,19 @@
}
@Override
- protected void onConfigurationChanged(Configuration newConfig) {
- mTextHeightRaw = getContext().getResources().getInteger(
- R.integer.scaled_password_text_size);
+ protected PinShapeInput inflatePinShapeInput(boolean isPinHinting) {
+ if (isPinHinting) {
+ return (PinShapeInput) LayoutInflater.from(mContext).inflate(
+ R.layout.keyguard_pin_shape_hinting_view, null);
+ } else {
+ return (PinShapeInput) LayoutInflater.from(mContext).inflate(
+ R.layout.keyguard_pin_shape_non_hinting_view, null);
+ }
+ }
+
+ @Override
+ protected boolean shouldSendAccessibilityEvent() {
+ return isFocused() || isSelected() && isShown();
}
@Override
@@ -201,8 +189,8 @@
int charHeight = (bounds.bottom - bounds.top);
float yPosition =
(getHeight() - getPaddingBottom() - getPaddingTop()) / 2 + getPaddingTop();
- canvas.clipRect(getPaddingLeft(), getPaddingTop(),
- getWidth() - getPaddingRight(), getHeight() - getPaddingBottom());
+ canvas.clipRect(getPaddingLeft(), getPaddingTop(), getWidth() - getPaddingRight(),
+ getHeight() - getPaddingBottom());
float charLength = bounds.right - bounds.left;
for (int i = 0; i < length; i++) {
CharState charState = mTextChars.get(i);
@@ -212,6 +200,67 @@
}
}
+ @Override
+ protected void onAppend(char c, int newLength) {
+ int visibleChars = mTextChars.size();
+ CharState charState;
+ if (newLength > visibleChars) {
+ charState = obtainCharState(c);
+ mTextChars.add(charState);
+ } else {
+ charState = mTextChars.get(newLength - 1);
+ charState.whichChar = c;
+ }
+ charState.startAppearAnimation();
+
+ // ensure that the previous element is being swapped
+ if (newLength > 1) {
+ CharState previousState = mTextChars.get(newLength - 2);
+ if (previousState.isDotSwapPending) {
+ previousState.swapToDotWhenAppearFinished();
+ }
+ }
+ }
+
+ @Override
+ protected void onDelete(int index) {
+ CharState charState = mTextChars.get(index);
+ charState.startRemoveAnimation(0, 0);
+ }
+
+ @Override
+ protected void onReset(boolean animated) {
+ if (animated) {
+ int length = mTextChars.size();
+ int middleIndex = (length - 1) / 2;
+ long delayPerElement = RESET_DELAY_PER_ELEMENT;
+ for (int i = 0; i < length; i++) {
+ CharState charState = mTextChars.get(i);
+ int delayIndex;
+ if (i <= middleIndex) {
+ delayIndex = i * 2;
+ } else {
+ int distToMiddle = i - middleIndex;
+ delayIndex = (length - 1) - (distToMiddle - 1) * 2;
+ }
+ long startDelay = delayIndex * delayPerElement;
+ startDelay = Math.min(startDelay, RESET_MAX_DELAY);
+ long maxDelay = delayPerElement * (length - 1);
+ maxDelay = Math.min(maxDelay, RESET_MAX_DELAY) + DISAPPEAR_DURATION;
+ charState.startRemoveAnimation(startDelay, maxDelay);
+ charState.removeDotSwapCallbacks();
+ }
+ } else {
+ mTextChars.clear();
+ }
+ }
+
+ @Override
+ protected void onUserActivity() {
+ mPM.userActivity(SystemClock.uptimeMillis(), false);
+ super.onUserActivity();
+ }
+
/**
* Reload colors from resources.
**/
@@ -225,8 +274,9 @@
}
@Override
- public boolean hasOverlappingRendering() {
- return false;
+ protected void onConfigurationChanged(Configuration newConfig) {
+ mTextHeightRaw = getContext().getResources().getInteger(
+ R.integer.scaled_password_text_size);
}
private Rect getCharBounds() {
@@ -252,67 +302,14 @@
return width;
}
-
- public void append(char c) {
- int visibleChars = mTextChars.size();
- CharSequence textbefore = getTransformedText();
- mText = mText + c;
- int newLength = mText.length();
- CharState charState;
- if (newLength > visibleChars) {
- charState = obtainCharState(c);
- mTextChars.add(charState);
- } else {
- charState = mTextChars.get(newLength - 1);
- charState.whichChar = c;
- }
- if (mPinShapeInput != null) {
- mPinShapeInput.append();
- }
- charState.startAppearAnimation();
-
- // ensure that the previous element is being swapped
- if (newLength > 1) {
- CharState previousState = mTextChars.get(newLength - 2);
- if (previousState.isDotSwapPending) {
- previousState.swapToDotWhenAppearFinished();
- }
- }
- userActivity();
- sendAccessibilityEventTypeViewTextChanged(textbefore, textbefore.length(), 0, 1);
+ private CharState obtainCharState(char c) {
+ CharState charState = new CharState();
+ charState.whichChar = c;
+ return charState;
}
- public void setUserActivityListener(UserActivityListener userActivityListener) {
- mUserActivityListener = userActivityListener;
- }
-
- private void userActivity() {
- mPM.userActivity(SystemClock.uptimeMillis(), false);
- if (mUserActivityListener != null) {
- mUserActivityListener.onUserActivity();
- }
- }
-
- public void deleteLastChar() {
- int length = mText.length();
- CharSequence textbefore = getTransformedText();
- if (length > 0) {
- mText = mText.substring(0, length - 1);
- CharState charState = mTextChars.get(length - 1);
- charState.startRemoveAnimation(0, 0);
- sendAccessibilityEventTypeViewTextChanged(textbefore, textbefore.length() - 1, 1, 0);
- if (mPinShapeInput != null) {
- mPinShapeInput.delete();
- }
- }
- userActivity();
- }
-
- public String getText() {
- return mText;
- }
-
- private CharSequence getTransformedText() {
+ @Override
+ protected CharSequence getTransformedText() {
int textLength = mTextChars.size();
StringBuilder stringBuilder = new StringBuilder(textLength);
for (int i = 0; i < textLength; i++) {
@@ -327,130 +324,6 @@
return stringBuilder;
}
- private CharState obtainCharState(char c) {
- CharState charState = new CharState();
- charState.whichChar = c;
- return charState;
- }
-
- public void reset(boolean animated, boolean announce) {
- CharSequence textbefore = getTransformedText();
- mText = "";
- int length = mTextChars.size();
- int middleIndex = (length - 1) / 2;
- long delayPerElement = RESET_DELAY_PER_ELEMENT;
- for (int i = 0; i < length; i++) {
- CharState charState = mTextChars.get(i);
- if (animated) {
- int delayIndex;
- if (i <= middleIndex) {
- delayIndex = i * 2;
- } else {
- int distToMiddle = i - middleIndex;
- delayIndex = (length - 1) - (distToMiddle - 1) * 2;
- }
- long startDelay = delayIndex * delayPerElement;
- startDelay = Math.min(startDelay, RESET_MAX_DELAY);
- long maxDelay = delayPerElement * (length - 1);
- maxDelay = Math.min(maxDelay, RESET_MAX_DELAY) + DISAPPEAR_DURATION;
- charState.startRemoveAnimation(startDelay, maxDelay);
- charState.removeDotSwapCallbacks();
- }
- }
- if (!animated) {
- mTextChars.clear();
- } else {
- userActivity();
- }
- if (mPinShapeInput != null) {
- mPinShapeInput.reset();
- }
- if (announce) {
- sendAccessibilityEventTypeViewTextChanged(textbefore, 0, textbefore.length(), 0);
- }
- }
-
- void sendAccessibilityEventTypeViewTextChanged(CharSequence beforeText, int fromIndex,
- int removedCount, int addedCount) {
- if (AccessibilityManager.getInstance(mContext).isEnabled() &&
- (isFocused() || isSelected() && isShown())) {
- AccessibilityEvent event =
- AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);
- event.setFromIndex(fromIndex);
- event.setRemovedCount(removedCount);
- event.setAddedCount(addedCount);
- event.setBeforeText(beforeText);
- CharSequence transformedText = getTransformedText();
- if (!TextUtils.isEmpty(transformedText)) {
- event.getText().add(transformedText);
- }
- event.setPassword(true);
- sendAccessibilityEventUnchecked(event);
- }
- }
-
- @Override
- public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
- super.onInitializeAccessibilityEvent(event);
-
- event.setClassName(EditText.class.getName());
- event.setPassword(true);
- }
-
- @Override
- public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
- super.onInitializeAccessibilityNodeInfo(info);
-
- info.setClassName(EditText.class.getName());
- info.setPassword(true);
- info.setText(getTransformedText());
-
- info.setEditable(true);
-
- info.setInputType(InputType.TYPE_NUMBER_VARIATION_PASSWORD);
- }
-
- /**
- * Sets whether to use pin shapes.
- */
- public void setUsePinShapes(boolean usePinShapes) {
- mUsePinShapes = usePinShapes;
- }
-
- /**
- * Determines whether AutoConfirmation feature is on.
- *
- * @param isPinHinting
- */
- public void setIsPinHinting(boolean isPinHinting) {
- // Do not reinflate the view if we are using the same one.
- if (mPinShapeInput != null && mIsPinHinting == isPinHinting) {
- return;
- }
- mIsPinHinting = isPinHinting;
-
- if (mPinShapeInput != null) {
- removeView(mPinShapeInput.getView());
- mPinShapeInput = null;
- }
-
- if (isPinHinting) {
- mPinShapeInput = (PinShapeInput) LayoutInflater.from(mContext).inflate(
- R.layout.keyguard_pin_shape_hinting_view, null);
- } else {
- mPinShapeInput = (PinShapeInput) LayoutInflater.from(mContext).inflate(
- R.layout.keyguard_pin_shape_non_hinting_view, null);
- }
- addView(mPinShapeInput.getView());
- }
-
- /**
- * Controls whether the last entered digit is briefly shown after being entered
- */
- public void setShowPassword(boolean enabled) {
- mShowPassword = enabled;
- }
-
private class CharState {
char whichChar;
ValueAnimator textAnimator;
@@ -468,6 +341,7 @@
Animator.AnimatorListener removeEndListener = new AnimatorListenerAdapter() {
private boolean mCancelled;
+
@Override
public void onAnimationCancel(Animator animation) {
mCancelled = true;
@@ -516,53 +390,53 @@
}
};
- private ValueAnimator.AnimatorUpdateListener dotSizeUpdater
- = new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- currentDotSizeFactor = (float) animation.getAnimatedValue();
- invalidate();
- }
- };
-
- private ValueAnimator.AnimatorUpdateListener textSizeUpdater
- = new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- boolean textVisibleBefore = isCharVisibleForA11y();
- float beforeTextSizeFactor = currentTextSizeFactor;
- currentTextSizeFactor = (float) animation.getAnimatedValue();
- if (textVisibleBefore != isCharVisibleForA11y()) {
- currentTextSizeFactor = beforeTextSizeFactor;
- CharSequence beforeText = getTransformedText();
- currentTextSizeFactor = (float) animation.getAnimatedValue();
- int indexOfThisChar = mTextChars.indexOf(CharState.this);
- if (indexOfThisChar >= 0) {
- sendAccessibilityEventTypeViewTextChanged(
- beforeText, indexOfThisChar, 1, 1);
+ private ValueAnimator.AnimatorUpdateListener mDotSizeUpdater =
+ new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ currentDotSizeFactor = (float) animation.getAnimatedValue();
+ invalidate();
}
- }
- invalidate();
- }
- };
+ };
- private ValueAnimator.AnimatorUpdateListener textTranslationUpdater
- = new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- currentTextTranslationY = (float) animation.getAnimatedValue();
- invalidate();
- }
- };
+ private ValueAnimator.AnimatorUpdateListener mTextSizeUpdater =
+ new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ boolean textVisibleBefore = isCharVisibleForA11y();
+ float beforeTextSizeFactor = currentTextSizeFactor;
+ currentTextSizeFactor = (float) animation.getAnimatedValue();
+ if (textVisibleBefore != isCharVisibleForA11y()) {
+ currentTextSizeFactor = beforeTextSizeFactor;
+ CharSequence beforeText = getTransformedText();
+ currentTextSizeFactor = (float) animation.getAnimatedValue();
+ int indexOfThisChar = mTextChars.indexOf(CharState.this);
+ if (indexOfThisChar >= 0) {
+ sendAccessibilityEventTypeViewTextChanged(beforeText,
+ indexOfThisChar, 1, 1);
+ }
+ }
+ invalidate();
+ }
+ };
- private ValueAnimator.AnimatorUpdateListener widthUpdater
- = new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- currentWidthFactor = (float) animation.getAnimatedValue();
- invalidate();
- }
- };
+ private ValueAnimator.AnimatorUpdateListener mTextTranslationUpdater =
+ new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ currentTextTranslationY = (float) animation.getAnimatedValue();
+ invalidate();
+ }
+ };
+
+ private ValueAnimator.AnimatorUpdateListener mWidthUpdater =
+ new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ currentWidthFactor = (float) animation.getAnimatedValue();
+ invalidate();
+ }
+ };
private Runnable dotSwapperRunnable = new Runnable() {
@Override
@@ -573,12 +447,15 @@
};
void startRemoveAnimation(long startDelay, long widthDelay) {
- boolean dotNeedsAnimation = (currentDotSizeFactor > 0.0f && dotAnimator == null)
- || (dotAnimator != null && dotAnimationIsGrowing);
- boolean textNeedsAnimation = (currentTextSizeFactor > 0.0f && textAnimator == null)
- || (textAnimator != null && textAnimationIsGrowing);
- boolean widthNeedsAnimation = (currentWidthFactor > 0.0f && widthAnimator == null)
- || (widthAnimator != null && widthAnimationIsGrowing);
+ boolean dotNeedsAnimation =
+ (currentDotSizeFactor > 0.0f && dotAnimator == null) || (dotAnimator != null
+ && dotAnimationIsGrowing);
+ boolean textNeedsAnimation =
+ (currentTextSizeFactor > 0.0f && textAnimator == null) || (textAnimator != null
+ && textAnimationIsGrowing);
+ boolean widthNeedsAnimation =
+ (currentWidthFactor > 0.0f && widthAnimator == null) || (widthAnimator != null
+ && widthAnimationIsGrowing);
if (dotNeedsAnimation) {
startDotDisappearAnimation(startDelay);
}
@@ -591,10 +468,10 @@
}
void startAppearAnimation() {
- boolean dotNeedsAnimation = !mShowPassword
- && (dotAnimator == null || !dotAnimationIsGrowing);
- boolean textNeedsAnimation = mShowPassword
- && (textAnimator == null || !textAnimationIsGrowing);
+ boolean dotNeedsAnimation =
+ !mShowPassword && (dotAnimator == null || !dotAnimationIsGrowing);
+ boolean textNeedsAnimation =
+ mShowPassword && (textAnimator == null || !textAnimationIsGrowing);
boolean widthNeedsAnimation = (widthAnimator == null || !widthAnimationIsGrowing);
if (dotNeedsAnimation) {
startDotAppearAnimation(0);
@@ -628,8 +505,8 @@
void swapToDotWhenAppearFinished() {
removeDotSwapCallbacks();
if (textAnimator != null) {
- long remainingDuration = textAnimator.getDuration()
- - textAnimator.getCurrentPlayTime();
+ long remainingDuration =
+ textAnimator.getDuration() - textAnimator.getCurrentPlayTime();
postDotSwap(remainingDuration + TEXT_REST_DURATION_AFTER_APPEAR);
} else {
performSwap();
@@ -638,14 +515,14 @@
private void performSwap() {
startTextDisappearAnimation(0);
- startDotAppearAnimation(DISAPPEAR_DURATION
- - DOT_APPEAR_TEXT_DISAPPEAR_OVERLAP_DURATION);
+ startDotAppearAnimation(
+ DISAPPEAR_DURATION - DOT_APPEAR_TEXT_DISAPPEAR_OVERLAP_DURATION);
}
private void startWidthDisappearAnimation(long widthDelay) {
cancelAnimator(widthAnimator);
widthAnimator = ValueAnimator.ofFloat(currentWidthFactor, 0.0f);
- widthAnimator.addUpdateListener(widthUpdater);
+ widthAnimator.addUpdateListener(mWidthUpdater);
widthAnimator.addListener(widthFinishListener);
widthAnimator.addListener(removeEndListener);
widthAnimator.setDuration((long) (DISAPPEAR_DURATION * currentWidthFactor));
@@ -657,7 +534,7 @@
private void startTextDisappearAnimation(long startDelay) {
cancelAnimator(textAnimator);
textAnimator = ValueAnimator.ofFloat(currentTextSizeFactor, 0.0f);
- textAnimator.addUpdateListener(textSizeUpdater);
+ textAnimator.addUpdateListener(mTextSizeUpdater);
textAnimator.addListener(textFinishListener);
textAnimator.setInterpolator(mDisappearInterpolator);
textAnimator.setDuration((long) (DISAPPEAR_DURATION * currentTextSizeFactor));
@@ -669,7 +546,7 @@
private void startDotDisappearAnimation(long startDelay) {
cancelAnimator(dotAnimator);
ValueAnimator animator = ValueAnimator.ofFloat(currentDotSizeFactor, 0.0f);
- animator.addUpdateListener(dotSizeUpdater);
+ animator.addUpdateListener(mDotSizeUpdater);
animator.addListener(dotFinishListener);
animator.setInterpolator(mDisappearInterpolator);
long duration = (long) (DISAPPEAR_DURATION * Math.min(currentDotSizeFactor, 1.0f));
@@ -683,7 +560,7 @@
private void startWidthAppearAnimation() {
cancelAnimator(widthAnimator);
widthAnimator = ValueAnimator.ofFloat(currentWidthFactor, 1.0f);
- widthAnimator.addUpdateListener(widthUpdater);
+ widthAnimator.addUpdateListener(mWidthUpdater);
widthAnimator.addListener(widthFinishListener);
widthAnimator.setDuration((long) (APPEAR_DURATION * (1f - currentWidthFactor)));
widthAnimator.start();
@@ -693,7 +570,7 @@
private void startTextAppearAnimation() {
cancelAnimator(textAnimator);
textAnimator = ValueAnimator.ofFloat(currentTextSizeFactor, 1.0f);
- textAnimator.addUpdateListener(textSizeUpdater);
+ textAnimator.addUpdateListener(mTextSizeUpdater);
textAnimator.addListener(textFinishListener);
textAnimator.setInterpolator(mAppearInterpolator);
textAnimator.setDuration((long) (APPEAR_DURATION * (1f - currentTextSizeFactor)));
@@ -703,7 +580,7 @@
// handle translation
if (textTranslateAnimator == null) {
textTranslateAnimator = ValueAnimator.ofFloat(1.0f, 0.0f);
- textTranslateAnimator.addUpdateListener(textTranslationUpdater);
+ textTranslateAnimator.addUpdateListener(mTextTranslationUpdater);
textTranslateAnimator.addListener(textTranslateFinishListener);
textTranslateAnimator.setInterpolator(mAppearInterpolator);
textTranslateAnimator.setDuration(APPEAR_DURATION);
@@ -717,14 +594,14 @@
// We perform an overshoot animation
ValueAnimator overShootAnimator = ValueAnimator.ofFloat(currentDotSizeFactor,
DOT_OVERSHOOT_FACTOR);
- overShootAnimator.addUpdateListener(dotSizeUpdater);
+ overShootAnimator.addUpdateListener(mDotSizeUpdater);
overShootAnimator.setInterpolator(mAppearInterpolator);
- long overShootDuration = (long) (DOT_APPEAR_DURATION_OVERSHOOT
- * OVERSHOOT_TIME_POSITION);
+ long overShootDuration =
+ (long) (DOT_APPEAR_DURATION_OVERSHOOT * OVERSHOOT_TIME_POSITION);
overShootAnimator.setDuration(overShootDuration);
ValueAnimator settleBackAnimator = ValueAnimator.ofFloat(DOT_OVERSHOOT_FACTOR,
1.0f);
- settleBackAnimator.addUpdateListener(dotSizeUpdater);
+ settleBackAnimator.addUpdateListener(mDotSizeUpdater);
settleBackAnimator.setDuration(DOT_APPEAR_DURATION_OVERSHOOT - overShootDuration);
settleBackAnimator.addListener(dotFinishListener);
AnimatorSet animatorSet = new AnimatorSet();
@@ -734,7 +611,7 @@
dotAnimator = animatorSet;
} else {
ValueAnimator growAnimator = ValueAnimator.ofFloat(currentDotSizeFactor, 1.0f);
- growAnimator.addUpdateListener(dotSizeUpdater);
+ growAnimator.addUpdateListener(mDotSizeUpdater);
growAnimator.setDuration((long) (APPEAR_DURATION * (1.0f - currentDotSizeFactor)));
growAnimator.addListener(dotFinishListener);
growAnimator.setStartDelay(delay);