Skip to content
Snippets Groups Projects
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
No related branches found
No related tags found
No related merge requests found
...@@ -25,9 +25,11 @@ import android.hardware.usb.UsbDevice; ...@@ -25,9 +25,11 @@ import android.hardware.usb.UsbDevice;
import android.os.Binder; import android.os.Binder;
import android.os.IBinder; import android.os.IBinder;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.SystemProperties;
import android.view.accessibility.AccessibilityInteractionClient; import android.view.accessibility.AccessibilityInteractionClient;
import android.view.accessibility.Flags; import android.view.accessibility.Flags;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FunctionalUtils; import com.android.internal.util.FunctionalUtils;
import java.io.IOException; import java.io.IOException;
...@@ -36,24 +38,46 @@ import java.util.concurrent.Executor; ...@@ -36,24 +38,46 @@ import java.util.concurrent.Executor;
/** /**
* Default implementation of {@link BrailleDisplayController}. * Default implementation of {@link BrailleDisplayController}.
*
* @hide
*/ */
// BrailleDisplayControllerImpl is not an API, but it implements BrailleDisplayController APIs. // BrailleDisplayControllerImpl is not an API, but it implements BrailleDisplayController APIs.
// This @FlaggedApi annotation tells the linter that this method delegates API checks to its // This @FlaggedApi annotation tells the linter that this method delegates API checks to its
// callers. // callers.
@FlaggedApi(Flags.FLAG_BRAILLE_DISPLAY_HID) @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 AccessibilityService mAccessibilityService;
private final Object mLock; private final Object mLock;
private final boolean mIsHidrawSupported;
private IBrailleDisplayConnection mBrailleDisplayConnection; private IBrailleDisplayConnection mBrailleDisplayConnection;
private Executor mCallbackExecutor; private Executor mCallbackExecutor;
private BrailleDisplayCallback mCallback; 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, BrailleDisplayControllerImpl(AccessibilityService accessibilityService,
Object lock) { Object lock) {
this(accessibilityService, lock, IS_HIDRAW_SUPPORTED);
}
@VisibleForTesting
public BrailleDisplayControllerImpl(AccessibilityService accessibilityService,
Object lock, boolean isHidrawSupported) {
mAccessibilityService = accessibilityService; mAccessibilityService = accessibilityService;
mLock = lock; mLock = lock;
mIsHidrawSupported = isHidrawSupported;
} }
@Override @Override
...@@ -113,6 +137,11 @@ final class BrailleDisplayControllerImpl implements BrailleDisplayController { ...@@ -113,6 +137,11 @@ final class BrailleDisplayControllerImpl implements BrailleDisplayController {
createConnection, createConnection,
@NonNull Executor callbackExecutor, @NonNull BrailleDisplayCallback callback) { @NonNull Executor callbackExecutor, @NonNull BrailleDisplayCallback callback) {
BrailleDisplayController.checkApiFlagIsEnabled(); BrailleDisplayController.checkApiFlagIsEnabled();
if (!mIsHidrawSupported) {
callbackExecutor.execute(() -> callback.onConnectionFailed(
BrailleDisplayCallback.FLAG_ERROR_CANNOT_ACCESS));
return;
}
if (isConnected()) { if (isConnected()) {
throw new IllegalStateException( throw new IllegalStateException(
"This service already has a connected Braille display"); "This service already has a connected Braille display");
......
...@@ -22,6 +22,7 @@ import static org.mockito.ArgumentMatchers.eq; ...@@ -22,6 +22,7 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbDevice;
import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.annotations.RequiresFlagsEnabled;
...@@ -58,6 +59,7 @@ public class BrailleDisplayControllerImplTest { ...@@ -58,6 +59,7 @@ public class BrailleDisplayControllerImplTest {
@Rule @Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
private AccessibilityService mAccessibilityService;
private BrailleDisplayController mBrailleDisplayController; private BrailleDisplayController mBrailleDisplayController;
@Mock @Mock
...@@ -76,12 +78,13 @@ public class BrailleDisplayControllerImplTest { ...@@ -76,12 +78,13 @@ public class BrailleDisplayControllerImplTest {
@Before @Before
public void test() { public void test() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
AccessibilityService accessibilityService = spy(new TestAccessibilityService()); mAccessibilityService = spy(new TestAccessibilityService());
doReturn((Executor) Runnable::run).when(accessibilityService).getMainExecutor(); doReturn((Executor) Runnable::run).when(mAccessibilityService).getMainExecutor();
doReturn(TEST_SERVICE_CONNECTION_ID).when(accessibilityService).getConnectionId(); doReturn(TEST_SERVICE_CONNECTION_ID).when(mAccessibilityService).getConnectionId();
AccessibilityInteractionClient.addConnection(TEST_SERVICE_CONNECTION_ID, AccessibilityInteractionClient.addConnection(TEST_SERVICE_CONNECTION_ID,
mAccessibilityServiceConnection, /*initializeCache=*/false); 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 // Automated CTS tests only use the BluetoothDevice version of BrailleDisplayController#connect
...@@ -104,4 +107,17 @@ public class BrailleDisplayControllerImplTest { ...@@ -104,4 +107,17 @@ public class BrailleDisplayControllerImplTest {
assertThrows(IllegalStateException.class, assertThrows(IllegalStateException.class,
() -> mBrailleDisplayController.connect(usbDevice, mBrailleDisplayCallback)); () -> 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);
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment