Android振动器 android.os.Vibrator
1.Java层 frameworks/base/core/java/android/os/Vibrator.java
Vibrator类的实力可以通过 getSystemService(VIBRATOR_SERVICE)获得实例。
两个方法:public abstract void vibrate(long milliseconds);/public abstract void vibrate(long[] pattern, int repeat);
public abstract void cancel();
查找路径:Activity.java-->ContextThemeWrapper.java-->ContextWrapper.java-->Context.java,getSystemService是Context.java类的抽象方法。其实现的类是ContextImpl.java,其中有段静态代码,注册所有context下能使用到的service。
registerService(VIBRATOR_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
return new SystemVibrator();
}});
Vibrator类只是个抽象类,具体实现的代码位于 SystemVibrator。位于\frameworks\base\core\java\android\os\目录下。两个方法的实现代码如下:
@Override
public void vibrate(long milliseconds) {
if (mService == null) {
Log.w(TAG, "Failed to vibrate; no vibrator service.");
return;
}
try {
mService.vibrate(milliseconds, mToken);
} catch (RemoteException e) {
Log.w(TAG, "Failed to vibrate.", e);
}
}
与
@Override
public void vibrate(long[] pattern, int repeat) {
if (mService == null) {
Log.w(TAG, "Failed to vibrate; no vibrator service.");
return;
}
// catch this here because the server will do nothing. pattern may
// not be null, let that be checked, because the server will drop it
// anyway
if (repeat < pattern.length) {
try {
mService.vibratePattern(pattern, repeat, mToken);
} catch (RemoteException e) {
Log.w(TAG, "Failed to vibrate.", e);
}
} else {
throw new ArrayIndexOutOfBoundsException();
}
}
还有
@Override
public void cancel() {
if (mService == null) {
return;
}
try {
mService.cancelVibrate(mToken);
} catch (RemoteException e) {
Log.w(TAG, "Failed to cancel vibration.", e);
}
}
查看mService,其声明代码如下:
mService = IVibratorService.Stub.asInterface(
ServiceManager.getService("vibrator"));
/*这里跟Binder机制有关。。。断片ing*/
定义是private final IVibratorService mService;
所以找找这个IVibratorService吧。
查找下\frameworks\base\core\java\android\os\IVibratorService.aidl,这里定义了接口。
package android.os;
/** {@hide} */
interface IVibratorService
{
boolean hasVibrator();
void vibrate(long milliseconds, IBinder token);
void vibratePattern(in long[] pattern, int repeat, IBinder token);
void cancelVibrate(IBinder token);
}
具体的实现位于VibratorService.java。(\frameworks\base\services\java\com\android\server\)
public class VibratorService extends IVibratorService.Stub
然后是vibrate方法:
public void vibrate(long milliseconds, IBinder token) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires VIBRATE permission");
}
int uid = Binder.getCallingUid();
// We're running in the system server so we cannot crash. Check for a
// timeout of 0 or negative. This will ensure that a vibration has
// either a timeout of > 0 or a non-null pattern.
if (milliseconds <= 0 || (mCurrentVibration != null
&& mCurrentVibration.hasLongerTimeout(milliseconds))) {
// Ignore this vibration since the current vibration will play for
// longer than milliseconds.
return;
}
Vibration vib = new Vibration(token, milliseconds, uid);
synchronized (mVibrations) {
removeVibrationLocked(token);
doCancelVibrateLocked();
mCurrentVibration = vib;
startVibrationLocked(vib);
}
}
然后是startVibrationLocked方法。
private void startVibrationLocked(final Vibration vib) {
if (vib.mTimeout != 0) {
doVibratorOn(vib.mTimeout);
mH.postDelayed(mVibrationRunnable, vib.mTimeout);
} else {
// mThread better be null here. doCancelVibrate should always be
// called before startNextVibrationLocked or startVibrationLocked.
mThread = new VibrateThread(vib);
mThread.start();
}
}
翻看了VibrateThread的run方法,最终还是调用了doVibratorOn方法。
所以看doVibratorOn方法:
private void doVibratorOn(long millis) {
synchronized (mInputDeviceVibrators) {
final int vibratorCount = mInputDeviceVibrators.size();
if (vibratorCount != 0) {
for (int i = 0; i < vibratorCount; i++) {
mInputDeviceVibrators.get(i).vibrate(millis);
}
} else {
vibratorOn(millis);
}
}
}
|---------首先是vibratorCount这个,假如这个不为0,那么是调用 Vibrator的vibrate方法。。断片:vibratorCount这个表示什么意义!
mInputDeviceVibrators的声明如下:
private final ArrayList
里面的每一个元素都是一个Vibrator的实力,Vibrator是个抽闲类。
mInputDeviceVibrators会在VibratorService.java中的updateInputDeviceVibrators方法添加元素:
mInputDeviceVibrators.clear();
if (mVibrateInputDevicesSetting) {
int[] ids = mIm.getInputDeviceIds();
for (int i = 0; i < ids.length; i++) {
InputDevice device = mIm.getInputDevice(ids[i]);
Vibrator vibrator = device.getVibrator();
if (vibrator.hasVibrator()) {
mInputDeviceVibrators.add(vibrator);
}
}
}
查看InputDevice类的getVibrator
public Vibrator getVibrator() {
synchronized (mMotionRanges) {
if (mVibrator == null) {
if (mHasVibrator) {
mVibrator = InputManager.getInstance().getInputDeviceVibrator(mId);
} else {
mVibrator = NullVibrator.getInstance();
}
}
return mVibrator;
}
}
所以数组 mInputDeviceVibrators中的元素有两种,都是抽象类Vibrator的子类:
一种是InputDeviceVibrator类,一种就是NullVibrator类了。
先说说InputDeviceVibrator类。
private final class InputDeviceVibrator extends Vibrator {
private final int mDeviceId;
private final Binder mToken;
public InputDeviceVibrator(int deviceId) {
mDeviceId = deviceId;
mToken = new Binder();
}
@Override
public boolean hasVibrator() {
return true;
}
@Override
public void vibrate(long milliseconds) {
vibrate(new long[] { 0, milliseconds}, -1);
}
@Override
public void vibrate(long[] pattern, int repeat) {
if (repeat >= pattern.length) {
throw new ArrayIndexOutOfBoundsException();
}
try {
mIm.vibrate(mDeviceId, pattern, repeat, mToken);
} catch (RemoteException ex) {
Log.w(TAG, "Failed to vibrate.", ex);
}
}
@Override
public void cancel() {
try {
mIm.cancelVibrate(mDeviceId, mToken);
} catch (RemoteException ex) {
Log.w(TAG, "Failed to cancel vibration.", ex);
}
}
}
这里关注public void vibrate(long[] pattern, int repeat)方法,最终调用mIm.vibrate(mDeviceId, pattern, repeat, mToken)。。坑爹的,mIm是个抽象类,又得去找其实例,然后穿越到InputManagerService.java,放看起vibrate方法:
public void vibrate(int deviceId, long[] pattern, int repeat, IBinder token) {
if (repeat >= pattern.length) {
throw new ArrayIndexOutOfBoundsException();
}
VibratorToken v;
synchronized (mVibratorLock) {
v = mVibratorTokens.get(token);
if (v == null) {
v = new VibratorToken(deviceId, token, mNextVibratorTokenValue++);
try {
token.linkToDeath(v, 0);
} catch (RemoteException ex) {
// give up
throw new RuntimeException(ex);
}
mVibratorTokens.put(token, v);
}
}
synchronized (v) {
v.mVibrating = true;
nativeVibrate(mPtr, deviceId, pattern, repeat, v.mTokenValue);
}
}
这里调用了JNI方法nativeVibrate,同样,InputDeviceVibrator的cancel方法也到了这里:
public void cancelVibrate(int deviceId, IBinder token) {
VibratorToken v;
synchronized (mVibratorLock) {
v = mVibratorTokens.get(token);
if (v == null || v.mDeviceId != deviceId) {
return; // nothing to cancel
}
}
cancelVibrateIfNeeded(v);
}
cancelVibrateIfNeeded方法最终调用nativeCancelVibrate方法。到达JNI层。
|||||||||
再来看看NullVibrator类。。不过既然是Null。。。那就是Null实现。
自此,vibrate跟cancel到达的JNI层的接口是:
private static native void nativeVibrate(int ptr, int deviceId, long[] pattern,
int repeat, int token);
private static native void nativeCancelVibrate(int ptr, int deviceId, int token);
|-------然后是vibratorCount为0的情况,直接调用vibratorOn,cancel同理。
自此,vibrate跟cancel到达的JNI层的接口是:
native static void vibratorOn(long milliseconds);
native static void vibratorOff();
2.JNI层
--对于nativeVibrate/nativeCancelVibrate,其实现位于com_android_server_input_InputManagerService.cpp中.
static void nativeVibrate(JNIEnv* env,
jclass clazz, jint ptr, jint deviceId, jlongArray patternObj,
jint repeat, jint token) {
NativeInputManager* im = reinterpret_cast
size_t patternSize = env->GetArrayLength(patternObj);
if (patternSize > MAX_VIBRATE_PATTERN_SIZE) {
ALOGI("Skipped requested vibration because the pattern size is %d "
"which is more than the maximum supported size of %d.",
patternSize, MAX_VIBRATE_PATTERN_SIZE);
return; // limit to reasonable size
}
jlong* patternMillis = static_cast
patternObj, NULL));
nsecs_t pattern[patternSize];
for (size_t i = 0; i < patternSize; i++) {
pattern[i] = max(jlong(0), min(patternMillis[i],
MAX_VIBRATE_PATTERN_DELAY_NSECS / 1000000LL)) * 1000000LL;
}
env->ReleasePrimitiveArrayCritical(patternObj, patternMillis, JNI_ABORT);
im->getInputManager()->getReader()->vibrate(deviceId, pattern, patternSize, repeat, token);
}
static void nativeCancelVibrate(JNIEnv* env,
jclass clazz, jint ptr, jint deviceId, jint token) {
NativeInputManager* im = reinterpret_cast
im->getInputManager()->getReader()->cancelVibrate(deviceId, token);
}
-- 对于vibratorOn /vibratorOff,其实现位于com_android_server_VibratorService.cpp中
static JNINativeMethod method_table[] = {
{ "vibratorExists", "()Z", (void*)vibratorExists },
{ "vibratorOn", "(J)V", (void*)vibratorOn },
{ "vibratorOff", "()V", (void*)vibratorOff }
};
static void vibratorOn(JNIEnv *env, jobject clazz, jlong timeout_ms)
{
// ALOGI("vibratorOn\n");
vibrator_on(timeout_ms);
}
static void vibratorOff(JNIEnv *env, jobject clazz)
{
// ALOGI("vibratorOff\n");
vibrator_off();
}
3.HAL层
vib rator_on/vibrator_off的定义位于头文件
/**
* Turn on vibrator
*
* @param timeout_ms number of milliseconds to vibrate
*
* @return 0 if successful, -1 if error
*/
int vibrator_on(int timeout_ms);
/**
* Turn off vibrator
*
* @return 0 if successful, -1 if error
*/
int vibrator_off();
HAL已经完成了实现。
\hardware\libhardware_legacy\vibrator\vibrator.c
/*
* Copyright (C) 2008 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.
*/
#include
#include "qemu.h"
#include
#include
#include
#include
#define THE_DEVICE "/sys/class/timed_output/vibrator/enable"
int vibrator_exists()
{
int fd;
#ifdef QEMU_HARDWARE
if (qemu_check()) {
return 1;
}
#endif
fd = open(THE_DEVICE, O_RDWR);
if(fd < 0)
return 0;
close(fd);
return 1;
}
static int sendit(int timeout_ms)
{
int nwr, ret, fd;
char value[20];
#ifdef QEMU_HARDWARE
if (qemu_check()) {
return qemu_control_command( "vibrator:%d", timeout_ms );
}
#endif
fd = open(THE_DEVICE, O_RDWR);
if(fd < 0)
return errno;
nwr = sprintf(value, "%d\n", timeout_ms);
ret = write(fd, value, nwr);
close(fd);
return (ret == nwr) ? 0 : -1;
}
int vibrator_on(int timeout_ms)
{
/* constant on, up to maximum allowed time */
return sendit(timeout_ms);
}
int vibrator_off()
{
return sendit(0);
}
这里使用的是Android的timed output机制,通过操纵/sys/class/timed_output/vibrator/enable节点启动或者停止启动器。
4.内核层
先看看timed output的驱动代码,位于Linux_Kernel_3x\drivers\staging\android\下。
#ifndef _LINUX_TIMED_OUTPUT_H
#define _LINUX_TIMED_OUTPUT_H
struct timed_output_dev {
const char *name;
/* enable the output and set the timer */
void (*enable)(struct timed_output_dev *sdev, int timeout);
/* returns the current number of milliseconds remaining on the timer */
int (*get_time)(struct timed_output_dev *sdev);
/* private data */
struct device *dev;
int index;
int state;
};
extern int timed_output_dev_register(struct timed_output_dev *dev);
extern void timed_output_dev_unregister(struct timed_output_dev *dev);
#endif
所有的timed output实现都需要定义在结构体timed_output_dev中。
Timed Output驱动程序框架将为每个设备在/sys/class/timed_output/目录中建立一个子目录,设备子目录中的enable文件就是设备的控制文件。读enable文件表示获得剩余时间,写这个文件表示根据时间振动。
这个具体情况具体实现,参考:
http://tech.it168.com/a2012/0201/1305/000001305847.shtmlhttp://tech.it168.com/a2012/0201/1305/000001305847.shtml