192 lines
6.5 KiB
Java
192 lines
6.5 KiB
Java
/*
|
|
* Copyright (C) 2020 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 android.hardware.input;
|
|
|
|
import android.annotation.CallbackExecutor;
|
|
import android.annotation.NonNull;
|
|
import android.app.ActivityThread;
|
|
import android.content.Context;
|
|
import android.hardware.vibrator.IVibrator;
|
|
import android.os.Binder;
|
|
import android.os.IVibratorStateListener;
|
|
import android.os.VibrationAttributes;
|
|
import android.os.VibrationEffect;
|
|
import android.os.Vibrator;
|
|
import android.os.VibratorInfo;
|
|
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;
|
|
|
|
/**
|
|
* 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 VibratorInfo mVibratorInfo;
|
|
private final Binder mToken;
|
|
private final InputManagerGlobal mGlobal;
|
|
|
|
@GuardedBy("mDelegates")
|
|
private final ArrayMap<OnVibratorStateChangedListener,
|
|
OnVibratorStateChangedListenerDelegate> mDelegates = new ArrayMap<>();
|
|
|
|
InputDeviceVibrator(int deviceId, int vibratorId) {
|
|
mGlobal = InputManagerGlobal.getInstance();
|
|
mDeviceId = deviceId;
|
|
mVibratorInfo = new VibratorInfo.Builder(vibratorId)
|
|
.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL)
|
|
// The supported effect and braking lists are known to be empty for input devices,
|
|
// which is different from not being set (that means the device support is unknown).
|
|
.setSupportedEffects(new int[0])
|
|
.setSupportedBraking(new int[0])
|
|
.build();
|
|
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 VibratorInfo getInfo() {
|
|
return mVibratorInfo;
|
|
}
|
|
|
|
@Override
|
|
public boolean hasVibrator() {
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean isVibrating() {
|
|
return mGlobal.isVibrating(mDeviceId);
|
|
}
|
|
|
|
/**
|
|
* 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) {
|
|
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) {
|
|
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 (!mGlobal.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) {
|
|
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 (!mGlobal.unregisterVibratorStateListener(mDeviceId, delegate)) {
|
|
Log.w(TAG, "Failed to unregister vibrate state listener");
|
|
return;
|
|
}
|
|
mDelegates.remove(listener);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean hasAmplitudeControl() {
|
|
return mVibratorInfo.hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL);
|
|
}
|
|
|
|
/**
|
|
* @hide
|
|
*/
|
|
@Override
|
|
public void vibrate(int uid, String opPkg, @NonNull VibrationEffect effect, String reason,
|
|
@NonNull VibrationAttributes attributes) {
|
|
mGlobal.vibrate(mDeviceId, effect, mToken);
|
|
}
|
|
|
|
@Override
|
|
public void cancel() {
|
|
mGlobal.cancelVibrate(mDeviceId, mToken);
|
|
}
|
|
|
|
@Override
|
|
public void cancel(int usageFilter) {
|
|
cancel();
|
|
}
|
|
}
|