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 Audio系统之RingerMode

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

android之声音管理器AudioManager的使用

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

静音模式

GlobalAction.java内静音模式 private final class SilentModeTriStateAction implements Action, View.OnCl...

Android L 音量调节问题分析

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

Android程序开机启动&&监听情景模式切换

要求:设置一个android应用程序开机启动一个服务,此服务用来监听情景模式的切换。 首先要知道在android中开机启动程序是通过广播机制实现的,在android手机启动完成之后,系统会发送一个名叫...

Android7.1勿扰功能简析

Android系统在5.1系统开始增加勿扰模式,渐渐的有着取代静音模式的趋势,最新的系统已经更新到7.1.1,我们来看一下最新的原生勿扰有哪些功能。...

CallAudioManager 是如何工作的

CallAudioManager是干啥的呢?单词分来来写 Call Audio Manager,一个管理通话中音频状态的类。初始化一张图看清CallAudioManager怎么来的 。 在Tel...
  • aaa111
  • aaa111
  • 2016年04月12日 10:31
  • 1320

Android M Zen mode(勿扰)分析

应用需要申请android.permission.ACCESS_NOTIFICATION_POLICY才可以操作Zen mode 在Settings下,用户可以设置哪些应用能控制Zen mode。...

Android Fragment详解(三): 实现Fragment的界面

为fragment添加用户界面:     Fragment一般作为activity的用户界面的一部分,把它自己的layout嵌入到activity的layout中。 一个     要为fragment...
  • t12x3456
  • t12x3456
  • 2012年10月24日 08:51
  • 18856

android 情景模式设置

大家仔细看下面我这个方法,它是用来设置这些情景模式的。 但是系统返回的状态只有三个,分别为: 1、public static final int RINGER_MODE_SILENT = 0;...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:RingerMode 设置和勿扰模式关系
举报原因:
原因补充:

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