From fb12466e8120040b02bb9cc77b4e299fe550d8f6 Mon Sep 17 00:00:00 2001 From: Asmita Poddar Date: Fri, 24 Mar 2023 08:48:51 +0000 Subject: [PATCH] Remove InputManager#getInstance Replace all instances of InputManager with instances of InputManagerGlobal. Add the context field in InputManager. All methods previously accessed through instances of InputManager have been refactored to be accessed through InputManagerGlobal, which is a singleton class. The SystemServiceRegistry no longer returns an instance of InputManager. Bug: b/267758905 Test: Pre-submit Change-Id: I2f3db1f5f4e27be9eb11d0d307aaee16a33f014d --- .../android/app/SystemServiceRegistry.java | 6 +- .../android/hardware/input/InputManager.java | 125 +++--------------- .../hardware/input/InputManagerGlobal.java | 80 ++++++++--- core/java/android/view/VelocityTracker.java | 5 +- .../input/InputDeviceBatteryListenerTest.kt | 14 +- .../input/InputDeviceLightsManagerTest.java | 12 +- .../input/InputDeviceSensorManagerTest.java | 10 +- .../hardware/input/InputManagerTest.kt | 15 ++- .../input/KeyboardBacklightListenerTest.kt | 14 +- .../InputMethodManagerServiceTestBase.java | 4 +- .../virtual/InputManagerMockHelper.java | 7 +- .../server/input/BatteryControllerTests.kt | 18 +-- .../android/server/input/KeyRemapperTests.kt | 6 +- .../input/KeyboardBacklightControllerTests.kt | 6 +- .../input/KeyboardLayoutManagerTests.kt | 6 +- .../vibrator/InputDeviceDelegateTest.java | 9 +- .../vibrator/VibratorManagerServiceTest.java | 11 +- 17 files changed, 178 insertions(+), 170 deletions(-) diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index dbba0c6f5e50a..4f5da99d539a5 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -506,10 +506,10 @@ public final class SystemServiceRegistry { // InputManager stores its own static instance for historical purposes. registerService(Context.INPUT_SERVICE, InputManager.class, - new ServiceFetcher() { + new CachedServiceFetcher() { @Override - public InputManager getService(ContextImpl ctx) { - return InputManager.getInstance(ctx.getOuterContext()); + public InputManager createService(ContextImpl ctx) { + return new InputManager(ctx.getOuterContext()); }}); registerService(Context.DISPLAY_SERVICE, DisplayManager.class, diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java index 9cacfff4b33a2..2fec02f91e392 100644 --- a/core/java/android/hardware/input/InputManager.java +++ b/core/java/android/hardware/input/InputManager.java @@ -53,11 +53,8 @@ import android.view.WindowManager.LayoutParams; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodSubtype; -import com.android.internal.annotations.VisibleForTesting; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -73,19 +70,9 @@ 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 InputManager sInstance; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private final IInputManager mIm; - /** - * We hold a weak reference to the context to avoid leaking it indefinitely, - * since we currently store the input manager instance as a static variable that - * will outlive any context. - */ - @Nullable - private WeakReference mWeakContext; - /** * Whether a PointerIcon is shown for stylus pointers. * Obtain using {@link #isStylusPointerIconEnabled()}. @@ -255,99 +242,43 @@ public final class InputManager { */ public static final int SWITCH_STATE_ON = 1; - private static String sVelocityTrackerStrategy; + private final InputManagerGlobal mGlobal; + private final Context mContext; - private InputManagerGlobal mGlobal; - - private InputManager() { + /** @hide */ + public InputManager(Context context) { mGlobal = InputManagerGlobal.getInstance(); mIm = mGlobal.getInputManagerService(); - try { - sVelocityTrackerStrategy = mIm.getVelocityTrackerStrategy(); - } catch (RemoteException ex) { - Log.w(TAG, "Could not get VelocityTracker strategy: " + ex); - } + mContext = context; } /** * Gets an instance of the input manager. * - * @return The input manager instance. + * Warning: The usage of this method is not supported! * - * @hide - */ - @VisibleForTesting - public static InputManager resetInstance(IInputManager inputManagerService) { - synchronized (InputManager.class) { - InputManagerGlobal.resetInstance(inputManagerService); - sInstance = new InputManager(); - return sInstance; - } - } - - /** - * Clear the instance of the input manager. + * @return The input manager instance. + * Use {@link Context#getSystemService(Class)} + * to obtain the InputManager instance. * - * @hide - */ - @VisibleForTesting - public static void clearInstance() { - synchronized (InputManager.class) { - InputManagerGlobal.clearInstance(); - sInstance = null; - } - } - - /** - * Gets an instance of the input manager. + * TODO (b/277717573): Soft remove this API in version V. + * TODO (b/277039664): Migrate app usage off this API. * - * @return The input manager instance. - * @deprecated Use {@link Context#getSystemService(Class)} or {@link #getInstance(Context)} - * to obtain the InputManager instance. * @hide */ @Deprecated @UnsupportedAppUsage public static InputManager getInstance() { - return getInstance(ActivityThread.currentApplication()); + return Objects.requireNonNull(ActivityThread.currentApplication()) + .getSystemService(InputManager.class); } /** - * Gets an instance of the input manager. - * - * @return The input manager instance. - * @hide - */ - public static InputManager getInstance(Context context) { - synchronized (InputManager.class) { - if (sInstance == null) { - sInstance = new InputManager(); - } - if (sInstance.mWeakContext == null || sInstance.mWeakContext.get() == null) { - sInstance.mWeakContext = new WeakReference(context); - } - return sInstance; - } - } - - @NonNull - private Context getContext() { - WeakReference weakContext = Objects.requireNonNull(mWeakContext, - "A context is required for InputManager. Get the InputManager instance using " - + "Context#getSystemService before calling this method."); - // If we get at this point, an app calling this function could potentially expect a - // Context that has disappeared due to garbage collection. Holding a weak reference - // is a temporary solution that should be resolved before the release of a - // production version. This is being tracked in b/267758905 - return Objects.requireNonNull(weakContext.get(), "missing Context"); - } - - /** - * Get the current VelocityTracker strategy. Only works when the system has fully booted up. + * Get the current VelocityTracker strategy. * @hide */ public String getVelocityTrackerStrategy() { - return sVelocityTrackerStrategy; + return mGlobal.getVelocityTrackerStrategy(); } /** @@ -584,11 +515,7 @@ public final class InputManager { @NonNull public KeyboardLayout[] getKeyboardLayoutsForInputDevice( @NonNull InputDeviceIdentifier identifier) { - try { - return mIm.getKeyboardLayoutsForInputDevice(identifier); - } catch (RemoteException ex) { - throw ex.rethrowFromSystemServer(); - } + return mGlobal.getKeyboardLayoutsForInputDevice(identifier); } /** @@ -647,19 +574,8 @@ public final class InputManager { @RequiresPermission(Manifest.permission.SET_KEYBOARD_LAYOUT) public void setCurrentKeyboardLayoutForInputDevice(@NonNull InputDeviceIdentifier identifier, @NonNull String keyboardLayoutDescriptor) { - if (identifier == null) { - throw new IllegalArgumentException("identifier must not be null"); - } - if (keyboardLayoutDescriptor == null) { - throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null"); - } - - try { - mIm.setCurrentKeyboardLayoutForInputDevice(identifier, - keyboardLayoutDescriptor); - } catch (RemoteException ex) { - throw ex.rethrowFromSystemServer(); - } + mGlobal.setCurrentKeyboardLayoutForInputDevice(identifier, + keyboardLayoutDescriptor); } /** @@ -956,8 +872,7 @@ public final class InputManager { */ @FloatRange(from = 0, to = 1) public float getMaximumObscuringOpacityForTouch() { - Context context = ActivityThread.currentApplication(); - return InputSettings.getMaximumObscuringOpacityForTouch(context); + return InputSettings.getMaximumObscuringOpacityForTouch(mContext); } /** @@ -1123,7 +1038,7 @@ public final class InputManager { */ public boolean isStylusPointerIconEnabled() { if (mIsStylusPointerIconEnabled == null) { - mIsStylusPointerIconEnabled = getContext().getResources() + mIsStylusPointerIconEnabled = mContext.getResources() .getBoolean(com.android.internal.R.bool.config_enableStylusPointerIcon) || InputProperties.force_enable_stylus_pointer_icon().orElse(false); } diff --git a/core/java/android/hardware/input/InputManagerGlobal.java b/core/java/android/hardware/input/InputManagerGlobal.java index 701980d5f6f30..5462171be7e18 100644 --- a/core/java/android/hardware/input/InputManagerGlobal.java +++ b/core/java/android/hardware/input/InputManagerGlobal.java @@ -102,17 +102,26 @@ public final class InputManagerGlobal { private static InputManagerGlobal sInstance; + private final String mVelocityTrackerStrategy; + private final IInputManager mIm; public InputManagerGlobal(IInputManager im) { mIm = im; + String strategy = null; + try { + strategy = mIm.getVelocityTrackerStrategy(); + } catch (RemoteException ex) { + Log.w(TAG, "Could not get VelocityTracker strategy: " + ex); + } + mVelocityTrackerStrategy = strategy; } /** * Gets an instance of the input manager global singleton. * - * @return The display manager instance, may be null early in system startup - * before the display manager has been fully initialized. + * @return The input manager instance, may be null early in system startup + * before the input manager has been fully initialized. */ public static InputManagerGlobal getInstance() { synchronized (InputManagerGlobal.class) { @@ -151,6 +160,14 @@ public final class InputManagerGlobal { } } + /** + * Get the current VelocityTracker strategy. + * Only works when the system has fully booted up. + */ + public String getVelocityTrackerStrategy() { + return mVelocityTrackerStrategy; + } + /** * @see InputManager#getInputDevice(int) */ @@ -309,9 +326,7 @@ public final class InputManagerGlobal { * @see InputManager#registerInputDeviceListener */ public void registerInputDeviceListener(InputDeviceListener listener, Handler handler) { - if (listener == null) { - throw new IllegalArgumentException("listener must not be null"); - } + Objects.requireNonNull(listener, "listener must not be null"); synchronized (mInputDeviceListeners) { populateInputDevicesLocked(); @@ -407,9 +422,7 @@ public final class InputManagerGlobal { * @see InputManager#getInputDeviceByDescriptor */ InputDevice getInputDeviceByDescriptor(String descriptor) { - if (descriptor == null) { - throw new IllegalArgumentException("descriptor must not be null."); - } + Objects.requireNonNull(descriptor, "descriptor must not be null."); synchronized (mInputDeviceListeners) { populateInputDevicesLocked(); @@ -526,9 +539,8 @@ public final class InputManagerGlobal { */ void registerOnTabletModeChangedListener( OnTabletModeChangedListener listener, Handler handler) { - if (listener == null) { - throw new IllegalArgumentException("listener must not be null"); - } + Objects.requireNonNull(listener, "listener must not be null"); + synchronized (mOnTabletModeChangedListeners) { if (mOnTabletModeChangedListeners == null) { initializeTabletModeListenerLocked(); @@ -546,9 +558,8 @@ public final class InputManagerGlobal { * @see InputManager#unregisterOnTabletModeChangedListener(OnTabletModeChangedListener) */ void unregisterOnTabletModeChangedListener(OnTabletModeChangedListener listener) { - if (listener == null) { - throw new IllegalArgumentException("listener must not be null"); - } + Objects.requireNonNull(listener, "listener must not be null"); + synchronized (mOnTabletModeChangedListeners) { int idx = findOnTabletModeChangedListenerLocked(listener); if (idx >= 0) { @@ -603,7 +614,7 @@ public final class InputManagerGlobal { /** * @see InputManager#addInputDeviceBatteryListener(int, Executor, InputDeviceBatteryListener) */ - void addInputDeviceBatteryListener(int deviceId, @NonNull Executor executor, + public void addInputDeviceBatteryListener(int deviceId, @NonNull Executor executor, @NonNull InputDeviceBatteryListener listener) { Objects.requireNonNull(executor, "executor should not be null"); Objects.requireNonNull(listener, "listener should not be null"); @@ -714,7 +725,7 @@ public final class InputManagerGlobal { } /** - * @see InputManager#getInputDeviceBatteryState(int, boolean) + * @see #getInputDeviceBatteryState(int, boolean) */ @NonNull public BatteryState getInputDeviceBatteryState(int deviceId, boolean hasBattery) { @@ -876,6 +887,38 @@ public final class InputManagerGlobal { } } + /** + * @see InputManager#getKeyboardLayoutsForInputDevice(InputDeviceIdentifier) + */ + @NonNull + public KeyboardLayout[] getKeyboardLayoutsForInputDevice( + @NonNull InputDeviceIdentifier identifier) { + try { + return mIm.getKeyboardLayoutsForInputDevice(identifier); + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } + } + + /** + * @see InputManager#setCurrentKeyboardLayoutForInputDevice + * (InputDeviceIdentifier, String) + */ + @RequiresPermission(Manifest.permission.SET_KEYBOARD_LAYOUT) + public void setCurrentKeyboardLayoutForInputDevice( + @NonNull InputDeviceIdentifier identifier, + @NonNull String keyboardLayoutDescriptor) { + Objects.requireNonNull(identifier, "identifier must not be null"); + Objects.requireNonNull(keyboardLayoutDescriptor, + "keyboardLayoutDescriptor must not be null"); + try { + mIm.setCurrentKeyboardLayoutForInputDevice(identifier, + keyboardLayoutDescriptor); + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } + } + /** * @see InputDevice#getSensorManager() */ @@ -1162,9 +1205,8 @@ public final class InputManagerGlobal { */ public boolean injectInputEvent(InputEvent event, int mode, int targetUid) { - if (event == null) { - throw new IllegalArgumentException("event must not be null"); - } + Objects.requireNonNull(event , "event must not be null"); + if (mode != InputEventInjectionSync.NONE && mode != InputEventInjectionSync.WAIT_FOR_FINISHED && mode != InputEventInjectionSync.WAIT_FOR_RESULT) { diff --git a/core/java/android/view/VelocityTracker.java b/core/java/android/view/VelocityTracker.java index 4a7ed644f9e2a..4464d1918565d 100644 --- a/core/java/android/view/VelocityTracker.java +++ b/core/java/android/view/VelocityTracker.java @@ -18,7 +18,7 @@ package android.view; import android.annotation.IntDef; import android.compat.annotation.UnsupportedAppUsage; -import android.hardware.input.InputManager; +import android.hardware.input.InputManagerGlobal; import android.util.ArrayMap; import android.util.Pools.SynchronizedPool; @@ -286,7 +286,8 @@ public final class VelocityTracker { private VelocityTracker(@VelocityTrackerStrategy int strategy) { // If user has not selected a specific strategy if (strategy == VELOCITY_TRACKER_STRATEGY_DEFAULT) { - final String strategyProperty = InputManager.getInstance().getVelocityTrackerStrategy(); + final String strategyProperty = InputManagerGlobal.getInstance() + .getVelocityTrackerStrategy(); // Check if user specified strategy by overriding system property. if (strategyProperty == null || strategyProperty.isEmpty()) { mStrategy = strategy; diff --git a/core/tests/coretests/src/android/hardware/input/InputDeviceBatteryListenerTest.kt b/core/tests/coretests/src/android/hardware/input/InputDeviceBatteryListenerTest.kt index 4f27e9997cf62..fdcc7c993ddde 100644 --- a/core/tests/coretests/src/android/hardware/input/InputDeviceBatteryListenerTest.kt +++ b/core/tests/coretests/src/android/hardware/input/InputDeviceBatteryListenerTest.kt @@ -15,11 +15,14 @@ */ package android.hardware.input +import android.content.Context +import android.content.ContextWrapper import android.hardware.BatteryState import android.os.Handler import android.os.HandlerExecutor import android.os.test.TestLooper import android.platform.test.annotations.Presubmit +import androidx.test.core.app.ApplicationProvider import com.android.server.testutils.any import java.util.concurrent.Executor import kotlin.test.assertEquals @@ -32,8 +35,10 @@ import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock +import org.mockito.Mockito import org.mockito.Mockito.anyInt import org.mockito.Mockito.doAnswer +import org.mockito.Mockito.`when` import org.mockito.junit.MockitoJUnit import org.mockito.junit.MockitoJUnitRunner @@ -53,6 +58,7 @@ class InputDeviceBatteryListenerTest { private var registeredListener: IInputDeviceBatteryListener? = null private val monitoredDevices = mutableListOf() private lateinit var executor: Executor + private lateinit var context: Context private lateinit var inputManager: InputManager @Mock @@ -60,11 +66,15 @@ class InputDeviceBatteryListenerTest { @Before fun setUp() { + context = Mockito.spy(ContextWrapper(ApplicationProvider.getApplicationContext())) testLooper = TestLooper() executor = HandlerExecutor(Handler(testLooper.looper)) registeredListener = null monitoredDevices.clear() - inputManager = InputManager.resetInstance(iInputManagerMock) + InputManagerGlobal.resetInstance(iInputManagerMock) + inputManager = InputManager(context) + `when`(context.getSystemService(Mockito.eq(Context.INPUT_SERVICE))) + .thenReturn(inputManager) // Handle battery listener registration. doAnswer { @@ -102,7 +112,7 @@ class InputDeviceBatteryListenerTest { @After fun tearDown() { - InputManager.clearInstance() + InputManagerGlobal.clearInstance() } private fun notifyBatteryStateChanged( diff --git a/core/tests/coretests/src/android/hardware/input/InputDeviceLightsManagerTest.java b/core/tests/coretests/src/android/hardware/input/InputDeviceLightsManagerTest.java index bf65af32e0ac1..1e505abbc1692 100644 --- a/core/tests/coretests/src/android/hardware/input/InputDeviceLightsManagerTest.java +++ b/core/tests/coretests/src/android/hardware/input/InputDeviceLightsManagerTest.java @@ -28,9 +28,12 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.content.Context; +import android.content.ContextWrapper; import android.hardware.lights.Light; import android.hardware.lights.LightState; import android.hardware.lights.LightsManager; @@ -40,6 +43,8 @@ import android.platform.test.annotations.Presubmit; import android.util.ArrayMap; import android.view.InputDevice; +import androidx.test.InstrumentationRegistry; + import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -76,12 +81,15 @@ public class InputDeviceLightsManagerTest { @Before public void setUp() throws Exception { + final Context context = spy(new ContextWrapper(InstrumentationRegistry.getContext())); when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[]{DEVICE_ID}); when(mIInputManagerMock.getInputDevice(eq(DEVICE_ID))).thenReturn( createInputDevice(DEVICE_ID)); - mInputManager = InputManager.resetInstance(mIInputManagerMock); + InputManagerGlobal.resetInstance(mIInputManagerMock); + mInputManager = new InputManager(context); + when(context.getSystemService(eq(Context.INPUT_SERVICE))).thenReturn(mInputManager); ArrayMap lightStatesById = new ArrayMap<>(); doAnswer(invocation -> { @@ -106,7 +114,7 @@ public class InputDeviceLightsManagerTest { @After public void tearDown() { - InputManager.clearInstance(); + InputManagerGlobal.clearInstance(); } private InputDevice createInputDevice(int id) { diff --git a/core/tests/coretests/src/android/hardware/input/InputDeviceSensorManagerTest.java b/core/tests/coretests/src/android/hardware/input/InputDeviceSensorManagerTest.java index 6cf2314fea45e..b33cfdda4a09a 100644 --- a/core/tests/coretests/src/android/hardware/input/InputDeviceSensorManagerTest.java +++ b/core/tests/coretests/src/android/hardware/input/InputDeviceSensorManagerTest.java @@ -81,9 +81,9 @@ public class InputDeviceSensorManagerTest { @Before public void setUp() throws Exception { final Context context = spy(new ContextWrapper(InstrumentationRegistry.getContext())); - InputManager inputManager = InputManager.resetInstance(mIInputManagerMock); - - when(context.getSystemService(eq(Context.INPUT_SERVICE))).thenReturn(inputManager); + InputManagerGlobal.resetInstance(mIInputManagerMock); + mInputManager = new InputManager(context); + when(context.getSystemService(eq(Context.INPUT_SERVICE))).thenReturn(mInputManager); when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[]{DEVICE_ID}); @@ -98,13 +98,11 @@ public class InputDeviceSensorManagerTest { .thenReturn(true); when(mIInputManagerMock.registerSensorListener(any())).thenReturn(true); - - mInputManager = context.getSystemService(InputManager.class); } @After public void tearDown() { - InputManager.clearInstance(); + InputManagerGlobal.clearInstance(); } private class InputTestSensorEventListener implements SensorEventListener { diff --git a/core/tests/coretests/src/android/hardware/input/InputManagerTest.kt b/core/tests/coretests/src/android/hardware/input/InputManagerTest.kt index ee7a6083a0e21..2ebe362b60f2b 100644 --- a/core/tests/coretests/src/android/hardware/input/InputManagerTest.kt +++ b/core/tests/coretests/src/android/hardware/input/InputManagerTest.kt @@ -15,11 +15,14 @@ */ package android.hardware.input +import android.content.Context +import android.content.ContextWrapper import android.content.res.Resources import android.platform.test.annotations.Presubmit import android.view.Display import android.view.DisplayInfo import android.view.InputDevice +import androidx.test.core.app.ApplicationProvider import org.junit.After import org.junit.Assert.assertNotNull import org.junit.Assert.assertEquals @@ -28,6 +31,7 @@ import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock +import org.mockito.Mockito import org.mockito.Mockito.eq import org.mockito.Mockito.`when` import org.mockito.junit.MockitoJUnit @@ -52,17 +56,20 @@ class InputManagerTest { @get:Rule val rule = MockitoJUnit.rule()!! - private lateinit var inputManager: InputManager - private lateinit var devicesChangedListener: IInputDevicesChangedListener private val deviceGenerationMap = mutableMapOf() + private lateinit var context: Context + private lateinit var inputManager: InputManager @Mock private lateinit var iInputManager: IInputManager @Before fun setUp() { - inputManager = InputManager.resetInstance(iInputManager) + context = Mockito.spy(ContextWrapper(ApplicationProvider.getApplicationContext())) + InputManagerGlobal.resetInstance(iInputManager) + inputManager = InputManager(context) + `when`(context.getSystemService(eq(Context.INPUT_SERVICE))).thenReturn(inputManager) `when`(iInputManager.inputDeviceIds).then { deviceGenerationMap.keys.toIntArray() } @@ -70,7 +77,7 @@ class InputManagerTest { @After fun tearDown() { - InputManager.clearInstance() + InputManagerGlobal.clearInstance() } private fun notifyDeviceChanged( diff --git a/core/tests/coretests/src/android/hardware/input/KeyboardBacklightListenerTest.kt b/core/tests/coretests/src/android/hardware/input/KeyboardBacklightListenerTest.kt index 91d19a19379d0..ce816ab98b126 100644 --- a/core/tests/coretests/src/android/hardware/input/KeyboardBacklightListenerTest.kt +++ b/core/tests/coretests/src/android/hardware/input/KeyboardBacklightListenerTest.kt @@ -16,10 +16,13 @@ package android.hardware.input +import android.content.Context +import android.content.ContextWrapper import android.os.Handler import android.os.HandlerExecutor import android.os.test.TestLooper import android.platform.test.annotations.Presubmit +import androidx.test.core.app.ApplicationProvider import com.android.server.testutils.any import org.junit.After import org.junit.Before @@ -27,7 +30,9 @@ import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock +import org.mockito.Mockito import org.mockito.Mockito.doAnswer +import org.mockito.Mockito.`when` import org.mockito.junit.MockitoJUnit import org.mockito.junit.MockitoJUnitRunner import java.util.concurrent.Executor @@ -51,6 +56,7 @@ class KeyboardBacklightListenerTest { private lateinit var testLooper: TestLooper private var registeredListener: IKeyboardBacklightListener? = null private lateinit var executor: Executor + private lateinit var context: Context private lateinit var inputManager: InputManager @Mock @@ -58,10 +64,14 @@ class KeyboardBacklightListenerTest { @Before fun setUp() { + context = Mockito.spy(ContextWrapper(ApplicationProvider.getApplicationContext())) + InputManagerGlobal.resetInstance(iInputManagerMock) testLooper = TestLooper() executor = HandlerExecutor(Handler(testLooper.looper)) registeredListener = null - inputManager = InputManager.resetInstance(iInputManagerMock) + inputManager = InputManager(context) + `when`(context.getSystemService(Mockito.eq(Context.INPUT_SERVICE))) + .thenReturn(inputManager) // Handle keyboard backlight listener registration. doAnswer { @@ -89,7 +99,7 @@ class KeyboardBacklightListenerTest { @After fun tearDown() { - InputManager.clearInstance() + InputManagerGlobal.clearInstance() } private fun notifyKeyboardBacklightChanged( diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java index 9829e57c6ef85..bb3a4766d2498 100644 --- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java +++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java @@ -36,7 +36,7 @@ import android.content.Context; import android.content.pm.PackageManagerInternal; 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.IBinder; import android.os.Process; @@ -178,7 +178,7 @@ public class InputMethodManagerServiceTestBase { // Injecting and mocked InputMethodBindingController and InputMethod. mMockInputMethodInvoker = IInputMethodInvoker.create(mMockInputMethod); - InputManager.resetInstance(mMockIInputManager); + InputManagerGlobal.resetInstance(mMockIInputManager); synchronized (ImfLock.class) { when(mMockInputMethodBindingController.getCurMethod()) .thenReturn(mMockInputMethodInvoker); diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/InputManagerMockHelper.java b/services/tests/servicestests/src/com/android/server/companion/virtual/InputManagerMockHelper.java index 3cc6b0103322d..5cadc0a5d036a 100644 --- a/services/tests/servicestests/src/com/android/server/companion/virtual/InputManagerMockHelper.java +++ b/services/tests/servicestests/src/com/android/server/companion/virtual/InputManagerMockHelper.java @@ -25,7 +25,7 @@ import static org.mockito.Mockito.when; import android.hardware.input.IInputDevicesChangedListener; import android.hardware.input.IInputManager; -import android.hardware.input.InputManager; +import android.hardware.input.InputManagerGlobal; import android.os.RemoteException; import android.testing.TestableLooper; import android.view.InputDevice; @@ -38,7 +38,8 @@ import java.util.Objects; import java.util.stream.IntStream; /** - * A test utility class used to share the logic for setting up {@link InputManager}'s callback for + * A test utility class used to share the logic for setting up + * {@link android.hardware.input.InputManager}'s callback for * when a virtual input device being added. */ class InputManagerMockHelper { @@ -76,7 +77,7 @@ class InputManagerMockHelper { // Set a new instance of InputManager for testing that uses the IInputManager mock as the // interface to the server. - InputManager.resetInstance(mIInputManagerMock); + InputManagerGlobal.resetInstance(mIInputManagerMock); } private long handleNativeOpenInputDevice(InvocationOnMock inv) { diff --git a/services/tests/servicestests/src/com/android/server/input/BatteryControllerTests.kt b/services/tests/servicestests/src/com/android/server/input/BatteryControllerTests.kt index e1a04ad5ab7d3..416b1f49f5d9a 100644 --- a/services/tests/servicestests/src/com/android/server/input/BatteryControllerTests.kt +++ b/services/tests/servicestests/src/com/android/server/input/BatteryControllerTests.kt @@ -19,8 +19,6 @@ package com.android.server.input import android.bluetooth.BluetoothAdapter import android.bluetooth.BluetoothDevice import android.bluetooth.BluetoothManager -import android.content.Context -import android.content.ContextWrapper import android.hardware.BatteryState.STATUS_CHARGING import android.hardware.BatteryState.STATUS_DISCHARGING import android.hardware.BatteryState.STATUS_FULL @@ -31,12 +29,14 @@ import android.hardware.input.IInputDeviceBatteryState import android.hardware.input.IInputDevicesChangedListener import android.hardware.input.IInputManager import android.hardware.input.InputManager +import android.hardware.input.InputManagerGlobal import android.os.Binder import android.os.IBinder import android.os.test.TestLooper import android.platform.test.annotations.Presubmit +import android.testing.TestableContext import android.view.InputDevice -import androidx.test.InstrumentationRegistry +import androidx.test.core.app.ApplicationProvider import com.android.server.input.BatteryController.BluetoothBatteryManager import com.android.server.input.BatteryController.BluetoothBatteryManager.BluetoothBatteryListener import com.android.server.input.BatteryController.POLLING_PERIOD_MILLIS @@ -66,7 +66,6 @@ import org.mockito.Mockito.clearInvocations import org.mockito.Mockito.eq import org.mockito.Mockito.mock import org.mockito.Mockito.never -import org.mockito.Mockito.spy import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.Mockito.verifyNoMoreInteractions @@ -197,17 +196,18 @@ class BatteryControllerTests { private lateinit var bluetoothBatteryManager: BluetoothBatteryManager private lateinit var batteryController: BatteryController - private lateinit var context: Context + private lateinit var context: TestableContext private lateinit var testLooper: TestLooper private lateinit var devicesChangedListener: IInputDevicesChangedListener private val deviceGenerationMap = mutableMapOf() @Before fun setup() { - context = spy(ContextWrapper(InstrumentationRegistry.getContext())) + context = TestableContext(ApplicationProvider.getApplicationContext()) testLooper = TestLooper() - val inputManager = InputManager.resetInstance(iInputManager) - `when`(context.getSystemService(eq(Context.INPUT_SERVICE))).thenReturn(inputManager) + InputManagerGlobal.resetInstance(iInputManager) + val inputManager = InputManager(context) + context.addMockSystemService(InputManager::class.java, inputManager) `when`(iInputManager.inputDeviceIds).then { deviceGenerationMap.keys.toIntArray() } @@ -256,7 +256,7 @@ class BatteryControllerTests { @After fun tearDown() { - InputManager.clearInstance() + InputManagerGlobal.clearInstance() } @Test diff --git a/services/tests/servicestests/src/com/android/server/input/KeyRemapperTests.kt b/services/tests/servicestests/src/com/android/server/input/KeyRemapperTests.kt index 705a5da9d60f2..c10f65195307b 100644 --- a/services/tests/servicestests/src/com/android/server/input/KeyRemapperTests.kt +++ b/services/tests/servicestests/src/com/android/server/input/KeyRemapperTests.kt @@ -20,6 +20,7 @@ import android.content.Context import android.content.ContextWrapper import android.hardware.input.IInputManager import android.hardware.input.InputManager +import android.hardware.input.InputManagerGlobal import android.os.test.TestLooper import android.platform.test.annotations.Presubmit import android.provider.Settings @@ -102,7 +103,8 @@ class KeyRemapperTests { dataStore, testLooper.looper ) - val inputManager = InputManager.resetInstance(iInputManager) + InputManagerGlobal.resetInstance(iInputManager) + val inputManager = InputManager(context) Mockito.`when`(context.getSystemService(Mockito.eq(Context.INPUT_SERVICE))) .thenReturn(inputManager) Mockito.`when`(iInputManager.inputDeviceIds).thenReturn(intArrayOf(DEVICE_ID)) @@ -110,7 +112,7 @@ class KeyRemapperTests { @After fun tearDown() { - InputManager.clearInstance() + InputManagerGlobal.clearInstance() } @Test diff --git a/services/tests/servicestests/src/com/android/server/input/KeyboardBacklightControllerTests.kt b/services/tests/servicestests/src/com/android/server/input/KeyboardBacklightControllerTests.kt index 00eb80d21f474..0f4d4e874a2eb 100644 --- a/services/tests/servicestests/src/com/android/server/input/KeyboardBacklightControllerTests.kt +++ b/services/tests/servicestests/src/com/android/server/input/KeyboardBacklightControllerTests.kt @@ -23,6 +23,7 @@ import android.hardware.input.IInputManager import android.hardware.input.IKeyboardBacklightListener import android.hardware.input.IKeyboardBacklightState import android.hardware.input.InputManager +import android.hardware.input.InputManagerGlobal import android.hardware.lights.Light import android.os.UEventObserver import android.os.test.TestLooper @@ -116,7 +117,8 @@ class KeyboardBacklightControllerTests { testLooper = TestLooper() keyboardBacklightController = KeyboardBacklightController(context, native, dataStore, testLooper.looper) - val inputManager = InputManager.resetInstance(iInputManager) + InputManagerGlobal.resetInstance(iInputManager) + val inputManager = InputManager(context) `when`(context.getSystemService(eq(Context.INPUT_SERVICE))).thenReturn(inputManager) `when`(iInputManager.inputDeviceIds).thenReturn(intArrayOf(DEVICE_ID)) `when`(native.setLightColor(anyInt(), anyInt(), anyInt())).then { @@ -131,7 +133,7 @@ class KeyboardBacklightControllerTests { @After fun tearDown() { - InputManager.clearInstance() + InputManagerGlobal.clearInstance() } @Test diff --git a/services/tests/servicestests/src/com/android/server/input/KeyboardLayoutManagerTests.kt b/services/tests/servicestests/src/com/android/server/input/KeyboardLayoutManagerTests.kt index 7729fa29667b8..ea3f3bca32ff8 100644 --- a/services/tests/servicestests/src/com/android/server/input/KeyboardLayoutManagerTests.kt +++ b/services/tests/servicestests/src/com/android/server/input/KeyboardLayoutManagerTests.kt @@ -25,6 +25,7 @@ import android.content.pm.ResolveInfo import android.content.pm.ServiceInfo import android.hardware.input.IInputManager import android.hardware.input.InputManager +import android.hardware.input.InputManagerGlobal import android.hardware.input.KeyboardLayout import android.icu.util.ULocale import android.os.Bundle @@ -144,7 +145,8 @@ class KeyboardLayoutManagerTests { } private fun setupInputDevices() { - val inputManager = InputManager.resetInstance(iInputManager) + InputManagerGlobal.resetInstance(iInputManager) + val inputManager = InputManager(context) Mockito.`when`(context.getSystemService(Mockito.eq(Context.INPUT_SERVICE))) .thenReturn(inputManager) @@ -852,4 +854,4 @@ class KeyboardLayoutManagerTests { ) } } -} \ No newline at end of file +} diff --git a/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java b/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java index 07b434538c7ba..2ab79fcdeae79 100644 --- a/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java +++ b/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java @@ -77,16 +77,19 @@ public class InputDeviceDelegateTest { private TestLooper mTestLooper; private ContextWrapper mContextSpy; + private InputManager mInputManager; private InputDeviceDelegate mInputDeviceDelegate; private IInputDevicesChangedListener mIInputDevicesChangedListener; @Before public void setUp() throws Exception { mTestLooper = new TestLooper(); - InputManager inputManager = InputManager.resetInstance(mIInputManagerMock); + InputManagerGlobal.resetInstance(mIInputManagerMock); mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext())); - when(mContextSpy.getSystemService(eq(Context.INPUT_SERVICE))).thenReturn(inputManager); + mInputManager = new InputManager(mContextSpy); + when(mContextSpy.getSystemService(eq(Context.INPUT_SERVICE))) + .thenReturn(mInputManager); doAnswer(invocation -> mIInputDevicesChangedListener = invocation.getArgument(0)) .when(mIInputManagerMock).registerInputDevicesChangedListener(any()); @@ -97,7 +100,7 @@ public class InputDeviceDelegateTest { @After public void tearDown() throws Exception { - InputManager.clearInstance(); + InputManagerGlobal.clearInstance(); } @Test diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java index 6bd280aae11d9..f158ce14549f7 100644 --- a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java @@ -47,6 +47,7 @@ import android.content.ContextWrapper; import android.content.pm.PackageManagerInternal; import android.hardware.input.IInputManager; import android.hardware.input.InputManager; +import android.hardware.input.InputManagerGlobal; import android.hardware.vibrator.IVibrator; import android.hardware.vibrator.IVibratorManager; import android.media.AudioAttributes; @@ -184,11 +185,13 @@ public class VibratorManagerServiceTest { private VirtualDeviceManagerInternal.AppsOnVirtualDeviceListener mRegisteredAppsOnVirtualDeviceListener; + private InputManager mInputManager; + @Before public void setUp() throws Exception { mTestLooper = new TestLooper(); mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext())); - InputManager inputManager = InputManager.resetInstance(mIInputManagerMock); + InputManagerGlobal.resetInstance(mIInputManagerMock); mVibrationConfig = new VibrationConfig(mContextSpy.getResources()); ContentResolver contentResolver = mSettingsProviderRule.mockContentResolver(mContextSpy); @@ -196,7 +199,10 @@ public class VibratorManagerServiceTest { mVibrator = new FakeVibrator(mContextSpy); when(mContextSpy.getSystemService(eq(Context.VIBRATOR_SERVICE))).thenReturn(mVibrator); - when(mContextSpy.getSystemService(eq(Context.INPUT_SERVICE))).thenReturn(inputManager); + + mInputManager = new InputManager(mContextSpy); + when(mContextSpy.getSystemService(eq(Context.INPUT_SERVICE))) + .thenReturn(mInputManager); when(mContextSpy.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOpsManagerMock); when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[0]); when(mPackageManagerInternalMock.getSystemUiServiceComponent()) @@ -259,6 +265,7 @@ public class VibratorManagerServiceTest { LocalServices.removeServiceForTest(PowerManagerInternal.class); // Ignore potential exceptions about the looper having never dispatched any messages. mTestLooper.stopAutoDispatchAndIgnoreExceptions(); + InputManagerGlobal.clearInstance(); } private VibratorManagerService createSystemReadyService() {