(转)android 静音与振动 (2011-07-12 09:49) 分类: android android 静音与振动1,设置静音和振动静音和振动都属于来电后的动作.所以在设置静音和振动时都只是设置一些标识,并往数据库写入相应标识.文件:packages/apps/settings/src/com/android/settings/SoundAndDisplaySettings.javaprivate CheckBoxPreference mSilent;private CheckBoxPreference mVibrate; private void setRingerMode(boolean silent, boolean vibrate) { if (silent) { mAudioManager.setRingerMode(vibrate ? AudioManager.RINGER_MODE_VIBRATE : AudioManager.RINGER_MODE_SILENT); } else { mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL); mAudioManager.setVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER, vibrate ? AudioManager.VIBRATE_SETTING_ON : AudioManager.VIBRATE_SETTING_OFF); } } public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { if (preference == mSilent || preference == mVibrate) { setRingerMode(mSilent.isChecked(), mVibrate.isChecked()); if (preference == mSilent) updateState(false); }...静音和振动是复选框按钮,两个中有一个发生变化时调用setRingerMode对状态进行设置;如下状态描术:RINGER_MODE_SILENT 静音,且无振动RINGER_MODE_VIBRATE 静音,但有振动RINGER_MODE_NORMAL 正常声音,振动开关由setVibrateSetting决定.铃响模式的设置是通过mAudioManager(音频管理器)来实现的.2 音频管理器服务mAudioManager所在服务如下:文件: frameworks/base/media/java/android/media/AudioManager.java public static final int RINGER_MODE_SILENT = 0; public static final int RINGER_MODE_VIBRATE = 1; public static final int RINGER_MODE_NORMAL = 2;public void setRingerMode(int ringerMode) { IAudioService service = getService(); try { service.setRingerMode(ringerMode); } catch (RemoteException e) { Log.e(TAG, "Dead object in setRingerMode", e); }}将铃响模式值传给音频接口服务IaudioServicepublic static final int VIBRATE_TYPE_RINGER = 0; public static final int VIBRATE_TYPE_NOTIFICATION = 1; public static final int VIBRATE_SETTING_OFF = 0; public static final int VIBRATE_SETTING_ON = 1; public static final int VIBRATE_SETTING_ONLY_SILENT = 2;public void setVibrateSetting(int vibrateTyp , int vibrateSetting) { IAudioService service = getService(); try { service.setVibrateSetting(vibrateType, vibrateSetting); } catch (RemoteException e) { Log.e(TAG, "Dead object in setVibrateSetting", e); }}将振动类型和振动设置传给音频接口服务IaudioService,IaudioService的定义如下:frameworks/base/media/java/android/media/IAudioService.aidlframeworks/base/media/java/android/media/AudioService.java文件: frameworks/base/media/java/android/media/AudioService.java文件: frameworks/base/core/java/android/provider/Settings.javapublic void setRingerMode(int ringerMode) { synchronized (mSettingsLock) { if (ringerMode != mRingerMode) { setRingerModeInt(ringerMode, true); // Send sticky broadcast broadcastRingerMode(); } }}将对应模式下的音量写入数据库,并将该模式广播.public void setVibrateSetting(int vibrateType, int vibrateSetting) { mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, vibrateType, vibrateSetting); // Broadcast change broadcastVibrateSetting(vibrateType); // Post message to set ringer mode (it in turn will post a message // to persist) sendMsg(mAudioHandler, MSG_PERSIST_VIBRATE_SETTING, SHARED_MSG, SENDMSG_NOOP, 0, 0, null, 0);}同样将振动模式写入数据库,并广播该模式.3 硬件服务文件:frameworks/base/services/java/com/android/server/HardwareService.java开始振动:public void vibrate(long milliseconds, IBinder token) { if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Requires VIBRATE permission"); } // 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); synchronized (mVibrations) { removeVibrationLocked(token); doCancelVibrateLocked(); mCurrentVibration = vib; startVibrationLocked(vib); }}private void startVibrationLocked(final Vibration vib) { if (vib.mTimeout != 0) { vibratorOn(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(); } }该接口允许设置振动的时间长度,通过调用vibratorOn(vib.mTimeout);实现对底层硬件的操作。取消振动:public void cancelVibrate(IBinder token) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.VIBRATE, "cancelVibrate"); // so wakelock calls will succeed long identity = Binder.clearCallingIdentity(); try { synchronized (mVibrations) { final Vibration vib = removeVibrationLocked(token); if (vib == mCurrentVibration) { doCancelVibrateLocked(); startNextVibrationLocked(); } } } finally { Binder.restoreCallingIdentity(identity); }}private void doCancelVibrateLocked() { if (mThread != null) { synchronized (mThread) { mThread.mDone = true; mThread.notify(); } mThread = null; } vibratorOff (); mH.removeCallbacks(mVibrationRunnable);}该接口允许停止振动,通过调用vibratorOff();实现对底层硬件的操作。4 硬件调用vibratorOn、vibratorOff对应的jni代码如下:文件:frameworks/base/services/jni/com_android_server_HardwareService.cppstatic void vibratorOn(JNIEnv *env, jobject clazz, jlong timeout_ms){ // LOGI("vibratorOn/n"); vibrator_on(timeout_ms);}static void vibratorOff(JNIEnv *env, jobject clazz){ // LOGI("vibratorOff/n"); vibrator_off();}vibrator_on、vibrator_off 接口的提供者为如下硬件原型。5, 硬件原型文件:hardware/libhardware_legacy/vibrator/vibrator.c#define THE_DEVICE "/sys/class/timed_output/vibrator/enable" 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);}由以上代码可知,开启振动时是往文件/sys/class/timed_output/vibrator/enable写入振动的时间长度;关闭振动时,其时间长度为0。/sys/class/timed_output/vibrator/enable 的真实路径根据实际作修改。6,驱动代码创建timed_output类kernel/drivers/staging/android/Timed_output.c在sys/class目录创建timed_output子目录和文件enable timed_output_class = class_create(THIS_MODULE, "timed_output");创建timed_output子目录 ret = device_create_file(tdev->dev, &dev_attr_enable);在sys/class/timed_output子目录创建文件enable static int create_timed_output_class(void){ if (!timed_output_class) { timed_output_class = class_create(THIS_MODULE, "timed_output"); if (IS_ERR(timed_output_class)) return PTR_ERR(timed_output_class); atomic_set(&device_count, 0); } return 0;}int timed_output_dev_register(struct timed_output_dev *tdev){ int ret; if (!tdev || !tdev->name || !tdev->enable || !tdev->get_time) return -EINVAL; ret = create_timed_output_class(); if (ret < 0) return ret; tdev->index = atomic_inc_return(&device_count); tdev->dev = device_create(timed_output_class, NULL, MKDEV(0, tdev->index), NULL, tdev->name); if (IS_ERR(tdev->dev)) return PTR_ERR(tdev->dev); ret = device_create_file(tdev->dev, &dev_attr_enable); if (ret < 0) goto err_create_file; dev_set_drvdata(tdev->dev, tdev); tdev->state = 0; return 0;err_create_file: device_destroy(timed_output_class, MKDEV(0, tdev->index)); printk(KERN_ERR "timed_output: Failed to register driver %s/n", tdev->name); return ret;}EXPORT_SYMBOL_GPL(timed_output_dev_register);驱动注册马达的驱动,注册一个定时器用于控制震动时间(回调函数vibrator_timer_func),注册两个队列,一共给马达打开用,一共为马达震动关闭用。 static void pmic_vibrator_on(struct work_struct *work){ set_pmic_vibrator(1);}static void pmic_vibrator_off(struct work_struct *work){ set_pmic_vibrator(0);}static void timed_vibrator_on(struct timed_output_dev *sdev){ schedule_work(&work_vibrator_on);}static void timed_vibrator_off(struct timed_output_dev *sdev){ schedule_work(&work_vibrator_off);}static void vibrator_enable(struct timed_output_dev *dev, int value){ hrtimer_cancel(&vibe_timer); if (value == 0) timed_vibrator_off(dev); else { value = (value > 15000 ? 15000 : value); timed_vibrator_on(dev); hrtimer_start(&vibe_timer, ktime_set(value / 1000, (value % 1000) * 1000000), HRTIMER_MODE_REL); }}static int vibrator_get_time(struct timed_output_dev *dev){ if (hrtimer_active(&vibe_timer)) { ktime_t r = hrtimer_get_remaining(&vibe_timer); return r.tv.sec * 1000 + r.tv.nsec / 1000000; } else return 0;}static enum hrtimer_restart vibrator_timer_func(struct hrtimer *timer){ timed_vibrator_off(NULL); return HRTIMER_NORESTART;}static struct timed_output_dev pmic_vibrator = { .name = "vibrator", .get_time = vibrator_get_time, .enable = vibrator_enable,};void __init pxa_init_pmic_vibrator(void){ INIT_WORK(&work_vibrator_on, pmic_vibrator_on); INIT_WORK(&work_vibrator_off, pmic_vibrator_off); hrtimer_init(&vibe_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); vibe_timer.function = vibrator_timer_func; timed_output_dev_register(&pmic_vibrator);}当上层要设置马达震动时,往文件/sys/class/timed_output/vibrator/enable写入振动的时间长度,通过static ssize_t enable_store( struct device *dev, struct device_attribute *attr, const char *buf, size_t size){ struct timed_output_dev *tdev = dev_get_drvdata(dev); int value; sscanf(buf, "%d", &value); tdev->enable(tdev, value); return size;}调用驱动的enable函数也就是vibrator_enable( .enable = vibrator_enable,) vibrator_enable | | vtimed_vibrator_on(dev); | | v schedule_work(&work_vibrator_on); | | vpmic_vibrator_on | | vset_pmic_vibrator(1); //给马达供电震动 | | v hrtimer_start(&vibe_timer, ktime_set(value / 1000, (value % 1000) * 1000000), HRTIMER_MODE_REL);最终是设置马达的硬件控制驱动管给马达供电,并且启动定时器,定时时间是上层给的参数。定时时间到了就调用定时器的回调函数vibrator_timer_funcvibrator_timer_func | | vtimed_vibrator_off(NULL); | | v schedule_work(&work_vibrator_off); | | vpmic_vibrator_off | | vset_pmic_vibrator(0); //断开马达的供电,马达停止震动最终是设置马达的硬件控制驱动管断开马达供电,停止马达震动

更多相关文章

  1. Android封装jar包,把当前项目设置成module,封装手机振动jar包给uni
  2. Android(安卓)振动器解析
  3. android手机通过串口蓝牙透传模块与AVR单片机通信实例。。。蓝牙
  4. Android(安卓)情景模式
  5. android的振动器Vibrator
  6. Timed out Device -- Vibrator
  7. Android(安卓)Mediaplayer设置静音和恢复声音
  8. Delphi xe7 up1 调用android振动功能
  9. android Vibrator使用示例

随机推荐

  1. Android中的系统广播集合
  2. [置顶] Android技术交流群
  3. No resource found that matches the giv
  4. Android ViewFlipper装载baseAdapter
  5. TimePicker的一些使用方法
  6. Android方法的传递值及其改变
  7. 日拱一卒(十三)
  8. Android配置打包名称
  9. 零碎知识点回顾——Activity横竖屏切换的
  10. Android(安卓)Support库和AndroidX冲突问