diff options
| author | 2024-08-21 00:32:09 +0000 | |
|---|---|---|
| committer | 2024-09-04 15:40:27 +0000 | |
| commit | b204fdee2eeb3035346eda368bfb05e91bb48230 (patch) | |
| tree | 14ee06a51786ecb801cb4aa58485adfc6a49d046 | |
| parent | ef3e2c83d4a8378d0b8e143591fe108d6b3aa29b (diff) | |
Guarding the touchpad visualiser window with the flag and settings
Guarded both the touchpad showDebugView and hideDebugView with both the touchpad visualizer flag and its developer option value in which both of them needs to be enabled in order to show the touchpad visualizer window.
Test: $ atest TouchpadDebugViewControllerTests.java
Test: Manual testing by flashing device and connecting the touchpad to see if the visualizer window will appear in both the cases when the toggle is enabled and when it is disabled
Bug: 359801523
Bug: 359212358
Flag: com.android.hardware.input.touchpad_visualizer
Change-Id: I6634a98f1af22175023fb474128514ced10a671c
4 files changed, 268 insertions, 39 deletions
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 1220542af02a..52bf5379d367 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -597,9 +597,6 @@ public class InputManagerService extends IInputManager.Stub mKeyRemapper.systemRunning(); mPointerIconCache.systemRunning(); mKeyboardGlyphManager.systemRunning(); - if (mTouchpadDebugViewController != null) { - mTouchpadDebugViewController.systemRunning(); - } } private void reloadDeviceAliases() { @@ -3340,6 +3337,13 @@ public class InputManagerService extends IInputManager.Stub } } + void updateTouchpadVisualizerEnabled(boolean enabled) { + mNative.setShouldNotifyTouchpadHardwareState(enabled); + if (mTouchpadDebugViewController != null) { + mTouchpadDebugViewController.updateTouchpadVisualizerEnabled(enabled); + } + } + void updatePointerLocationEnabled(boolean enabled) { mWindowManagerCallbacks.notifyPointerLocationChanged(enabled); } diff --git a/services/core/java/com/android/server/input/InputSettingsObserver.java b/services/core/java/com/android/server/input/InputSettingsObserver.java index ef61d02cd999..835fb72e524a 100644 --- a/services/core/java/com/android/server/input/InputSettingsObserver.java +++ b/services/core/java/com/android/server/input/InputSettingsObserver.java @@ -180,7 +180,7 @@ class InputSettingsObserver extends ContentObserver { } private void updateTouchpadHardwareStateNotificationsEnabled() { - mNative.setShouldNotifyTouchpadHardwareState(InputSettings.useTouchpadVisualizer(mContext)); + mService.updateTouchpadVisualizerEnabled(InputSettings.useTouchpadVisualizer(mContext)); } private void updateTouchpadRightClickZoneEnabled() { diff --git a/services/core/java/com/android/server/input/debug/TouchpadDebugViewController.java b/services/core/java/com/android/server/input/debug/TouchpadDebugViewController.java index 1e59167fdb9f..c28e74a02071 100644 --- a/services/core/java/com/android/server/input/debug/TouchpadDebugViewController.java +++ b/services/core/java/com/android/server/input/debug/TouchpadDebugViewController.java @@ -18,12 +18,10 @@ package com.android.server.input.debug; import android.annotation.Nullable; import android.content.Context; -import android.hardware.display.DisplayManager; import android.hardware.input.InputManager; import android.os.Handler; import android.os.Looper; import android.util.Slog; -import android.view.Display; import android.view.InputDevice; import android.view.WindowManager; @@ -32,7 +30,7 @@ import com.android.server.input.TouchpadHardwareProperties; import java.util.Objects; -public class TouchpadDebugViewController { +public class TouchpadDebugViewController implements InputManager.InputDeviceListener { private static final String TAG = "TouchpadDebugView"; @@ -43,49 +41,61 @@ public class TouchpadDebugViewController { private TouchpadDebugView mTouchpadDebugView; private final InputManagerService mInputManagerService; + private boolean mTouchpadVisualizerEnabled = false; public TouchpadDebugViewController(Context context, Looper looper, - InputManagerService inputManagerService) { - final DisplayManager displayManager = Objects.requireNonNull( - context.getSystemService(DisplayManager.class)); - final Display defaultDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY); - mContext = context.createDisplayContext(defaultDisplay); + InputManagerService inputManagerService) { + //TODO(b/363979581): Handle multi-display scenarios + mContext = context; mHandler = new Handler(looper); mInputManagerService = inputManagerService; } - public void systemRunning() { + @Override + public void onInputDeviceAdded(int deviceId) { final InputManager inputManager = Objects.requireNonNull( mContext.getSystemService(InputManager.class)); - inputManager.registerInputDeviceListener(mInputDeviceListener, mHandler); - for (int deviceId : inputManager.getInputDeviceIds()) { - mInputDeviceListener.onInputDeviceAdded(deviceId); + InputDevice inputDevice = inputManager.getInputDevice(deviceId); + + if (Objects.requireNonNull(inputDevice).supportsSource( + InputDevice.SOURCE_TOUCHPAD | InputDevice.SOURCE_MOUSE) + && mTouchpadVisualizerEnabled) { + showDebugView(deviceId); } } - private final InputManager.InputDeviceListener mInputDeviceListener = - new InputManager.InputDeviceListener() { - @Override - public void onInputDeviceAdded(int deviceId) { - final InputManager inputManager = Objects.requireNonNull( - mContext.getSystemService(InputManager.class)); - InputDevice inputDevice = inputManager.getInputDevice(deviceId); - - if (Objects.requireNonNull(inputDevice).supportsSource( - InputDevice.SOURCE_TOUCHPAD | InputDevice.SOURCE_MOUSE)) { - showDebugView(deviceId); - } - } - - @Override - public void onInputDeviceRemoved(int deviceId) { - hideDebugView(deviceId); - } - - @Override - public void onInputDeviceChanged(int deviceId) { - } - }; + @Override + public void onInputDeviceRemoved(int deviceId) { + hideDebugView(deviceId); + } + + @Override + public void onInputDeviceChanged(int deviceId) { + } + + /** + * Notify the controller that the touchpad visualizer setting value has changed. + * This must be called from the same looper thread as {@code mHandler}. + */ + public void updateTouchpadVisualizerEnabled(boolean touchpadVisualizerEnabled) { + if (mTouchpadVisualizerEnabled == touchpadVisualizerEnabled) { + return; + } + mTouchpadVisualizerEnabled = touchpadVisualizerEnabled; + final InputManager inputManager = Objects.requireNonNull( + mContext.getSystemService(InputManager.class)); + if (touchpadVisualizerEnabled) { + inputManager.registerInputDeviceListener(this, mHandler); + for (int deviceId : inputManager.getInputDeviceIds()) { + onInputDeviceAdded(deviceId); + } + } else { + if (mTouchpadDebugView != null) { + hideDebugView(mTouchpadDebugView.getTouchpadId()); + } + inputManager.unregisterInputDeviceListener(this); + } + } private void showDebugView(int touchpadId) { if (mTouchpadDebugView != null) { diff --git a/tests/Input/src/com/android/server/input/debug/TouchpadDebugViewControllerTests.java b/tests/Input/src/com/android/server/input/debug/TouchpadDebugViewControllerTests.java new file mode 100644 index 000000000000..c7ebd3a27a2e --- /dev/null +++ b/tests/Input/src/com/android/server/input/debug/TouchpadDebugViewControllerTests.java @@ -0,0 +1,215 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.input.debug; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.graphics.Rect; +import android.hardware.input.InputManager; +import android.testing.AndroidTestingRunner; +import android.testing.TestableContext; +import android.testing.TestableLooper; +import android.testing.TestableLooper.RunWithLooper; +import android.view.InputDevice; +import android.view.WindowInsets; +import android.view.WindowManager; +import android.view.WindowMetrics; + +import androidx.test.platform.app.InstrumentationRegistry; + +import com.android.server.input.InputManagerService; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +/** + * Build/Install/Run: + * atest TouchpadDebugViewControllerTests + */ + +@RunWith(AndroidTestingRunner.class) +@RunWithLooper +public class TouchpadDebugViewControllerTests { + private static final int DEVICE_ID = 1000; + private static final String TAG = "TouchpadDebugViewController"; + + @Rule + public final MockitoRule mockito = MockitoJUnit.rule(); + + private Context mContext; + private TouchpadDebugViewController mTouchpadDebugViewController; + @Mock + private InputManager mInputManagerMock; + @Mock + private InputManagerService mInputManagerServiceMock; + @Mock + private WindowManager mWindowManagerMock; + private TestableLooper mTestableLooper; + + @Before + public void setup() throws Exception { + mContext = InstrumentationRegistry.getInstrumentation().getContext(); + TestableContext mTestableContext = new TestableContext(mContext); + mTestableContext.addMockSystemService(WindowManager.class, mWindowManagerMock); + + Rect bounds = new Rect(0, 0, 2560, 1600); + WindowMetrics metrics = new WindowMetrics(bounds, new WindowInsets(bounds), 1.0f); + + when(mWindowManagerMock.getCurrentWindowMetrics()).thenReturn(metrics); + + unMockTouchpad(); + + mTestableLooper = TestableLooper.get(this); + + mTestableContext.addMockSystemService(InputManager.class, mInputManagerMock); + + mTouchpadDebugViewController = new TouchpadDebugViewController(mTestableContext, + mTestableLooper.getLooper(), mInputManagerServiceMock); + } + + private InputDevice createTouchpadInputDevice(int id) { + return new InputDevice.Builder() + .setId(id) + .setSources(InputDevice.SOURCE_TOUCHPAD | InputDevice.SOURCE_MOUSE) + .setName("Test Device " + id) + .build(); + } + + private void mockTouchpad() { + when(mInputManagerMock.getInputDeviceIds()).thenReturn(new int[]{DEVICE_ID}); + when(mInputManagerMock.getInputDevice(eq(DEVICE_ID))).thenReturn( + createTouchpadInputDevice(DEVICE_ID)); + } + + private void unMockTouchpad() { + when(mInputManagerMock.getInputDeviceIds()).thenReturn(new int[]{}); + when(mInputManagerMock.getInputDevice(eq(DEVICE_ID))).thenReturn(null); + } + + @Test + public void touchpadConnectedWhileSettingDisabled() throws Exception { + mTouchpadDebugViewController.updateTouchpadVisualizerEnabled(false); + + mockTouchpad(); + mTouchpadDebugViewController.onInputDeviceAdded(DEVICE_ID); + + verify(mWindowManagerMock, never()).addView(any(), any()); + verify(mWindowManagerMock, never()).removeView(any()); + } + + @Test + public void settingEnabledWhileNoTouchpadConnected() throws Exception { + mTouchpadDebugViewController.updateTouchpadVisualizerEnabled(true); + + verify(mWindowManagerMock, never()).addView(any(), any()); + verify(mWindowManagerMock, never()).removeView(any()); + } + + @Test + public void touchpadConnectedWhileSettingEnabled() throws Exception { + mTouchpadDebugViewController.updateTouchpadVisualizerEnabled(true); + + mockTouchpad(); + mTouchpadDebugViewController.onInputDeviceAdded(DEVICE_ID); + + verify(mWindowManagerMock, times(1)).addView(any(), any()); + verify(mWindowManagerMock, never()).removeView(any()); + } + + @Test + public void touchpadConnectedWhileSettingEnabledThenDisabled() throws Exception { + mTouchpadDebugViewController.updateTouchpadVisualizerEnabled(true); + + mockTouchpad(); + mTouchpadDebugViewController.onInputDeviceAdded(DEVICE_ID); + + verify(mWindowManagerMock, times(1)).addView(any(), any()); + verify(mWindowManagerMock, never()).removeView(any()); + + mTouchpadDebugViewController.updateTouchpadVisualizerEnabled(false); + + verify(mWindowManagerMock, times(1)).addView(any(), any()); + verify(mWindowManagerMock, times(1)).removeView(any()); + } + + @Test + public void touchpadConnectedWhileSettingDisabledThenEnabled() throws Exception { + mTouchpadDebugViewController.updateTouchpadVisualizerEnabled(false); + + mockTouchpad(); + mTouchpadDebugViewController.onInputDeviceAdded(DEVICE_ID); + + verify(mWindowManagerMock, never()).addView(any(), any()); + verify(mWindowManagerMock, never()).removeView(any()); + + mTouchpadDebugViewController.updateTouchpadVisualizerEnabled(true); + + verify(mWindowManagerMock, times(1)).addView(any(), any()); + verify(mWindowManagerMock, never()).removeView(any()); + } + + @Test + public void touchpadConnectedWhileSettingDisabledThenTouchpadDisconnected() throws Exception { + mTouchpadDebugViewController.updateTouchpadVisualizerEnabled(false); + + mockTouchpad(); + mTouchpadDebugViewController.onInputDeviceAdded(DEVICE_ID); + + verify(mWindowManagerMock, never()).addView(any(), any()); + verify(mWindowManagerMock, never()).removeView(any()); + + unMockTouchpad(); + mTouchpadDebugViewController.onInputDeviceRemoved(DEVICE_ID); + + verify(mWindowManagerMock, never()).addView(any(), any()); + verify(mWindowManagerMock, never()).removeView(any()); + } + + @Test + public void touchpadConnectedWhileSettingEnabledThenTouchpadDisconnectedThenSettingDisabled() + throws Exception { + mTouchpadDebugViewController.updateTouchpadVisualizerEnabled(true); + + mockTouchpad(); + mTouchpadDebugViewController.onInputDeviceAdded(DEVICE_ID); + + verify(mWindowManagerMock, times(1)).addView(any(), any()); + verify(mWindowManagerMock, never()).removeView(any()); + + unMockTouchpad(); + mTouchpadDebugViewController.onInputDeviceRemoved(DEVICE_ID); + + verify(mWindowManagerMock, times(1)).addView(any(), any()); + verify(mWindowManagerMock, times(1)).removeView(any()); + + mTouchpadDebugViewController.updateTouchpadVisualizerEnabled(false); + + verify(mWindowManagerMock, times(1)).addView(any(), any()); + verify(mWindowManagerMock, times(1)).removeView(any()); + } +} |