您的位置:首页 > 移动开发 > Android开发

Android & Vibrator

2014-03-06 17:26 225 查看
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();

}}); <SPAN></SPAN>

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> mInputDeviceVibrators = new ArrayList<Vibrator>();

里面的每一个元素都是一个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<NativeInputManager*>(ptr);

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<jlong*>(env->GetPrimitiveArrayCritical(

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<NativeInputManager*>(ptr);

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的定义位于头文件<hardware_legacy/vibrator.h>(\hardware\libhardware_legacy\include\hardware_legacy\)

/**

* 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 <hardware_legacy/vibrator.h>

#include "qemu.h"

#include <stdio.h>

#include <unistd.h>

#include <fcntl.h>

#include <errno.h>

#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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: