Merge "Move InputDevicesChangedListener & other functions to InputManagerGlobal" into udc-dev

This commit is contained in:
Asmita Poddar
2023-03-14 11:18:58 +00:00
committed by Android (Google) Code Review
7 changed files with 326 additions and 255 deletions

View File

@@ -88,10 +88,6 @@ public final class InputManager {
// To enable these logs, run: 'adb shell setprop log.tag.InputManager DEBUG' (requires restart)
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final int MSG_DEVICE_ADDED = 1;
private static final int MSG_DEVICE_REMOVED = 2;
private static final int MSG_DEVICE_CHANGED = 3;
private static InputManager sInstance;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
@@ -112,12 +108,6 @@ public final class InputManager {
@Nullable
private Boolean mIsStylusPointerIconEnabled = null;
// Guarded by mInputDevicesLock
private final Object mInputDevicesLock = new Object();
private SparseArray<InputDevice> mInputDevices;
private InputDevicesChangedListener mInputDevicesChangedListener;
private final ArrayList<InputDeviceListenerDelegate> mInputDeviceListeners = new ArrayList<>();
// Guarded by mTabletModeLock
private final Object mTabletModeLock = new Object();
@SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
@@ -403,27 +393,7 @@ public final class InputManager {
*/
@Nullable
public InputDevice getInputDevice(int id) {
synchronized (mInputDevicesLock) {
populateInputDevicesLocked();
int index = mInputDevices.indexOfKey(id);
if (index < 0) {
return null;
}
InputDevice inputDevice = mInputDevices.valueAt(index);
if (inputDevice == null) {
try {
inputDevice = mIm.getInputDevice(id);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
if (inputDevice != null) {
mInputDevices.setValueAt(index, inputDevice);
}
}
return inputDevice;
}
return mGlobal.getInputDevice(id);
}
/**
@@ -433,34 +403,7 @@ public final class InputManager {
* @hide
*/
public InputDevice getInputDeviceByDescriptor(String descriptor) {
if (descriptor == null) {
throw new IllegalArgumentException("descriptor must not be null.");
}
synchronized (mInputDevicesLock) {
populateInputDevicesLocked();
int numDevices = mInputDevices.size();
for (int i = 0; i < numDevices; i++) {
InputDevice inputDevice = mInputDevices.valueAt(i);
if (inputDevice == null) {
int id = mInputDevices.keyAt(i);
try {
inputDevice = mIm.getInputDevice(id);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
if (inputDevice == null) {
continue;
}
mInputDevices.setValueAt(i, inputDevice);
}
if (descriptor.equals(inputDevice.getDescriptor())) {
return inputDevice;
}
}
return null;
}
return mGlobal.getInputDeviceByDescriptor(descriptor);
}
/**
@@ -468,16 +411,7 @@ public final class InputManager {
* @return The input device ids.
*/
public int[] getInputDeviceIds() {
synchronized (mInputDevicesLock) {
populateInputDevicesLocked();
final int count = mInputDevices.size();
final int[] ids = new int[count];
for (int i = 0; i < count; i++) {
ids[i] = mInputDevices.keyAt(i);
}
return ids;
}
return mGlobal.getInputDeviceIds();
}
/**
@@ -547,17 +481,7 @@ public final class InputManager {
* @see #unregisterInputDeviceListener
*/
public void registerInputDeviceListener(InputDeviceListener listener, Handler handler) {
if (listener == null) {
throw new IllegalArgumentException("listener must not be null");
}
synchronized (mInputDevicesLock) {
populateInputDevicesLocked();
int index = findInputDeviceListenerLocked(listener);
if (index < 0) {
mInputDeviceListeners.add(new InputDeviceListenerDelegate(listener, handler));
}
}
mGlobal.registerInputDeviceListener(listener, handler);
}
/**
@@ -568,28 +492,7 @@ public final class InputManager {
* @see #registerInputDeviceListener
*/
public void unregisterInputDeviceListener(InputDeviceListener listener) {
if (listener == null) {
throw new IllegalArgumentException("listener must not be null");
}
synchronized (mInputDevicesLock) {
int index = findInputDeviceListenerLocked(listener);
if (index >= 0) {
InputDeviceListenerDelegate d = mInputDeviceListeners.get(index);
d.removeCallbacksAndMessages(null);
mInputDeviceListeners.remove(index);
}
}
}
private int findInputDeviceListenerLocked(InputDeviceListener listener) {
final int numListeners = mInputDeviceListeners.size();
for (int i = 0; i < numListeners; i++) {
if (mInputDeviceListeners.get(i).mListener == listener) {
return i;
}
}
return -1;
mGlobal.unregisterInputDeviceListener(listener);
}
/**
@@ -1543,120 +1446,9 @@ public final class InputManager {
*/
@Nullable
public HostUsiVersion getHostUsiVersion(@NonNull Display display) {
Objects.requireNonNull(display, "display should not be null");
// Return the first valid USI version reported by any input device associated with
// the display.
synchronized (mInputDevicesLock) {
populateInputDevicesLocked();
for (int i = 0; i < mInputDevices.size(); i++) {
final InputDevice device = getInputDevice(mInputDevices.keyAt(i));
if (device != null && device.getAssociatedDisplayId() == display.getDisplayId()) {
if (device.getHostUsiVersion() != null) {
return device.getHostUsiVersion();
}
}
}
}
// If there are no input devices that report a valid USI version, see if there is a config
// that specifies the USI version for the display. This is to handle cases where the USI
// input device is not registered by the kernel/driver all the time.
try {
return mIm.getHostUsiVersionFromDisplayConfig(display.getDisplayId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
return mGlobal.getHostUsiVersion(display);
}
private void populateInputDevicesLocked() {
if (mInputDevicesChangedListener == null) {
final InputDevicesChangedListener listener = new InputDevicesChangedListener();
try {
mIm.registerInputDevicesChangedListener(listener);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
mInputDevicesChangedListener = listener;
}
if (mInputDevices == null) {
final int[] ids;
try {
ids = mIm.getInputDeviceIds();
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
mInputDevices = new SparseArray<>();
for (int id : ids) {
mInputDevices.put(id, null);
}
}
}
private void onInputDevicesChanged(int[] deviceIdAndGeneration) {
if (DEBUG) {
Log.d(TAG, "Received input devices changed.");
}
synchronized (mInputDevicesLock) {
for (int i = mInputDevices.size(); --i > 0; ) {
final int deviceId = mInputDevices.keyAt(i);
if (!containsDeviceId(deviceIdAndGeneration, deviceId)) {
if (DEBUG) {
Log.d(TAG, "Device removed: " + deviceId);
}
mInputDevices.removeAt(i);
sendMessageToInputDeviceListenersLocked(MSG_DEVICE_REMOVED, deviceId);
}
}
for (int i = 0; i < deviceIdAndGeneration.length; i += 2) {
final int deviceId = deviceIdAndGeneration[i];
int index = mInputDevices.indexOfKey(deviceId);
if (index >= 0) {
final InputDevice device = mInputDevices.valueAt(index);
if (device != null) {
final int generation = deviceIdAndGeneration[i + 1];
if (device.getGeneration() != generation) {
if (DEBUG) {
Log.d(TAG, "Device changed: " + deviceId);
}
mInputDevices.setValueAt(index, null);
sendMessageToInputDeviceListenersLocked(MSG_DEVICE_CHANGED, deviceId);
}
}
} else {
if (DEBUG) {
Log.d(TAG, "Device added: " + deviceId);
}
mInputDevices.put(deviceId, null);
sendMessageToInputDeviceListenersLocked(MSG_DEVICE_ADDED, deviceId);
}
}
}
}
private void sendMessageToInputDeviceListenersLocked(int what, int deviceId) {
final int numListeners = mInputDeviceListeners.size();
for (int i = 0; i < numListeners; i++) {
InputDeviceListenerDelegate listener = mInputDeviceListeners.get(i);
listener.sendMessage(listener.obtainMessage(what, deviceId, 0));
}
}
private static boolean containsDeviceId(int[] deviceIdAndGeneration, int deviceId) {
for (int i = 0; i < deviceIdAndGeneration.length; i += 2) {
if (deviceIdAndGeneration[i] == deviceId) {
return true;
}
}
return false;
}
private void onTabletModeChanged(long whenNanos, boolean inTabletMode) {
if (DEBUG) {
Log.d(TAG, "Received tablet mode changed: "
@@ -2149,7 +1941,7 @@ public final class InputManager {
public interface InputDeviceListener {
/**
* Called whenever an input device has been added to the system.
* Use {@link InputManager#getInputDevice} to get more information about the device.
* Use {@link InputManagerGlobal#getInputDevice} to get more information about the device.
*
* @param deviceId The id of the input device that was added.
*/
@@ -2172,37 +1964,6 @@ public final class InputManager {
void onInputDeviceChanged(int deviceId);
}
private final class InputDevicesChangedListener extends IInputDevicesChangedListener.Stub {
@Override
public void onInputDevicesChanged(int[] deviceIdAndGeneration) throws RemoteException {
InputManager.this.onInputDevicesChanged(deviceIdAndGeneration);
}
}
private static final class InputDeviceListenerDelegate extends Handler {
public final InputDeviceListener mListener;
public InputDeviceListenerDelegate(InputDeviceListener listener, Handler handler) {
super(handler != null ? handler.getLooper() : Looper.myLooper());
mListener = listener;
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_DEVICE_ADDED:
mListener.onInputDeviceAdded(msg.arg1);
break;
case MSG_DEVICE_REMOVED:
mListener.onInputDeviceRemoved(msg.arg1);
break;
case MSG_DEVICE_CHANGED:
mListener.onInputDeviceChanged(msg.arg1);
break;
}
}
}
/** @hide */
public interface OnTabletModeChangedListener {
/**

View File

@@ -16,9 +16,25 @@
package android.hardware.input;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.hardware.input.InputManager.InputDeviceListener;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
import android.util.SparseArray;
import android.view.Display;
import android.view.InputDevice;
import com.android.internal.annotations.GuardedBy;
import java.util.ArrayList;
import java.util.Objects;
/**
* Manages communication with the input manager service on behalf of
@@ -28,6 +44,20 @@ import android.os.ServiceManager;
*/
public final class InputManagerGlobal {
private static final String TAG = "InputManagerGlobal";
// To enable these logs, run: 'adb shell setprop log.tag.InputManagerGlobal DEBUG'
// (requires restart)
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final int MSG_DEVICE_ADDED = 1;
private static final int MSG_DEVICE_REMOVED = 2;
private static final int MSG_DEVICE_CHANGED = 3;
@GuardedBy("mInputDeviceListeners")
@Nullable private SparseArray<InputDevice> mInputDevices;
@GuardedBy("mInputDeviceListeners")
@Nullable private InputDevicesChangedListener mInputDevicesChangedListener;
@GuardedBy("mInputDeviceListeners")
private final ArrayList<InputDeviceListenerDelegate> mInputDeviceListeners = new ArrayList<>();
private static InputManagerGlobal sInstance;
@@ -79,4 +109,280 @@ public final class InputManagerGlobal {
sInstance = null;
}
}
/**
* @see InputManager#getInputDevice(int)
*/
@Nullable
public InputDevice getInputDevice(int id) {
synchronized (mInputDeviceListeners) {
populateInputDevicesLocked();
int index = mInputDevices.indexOfKey(id);
if (index < 0) {
return null;
}
InputDevice inputDevice = mInputDevices.valueAt(index);
if (inputDevice == null) {
try {
inputDevice = mIm.getInputDevice(id);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
if (inputDevice != null) {
mInputDevices.setValueAt(index, inputDevice);
}
}
return inputDevice;
}
}
@GuardedBy("mInputDeviceListeners")
private void populateInputDevicesLocked() {
if (mInputDevicesChangedListener == null) {
final InputDevicesChangedListener
listener = new InputDevicesChangedListener();
try {
mIm.registerInputDevicesChangedListener(listener);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
mInputDevicesChangedListener = listener;
}
if (mInputDevices == null) {
final int[] ids;
try {
ids = mIm.getInputDeviceIds();
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
mInputDevices = new SparseArray<>();
for (int id : ids) {
mInputDevices.put(id, null);
}
}
}
private final class InputDevicesChangedListener extends IInputDevicesChangedListener.Stub {
@Override
public void onInputDevicesChanged(int[] deviceIdAndGeneration) throws RemoteException {
InputManagerGlobal.this.onInputDevicesChanged(deviceIdAndGeneration);
}
}
private void onInputDevicesChanged(int[] deviceIdAndGeneration) {
if (DEBUG) {
Log.d(TAG, "Received input devices changed.");
}
synchronized (mInputDeviceListeners) {
for (int i = mInputDevices.size(); --i > 0; ) {
final int deviceId = mInputDevices.keyAt(i);
if (!containsDeviceId(deviceIdAndGeneration, deviceId)) {
if (DEBUG) {
Log.d(TAG, "Device removed: " + deviceId);
}
mInputDevices.removeAt(i);
sendMessageToInputDeviceListenersLocked(MSG_DEVICE_REMOVED, deviceId);
}
}
for (int i = 0; i < deviceIdAndGeneration.length; i += 2) {
final int deviceId = deviceIdAndGeneration[i];
int index = mInputDevices.indexOfKey(deviceId);
if (index >= 0) {
final InputDevice device = mInputDevices.valueAt(index);
if (device != null) {
final int generation = deviceIdAndGeneration[i + 1];
if (device.getGeneration() != generation) {
if (DEBUG) {
Log.d(TAG, "Device changed: " + deviceId);
}
mInputDevices.setValueAt(index, null);
sendMessageToInputDeviceListenersLocked(MSG_DEVICE_CHANGED, deviceId);
}
}
} else {
if (DEBUG) {
Log.d(TAG, "Device added: " + deviceId);
}
mInputDevices.put(deviceId, null);
sendMessageToInputDeviceListenersLocked(MSG_DEVICE_ADDED, deviceId);
}
}
}
}
private static final class InputDeviceListenerDelegate extends Handler {
public final InputDeviceListener mListener;
InputDeviceListenerDelegate(InputDeviceListener listener, Handler handler) {
super(handler != null ? handler.getLooper() : Looper.myLooper());
mListener = listener;
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_DEVICE_ADDED:
mListener.onInputDeviceAdded(msg.arg1);
break;
case MSG_DEVICE_REMOVED:
mListener.onInputDeviceRemoved(msg.arg1);
break;
case MSG_DEVICE_CHANGED:
mListener.onInputDeviceChanged(msg.arg1);
break;
}
}
}
private static boolean containsDeviceId(int[] deviceIdAndGeneration, int deviceId) {
for (int i = 0; i < deviceIdAndGeneration.length; i += 2) {
if (deviceIdAndGeneration[i] == deviceId) {
return true;
}
}
return false;
}
@GuardedBy("mInputDeviceListeners")
private void sendMessageToInputDeviceListenersLocked(int what, int deviceId) {
final int numListeners = mInputDeviceListeners.size();
for (int i = 0; i < numListeners; i++) {
InputDeviceListenerDelegate listener = mInputDeviceListeners.get(i);
listener.sendMessage(listener.obtainMessage(what, deviceId, 0));
}
}
/**
* @see InputManager#registerInputDeviceListener
*/
public void registerInputDeviceListener(InputDeviceListener listener, Handler handler) {
if (listener == null) {
throw new IllegalArgumentException("listener must not be null");
}
synchronized (mInputDeviceListeners) {
populateInputDevicesLocked();
int index = findInputDeviceListenerLocked(listener);
if (index < 0) {
mInputDeviceListeners.add(new InputDeviceListenerDelegate(listener, handler));
}
}
}
/**
* @see InputManager#unregisterInputDeviceListener
*/
public void unregisterInputDeviceListener(InputDeviceListener listener) {
if (listener == null) {
throw new IllegalArgumentException("listener must not be null");
}
synchronized (mInputDeviceListeners) {
int index = findInputDeviceListenerLocked(listener);
if (index >= 0) {
InputDeviceListenerDelegate d = mInputDeviceListeners.get(index);
d.removeCallbacksAndMessages(null);
mInputDeviceListeners.remove(index);
}
}
}
@GuardedBy("mInputDeviceListeners")
private int findInputDeviceListenerLocked(InputDeviceListener listener) {
final int numListeners = mInputDeviceListeners.size();
for (int i = 0; i < numListeners; i++) {
if (mInputDeviceListeners.get(i).mListener == listener) {
return i;
}
}
return -1;
}
/**
* @see InputManager#getInputDeviceIds
*/
public int[] getInputDeviceIds() {
synchronized (mInputDeviceListeners) {
populateInputDevicesLocked();
final int count = mInputDevices.size();
final int[] ids = new int[count];
for (int i = 0; i < count; i++) {
ids[i] = mInputDevices.keyAt(i);
}
return ids;
}
}
/**
* @see InputManager#getInputDeviceByDescriptor
*/
InputDevice getInputDeviceByDescriptor(String descriptor) {
if (descriptor == null) {
throw new IllegalArgumentException("descriptor must not be null.");
}
synchronized (mInputDeviceListeners) {
populateInputDevicesLocked();
int numDevices = mInputDevices.size();
for (int i = 0; i < numDevices; i++) {
InputDevice inputDevice = mInputDevices.valueAt(i);
if (inputDevice == null) {
int id = mInputDevices.keyAt(i);
try {
inputDevice = mIm.getInputDevice(id);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
if (inputDevice == null) {
continue;
}
mInputDevices.setValueAt(i, inputDevice);
}
if (descriptor.equals(inputDevice.getDescriptor())) {
return inputDevice;
}
}
return null;
}
}
/**
* @see InputManager#getHostUsiVersion
*/
@Nullable
HostUsiVersion getHostUsiVersion(@NonNull Display display) {
Objects.requireNonNull(display, "display should not be null");
// Return the first valid USI version reported by any input device associated with
// the display.
synchronized (mInputDeviceListeners) {
populateInputDevicesLocked();
for (int i = 0; i < mInputDevices.size(); i++) {
final InputDevice device = getInputDevice(mInputDevices.keyAt(i));
if (device != null && device.getAssociatedDisplayId() == display.getDisplayId()) {
if (device.getHostUsiVersion() != null) {
return device.getHostUsiVersion();
}
}
}
}
// If there are no input devices that report a valid USI version, see if there is a config
// that specifies the USI version for the display. This is to handle cases where the USI
// input device is not registered by the kernel/driver all the time.
try {
return mIm.getHostUsiVersionFromDisplayConfig(display.getDisplayId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}

View File

@@ -29,6 +29,7 @@ import android.hardware.SensorManager;
import android.hardware.input.HostUsiVersion;
import android.hardware.input.InputDeviceIdentifier;
import android.hardware.input.InputManager;
import android.hardware.input.InputManagerGlobal;
import android.hardware.lights.LightsManager;
import android.icu.util.ULocale;
import android.os.Build;
@@ -742,7 +743,7 @@ public final class InputDevice implements Parcelable {
*/
@Nullable
public static InputDevice getDevice(int id) {
return InputManager.getInstance().getInputDevice(id);
return InputManagerGlobal.getInstance().getInputDevice(id);
}
/**
@@ -750,7 +751,7 @@ public final class InputDevice implements Parcelable {
* @return The input device ids.
*/
public static int[] getDeviceIds() {
return InputManager.getInstance().getInputDeviceIds();
return InputManagerGlobal.getInstance().getInputDeviceIds();
}
/**

View File

@@ -28,6 +28,7 @@ import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Rect;
import android.hardware.input.InputManager;
import android.hardware.input.InputManagerGlobal;
import android.os.Build;
import android.os.Bundle;
import android.os.RemoteException;
@@ -1188,7 +1189,7 @@ public class ViewConfiguration {
}
private static boolean isInputDeviceInfoValid(int id, int axis, int source) {
InputDevice device = InputManager.getInstance().getInputDevice(id);
InputDevice device = InputManagerGlobal.getInstance().getInputDevice(id);
return device != null && device.getMotionRange(axis, source) != null;
}

View File

@@ -23,6 +23,7 @@ import android.graphics.PointF;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.input.InputDeviceIdentifier;
import android.hardware.input.InputManager;
import android.hardware.input.InputManagerGlobal;
import android.hardware.input.VirtualKeyEvent;
import android.hardware.input.VirtualMouseButtonEvent;
import android.hardware.input.VirtualMouseRelativeEvent;
@@ -686,7 +687,7 @@ class InputController {
mListener = new InputManager.InputDeviceListener() {
@Override
public void onInputDeviceAdded(int deviceId) {
final InputDevice device = InputManager.getInstance().getInputDevice(
final InputDevice device = InputManagerGlobal.getInstance().getInputDevice(
deviceId);
Objects.requireNonNull(device, "Newly added input device was null.");
if (!device.getName().equals(deviceName)) {

View File

@@ -28,7 +28,7 @@ import static org.mockito.Mockito.verify;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.input.IInputManager;
import android.hardware.input.InputManager;
import android.hardware.input.InputManagerGlobal;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
@@ -109,7 +109,7 @@ public class InputControllerTest {
device1Id).isNotEqualTo(device2Id);
int[] deviceIds = InputManager.getInstance().getInputDeviceIds();
int[] deviceIds = InputManagerGlobal.getInstance().getInputDeviceIds();
assertWithMessage("InputManager's deviceIds list should contain id of device 1").that(
deviceIds).asList().contains(device1Id);
assertWithMessage("InputManager's deviceIds list should contain id of device 2").that(
@@ -153,7 +153,7 @@ public class InputControllerTest {
deviceToken, /* displayId= */ 1, /* touchpadHeight= */ 50, /* touchpadWidth= */ 50);
int deviceId = mInputController.getInputDeviceId(deviceToken);
int[] deviceIds = InputManager.getInstance().getInputDeviceIds();
int[] deviceIds = InputManagerGlobal.getInstance().getInputDeviceIds();
assertWithMessage("InputManager's deviceIds list should contain id of the device").that(
deviceIds).asList().contains(deviceId);

View File

@@ -34,6 +34,7 @@ import android.content.ContextWrapper;
import android.hardware.input.IInputDevicesChangedListener;
import android.hardware.input.IInputManager;
import android.hardware.input.InputManager;
import android.hardware.input.InputManagerGlobal;
import android.os.CombinedVibration;
import android.os.Handler;
import android.os.Process;
@@ -82,8 +83,8 @@ public class InputDeviceDelegateTest {
@Before
public void setUp() throws Exception {
mTestLooper = new TestLooper();
mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
InputManager inputManager = InputManager.resetInstance(mIInputManagerMock);
mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
when(mContextSpy.getSystemService(eq(Context.INPUT_SERVICE))).thenReturn(inputManager);
doAnswer(invocation -> mIInputDevicesChangedListener = invocation.getArgument(0))
@@ -314,7 +315,7 @@ public class InputDeviceDelegateTest {
deviceIdsAndGenerations[i + 1] = 2; // update by increasing it's generation to 2.
}
// Force initialization of mIInputDevicesChangedListener, if it still haven't
InputManager.getInstance().getInputDeviceIds();
InputManagerGlobal.getInstance().getInputDeviceIds();
mIInputDevicesChangedListener.onInputDevicesChanged(deviceIdsAndGenerations);
// Makes sure all callbacks from InputDeviceDelegate are executed.
mTestLooper.dispatchAll();