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. js操作table倒叙显示序号的问题

    今天遇到一奇葩问题,就是在js添加table时,序号是倒叙显示的,而且数据库查出来时正序的,为什么显示是倒叙的呢? 我百度一番,终于有了结果: var newRow=table.insertRow(- ...

  2. [转]ANDROID L——Material Design详解(动画篇)

    转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! 转自:http://blog.csdn.net/a396901990/article/de ...

  3. iOS7跳转AppStore地址

    跳转AppStore地址改变: 由 itms-apps://ax.itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews? ...

  4. face mask in opencv

    http://stackoverflow.com/questions/22427550/face-mask-in-opencv

  5. Oracle ORA-12519: TNS:no appropriate service handler found 解决

    有时候连得上数据库,有时候又连不上. 可能是数据库上当前的连接数目已经超过了它能够处理的最大值. select count(*) from v$process --当前的连接数select value ...

  6. you need to upgrade the working copy first

    is too old (format 29) to work with client version '1.9.4 (r1740329)' (expects format 31) 2016年09月18 ...

  7. vsftp 定时任务同步

    yum install db4-utils.x86_64 -y yum install ftp vsftp lftp 在客户端 和服务端都安装vsftp服务 并配置虚拟账号 上传包内文件 [root@ ...

  8. Java基础——常用类(Date、File)以及包装类

    本文要点: 基本数据类型的包装类 字符串相关类: 不可变字符序列:String 可变字符序列:StringBuffer.StringBuilder 时间处理相关类: Date DateFormat.S ...

  9. 无线AP_H3C WA2620i-AGN配置

    设置Console口登录AP设备的用户进行密码认证: <Sysname> system-view //进入系统视图 [WA2620i-AGN]user-interface console ...

  10. [GeoServer]重拾GeoServer之安装篇

    GeoServer的项目是一个完整的Java(J2EE)系统,现实了OpenGIS联盟的网络功能服务器规范和网络覆盖服务器规范,并且集成了Web地图服务器. 在大三的时候WebGIS课程中老师讲解过一 ...