Merge "Add vibrator state listener support for input device vibrator" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
2fa12f8ec3
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
@@ -1483,6 +1484,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.
|
||||
|
||||
@@ -57,6 +57,7 @@ import android.os.CombinedVibrationEffect;
|
||||
import android.os.Environment;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.IVibratorStateListener;
|
||||
import android.os.InputEventInjectionResult;
|
||||
import android.os.InputEventInjectionSync;
|
||||
import android.os.LocaleList;
|
||||
@@ -64,6 +65,7 @@ import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.MessageQueue;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteCallbackList;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ResultReceiver;
|
||||
import android.os.ShellCallback;
|
||||
@@ -77,6 +79,7 @@ import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseBooleanArray;
|
||||
import android.view.Display;
|
||||
import android.view.IInputFilter;
|
||||
import android.view.IInputFilterHost;
|
||||
@@ -100,6 +103,7 @@ import com.android.internal.notification.SystemNotificationChannels;
|
||||
import com.android.internal.os.SomeArgs;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.internal.util.DumpUtils;
|
||||
import com.android.internal.util.Preconditions;
|
||||
import com.android.internal.util.XmlUtils;
|
||||
import com.android.server.DisplayThread;
|
||||
import com.android.server.LocalServices;
|
||||
@@ -221,6 +225,14 @@ public class InputManagerService extends IInputManager.Stub
|
||||
private Map<IBinder, VibratorToken> mVibratorTokens = new ArrayMap<IBinder, VibratorToken>();
|
||||
private int mNextVibratorTokenValue;
|
||||
|
||||
// List of currently registered vibrator state changed listeners by device id.
|
||||
@GuardedBy("mVibratorLock")
|
||||
private final SparseArray<RemoteCallbackList<IVibratorStateListener>> mVibratorStateListeners =
|
||||
new SparseArray<RemoteCallbackList<IVibratorStateListener>>();
|
||||
// List of vibrator states by device id.
|
||||
@GuardedBy("mVibratorLock")
|
||||
private final SparseBooleanArray mIsVibrating = new SparseBooleanArray();
|
||||
|
||||
// State for lid switch
|
||||
// Lock for the lid switch state. Held when triggering callbacks to guarantee lid switch events
|
||||
// are delivered in order. For ex, when a new lid switch callback is registered the lock is held
|
||||
@@ -2008,6 +2020,92 @@ public class InputManagerService extends IInputManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
// Native callback.
|
||||
private void notifyVibratorState(int deviceId, boolean isOn) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "notifyVibratorState: deviceId=" + deviceId + " isOn=" + isOn);
|
||||
}
|
||||
synchronized (mVibratorLock) {
|
||||
mIsVibrating.put(deviceId, isOn);
|
||||
notifyVibratorStateListenersLocked(deviceId);
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mVibratorLock")
|
||||
private void notifyVibratorStateListenersLocked(int deviceId) {
|
||||
if (!mVibratorStateListeners.contains(deviceId)) {
|
||||
if (DEBUG) {
|
||||
Slog.v(TAG, "Device " + deviceId + " doesn't have vibrator state listener.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
RemoteCallbackList<IVibratorStateListener> listeners =
|
||||
mVibratorStateListeners.get(deviceId);
|
||||
final int length = listeners.beginBroadcast();
|
||||
try {
|
||||
for (int i = 0; i < length; i++) {
|
||||
notifyVibratorStateListenerLocked(deviceId, listeners.getBroadcastItem(i));
|
||||
}
|
||||
} finally {
|
||||
listeners.finishBroadcast();
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mVibratorLock")
|
||||
private void notifyVibratorStateListenerLocked(int deviceId, IVibratorStateListener listener) {
|
||||
try {
|
||||
listener.onVibrating(mIsVibrating.get(deviceId));
|
||||
} catch (RemoteException | RuntimeException e) {
|
||||
Slog.e(TAG, "Vibrator state listener failed to call", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
public boolean registerVibratorStateListener(int deviceId, IVibratorStateListener listener) {
|
||||
Preconditions.checkNotNull(listener, "listener must not be null");
|
||||
|
||||
RemoteCallbackList<IVibratorStateListener> listeners;
|
||||
synchronized (mVibratorLock) {
|
||||
if (!mVibratorStateListeners.contains(deviceId)) {
|
||||
listeners = new RemoteCallbackList<>();
|
||||
mVibratorStateListeners.put(deviceId, listeners);
|
||||
} else {
|
||||
listeners = mVibratorStateListeners.get(deviceId);
|
||||
}
|
||||
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
if (!listeners.register(listener)) {
|
||||
Slog.e(TAG, "Could not register vibrator state listener " + listener);
|
||||
return false;
|
||||
}
|
||||
// Notify its callback after new client registered.
|
||||
notifyVibratorStateListenerLocked(deviceId, listener);
|
||||
return true;
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
public boolean unregisterVibratorStateListener(int deviceId, IVibratorStateListener listener) {
|
||||
synchronized (mVibratorLock) {
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
if (!mVibratorStateListeners.contains(deviceId)) {
|
||||
Slog.w(TAG, "Vibrator state listener " + deviceId + " doesn't exist");
|
||||
return false;
|
||||
}
|
||||
RemoteCallbackList<IVibratorStateListener> listeners =
|
||||
mVibratorStateListeners.get(deviceId);
|
||||
return listeners.unregister(listener);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Binder call
|
||||
@Override
|
||||
public int getBatteryStatus(int deviceId) {
|
||||
|
||||
@@ -106,6 +106,7 @@ static struct {
|
||||
jmethodID notifyFocusChanged;
|
||||
jmethodID notifySensorEvent;
|
||||
jmethodID notifySensorAccuracy;
|
||||
jmethodID notifyVibratorState;
|
||||
jmethodID notifyUntrustedTouch;
|
||||
jmethodID filterInputEvent;
|
||||
jmethodID interceptKeyBeforeQueueing;
|
||||
@@ -305,6 +306,7 @@ public:
|
||||
const std::vector<float>& values) override;
|
||||
void notifySensorAccuracy(int32_t deviceId, InputDeviceSensorType sensorType,
|
||||
InputDeviceSensorAccuracy accuracy) override;
|
||||
void notifyVibratorState(int32_t deviceId, bool isOn) override;
|
||||
void notifyUntrustedTouch(const std::string& obscuringPackage) override;
|
||||
bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) override;
|
||||
void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) override;
|
||||
@@ -918,6 +920,18 @@ void NativeInputManager::notifySensorAccuracy(int32_t deviceId, InputDeviceSenso
|
||||
checkAndClearExceptionFromCallback(env, "notifySensorAccuracy");
|
||||
}
|
||||
|
||||
void NativeInputManager::notifyVibratorState(int32_t deviceId, bool isOn) {
|
||||
#if DEBUG_INPUT_DISPATCHER_POLICY
|
||||
ALOGD("notifyVibratorState isOn:%d", isOn);
|
||||
#endif
|
||||
ATRACE_CALL();
|
||||
JNIEnv* env = jniEnv();
|
||||
ScopedLocalFrame localFrame(env);
|
||||
env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyVibratorState,
|
||||
static_cast<jint>(deviceId), static_cast<jboolean>(isOn));
|
||||
checkAndClearExceptionFromCallback(env, "notifyVibratorState");
|
||||
}
|
||||
|
||||
void NativeInputManager::getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) {
|
||||
ATRACE_CALL();
|
||||
JNIEnv* env = jniEnv();
|
||||
@@ -2248,6 +2262,8 @@ int register_android_server_InputManager(JNIEnv* env) {
|
||||
|
||||
GET_METHOD_ID(gServiceClassInfo.notifySensorAccuracy, clazz, "notifySensorAccuracy", "(III)V");
|
||||
|
||||
GET_METHOD_ID(gServiceClassInfo.notifyVibratorState, clazz, "notifyVibratorState", "(IZ)V");
|
||||
|
||||
GET_METHOD_ID(gServiceClassInfo.notifyUntrustedTouch, clazz, "notifyUntrustedTouch",
|
||||
"(Ljava/lang/String;)V");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user