Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6a02b08b authored by Aaron Liu's avatar Aaron Liu
Browse files

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
parent 7c1f1cfc
Loading
Loading
Loading
Loading
+12 −2
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@ import com.android.systemui.R;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.biometrics.AuthRippleController;
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.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
@@ -112,6 +113,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
    @NonNull private final VibratorHelper mVibrator;
    @Nullable private final AuthRippleController mAuthRippleController;
    @NonNull private final FeatureFlags mFeatureFlags;
    @NonNull private final PrimaryBouncerInteractor mPrimaryBouncerInteractor;
    @NonNull private final KeyguardTransitionInteractor mTransitionInteractor;
    @NonNull private final KeyguardInteractor mKeyguardInteractor;

@@ -180,7 +182,8 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
            @NonNull @Main Resources resources,
            @NonNull KeyguardTransitionInteractor transitionInteractor,
            @NonNull KeyguardInteractor keyguardInteractor,
            @NonNull FeatureFlags featureFlags
            @NonNull FeatureFlags featureFlags,
            PrimaryBouncerInteractor primaryBouncerInteractor
    ) {
        super(view);
        mStatusBarStateController = statusBarStateController;
@@ -197,6 +200,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
        mTransitionInteractor = transitionInteractor;
        mKeyguardInteractor = keyguardInteractor;
        mFeatureFlags = featureFlags;
        mPrimaryBouncerInteractor = primaryBouncerInteractor;

        mMaxBurnInOffsetX = resources.getDimensionPixelSize(R.dimen.udfps_burn_in_offset_x);
        mMaxBurnInOffsetY = resources.getDimensionPixelSize(R.dimen.udfps_burn_in_offset_y);
@@ -325,8 +329,14 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
            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())
                && mView.getContentDescription() != null && mView.isVisibleToUser()) {
                && mView.getContentDescription() != null && accessibilityEnabled) {
            mView.announceForAccessibility(mView.getContentDescription());
        }
    }
+4 −1
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.AuthController;
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.dump.DumpManager;
import com.android.systemui.flags.FakeFeatureFlags;
@@ -92,6 +93,7 @@ public class LockIconViewControllerBaseTest extends SysuiTestCase {
    protected @Mock KeyguardTransitionRepository mTransitionRepository;
    protected FakeExecutor mDelayableExecutor = new FakeExecutor(new FakeSystemClock());
    protected FakeFeatureFlags mFeatureFlags;
    protected @Mock PrimaryBouncerInteractor mPrimaryBouncerInteractor;

    protected LockIconViewController mUnderTest;

@@ -161,7 +163,8 @@ public class LockIconViewControllerBaseTest extends SysuiTestCase {
                new KeyguardTransitionInteractor(mTransitionRepository,
                        TestScopeProvider.getTestScope().getBackgroundScope()),
                KeyguardInteractorFactory.create(mFeatureFlags).getKeyguardInteractor(),
                mFeatureFlags
                mFeatureFlags,
                mPrimaryBouncerInteractor
        );
    }

+72 −0
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import android.hardware.biometrics.BiometricSourceType;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.Pair;
import android.view.View;

import androidx.test.filters.SmallTest;

@@ -267,4 +268,75 @@ public class LockIconViewControllerTest extends LockIconViewControllerBaseTest {
        // THEN the lock icon is shown
        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);
    }
}