Merge changes Ia1128b9d,I018e067e into udc-dev

* changes:
  Fix lockout state for auto pin confirm
  Fix pin error scenario for talkback.
This commit is contained in:
Aaron Liu
2023-05-12 17:35:45 +00:00
committed by Android (Google) Code Review
8 changed files with 101 additions and 50 deletions

View File

@@ -179,10 +179,10 @@ public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKey
handleAttemptLockout(deadline); handleAttemptLockout(deadline);
} }
} }
mView.resetPasswordText(true /* animate */, false /* announce deletion if no match */);
if (timeoutMs == 0) { if (timeoutMs == 0) {
mMessageAreaController.setMessage(mView.getWrongPasswordStringId()); mMessageAreaController.setMessage(mView.getWrongPasswordStringId());
} }
mView.resetPasswordText(true /* animate */, false /* announce deletion if no match */);
startErrorAnimation(); startErrorAnimation();
} }
} }

View File

@@ -18,7 +18,9 @@ package com.android.keyguard;
import android.content.res.ColorStateList; import android.content.res.ColorStateList;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.text.Editable;
import android.text.TextUtils; import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.View; import android.view.View;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
@@ -45,6 +47,31 @@ public class KeyguardMessageAreaController<T extends KeyguardMessageArea>
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final ConfigurationController mConfigurationController; private final ConfigurationController mConfigurationController;
private final AnnounceRunnable mAnnounceRunnable; private final AnnounceRunnable mAnnounceRunnable;
private final TextWatcher mTextWatcher = new TextWatcher() {
@Override
public void afterTextChanged(Editable editable) {
CharSequence msg = editable;
if (!TextUtils.isEmpty(msg)) {
mView.removeCallbacks(mAnnounceRunnable);
mAnnounceRunnable.setTextToAnnounce(msg);
mView.postDelayed(() -> {
if (msg == mView.getText()) {
mAnnounceRunnable.run();
}
}, ANNOUNCEMENT_DELAY);
}
}
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
/* no-op */
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
/* no-op */
}
};
private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() { private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
public void onFinishedGoingToSleep(int why) { public void onFinishedGoingToSleep(int why) {
@@ -89,12 +116,14 @@ public class KeyguardMessageAreaController<T extends KeyguardMessageArea>
mKeyguardUpdateMonitor.registerCallback(mInfoCallback); mKeyguardUpdateMonitor.registerCallback(mInfoCallback);
mView.setSelected(mKeyguardUpdateMonitor.isDeviceInteractive()); mView.setSelected(mKeyguardUpdateMonitor.isDeviceInteractive());
mView.onThemeChanged(); mView.onThemeChanged();
mView.addTextChangedListener(mTextWatcher);
} }
@Override @Override
protected void onViewDetached() { protected void onViewDetached() {
mConfigurationController.removeCallback(mConfigurationListener); mConfigurationController.removeCallback(mConfigurationListener);
mKeyguardUpdateMonitor.removeCallback(mInfoCallback); mKeyguardUpdateMonitor.removeCallback(mInfoCallback);
mView.removeTextChangedListener(mTextWatcher);
} }
/** /**
@@ -113,12 +142,6 @@ public class KeyguardMessageAreaController<T extends KeyguardMessageArea>
*/ */
public void setMessage(CharSequence s, boolean animate) { public void setMessage(CharSequence s, boolean animate) {
mView.setMessage(s, animate); mView.setMessage(s, animate);
CharSequence msg = mView.getText();
if (!TextUtils.isEmpty(msg)) {
mView.removeCallbacks(mAnnounceRunnable);
mAnnounceRunnable.setTextToAnnounce(msg);
mView.postDelayed(mAnnounceRunnable, ANNOUNCEMENT_DELAY);
}
} }
public void setMessage(int resId) { public void setMessage(int resId) {

View File

@@ -82,9 +82,6 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView
protected void setPasswordEntryInputEnabled(boolean enabled) { protected void setPasswordEntryInputEnabled(boolean enabled) {
mPasswordEntry.setEnabled(enabled); mPasswordEntry.setEnabled(enabled);
mOkButton.setEnabled(enabled); mOkButton.setEnabled(enabled);
if (enabled && !mPasswordEntry.hasFocus()) {
mPasswordEntry.requestFocus();
}
} }
@Override @Override

View File

@@ -16,8 +16,6 @@
package com.android.keyguard; package com.android.keyguard;
import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.DEFAULT_PIN_LENGTH;
import android.view.View; import android.view.View;
import com.android.internal.util.LatencyTracker; import com.android.internal.util.LatencyTracker;
@@ -42,10 +40,9 @@ public class KeyguardPinViewController
private NumPadButton mBackspaceKey; private NumPadButton mBackspaceKey;
private View mOkButton = mView.findViewById(R.id.key_enter); private View mOkButton = mView.findViewById(R.id.key_enter);
private int mUserId;
private long mPinLength; private long mPinLength;
private int mPasswordFailedAttempts; private boolean mDisabledAutoConfirmation;
protected KeyguardPinViewController(KeyguardPINView view, protected KeyguardPinViewController(KeyguardPINView view,
KeyguardUpdateMonitor keyguardUpdateMonitor, KeyguardUpdateMonitor keyguardUpdateMonitor,
@@ -84,9 +81,8 @@ public class KeyguardPinViewController
protected void onUserInput() { protected void onUserInput() {
super.onUserInput(); super.onUserInput();
if (isAutoConfirmation()) { if (isAutoPinConfirmEnabledInSettings()) {
updateOKButtonVisibility(); updateAutoConfirmationState();
updateBackSpaceVisibility();
if (mPasswordEntry.getText().length() == mPinLength if (mPasswordEntry.getText().length() == mPinLength
&& mOkButton.getVisibility() == View.INVISIBLE) { && mOkButton.getVisibility() == View.INVISIBLE) {
verifyPasswordAndUnlock(); verifyPasswordAndUnlock();
@@ -103,13 +99,9 @@ public class KeyguardPinViewController
@Override @Override
public void startAppearAnimation() { public void startAppearAnimation() {
if (mFeatureFlags.isEnabled(Flags.AUTO_PIN_CONFIRMATION)) { if (mFeatureFlags.isEnabled(Flags.AUTO_PIN_CONFIRMATION)) {
mUserId = KeyguardUpdateMonitor.getCurrentUser(); mPinLength = mLockPatternUtils.getPinLength(KeyguardUpdateMonitor.getCurrentUser());
mPinLength = mLockPatternUtils.getPinLength(mUserId);
mBackspaceKey.setTransparentMode(/* isTransparentMode= */ isAutoConfirmation());
updateOKButtonVisibility();
updateBackSpaceVisibility();
mPasswordEntry.setUsePinShapes(true); mPasswordEntry.setUsePinShapes(true);
mPasswordEntry.setIsPinHinting(isAutoConfirmation() && isPinHinting()); updateAutoConfirmationState();
} }
super.startAppearAnimation(); super.startAppearAnimation();
} }
@@ -120,13 +112,25 @@ public class KeyguardPinViewController
mKeyguardUpdateMonitor.needsSlowUnlockTransition(), finishRunnable); mKeyguardUpdateMonitor.needsSlowUnlockTransition(), finishRunnable);
} }
@Override
protected void handleAttemptLockout(long elapsedRealtimeDeadline) {
super.handleAttemptLockout(elapsedRealtimeDeadline);
updateAutoConfirmationState();
}
private void updateAutoConfirmationState() {
mDisabledAutoConfirmation = mLockPatternUtils.getCurrentFailedPasswordAttempts(
KeyguardUpdateMonitor.getCurrentUser()) >= MIN_FAILED_PIN_ATTEMPTS;
updateOKButtonVisibility();
updateBackSpaceVisibility();
updatePinHinting();
}
/** /**
* Updates the visibility of the OK button for auto confirm feature * Updates the visibility of the OK button for auto confirm feature
*/ */
private void updateOKButtonVisibility() { private void updateOKButtonVisibility() {
mPasswordFailedAttempts = mLockPatternUtils.getCurrentFailedPasswordAttempts(mUserId); if (isAutoPinConfirmEnabledInSettings() && !mDisabledAutoConfirmation) {
if (isAutoConfirmation() && mPasswordFailedAttempts < MIN_FAILED_PIN_ATTEMPTS) {
mOkButton.setVisibility(View.INVISIBLE); mOkButton.setVisibility(View.INVISIBLE);
} else { } else {
mOkButton.setVisibility(View.VISIBLE); mOkButton.setVisibility(View.VISIBLE);
@@ -134,33 +138,41 @@ public class KeyguardPinViewController
} }
/** /**
* Updates the visibility and the enabled state of the backspace. * Updates the visibility and the enabled state of the backspace.
* Visibility changes are only for auto confirmation configuration. * Visibility changes are only for auto confirmation configuration.
*/ */
private void updateBackSpaceVisibility() { private void updateBackSpaceVisibility() {
if (!isAutoConfirmation()) { boolean isAutoConfirmation = isAutoPinConfirmEnabledInSettings();
return; mBackspaceKey.setTransparentMode(/* isTransparentMode= */
} isAutoConfirmation && !mDisabledAutoConfirmation);
if (isAutoConfirmation) {
if (mPasswordEntry.getText().length() > 0) { if (mPasswordEntry.getText().length() > 0
mBackspaceKey.setVisibility(View.VISIBLE); || mDisabledAutoConfirmation) {
} else { mBackspaceKey.setVisibility(View.VISIBLE);
mBackspaceKey.setVisibility(View.INVISIBLE); } else {
mBackspaceKey.setVisibility(View.INVISIBLE);
}
} }
} }
/** Updates whether to use pin hinting or not. */
void updatePinHinting() {
mPasswordEntry.setIsPinHinting(isAutoPinConfirmEnabledInSettings() && isPinHinting()
&& !mDisabledAutoConfirmation);
}
/** /**
* Responsible for identifying if PIN hinting is to be enabled or not * Responsible for identifying if PIN hinting is to be enabled or not
*/ */
private boolean isPinHinting() { private boolean isPinHinting() {
return mLockPatternUtils.getPinLength(mUserId) == DEFAULT_PIN_LENGTH; return mLockPatternUtils.getPinLength(KeyguardUpdateMonitor.getCurrentUser())
== DEFAULT_PIN_LENGTH;
} }
/** /**
* Responsible for identifying if auto confirm is enabled or not in Settings * Responsible for identifying if auto confirm is enabled or not in Settings
*/ */
private boolean isAutoConfirmation() { private boolean isAutoPinConfirmEnabledInSettings() {
//Checks if user has enabled the auto confirm in Settings //Checks if user has enabled the auto confirm in Settings
return mLockPatternUtils.isAutoPinConfirmEnabled(mUserId); return mLockPatternUtils.isAutoPinConfirmEnabled(KeyguardUpdateMonitor.getCurrentUser());
} }
} }

View File

@@ -116,7 +116,12 @@ public class NumPadButton extends AlphaOptimizedImageButton implements NumPadAni
* @param isTransparentMode * @param isTransparentMode
*/ */
public void setTransparentMode(boolean isTransparentMode) { public void setTransparentMode(boolean isTransparentMode) {
if (mIsTransparentMode == isTransparentMode) {
return;
}
mIsTransparentMode = isTransparentMode; mIsTransparentMode = isTransparentMode;
if (isTransparentMode) { if (isTransparentMode) {
setBackgroundColor(getResources().getColor(android.R.color.transparent)); setBackgroundColor(getResources().getColor(android.R.color.transparent));
} else { } else {

View File

@@ -101,6 +101,7 @@ public class PasswordTextView extends FrameLayout {
private Interpolator mFastOutSlowInInterpolator; private Interpolator mFastOutSlowInInterpolator;
private boolean mShowPassword = true; private boolean mShowPassword = true;
private UserActivityListener mUserActivityListener; private UserActivityListener mUserActivityListener;
private boolean mIsPinHinting;
private PinShapeInput mPinShapeInput; private PinShapeInput mPinShapeInput;
private boolean mUsePinShapes = false; private boolean mUsePinShapes = false;
@@ -419,10 +420,15 @@ public class PasswordTextView extends FrameLayout {
/** /**
* Determines whether AutoConfirmation feature is on. * Determines whether AutoConfirmation feature is on.
* *
* @param usePinShapes
* @param isPinHinting * @param isPinHinting
*/ */
public void setIsPinHinting(boolean 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) { if (mPinShapeInput != null) {
removeView(mPinShapeInput.getView()); removeView(mPinShapeInput.getView());
mPinShapeInput = null; mPinShapeInput = null;

View File

@@ -27,6 +27,8 @@ import static org.mockito.Mockito.when;
import android.test.suitebuilder.annotation.SmallTest; import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner; import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper; import android.testing.TestableLooper;
import android.text.Editable;
import android.text.TextWatcher;
import com.android.systemui.SysuiTestCase; import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -93,16 +95,16 @@ public class KeyguardMessageAreaControllerTest extends SysuiTestCase {
} }
@Test @Test
public void testSetMessage_AnnounceForAccessibility() { public void textChanged_AnnounceForAccessibility() {
ArgumentCaptor<Runnable> argumentCaptor = ArgumentCaptor.forClass(Runnable.class); ArgumentCaptor<TextWatcher> textWatcherArgumentCaptor = ArgumentCaptor.forClass(
when(mKeyguardMessageArea.getText()).thenReturn("abc"); TextWatcher.class);
mMessageAreaController.setMessage("abc"); mMessageAreaController.onViewAttached();
verify(mKeyguardMessageArea).addTextChangedListener(textWatcherArgumentCaptor.capture());
verify(mKeyguardMessageArea).setMessage("abc", /* animate= */ true); textWatcherArgumentCaptor.getValue().afterTextChanged(
Editable.Factory.getInstance().newEditable("abc"));
verify(mKeyguardMessageArea).removeCallbacks(any(Runnable.class)); verify(mKeyguardMessageArea).removeCallbacks(any(Runnable.class));
verify(mKeyguardMessageArea).postDelayed(argumentCaptor.capture(), anyLong()); verify(mKeyguardMessageArea).postDelayed(any(Runnable.class), anyLong());
argumentCaptor.getValue().run();
verify(mKeyguardMessageArea).announceForAccessibility("abc");
} }
@Test @Test

View File

@@ -152,9 +152,15 @@ class KeyguardPinViewControllerTest : SysuiTestCase() {
`when`(passwordTextView.text).thenReturn("") `when`(passwordTextView.text).thenReturn("")
pinViewController.startAppearAnimation() pinViewController.startAppearAnimation()
verify(deleteButton).visibility = View.INVISIBLE verify(deleteButton).visibility = View.VISIBLE
verify(enterButton).visibility = View.VISIBLE verify(enterButton).visibility = View.VISIBLE
verify(passwordTextView).setUsePinShapes(true) verify(passwordTextView).setUsePinShapes(true)
verify(passwordTextView).setIsPinHinting(true) verify(passwordTextView).setIsPinHinting(false)
}
@Test
fun handleLockout_readsNumberOfErrorAttempts() {
pinViewController.handleAttemptLockout(0)
verify(lockPatternUtils).getCurrentFailedPasswordAttempts(anyInt())
} }
} }