Prevent lock icon a11y when unlocking.
When we are unlocking the lock icon is reading out a content description, indicating that it is locked. In consequence, talkback will often read "device locked. device unlocked" when unlocking the phone when talk back is on. A lot of the keyguard states don't seem viable to use here, but I found that the bouncer indicates that it is animating away here. Fixes: 284902478 Test: with talk back on, open notification in LS and authenticate Test: with talk back on, swipe up bouncer and authenticate Change-Id: I8ae54095c55a5ca0816878f27b368c3a9abd73e3
This commit is contained in:
@@ -56,6 +56,7 @@ import com.android.systemui.R;
|
|||||||
import com.android.systemui.biometrics.AuthController;
|
import com.android.systemui.biometrics.AuthController;
|
||||||
import com.android.systemui.biometrics.AuthRippleController;
|
import com.android.systemui.biometrics.AuthRippleController;
|
||||||
import com.android.systemui.biometrics.UdfpsController;
|
import com.android.systemui.biometrics.UdfpsController;
|
||||||
|
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
|
||||||
import com.android.systemui.dagger.SysUISingleton;
|
import com.android.systemui.dagger.SysUISingleton;
|
||||||
import com.android.systemui.dagger.qualifiers.Main;
|
import com.android.systemui.dagger.qualifiers.Main;
|
||||||
import com.android.systemui.dump.DumpManager;
|
import com.android.systemui.dump.DumpManager;
|
||||||
@@ -112,6 +113,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
|
|||||||
@NonNull private final VibratorHelper mVibrator;
|
@NonNull private final VibratorHelper mVibrator;
|
||||||
@Nullable private final AuthRippleController mAuthRippleController;
|
@Nullable private final AuthRippleController mAuthRippleController;
|
||||||
@NonNull private final FeatureFlags mFeatureFlags;
|
@NonNull private final FeatureFlags mFeatureFlags;
|
||||||
|
@NonNull private final PrimaryBouncerInteractor mPrimaryBouncerInteractor;
|
||||||
@NonNull private final KeyguardTransitionInteractor mTransitionInteractor;
|
@NonNull private final KeyguardTransitionInteractor mTransitionInteractor;
|
||||||
@NonNull private final KeyguardInteractor mKeyguardInteractor;
|
@NonNull private final KeyguardInteractor mKeyguardInteractor;
|
||||||
|
|
||||||
@@ -180,7 +182,8 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
|
|||||||
@NonNull @Main Resources resources,
|
@NonNull @Main Resources resources,
|
||||||
@NonNull KeyguardTransitionInteractor transitionInteractor,
|
@NonNull KeyguardTransitionInteractor transitionInteractor,
|
||||||
@NonNull KeyguardInteractor keyguardInteractor,
|
@NonNull KeyguardInteractor keyguardInteractor,
|
||||||
@NonNull FeatureFlags featureFlags
|
@NonNull FeatureFlags featureFlags,
|
||||||
|
PrimaryBouncerInteractor primaryBouncerInteractor
|
||||||
) {
|
) {
|
||||||
super(view);
|
super(view);
|
||||||
mStatusBarStateController = statusBarStateController;
|
mStatusBarStateController = statusBarStateController;
|
||||||
@@ -197,6 +200,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
|
|||||||
mTransitionInteractor = transitionInteractor;
|
mTransitionInteractor = transitionInteractor;
|
||||||
mKeyguardInteractor = keyguardInteractor;
|
mKeyguardInteractor = keyguardInteractor;
|
||||||
mFeatureFlags = featureFlags;
|
mFeatureFlags = featureFlags;
|
||||||
|
mPrimaryBouncerInteractor = primaryBouncerInteractor;
|
||||||
|
|
||||||
mMaxBurnInOffsetX = resources.getDimensionPixelSize(R.dimen.udfps_burn_in_offset_x);
|
mMaxBurnInOffsetX = resources.getDimensionPixelSize(R.dimen.udfps_burn_in_offset_x);
|
||||||
mMaxBurnInOffsetY = resources.getDimensionPixelSize(R.dimen.udfps_burn_in_offset_y);
|
mMaxBurnInOffsetY = resources.getDimensionPixelSize(R.dimen.udfps_burn_in_offset_y);
|
||||||
@@ -325,8 +329,14 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
|
|||||||
mView.setContentDescription(null);
|
mView.setContentDescription(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean accessibilityEnabled =
|
||||||
|
!mPrimaryBouncerInteractor.isAnimatingAway() && mView.isVisibleToUser();
|
||||||
|
mView.setImportantForAccessibility(
|
||||||
|
accessibilityEnabled ? View.IMPORTANT_FOR_ACCESSIBILITY_YES
|
||||||
|
: View.IMPORTANT_FOR_ACCESSIBILITY_NO);
|
||||||
|
|
||||||
if (!Objects.equals(prevContentDescription, mView.getContentDescription())
|
if (!Objects.equals(prevContentDescription, mView.getContentDescription())
|
||||||
&& mView.getContentDescription() != null && mView.isVisibleToUser()) {
|
&& mView.getContentDescription() != null && accessibilityEnabled) {
|
||||||
mView.announceForAccessibility(mView.getContentDescription());
|
mView.announceForAccessibility(mView.getContentDescription());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ import com.android.systemui.R;
|
|||||||
import com.android.systemui.SysuiTestCase;
|
import com.android.systemui.SysuiTestCase;
|
||||||
import com.android.systemui.biometrics.AuthController;
|
import com.android.systemui.biometrics.AuthController;
|
||||||
import com.android.systemui.biometrics.AuthRippleController;
|
import com.android.systemui.biometrics.AuthRippleController;
|
||||||
|
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
|
||||||
import com.android.systemui.doze.util.BurnInHelperKt;
|
import com.android.systemui.doze.util.BurnInHelperKt;
|
||||||
import com.android.systemui.dump.DumpManager;
|
import com.android.systemui.dump.DumpManager;
|
||||||
import com.android.systemui.flags.FakeFeatureFlags;
|
import com.android.systemui.flags.FakeFeatureFlags;
|
||||||
@@ -92,6 +93,7 @@ public class LockIconViewControllerBaseTest extends SysuiTestCase {
|
|||||||
protected @Mock KeyguardTransitionRepository mTransitionRepository;
|
protected @Mock KeyguardTransitionRepository mTransitionRepository;
|
||||||
protected FakeExecutor mDelayableExecutor = new FakeExecutor(new FakeSystemClock());
|
protected FakeExecutor mDelayableExecutor = new FakeExecutor(new FakeSystemClock());
|
||||||
protected FakeFeatureFlags mFeatureFlags;
|
protected FakeFeatureFlags mFeatureFlags;
|
||||||
|
protected @Mock PrimaryBouncerInteractor mPrimaryBouncerInteractor;
|
||||||
|
|
||||||
protected LockIconViewController mUnderTest;
|
protected LockIconViewController mUnderTest;
|
||||||
|
|
||||||
@@ -161,7 +163,8 @@ public class LockIconViewControllerBaseTest extends SysuiTestCase {
|
|||||||
new KeyguardTransitionInteractor(mTransitionRepository,
|
new KeyguardTransitionInteractor(mTransitionRepository,
|
||||||
TestScopeProvider.getTestScope().getBackgroundScope()),
|
TestScopeProvider.getTestScope().getBackgroundScope()),
|
||||||
KeyguardInteractorFactory.create(mFeatureFlags).getKeyguardInteractor(),
|
KeyguardInteractorFactory.create(mFeatureFlags).getKeyguardInteractor(),
|
||||||
mFeatureFlags
|
mFeatureFlags,
|
||||||
|
mPrimaryBouncerInteractor
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import android.hardware.biometrics.BiometricSourceType;
|
|||||||
import android.testing.AndroidTestingRunner;
|
import android.testing.AndroidTestingRunner;
|
||||||
import android.testing.TestableLooper;
|
import android.testing.TestableLooper;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
@@ -267,4 +268,75 @@ public class LockIconViewControllerTest extends LockIconViewControllerBaseTest {
|
|||||||
// THEN the lock icon is shown
|
// THEN the lock icon is shown
|
||||||
verify(mLockIconView).setContentDescription(LOCKED_LABEL);
|
verify(mLockIconView).setContentDescription(LOCKED_LABEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void lockIconAccessibility_notVisibleToUser() {
|
||||||
|
// GIVEN lock icon controller is initialized and view is attached
|
||||||
|
init(/* useMigrationFlag= */false);
|
||||||
|
captureKeyguardStateCallback();
|
||||||
|
captureKeyguardUpdateMonitorCallback();
|
||||||
|
|
||||||
|
// GIVEN user has unlocked with a biometric auth (ie: face auth)
|
||||||
|
// and biometric running state changes
|
||||||
|
when(mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(anyInt())).thenReturn(true);
|
||||||
|
mKeyguardUpdateMonitorCallback.onBiometricRunningStateChanged(false,
|
||||||
|
BiometricSourceType.FACE);
|
||||||
|
reset(mLockIconView);
|
||||||
|
when(mLockIconView.isVisibleToUser()).thenReturn(false);
|
||||||
|
|
||||||
|
// WHEN the unlocked state changes
|
||||||
|
when(mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(anyInt())).thenReturn(false);
|
||||||
|
mKeyguardStateCallback.onUnlockedChanged();
|
||||||
|
|
||||||
|
// THEN the lock icon is shown
|
||||||
|
verify(mLockIconView).setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void lockIconAccessibility_bouncerAnimatingAway() {
|
||||||
|
// GIVEN lock icon controller is initialized and view is attached
|
||||||
|
init(/* useMigrationFlag= */false);
|
||||||
|
captureKeyguardStateCallback();
|
||||||
|
captureKeyguardUpdateMonitorCallback();
|
||||||
|
|
||||||
|
// GIVEN user has unlocked with a biometric auth (ie: face auth)
|
||||||
|
// and biometric running state changes
|
||||||
|
when(mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(anyInt())).thenReturn(true);
|
||||||
|
mKeyguardUpdateMonitorCallback.onBiometricRunningStateChanged(false,
|
||||||
|
BiometricSourceType.FACE);
|
||||||
|
reset(mLockIconView);
|
||||||
|
when(mLockIconView.isVisibleToUser()).thenReturn(true);
|
||||||
|
when(mPrimaryBouncerInteractor.isAnimatingAway()).thenReturn(true);
|
||||||
|
|
||||||
|
// WHEN the unlocked state changes
|
||||||
|
when(mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(anyInt())).thenReturn(false);
|
||||||
|
mKeyguardStateCallback.onUnlockedChanged();
|
||||||
|
|
||||||
|
// THEN the lock icon is shown
|
||||||
|
verify(mLockIconView).setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void lockIconAccessibility_bouncerNotAnimatingAway_viewVisible() {
|
||||||
|
// GIVEN lock icon controller is initialized and view is attached
|
||||||
|
init(/* useMigrationFlag= */false);
|
||||||
|
captureKeyguardStateCallback();
|
||||||
|
captureKeyguardUpdateMonitorCallback();
|
||||||
|
|
||||||
|
// GIVEN user has unlocked with a biometric auth (ie: face auth)
|
||||||
|
// and biometric running state changes
|
||||||
|
when(mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(anyInt())).thenReturn(true);
|
||||||
|
mKeyguardUpdateMonitorCallback.onBiometricRunningStateChanged(false,
|
||||||
|
BiometricSourceType.FACE);
|
||||||
|
reset(mLockIconView);
|
||||||
|
when(mLockIconView.isVisibleToUser()).thenReturn(true);
|
||||||
|
when(mPrimaryBouncerInteractor.isAnimatingAway()).thenReturn(false);
|
||||||
|
|
||||||
|
// WHEN the unlocked state changes
|
||||||
|
when(mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(anyInt())).thenReturn(false);
|
||||||
|
mKeyguardStateCallback.onUnlockedChanged();
|
||||||
|
|
||||||
|
// THEN the lock icon is shown
|
||||||
|
verify(mLockIconView).setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user