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

Commit 2b095632 authored by Grace Cheng's avatar Grace Cheng
Browse files

Disable timed dialog dismissal when a11y enabled

Only use mDismissDialogTimeout when accessibility is disabled. When
accessibility is enabled, do not dismiss dialog until sensor is touched,
or focus is moved away from dialog.

Flag: NONE
Test: atest SideFpsEventHandlerTest
Fixes: 324488176
Change-Id: I4c953f938bbc0102188cc87f12eb8617b00f6184
parent 001df5f3
Loading
Loading
Loading
Loading
+13 −1
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;

import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
@@ -66,6 +67,7 @@ public class SideFpsEventHandler implements View.OnClickListener {
    private final int mDismissDialogTimeout;
    @Nullable
    private SideFpsToast mDialog;
    private final AccessibilityManager mAccessibilityManager;
    private final Runnable mTurnOffDialog =
            () -> {
                dismissDialog("mTurnOffDialog");
@@ -96,6 +98,7 @@ public class SideFpsEventHandler implements View.OnClickListener {
            DialogProvider provider) {
        mContext = context;
        mHandler = handler;
        mAccessibilityManager = mContext.getSystemService(AccessibilityManager.class);
        mPowerManager = powerManager;
        mBiometricState = STATE_IDLE;
        mSideFpsEventHandlerReady = new AtomicBoolean(false);
@@ -157,7 +160,9 @@ public class SideFpsEventHandler implements View.OnClickListener {
                                mHandler.removeCallbacks(mTurnOffDialog);
                            }
                            showDialog(eventTime, "Enroll Power Press");
                            if (!mAccessibilityManager.isEnabled()) {
                                mHandler.postDelayed(mTurnOffDialog, mDismissDialogTimeout);
                            }
                        });
                return true;
            case STATE_BP_AUTH:
@@ -231,6 +236,10 @@ public class SideFpsEventHandler implements View.OnClickListener {
                                        public void onBiometricAction(
                                                @BiometricStateListener.Action int action) {
                                            Log.d(TAG, "onBiometricAction " + action);
                                            if (mAccessibilityManager != null
                                                    && mAccessibilityManager.isEnabled()) {
                                                dismissDialog("mTurnOffDialog");
                                            }
                                        }
                                    });
                            mSideFpsEventHandlerReady.set(true);
@@ -256,6 +265,9 @@ public class SideFpsEventHandler implements View.OnClickListener {
        mLastPowerPressTime = time;
        mDialog.show();
        mDialog.setOnClickListener(this);
        if (mAccessibilityManager.isEnabled()) {
            mDialog.addAccessibilityDelegate();
        }
    }

    interface DialogProvider {
+25 −1
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.policy;

import android.annotation.NonNull;
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
@@ -23,6 +24,7 @@ import android.view.Gravity;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.widget.Button;

import com.android.internal.R;
@@ -34,7 +36,6 @@ import com.android.internal.R;
 * This dialog is used by {@link SideFpsEventHandler}
 */
public class SideFpsToast extends Dialog {

    SideFpsToast(Context context) {
        super(context);
    }
@@ -66,4 +67,27 @@ public class SideFpsToast extends Dialog {
            turnOffScreen.setOnClickListener(listener);
        }
    }

    /**
     * When accessibility mode is on, add AccessibilityDelegate to dismiss dialog when focus is
     * moved away from the dialog.
     */
    public void addAccessibilityDelegate() {
        final Button turnOffScreen = findViewById(R.id.turn_off_screen);
        if (turnOffScreen != null) {
            turnOffScreen.setAccessibilityDelegate(new View.AccessibilityDelegate() {
                @Override
                public void onInitializeAccessibilityEvent(@NonNull View host,
                        @NonNull AccessibilityEvent event) {
                    if (event.getEventType()
                            == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED
                            && isShowing()) {
                        dismiss();
                    }
                    super.onInitializeAccessibilityEvent(host, event);
                }
            });

        }
    }
}
+58 −9
Original line number Diff line number Diff line
@@ -31,11 +31,13 @@ import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
import android.os.Handler;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.test.TestLooper;
import android.testing.AndroidTestingRunner;
import android.testing.TestableContext;
import android.testing.TestableResources;
import android.view.Window;
import android.view.accessibility.AccessibilityManager;

import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -48,7 +50,8 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;

import java.util.List;

