1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
|
/*
* 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 InputManager mInputManager;
@GuardedBy("mDelegates")
private final ArrayMap<OnVibratorStateChangedListener,
OnVibratorStateChangedListenerDelegate> mDelegates = new ArrayMap<>();
InputDeviceVibrator(InputManager inputManager, int deviceId, int vibratorId) {
mInputManager = inputManager;
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
protected VibratorInfo getInfo() {
return mVibratorInfo;
}
@Override
public boolean hasVibrator() {
return true;
}
@Override
public boolean isVibrating() {
return mInputManager.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 (!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) {
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
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) {
mInputManager.vibrate(mDeviceId, effect, mToken);
}
@Override
public void cancel() {
mInputManager.cancelVibrate(mDeviceId, mToken);
}
@Override
public void cancel(int usageFilter) {
cancel();
}
}
|