RingerMode 设置和勿扰模式关系

原创 2016年08月30日 17:07:15

问题引入,在项目中,Android6.0项目中,客户要求去掉勿扰模式,当时我们只是去掉了勿扰模式的界面显示部分,即在SystemUI 的VolumeDialog.java类当中去掉了勿扰模式显示的部分和设置中界面显示部分。而实际的功能并为做修改。这样做之后又出现了新问题。

android5.1以后,在按音量下键时,将音量调到0之后,在继续按音量下键,会将情景模式调到勿扰模式,无法直接调到静音模式。我们在界面修改,在铃声到0后震动模式后,再次点击音量下键时,在更新界面处显示静音图标,以为这样可以规避问题满足客户需求,结果发现,当选择震动模式后,点击音量下到静音,这样没有问题。但是在设置中,先选择震动模式,然后关闭静音时震动,则应该到静音模式,实际上按音量下键调出volumeDialog时,显示的还是震动图标,而此时状态栏中显示的确实是静音图标?如果我们直接从正常的铃音模式切换到静音模式,那么图标都显示正常的。why?为什么这么神奇?为了解决上面问题,到代码中查找原因:

 

首先先说一下,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;

 

此处务必记住, AudioManager中定义的铃声类型(RingerMode)只有以上三种,并没有勿扰模式。所以说,勿扰模式是属于情景模式,但是不属于铃声模式的范畴。

 

其次, AudioManager.java这个类还定义了设置和获取铃声模式的public方法,getRingerMode(),setRingerMode(int)


进入到setRingerMode(int)发现,调用的是AudioService.java的setRingerModeExternal(),

继续调用到AudioService.java的setRingerMode(ringerMode, caller, true /*external*/)。

而设置铃声模式主要的实现就是在AudioService.java的setRingerMode()中,此处第三个参数传入的是true,setRingerMode的方法如下


在setRingerMode中前面的判断先不关注,直接看try语句里面的部分,当调用AudioManager的setRingerMode方法后,传入的参数external 是true,那么会进入到try语句中的上半部分。即调用setRingerModeExt(),


这个方法先判断传入的ringerMode值是否和mRingerModeExternal相等,若不同的话,直接将传入的ringerMode值赋给了mRingerModeExternal,然后发送RINGER_MODE_CHANGED_ACTION广播。

接下来setRingerMode()方法会去检查是否要去更新mRingerModeInternal这个变量的值。



而此时ringerMode又是从mRingerModeDelegate.onSetRingerModeExternal中从新更新了依次。Ringermodedelegate类是一个接口,而ZenModeHelper.java的RingerModeDelegate内部类实现了该接口,接下来看RingerModeDelegate类的onSetRingerModeExternal方法,现在才到了今天想分享的关键地方,也是引起项目出现问题的地方。

先看onSetRingerModeExternal实现


这个方法参数有点多,先解释下:

ringerModeOld  本次还未设置之前的ringerMode值,对应与Audioservice中的mRingerModeExternal的值

ringerModeNew  本次即将要设置的ringerMode值,该值是从第三方应用或系统应用,如设置,systemUI下来栏中图标传过来的值。

caller 调用者,那个应用来调的(分析该问题,可不关注)

ringerModeInternal 当前AudioService中mRingerMode的值,

policy 可不关注

 

搞清楚这些参数意思之后,再来分析代码,

boolean isChange 是判断当前ringerMode(mRingerModeExternal)值和即将要设置的ringerMode值是否相等,

isVibrate 是当前ringerModeInternal(对应与AudioService的mRingerMode值)是否是震动模式

 

然后判断即将要设置的ringerMode是那种类型,震动或者normal模式时,直接关闭勿扰模式,返回ringerModeInternalOut,也就是ringerModeNew,当ringerMode是静音模式时,判断isChange是否为true,true则进入勿扰,然后更新ringerModeInternalOut,再返回ringerModeInternalOut,而出现问题的地方是这里。先说流程,后面在分析问题。

 

返回之后又回到了AudioService的setRingerMode方法,再判断返回的ringerMode和当前的ringerModeInternal是否相等,若不相等,则调用setRingerModeInt()方法,



ringerModeInternal是否相等,若不相等,则调用setRingerModeInt()方法,

 

该方法即去同步设置mRingMode的值,然后发送INTERNAL_RINGER_MODE_CHANGED_ACTION广播。可见AudioService中的mRingerMode和mRingerModeExternal是否需要同步起作用的还是在Ringermodedelegate中。

 

现在来分析出现问题的原因,问题是:在设置或者systemUI中先打开静音模式开关,在打开静音时震动开关,此时是震动模式,然后关闭静音时震动开关,此时状态栏中显示的是静音模式,按音量下键,查看volumeDialog发现,是震动图标。这个问题的原因还是要看onSetRingerModeExternal方法。

这种情况下,onSetRingerModeExternal的几个参数相当与:

ringerModeOld  是震动模式

ringerModeNew  是静音模式

ringerModeInternal  震动模式

isChange true

