Android振動器 android.os.Vibrator html
1.Java層 frameworks/base/core/java/android/os/Vibrator.java 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。 android
registerService(VIBRATOR_SERVICE, new ServiceFetcher() { public Object createService(ContextImpl ctx) { return new SystemVibrator(); }});
Vibrator類只是個抽象類,具體實現的代碼位於 SystemVibrator。位於\frameworks\base\core\java\android\os\目錄下。兩個方法的實現代碼以下: express
@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); } }
與 apache
@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,其聲明代碼以下: app
mService = IVibratorService.Stub.asInterface( ServiceManager.getService("vibrator"));
/*這裏跟Binder機制有關。。。斷片ing*/ 框架
定義是private final IVibratorService mService;
因此找找這個IVibratorService吧。
查找下\frameworks\base\core\java\android\os\IVibratorService.aidl,這裏定義了接口。 less
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 ide
而後是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方法。
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這個表示什麼意義!
private final ArrayList<Vibrator> mInputDeviceVibrators = new ArrayList<Vibrator>();裏面的每個元素都是一個Vibrator的實力,Vibrator是個抽閒類。
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的子類:
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層。
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同理。
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(); }
/** * 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已經完成了實現。
/* * 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