Skip to content

Commit a47425a

Browse files
author
Jeff Brown
committed
Add support for input devices that have vibrators.
Added a getVibrator() method to InputDevice which returns a Vibrator associated with that input device. Its uses the same API as the system vibrator which makes it easy for applications to be modified to use one or the other. Bug: 6334179 Change-Id: Ifc7f13dbcb778670f3f1c07ccc562334e6109d2e
1 parent c234613 commit a47425a

File tree

15 files changed

+589
-7
lines changed

15 files changed

+589
-7
lines changed

api/current.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22327,6 +22327,7 @@ package android.view {
2232722327
method public java.util.List<android.view.InputDevice.MotionRange> getMotionRanges();
2232822328
method public java.lang.String getName();
2232922329
method public int getSources();
22330+
method public android.os.Vibrator getVibrator();
2233022331
method public boolean isVirtual();
2233122332
method public void writeToParcel(android.os.Parcel, int);
2233222333
field public static final android.os.Parcelable.Creator CREATOR;

core/java/android/hardware/input/IInputManager.aidl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package android.hardware.input;
1818

1919
import android.hardware.input.KeyboardLayout;
2020
import android.hardware.input.IInputDevicesChangedListener;
21+
import android.os.IBinder;
2122
import android.view.InputDevice;
2223
import android.view.InputEvent;
2324

@@ -46,4 +47,8 @@ interface IInputManager {
4647

4748
// Registers an input devices changed listener.
4849
void registerInputDevicesChangedListener(IInputDevicesChangedListener listener);
50+
51+
// Input device vibrator control.
52+
void vibrate(int deviceId, in long[] pattern, int repeat, IBinder token);
53+
void cancelVibrate(int deviceId, IBinder token);
4954
}

core/java/android/hardware/input/InputManager.java

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,14 @@
1919
import android.annotation.SdkConstant;
2020
import android.annotation.SdkConstant.SdkConstantType;
2121
import android.content.Context;
22+
import android.os.Binder;
2223
import android.os.Handler;
2324
import android.os.IBinder;
2425
import android.os.Looper;
2526
import android.os.Message;
2627
import android.os.RemoteException;
2728
import android.os.ServiceManager;
29+
import android.os.Vibrator;
2830
import android.provider.Settings;
2931
import android.provider.Settings.SettingNotFoundException;
3032
import android.util.Log;
@@ -586,6 +588,15 @@ private static boolean containsDeviceId(int[] deviceIdAndGeneration, int deviceI
586588
return false;
587589
}
588590

591+
/**
592+
* Gets a vibrator service associated with an input device, assuming it has one.
593+
* @return The vibrator, never null.
594+
* @hide
595+
*/
596+
public Vibrator getInputDeviceVibrator(int deviceId) {
597+
return new InputDeviceVibrator(deviceId);
598+
}
599+
589600
/**
590601
* Listens for changes in input devices.
591602
*/
@@ -645,4 +656,45 @@ public void handleMessage(Message msg) {
645656
}
646657
}
647658
}
659+
660+
private final class InputDeviceVibrator extends Vibrator {
661+
private final int mDeviceId;
662+
private final Binder mToken;
663+
664+
public InputDeviceVibrator(int deviceId) {
665+
mDeviceId = deviceId;
666+
mToken = new Binder();
667+
}
668+
669+
@Override
670+
public boolean hasVibrator() {
671+
return true;
672+
}
673+
674+
@Override
675+
public void vibrate(long milliseconds) {
676+
vibrate(new long[] { 0, milliseconds}, -1);
677+
}
678+
679+
@Override
680+
public void vibrate(long[] pattern, int repeat) {
681+
if (repeat >= pattern.length) {
682+
throw new ArrayIndexOutOfBoundsException();
683+
}
684+
try {
685+
mIm.vibrate(mDeviceId, pattern, repeat, mToken);
686+
} catch (RemoteException ex) {
687+
Log.w(TAG, "Failed to vibrate.", ex);
688+
}
689+
}
690+
691+
@Override
692+
public void cancel() {
693+
try {
694+
mIm.cancelVibrate(mDeviceId, mToken);
695+
} catch (RemoteException ex) {
696+
Log.w(TAG, "Failed to cancel vibration.", ex);
697+
}
698+
}
699+
}
648700
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright (C) 2012 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package android.os;
18+
19+
import android.util.Log;
20+
21+
/**
22+
* Vibrator implementation that does nothing.
23+
*
24+
* @hide
25+
*/
26+
public class NullVibrator extends Vibrator {
27+
private static final NullVibrator sInstance = new NullVibrator();
28+
29+
private NullVibrator() {
30+
}
31+
32+
public static NullVibrator getInstance() {
33+
return sInstance;
34+
}
35+
36+
@Override
37+
public boolean hasVibrator() {
38+
return false;
39+
}
40+
41+
@Override
42+
public void vibrate(long milliseconds) {
43+
}
44+
45+
@Override
46+
public void vibrate(long[] pattern, int repeat) {
47+
if (repeat >= pattern.length) {
48+
throw new ArrayIndexOutOfBoundsException();
49+
}
50+
}
51+
52+
@Override
53+
public void cancel() {
54+
}
55+
}