isVibrate true  

这样的话按照代码流程,ringerModeInternalOut最终赋的值还是AudioManager.RINGER_MODE_VIBRATE,那么进入AudioService中会将mRingterMode的值设置成AudioManager.RINGER_MODE_VIBRATE,但是此时mRingerModeExternal的值是AudioManager.RINGER_MODE_SILENT,而设置中和systemUI状态栏使用的是mRingerModeExternal,所以显示的是静音,而且状态栏和设置中监听的广播也是RINGER_MODE_CHANGED_ACTION,即mRingerModeExternal改变后发出的广播。而VolumeDialog.java中用到的是mRingterMode(这个可到该类中去看,是通过AudioManager.getRingerModeInternal()获取的),当然显示的是震动图标了。

 

另一个问题,为什么我先设置成normal模式,再设置成静音模式时,都显示正常呢?

这种情况下,因为我们先设置了normal模式,那么onSetRingerModeExternal的参数相当与:

ringerModeOld  正常模式

ringerModeNew  静音模式

ringerModeInternal  正常模式

isChange true

isVibrate false

 

 此时依然会将情景模式切换到勿扰,但因为现在isVibrate是false,所以返回的ringerModeInternalOut是AudioManager.RINGER_MODE_SILENT,然后AudioService中同样会将mRingerMode设置成AudioManager.RINGER_MODE_SILENT,所以此时mRingerMode和mRingerModeExternal相同,都是AudioManager.RINGER_MODE_SILENT,所以这时候无论在systemUI,Settings还是VolumeDialog.java都显示静音。

 

到此,该问题的原因已经清晰~~~














版权声明:本文为博主原创文章,未经博主允许不得转载。

android之声音管理器AudioManager的使用

Android声音管理AudioManager使用手机都有声音模式,声音、静音还有震动,甚至震动加声音兼备,这些都是手机的基本功能。在Android手机中,我们同样可以通过Android的SDK提供的...
  • chenzheng_java
  • chenzheng_java
  • 2011年03月20日 18:29
  • 20324

Android Audio系统之RingerMode

田海立@CSDN2012-04-11本文介绍Android系统中Audio里的RingerMode。从使用的角度,只要关注第一节AudioManager中对于RingerMode的接口;后面章节讲解了...
  • thl789
  • thl789
  • 2012年04月11日 19:03
  • 12522

静音模式

GlobalAction.java内静音模式 private final class SilentModeTriStateAction implements Action, View.OnCl...
  • u011404910
  • u011404910
  • 2016年03月05日 11:14
  • 931

zen mode

1.    Ringer mode与zen mode的互相影响 这分部主要由ZenModeHelper完成. Ringer mode对zen mode的影响: setRingerModeExterna...
  • ygd11
  • ygd11
  • 2015年04月24日 02:06
  • 2891

RingerMode 设置和勿扰模式关系

问题引入,在项目中,Android6.0项目中,客户要求去掉勿扰模式,当时我们只是去掉了勿扰模式的界面显示部分,即在SystemUI 的VolumeDialog.java类当中去掉了勿扰模式显示的部分...
  • qidabing
  • qidabing
  • 2017年06月29日 20:50
  • 254

Android7.1勿扰功能简析

Android系统在5.1系统开始增加勿扰模式,渐渐的有着取代静音模式的趋势,最新的系统已经更新到7.1.1,我们来看一下最新的原生勿扰有哪些功能。...
  • tubby_ting
  • tubby_ting
  • 2017年02月08日 11:04
  • 2612

Android L 音量调节问题分析

Android升到5.0或5.1之后,细心的同学可能会发现,在我们调节音量的时候,无法调到静音模式。音量调到1的时候,再往下调,就变成震动模式了。如果你说再按下键不就是静音模式了吗?其实这不是静音模式...
  • woshing123456
  • woshing123456
  • 2015年05月14日 18:57
  • 1144

系统音量条

最近在定制Android系统音量条,发现代码还是蛮多的,下面总结一下。 代码是基于5.1.1版本的。 系统音量条的代码是在/frameworks/base/packages/SystemUI/sr...
  • u013082948
  • u013082948
  • 2017年03月02日 11:05
  • 612

android 静音与振动

android 静音与振动 1,设置静音和振动 静音和振动都属于来电后的动作.所以在设置静音和振动时都只是设置一些标识,并往数据库写入相应标识. 文件:packages/apps/setting...
  • Buaaroid
  • Buaaroid
  • 2014年06月26日 16:41
  • 1810

Android5.0 静音模式下让闹钟仍然响铃

最近在看Android 5.0的代码,发现可以通过音量键来控制情景模式,而且在此次升级的静音模式可谓是完全静音了,就连闹钟都不会发音。 我要做一个可以在静音模式下选择闹钟是否仍然响铃的开关。 本文仅为...
  • hello_gson
  • hello_gson
  • 2015年02月13日 16:09
  • 3270
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:RingerMode 设置和勿扰模式关系
举报原因:
原因补充:

(最多只允许输入30个字)