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

Commit d8163ff7 authored by Daniel Norman's avatar Daniel Norman
Browse files

Use a sysprop so connect APIs fail fast if HIDRAW is not supported.

Bug: 311783331
Test: atest BrailleDisplayControllerImplTest
Test: Manually set sysprop on my device, observe API returns failure
Change-Id: I12106e620fbf84d48673e3d113343c2a0954e744
parent a820b6f8
Loading
Loading
Loading
Loading
+30 −1
Original line number Diff line number Diff line
@@ -25,9 +25,11 @@ import android.hardware.usb.UsbDevice;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.view.accessibility.AccessibilityInteractionClient;
import android.view.accessibility.Flags;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FunctionalUtils;

import java.io.IOException;
@@ -36,24 +38,46 @@ import java.util.concurrent.Executor;

/**
 * Default implementation of {@link BrailleDisplayController}.
 *
 * @hide
 */
// BrailleDisplayControllerImpl is not an API, but it implements BrailleDisplayController APIs.
// This @FlaggedApi annotation tells the linter that this method delegates API checks to its
// callers.
@FlaggedApi(Flags.FLAG_BRAILLE_DISPLAY_HID)
final class BrailleDisplayControllerImpl implements BrailleDisplayController {
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
public final class BrailleDisplayControllerImpl implements BrailleDisplayController {

    private final AccessibilityService mAccessibilityService;
    private final Object mLock;
    private final boolean mIsHidrawSupported;

    private IBrailleDisplayConnection mBrailleDisplayConnection;
    private Executor mCallbackExecutor;
    private BrailleDisplayCallback mCallback;

    /**
     * Read-only property that returns whether HIDRAW access is supported on this device.
     *
     * <p>Defaults to true.
     *
     * <p>Device manufacturers without HIDRAW kernel support can set this to false in
     * the device's product makefile.
     */
    private static final boolean IS_HIDRAW_SUPPORTED = SystemProperties.getBoolean(
            "ro.accessibility.support_hidraw", true);

    BrailleDisplayControllerImpl(AccessibilityService accessibilityService,
            Object lock) {
        this(accessibilityService, lock, IS_HIDRAW_SUPPORTED);
    }

    @VisibleForTesting
    public BrailleDisplayControllerImpl(AccessibilityService accessibilityService,
            Object lock, boolean isHidrawSupported) {
        mAccessibilityService = accessibilityService;
        mLock = lock;
        mIsHidrawSupported = isHidrawSupported;
    }

    @Override
@@ -113,6 +137,11 @@ final class BrailleDisplayControllerImpl implements BrailleDisplayController {
                    createConnection,
            @NonNull Executor callbackExecutor, @NonNull BrailleDisplayCallback callback) {
        BrailleDisplayController.checkApiFlagIsEnabled();
        if (!mIsHidrawSupported) {
            callbackExecutor.execute(() -> callback.onConnectionFailed(
                    BrailleDisplayCallback.FLAG_ERROR_CANNOT_ACCESS));
            return;
        }
        if (isConnected()) {
            throw new IllegalStateException(
                    "This service already has a connected Braille display");
+20 −4
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;

import android.hardware.usb.UsbDevice;
import android.platform.test.annotations.RequiresFlagsEnabled;
@@ -58,6 +59,7 @@ public class BrailleDisplayControllerImplTest {
    @Rule
    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();

    private AccessibilityService mAccessibilityService;
    private BrailleDisplayController mBrailleDisplayController;

    @Mock
@@ -76,12 +78,13 @@ public class BrailleDisplayControllerImplTest {
    @Before
    public void test() {
        MockitoAnnotations.initMocks(this);
        AccessibilityService accessibilityService = spy(new TestAccessibilityService());
        doReturn((Executor) Runnable::run).when(accessibilityService).getMainExecutor();
        doReturn(TEST_SERVICE_CONNECTION_ID).when(accessibilityService).getConnectionId();
        mAccessibilityService = spy(new TestAccessibilityService());
        doReturn((Executor) Runnable::run).when(mAccessibilityService).getMainExecutor();
        doReturn(TEST_SERVICE_CONNECTION_ID).when(mAccessibilityService).getConnectionId();
        AccessibilityInteractionClient.addConnection(TEST_SERVICE_CONNECTION_ID,
                mAccessibilityServiceConnection, /*initializeCache=*/false);
        mBrailleDisplayController = accessibilityService.getBrailleDisplayController();
        mBrailleDisplayController = new BrailleDisplayControllerImpl(
                mAccessibilityService, new Object(), /*isHidrawSupported=*/true);
    }

    // Automated CTS tests only use the BluetoothDevice version of BrailleDisplayController#connect
@@ -104,4 +107,17 @@ public class BrailleDisplayControllerImplTest {
        assertThrows(IllegalStateException.class,
                () -> mBrailleDisplayController.connect(usbDevice, mBrailleDisplayCallback));
    }

    @Test
    public void connect_HidrawNotSupported_callsOnConnectionFailed() {
        BrailleDisplayController controller = new BrailleDisplayControllerImpl(
                mAccessibilityService, new Object(), /*isHidrawSupported=*/false);
        UsbDevice usbDevice = Mockito.mock(UsbDevice.class);

        controller.connect(usbDevice, mBrailleDisplayCallback);

        verify(mBrailleDisplayCallback).onConnectionFailed(
                BrailleDisplayController.BrailleDisplayCallback.FLAG_ERROR_CANNOT_ACCESS);
        verifyZeroInteractions(mAccessibilityServiceConnection);
    }
}