diff options
| author | Chris Ye <lzye@google.com> | 2021-02-03 17:10:55 -0800 |
|---|---|---|
| committer | Chris Ye <lzye@google.com> | 2021-02-05 09:38:18 -0800 |
| commit | f3a1533aa74759d37aa084cc598c077faf42fe7c (patch) | |
| tree | c295b8675b20fb7ba7d464ffb6136bebd63842d2 /core/java/android | |
| parent | 277cfb354dc76da33cb7c2cfaa914cedf73e130c (diff) | |
Add vibrator state listener support for input device vibrator
Extend Vibrator state and listener support to InputDevice vibrator.
InputDevice users can use the Vibrator listener API to register listener
to vibrator for state change.
Bug: 161634264
Test: atest InputDeviceVibratorTest
Change-Id: I991d3e79ad1734b5c6c99b802aab030bd1597daf
Diffstat (limited to 'core/java/android')
| -rw-r--r-- | core/java/android/hardware/input/IInputManager.aidl | 3 | ||||
| -rw-r--r-- | core/java/android/hardware/input/InputDeviceVibrator.java | 93 | ||||
| -rw-r--r-- | core/java/android/hardware/input/InputManager.java | 27 |
3 files changed, 116 insertions, 7 deletions
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl index c69c47f80d01..eaa38f3e862c 100644 --- a/core/java/android/hardware/input/IInputManager.aidl +++ b/core/java/android/hardware/input/IInputManager.aidl @@ -26,6 +26,7 @@ import android.os.CombinedVibrationEffect; import android.hardware.input.IInputSensorEventListener; import android.hardware.input.InputSensorInfo; import android.os.IBinder; +import android.os.IVibratorStateListener; import android.os.VibrationEffect; import android.view.InputDevice; import android.view.InputEvent; @@ -92,6 +93,8 @@ interface IInputManager { void cancelVibrate(int deviceId, IBinder token); int[] getVibratorIds(int deviceId); boolean isVibrating(int deviceId); + boolean registerVibratorStateListener(int deviceId, in IVibratorStateListener listener); + boolean unregisterVibratorStateListener(int deviceId, in IVibratorStateListener listener); // Input device battery query. int getBatteryStatus(int deviceId); diff --git a/core/java/android/hardware/input/InputDeviceVibrator.java b/core/java/android/hardware/input/InputDeviceVibrator.java index c60d6ce46fdb..f4d8a65d54c6 100644 --- a/core/java/android/hardware/input/InputDeviceVibrator.java +++ b/core/java/android/hardware/input/InputDeviceVibrator.java @@ -18,10 +18,18 @@ package android.hardware.input; import android.annotation.CallbackExecutor; import android.annotation.NonNull; +import android.app.ActivityThread; +import android.content.Context; import android.os.Binder; +import android.os.IVibratorStateListener; import android.os.VibrationAttributes; import android.os.VibrationEffect; import android.os.Vibrator; +import android.util.ArrayMap; +import android.util.Log; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.Preconditions; import java.util.concurrent.Executor; @@ -29,12 +37,18 @@ import java.util.concurrent.Executor; * Vibrator implementation that communicates with the input device vibrators. */ final class InputDeviceVibrator extends Vibrator { + private static final String TAG = "InputDeviceVibrator"; + // mDeviceId represents InputDevice ID the vibrator belongs to private final int mDeviceId; private final int mVibratorId; private final Binder mToken; private final InputManager mInputManager; + @GuardedBy("mDelegates") + private final ArrayMap<OnVibratorStateChangedListener, + OnVibratorStateChangedListenerDelegate> mDelegates = new ArrayMap<>(); + InputDeviceVibrator(InputManager inputManager, int deviceId, int vibratorId) { mInputManager = inputManager; mDeviceId = deviceId; @@ -42,6 +56,23 @@ final class InputDeviceVibrator extends Vibrator { mToken = new Binder(); } + private class OnVibratorStateChangedListenerDelegate extends + IVibratorStateListener.Stub { + private final Executor mExecutor; + private final OnVibratorStateChangedListener mListener; + + OnVibratorStateChangedListenerDelegate(@NonNull OnVibratorStateChangedListener listener, + @NonNull Executor executor) { + mExecutor = executor; + mListener = listener; + } + + @Override + public void onVibrating(boolean isVibrating) { + mExecutor.execute(() -> mListener.onVibratorStateChanged(isVibrating)); + } + } + @Override public boolean hasVibrator() { return true; @@ -52,25 +83,73 @@ final class InputDeviceVibrator extends Vibrator { return mInputManager.isVibrating(mDeviceId); } - /* TODO: b/161634264 Support Vibrator listener API in input devices */ + /** + * Adds a listener for vibrator state changes. Callbacks will be executed on the main thread. + * If the listener was previously added and not removed, this call will be ignored. + * + * @param listener listener to be added + */ @Override public void addVibratorStateListener(@NonNull OnVibratorStateChangedListener listener) { - throw new UnsupportedOperationException( - "addVibratorStateListener not supported in InputDeviceVibrator"); + Preconditions.checkNotNull(listener); + Context context = ActivityThread.currentApplication(); + addVibratorStateListener(context.getMainExecutor(), listener); } + /** + * Adds a listener for vibrator state change. If the listener was previously added and not + * removed, this call will be ignored. + * + * @param listener Listener to be added. + * @param executor The {@link Executor} on which the listener's callbacks will be executed on. + */ @Override public void addVibratorStateListener( @NonNull @CallbackExecutor Executor executor, @NonNull OnVibratorStateChangedListener listener) { - throw new UnsupportedOperationException( - "addVibratorStateListener not supported in InputDeviceVibrator"); + Preconditions.checkNotNull(listener); + Preconditions.checkNotNull(executor); + + synchronized (mDelegates) { + // If listener is already registered, reject and return. + if (mDelegates.containsKey(listener)) { + Log.w(TAG, "Listener already registered."); + return; + } + + final OnVibratorStateChangedListenerDelegate delegate = + new OnVibratorStateChangedListenerDelegate(listener, executor); + if (!mInputManager.registerVibratorStateListener(mDeviceId, delegate)) { + Log.w(TAG, "Failed to register vibrate state listener"); + return; + } + mDelegates.put(listener, delegate); + + } } + /** + * Removes the listener for vibrator state changes. If the listener was not previously + * registered, this call will do nothing. + * + * @param listener Listener to be removed. + */ @Override public void removeVibratorStateListener(@NonNull OnVibratorStateChangedListener listener) { - throw new UnsupportedOperationException( - "removeVibratorStateListener not supported in InputDeviceVibrator"); + Preconditions.checkNotNull(listener); + + synchronized (mDelegates) { + // Check if the listener is registered, otherwise will return. + if (mDelegates.containsKey(listener)) { + final OnVibratorStateChangedListenerDelegate delegate = mDelegates.get(listener); + + if (!mInputManager.unregisterVibratorStateListener(mDeviceId, delegate)) { + Log.w(TAG, "Failed to unregister vibrate state listener"); + return; + } + mDelegates.remove(listener); + } + } } @Override diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java index 185c59d8ccfc..8a01c660ebd0 100644 --- a/core/java/android/hardware/input/InputManager.java +++ b/core/java/android/hardware/input/InputManager.java @@ -35,6 +35,7 @@ import android.os.Build; import android.os.CombinedVibrationEffect; import android.os.Handler; import android.os.IBinder; +import android.os.IVibratorStateListener; import android.os.InputEventInjectionSync; import android.os.Looper; import android.os.Message; @@ -1484,6 +1485,32 @@ public final class InputManager { } /** + * Register input device vibrator state listener + * + * @hide + */ + public boolean registerVibratorStateListener(int deviceId, IVibratorStateListener listener) { + try { + return mIm.registerVibratorStateListener(deviceId, listener); + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } + } + + /** + * Unregister input device vibrator state listener + * + * @hide + */ + public boolean unregisterVibratorStateListener(int deviceId, IVibratorStateListener listener) { + try { + return mIm.unregisterVibratorStateListener(deviceId, listener); + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } + } + + /** * Gets a sensor manager service associated with an input device, always create a new instance. * @return The sensor manager, never null. * @hide |