core/java/android/view/InputDevice.java

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@
1616

1717
package android.view;
1818

19+
import android.content.Context;
1920
import android.hardware.input.InputManager;
2021
import android.os.Parcel;
2122
import android.os.Parcelable;
23+
import android.os.Vibrator;
24+
import android.os.NullVibrator;
2225

2326
import java.util.ArrayList;
2427
import java.util.List;
@@ -46,8 +49,11 @@ public final class InputDevice implements Parcelable {
4649
private final int mSources;
4750
private final int mKeyboardType;
4851
private final KeyCharacterMap mKeyCharacterMap;
52+
private final boolean mHasVibrator;
4953
private final ArrayList<MotionRange> mMotionRanges = new ArrayList<MotionRange>();
5054

55+
private Vibrator mVibrator; // guarded by mMotionRanges during initialization
56+
5157
/**
5258
* A mask for input source classes.
5359
*
@@ -304,14 +310,15 @@ public InputDevice[] newArray(int size) {
304310

305311
// Called by native code.
306312
private InputDevice(int id, int generation, String name, String descriptor, int sources,
307-
int keyboardType, KeyCharacterMap keyCharacterMap) {
313+
int keyboardType, KeyCharacterMap keyCharacterMap, boolean hasVibrator) {
308314
mId = id;
309315
mGeneration = generation;
310316
mName = name;
311317
mDescriptor = descriptor;
312318
mSources = sources;
313319
mKeyboardType = keyboardType;
314320
mKeyCharacterMap = keyCharacterMap;
321+
mHasVibrator = hasVibrator;
315322
}
316323

317324
private InputDevice(Parcel in) {
@@ -322,6 +329,7 @@ private InputDevice(Parcel in) {
322329
mSources = in.readInt();
323330
mKeyboardType = in.readInt();
324331
mKeyCharacterMap = KeyCharacterMap.CREATOR.createFromParcel(in);
332+
mHasVibrator = in.readInt() != 0;
325333

326334
for (;;) {
327335
int axis = in.readInt();
@@ -521,6 +529,31 @@ private void addMotionRange(int axis, int source,
521529
mMotionRanges.add(new MotionRange(axis, source, min, max, flat, fuzz));
522530
}
523531

532+
/**
533+
* Gets the vibrator service associated with the device, if there is one.
534+
* Even if the device does not have a vibrator, the result is never null.
535+
* Use {@link Vibrator#hasVibrator} to determine whether a vibrator is
536+
* present.
537+
*
538+
* Note that the vibrator associated with the device may be different from
539+
* the system vibrator. To obtain an instance of the system vibrator instead, call
540+
* {@link Context#getSystemService} with {@link Context#VIBRATOR_SERVICE} as argument.
541+
*
542+
* @return The vibrator service associated with the device, never null.
543+
*/
544+
public Vibrator getVibrator() {
545+
synchronized (mMotionRanges) {
546+
if (mVibrator == null) {
547+
if (mHasVibrator) {
548+
mVibrator = InputManager.getInstance().getInputDeviceVibrator(mId);
549+
} else {
550+
mVibrator = NullVibrator.getInstance();
551+
}
552+
}
553+
return mVibrator;
554+
}
555+
}
556+
524557
/**
525558
* Provides information about the range of values for a particular {@link MotionEvent} axis.
526559
*
@@ -617,6 +650,7 @@ public void writeToParcel(Parcel out, int flags) {
617650
out.writeInt(mSources);
618651
out.writeInt(mKeyboardType);
619652
mKeyCharacterMap.writeToParcel(out, flags);
653+
out.writeInt(mHasVibrator ? 1 : 0);
620654

621655
final int numRanges = mMotionRanges.size();
622656
for (int i = 0; i < numRanges; i++) {
@@ -657,6 +691,8 @@ public String toString() {
657691
}
658692
description.append("\n");
659693

694+
description.append(" Has Vibrator: ").append(mHasVibrator).append("\n");
695+
660696
description.append(" Sources: 0x").append(Integer.toHexString(mSources)).append(" (");
661697
appendSourceDescriptionIfApplicable(description, SOURCE_KEYBOARD, "keyboard");
662698
appendSourceDescriptionIfApplicable(description, SOURCE_DPAD, "dpad");

core/jni/android_view_InputDevice.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ jobject android_view_InputDevice_create(JNIEnv* env, const InputDeviceInfo& devi
5757
gInputDeviceClassInfo.ctor, deviceInfo.getId(), deviceInfo.getGeneration(),
5858
nameObj.get(), descriptorObj.get(),
5959
deviceInfo.getSources(), deviceInfo.getKeyboardType(),
60-
kcmObj.get()));
60+
kcmObj.get(), deviceInfo.hasVibrator()));
6161

6262
const Vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges();
6363
for (size_t i = 0; i < ranges.size(); i++) {
@@ -87,7 +87,7 @@ int register_android_view_InputDevice(JNIEnv* env)
8787
gInputDeviceClassInfo.clazz = jclass(env->NewGlobalRef(gInputDeviceClassInfo.clazz));
8888

8989
GET_METHOD_ID(gInputDeviceClassInfo.ctor, gInputDeviceClassInfo.clazz,
90-
"<init>", "(IILjava/lang/String;Ljava/lang/String;IILandroid/view/KeyCharacterMap;)V");
90+
"<init>", "(IILjava/lang/String;Ljava/lang/String;IILandroid/view/KeyCharacterMap;Z)V");
9191

9292
GET_METHOD_ID(gInputDeviceClassInfo.addMotionRange, gInputDeviceClassInfo.clazz,
9393
"addMotionRange", "(IIFFFF)V");

include/androidfw/InputDevice.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ class InputDeviceInfo {
9393
return mKeyCharacterMap;
9494
}
9595

96+
inline void setVibrator(bool hasVibrator) { mHasVibrator = hasVibrator; }
97+
inline bool hasVibrator() const { return mHasVibrator; }
98+
9699
inline const Vector<MotionRange>& getMotionRanges() const {
97100
return mMotionRanges;
98101
}
@@ -105,6 +108,7 @@ class InputDeviceInfo {
105108
uint32_t mSources;
106109
int32_t mKeyboardType;
107110
sp<KeyCharacterMap> mKeyCharacterMap;
111+
bool mHasVibrator;
108112

109113
Vector<MotionRange> mMotionRanges;
110114
};

libs/androidfw/InputDevice.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ InputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other) :
136136
mSources(other.mSources),
137137
mKeyboardType(other.mKeyboardType),
138138
mKeyCharacterMap(other.mKeyCharacterMap),
139+
mHasVibrator(other.mHasVibrator),
139140
mMotionRanges(other.mMotionRanges) {
140141
}
141142

@@ -150,6 +151,7 @@ void InputDeviceInfo::initialize(int32_t id, int32_t generation,
150151
mDescriptor = descriptor;
151152
mSources = 0;
152153
mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE;
154+
mHasVibrator = false;
153155
mMotionRanges.clear();
154156
}
155157

0 commit comments

Comments
 (0)