@@ -71,10 +74,16 @@ public class SideFpsEventHandlerTest {

    private static final Integer AUTO_DISMISS_DIALOG = 500;

    @Rule
    public MockitoRule rule = MockitoJUnit.rule();

    @Rule
    public TestableContext mContext =
            new TestableContext(InstrumentationRegistry.getContext(), null);

    private final AccessibilityManager mAccessibilityManager =
            mContext.getSystemService(AccessibilityManager.class);

    @Mock
    private PackageManager mPackageManager;
    @Mock
@@ -89,9 +98,8 @@ public class SideFpsEventHandlerTest {
    private BiometricStateListener mBiometricStateListener;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);

    public void setup() throws RemoteException {
        disableAccessibility();
        mContext.addMockSystemService(PackageManager.class, mPackageManager);
        mContext.addMockSystemService(FingerprintManager.class, mFingerprintManager);
        TestableResources resources = mContext.getOrCreateTestableResources();
@@ -192,9 +200,8 @@ public class SideFpsEventHandlerTest {
    }

    @Test
    public void dialogDismissesAfterTime() throws Exception {
    public void dialogDismissesAfterTime_accessibilityDisabled() throws Exception {
        setupWithSensor(true /* hasSfps */, true /* initialized */);

        setBiometricState(BiometricStateListener.STATE_ENROLLING);
        when(mDialog.isShowing()).thenReturn(true);
        assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isTrue();
@@ -207,9 +214,23 @@ public class SideFpsEventHandlerTest {
    }

    @Test
    public void dialogDoesNotDismissOnSensorTouch() throws Exception {
    public void dialogDoesNotDismissAfterTime_accessibilityEnabled() throws Exception {
        enableAccessibility();
        setupWithSensor(true /* hasSfps */, true /* initialized */);
        setBiometricState(BiometricStateListener.STATE_ENROLLING);
        when(mDialog.isShowing()).thenReturn(true);
        assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isTrue();

        mLooper.dispatchAll();
        verify(mDialog).show();
        mLooper.moveTimeForward(AUTO_DISMISS_DIALOG);
        mLooper.dispatchAll();
        verify(mDialog, never()).dismiss();
    }

    @Test
    public void dialogDoesNotDismissOnSensorTouch_accessibilityDisabled() throws Exception {
        setupWithSensor(true /* hasSfps */, true /* initialized */);
        setBiometricState(BiometricStateListener.STATE_ENROLLING);
        when(mDialog.isShowing()).thenReturn(true);
        assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isTrue();
@@ -218,12 +239,26 @@ public class SideFpsEventHandlerTest {
        verify(mDialog).show();

        mBiometricStateListener.onBiometricAction(BiometricStateListener.ACTION_SENSOR_TOUCH);
        mLooper.moveTimeForward(AUTO_DISMISS_DIALOG - 1);
        mLooper.dispatchAll();

        verify(mDialog, never()).dismiss();
    }

    @Test
    public void dialogDismissesOnSensorTouch_accessibilityEnabled() throws Exception {
        enableAccessibility();
        setupWithSensor(true /* hasSfps */, true /* initialized */);
        setBiometricState(BiometricStateListener.STATE_ENROLLING);
        when(mDialog.isShowing()).thenReturn(true);
        assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isTrue();

        mLooper.dispatchAll();
        verify(mDialog).show();

        mBiometricStateListener.onBiometricAction(BiometricStateListener.ACTION_SENSOR_TOUCH);
        mLooper.dispatchAll();
        verify(mDialog).dismiss();
    }

    private void setBiometricState(@BiometricStateListener.State int newState) {
        if (mBiometricStateListener != null) {
            mBiometricStateListener.onStateChanged(newState);
@@ -231,6 +266,20 @@ public class SideFpsEventHandlerTest {
        }
    }

    private void enableAccessibility() throws RemoteException {
        if (mAccessibilityManager != null) {
            mAccessibilityManager.getClient().setState(1);
            mLooper.dispatchAll();
        }
    }

    private void disableAccessibility() throws RemoteException {
        if (mAccessibilityManager != null) {
            mAccessibilityManager.getClient().setState(0);
            mLooper.dispatchAll();
        }
    }

    private void setupWithSensor(boolean hasSfps, boolean initialized) throws Exception {
        when(mPackageManager.hasSystemFeature(eq(PackageManager.FEATURE_FINGERPRINT)))
                .thenReturn(true);