adb测试震动 1 2 3 4 root@a # busybox find -name "vibrator" root@a # busybox find -name "vibrator" ./sys/ devices/virtual/ timed_output/vibrator ./sys/ class /timed_output/ vibrator
向enable文件写入成功,就立即震动,震动的持续时间即是写入的值,单位为ms
1 2 3 root@ a # echo '10000' > /sys/class /timed_output /vibrator /enable root @a # cat /sys /class /timed_output /vibrator /enable 3290
读enable文件来获得震动剩余的时间
1 2 root@ a # echo ‘0 ’> /sys/class /timed_output /vibrator /enable
按键触摸反馈 代码路径 1 /frameworks/ base/policy/ src/com/ android/internal/ policy/impl/ PhoneWindowManager.java
interceptKeyBeforeQueueing函数中添加如下代码:
1 2 3 4 if (down&&(keyCode == KeyEvent.KEYCODE_HOME ) ||(keyCode == KeyEvent.KEYCODE_MENU )||(keyCode == KeyEvent.KEYCODE_BACK )){ performHapticFeedbackLw (null , HapticFeedbackConstants.VIRTUAL_KEY , false ); }
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 @Override public boolean performHapticFeedbackLw (WindowState win, int effectId, boolean always) { if (!mVibrator.hasVibrator()) { return false ; } final boolean hapticsDisabled = Settings.System.getIntForUser(mContext.getContentResolver(), Settings.Settings.System.HAPTIC_FEEDBACK_ENABLED.HAPTIC_FEEDBACK_ENABLED, 0 , UserHandle.USER_CURRENT) == 0 ; if (hapticsDisabled && !always) { return false ; } Settings.System.HAPTIC_FEEDBACK_ENABLED long [] pattern = null ; switch (effectId) { case HapticFeedbackConstants.LONG_PRESS: pattern = mLongPressVibePattern; break ; case HapticFeedbackConstants.VIRTUAL_KEY: pattern = mVirtualKeyVibePattern; break ; case HapticFeedbackConstants.KEYBOARD_TAP: pattern = mKeyboardTapVibePattern; break ; case HapticFeedbackConstants.CLOCK_TICK: pattern = mClockTickVibePattern; break ; case HapticFeedbackConstants.CALENDAR_DATE: pattern = mCalendarDateVibePattern; break ; case HapticFeedbackConstants.SAFE_MODE_DISABLED: pattern = mSafeModeDisabledVibePattern; break ; case HapticFeedbackConstants.SAFE_MODE_ENABLED: pattern = mSafeModeEnabledVibePattern; break ; default : return false ; } int owningUid; String owningPackage; if (win != null ) { owningUid = win.getOwningUid(); owningPackage = win.getOwningPackage(); } else { owningUid = android.os.Process.myUid(); owningPackage = mContext.getOpPackageName(); } if (pattern.length == 1 ) { mVibrator.vibrate(owningUid, owningPackage, pattern[0 ], VIBRATION_ATTRIBUTES); } else { mVibrator.vibrate(owningUid, owningPackage, pattern, -1 , VIBRATION_ATTRIBUTES); } return true ; }
如震动值由 mVirtualKeyVibePattern = getLongIntArray(mContext.getResources(), com.android.internal.R.array.config_virtualKeyVibePattern);获得。 配置文件在
1 2 3 4 5 6 7 8 9 10 11 frameworks/base/core/res/res/values/config.xml <integer-array name ="config_virtualKeyVibePattern" > <item > 0</item > <item > 10</item > <item > 20</item > <item > 30</item > </integer-array > ... .. .
View长按触发震动 长按button震动
1 2 3 4 5 6 7 8 9 10 11 12 Button click= (Button) findViewById (R.id.click); click.setOnLongClickListener (new View.OnLongClickListener () { @Override public boolean onLongClick (View v) { Toast.makeText (MainActivity.this ,"长按点击" ,Toast.LENGTH_SHORT).show (); return true ; } });
2.View.setOnLongClickListener源码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public void setOnLongClickListener (@Nullable OnLongClickListener l ) { if (!isLongClickable ()) { setLongClickable (true ); } getListenerInfo ().mOnLongClickListener = l; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public boolean performLongClick () { sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); boolean handled = false ; ListenerInfo li = mListenerInfo; if (li != null && li.mOnLongClickListener != null ) { handled = li.mOnLongClickListener.onLongClick(View.this ); } if (!handled) { handled = showContextMenu(); } if (handled) { performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); } return handled; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public boolean performHapticFeedback (int feedbackConstant, int flags) { if (mAttachInfo == null ) { return false ; } if ((flags & HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0 && !isHapticFeedbackEnabled()) { return false ; } return mAttachInfo.mRootCallbacks.performHapticFeedback(feedbackConstant, (flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0 ); }
5.HapticFeedbackConstants的3个常量 1 2 3 HapticFeedbackConstants.LONG_PRESS HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING
6.HapticFeedbackConstants使用方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <Button android :layout_width="wrap_content" android :id="@+id/click" android :layout_height="wrap_content" android :hapticFeedbackEnabled="false" android :text="make" /> ... click.setOnClickListener (new View .OnClickListener () { @Override public void onClick (View v ) { v.performHapticFeedback (HapticFeedbackConstants .LONG_PRESS ,HapticFeedbackConstants .FLAG_IGNORE_GLOBAL_SETTING ); } });
代码介绍 APP层 获取服务后,调用vibrate()方法,实现震动
1 2 mVibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE)mVibrator.vibrate(50 )
Framework层 framework层代码
1 2 3 4 frameworks/base/ services/java/ com/android/ server/VibratorService.java frameworks/base/ core/java/ android/os/ IVibratorService.aidl frameworks/base/ core/java/ android/os/ Vibrator.java frameworks/base/ core/java/ android/os/ SystemVibrator.java
VibratorService.java 有SystemService拉起的服务。实现IVibratorService.aidl的接口,从而实现VibratorService;它的函数接口,是通过调用JNI层对应的马达控制函数来实现的。
Vibrator.java 是VibratorService开放给应用层的调用类。Vibrator是抽象类。它便于我们支持不同类型的马达。
SystemVibrator.java 它是Vibrator.java的子类,实现了vibration的服务接口。 在构造函数中,通过 IVibratorService.Stub.asInterface(ServiceManager.getService(“vibrator”)) 获取马达服务,实际上获取的是VibratorService对象。 SystemVibrator的接口都是调用VibratorService接口实现的
JNI及HAL层 代码路径
1 2 frameworks/base/ services/jni/ com_android_server_VibratorService.cpp hardware/libhardware_legacy/ vibrator/vibrator.c
通过vibrator中sendit函数将对vibrator的控制写进“/sys/class/timed_output/vibrator/enable”节点中。