android 静音与振动
1,设置静音和振动
静音和振动都属于来电后的动作.所以在设置静音和振动时都只是设置一些标识,并往数据库写入相应标识.

文件:packages/apps/settings/src/com/android/settings/SoundAndDisplaySettings.java

private 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);

}

}

将铃响模式值传给音频接口服务IaudioService

public 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.aidl

frameworks/base/media/java/android/media/AudioService.java

文件: frameworks/base/media/java/android/media/AudioService.java

文件: frameworks/base/core/java/android/provider/Settings.java

public 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.cpp

static 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

|

|

v

timed_vibrator_on(dev);

|

|

v

schedule_work(&work_vibrator_on);

|

|

v

pmic_vibrator_on

|

|

v

set_pmic_vibrator(1);   //给马达供电震动

|

|

v

hrtimer_start(&vibe_timer,
         ktime_set(value / 1000, (value % 1000) * 1000000),
         HRTIMER_MODE_REL);

最终是设置马达的硬件控制驱动管给马达供电,并且启动定时器,定时时间是上层给的参数。

定时时间到了就调用定时器的回调函数vibrator_timer_func
vibrator_timer_func

|

|

v

timed_vibrator_off(NULL);

|

|

v

schedule_work(&work_vibrator_off);

|

|

v

pmic_vibrator_off

|

|

v

set_pmic_vibrator(0);     //断开马达的供电,马达停止震动

最终是设置马达的硬件控制驱动管断开马达供电,停止马达震动

android设置系统模式的更多相关文章

  1. android设置系统横屏方案

    效果如下: 实现方案: 1.ChangeOrientationService.java /** * @描述 强制旋转屏幕服务 * @作者 tll * @时间 2018/1/5 */ public cl ...

  2. Android设置系统开机自己主动永不休眠

    android4.2系统增永不休眠同一时候隐藏休眠选项 1. android\frameworks\base\packages\SettingsProvider\res\values\defaults ...

  3. android 设置系统屏幕亮度

    /** * 获得当前屏幕亮度的模式 * SCREEN_BRIGHTNESS_MODE_AUTOMATIC=1 为自动调节屏幕亮度 * SCREEN_BRIGHTNESS_MODE_MANUAL=0 为 ...

  4. android设置系统默认开机时间

    1.设置RTC时间,该时间是如果RCT时钟断电以后使用的默认时间 Android L之前: \alps\mediatek\custom\[project]\preloader\ inc\cust_rt ...

  5. Android 通过应用程序来设置系统的日期和时间中的

    Android 通过应用程序来设置系统的日期和时间中的 android 2.3 android 4.0 测试可行,刚需ROOT权限. import java.io.DataOutputStream; ...

  6. Linux设置系统运行模式

    Linux系统有7个运行级别(runlevel): 运行级别0:系统停机状态,系统默认运行级别不能设为0,否则不能正常启动 运行级别1:单用户工作状态,root权限,用于系统维护,禁止远程登陆 运行级 ...

  7. Android开发技巧——设置系统状态栏颜色

    开门见山,先来三张效果图: 然后我们再来讲如何实现以及如何快速地实现. 如何实现 实现设置系统状态栏颜色需要至少在Android 4.4.2(API 19)以上.这是因为,在这个版本以下,没有任何的A ...

  8. [Android] 字体使用dp单位避免设置系统字体大小对排版的影响

    [Android] 字体使用dp单位避免设置系统字体大小对排版的影响 以魄族mx3为例,在设置->显示->字体大小中能够选择字号大小例如以下图: 图1. 魄族mx3 会导致软件在有固定定高 ...

  9. Android : 反射机制获取或设置系统属性(SystemProperties)【转】

    本文转载自:https://blog.csdn.net/wei_lei/article/details/70312512 Android.os.SystemProperties 提供了获取和设置系统属 ...

随机推荐

  1. ubuntu12.04 安装 php5.4/php5.5

    1:修改源(我使用163的源)直接修改/etc/apt/sources.list deb http://mirrors.163.com/ubuntu/ precise main universe re ...

  2. JS性能消耗在哪里?

    内部原因:构造,递归,循环,拷贝,动态执行,字符串操作等   1.过度的封装(过多的创建“庞大的”对象,但是如果在允许的条件下,面向对象的封装是可以提高维护性,而且符合我们的高内聚低耦合原则): 2. ...

  3. uzqp文件的加解密

    帮朋友做的,根据python版本翻译成的java版本,记录一下代码 import java.io.File; import java.io.FileInputStream; import java.i ...

  4. position定位的小问题

    css中position定位有四个属性,分别是:static.fixed.relative.absolute. 其中,static是默认值,未脱离文档流,元素的位置即按照文档结构的顺序进行定位排序: ...

  5. [LeetCode]题解(python):057-Insert Interval

    题目来源 https://leetcode.com/problems/insert-interval/ Given a set of non-overlapping intervals, insert ...

  6. Android笔记:真机调试无法输出Log 信息的问题

    机器在出厂时将log的级别做了限制,方法是:拨号盘输入*20121220# -> 选择日志输出级别 -> 选择Java log level -> 选择LOGD即可. 方法是:拨号盘输 ...

  7. 用JQuery给图片添加鼠标移入移出事件

    $("#addLineImg").mouseover( function(){ $("#addLineImg").attr("src",&q ...

  8. SWD模式连接与注意事项

    JTAG模式与SWD模式连接图 SWD 仿真模式概念简述 一.SWD 和传统的调试方式区别 1. SWD 模式比 JTAG 在高速模式下面更加可靠. 在大数据量的情况下面 JTAG 下载程序会失败, ...

  9. Interview with BOA

    1. BFS 2. QuickSort 3. PCA, 1000 articles, so many factors, how to reduce factors. 4. newton's metho ...

  10. JQuery: 基本知识了解

    一.介绍:jQuery 是一个 JavaScript函数库.它极大地简化了 JavaScript 编程.jQuery 库可以通过一行简单的标记被添加到网页中.jQuery 是一个轻量级的"写 ...