问题引入,在项目中,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都显示静音。

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

RingerMode 设置和勿扰模式关系相关推荐

  1. android 勿扰模式代码,Android N Zen Mode (勿扰模式)设置流程

    Android N去除了情景模式,取而代之的是勿扰模式.勿扰模式的入口有两处,下拉栏和设置声音里面.下面我们就从设置声音入口,看看勿扰模式的设置流程. 首先,勿扰模式的首页有三种选项,分别是仅允许优先 ...

  2. MIUI12设置勿扰模式下来电白名单步骤

    描述:MIUI12设置勿扰模式下来电白名单步骤 步骤:设置-搜索勿扰-允许来电提醒选择联系人

  3. 按键添加震动功能。设置-》应用和通知-》通知-》高级-》勿扰模式立即开启按钮放置界面首行。

    按键添加震动功能: /frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java 比如Ho ...

  4. Mac 勿扰模式周期性开关闭功能实现脚本

    专心开发工作的时候,通知滴滴答答响个不停,影响效率和心情? . 发现 Mac 提供了临时屏蔽通知的功能,就是 勿扰模式. 不错,可以安心工作了.缺点就是容易忘记关闭勿扰,错过一些重要的通知. 可是每次 ...

  5. android 勿扰模式代码,android Lollipop勿扰模式

    android的L新版本中增加了"打扰"的新功能,相信很多同学搞不明白.找了一篇介绍勿扰模式很好的文章,可惜是英文的,现翻译如下,相信读完此问,你会理解android对勿扰模式的设 ...

  6. Android Zenmode/DND(勿扰模式) 实现原理剖析

    引言 Android手机越来越多的向着用户体验提升方面靠近,那么Zenmode就会变得越来越重要. 近年来,也有很多的新功能依赖于ZenMode去实现,也有很多专利在这个方面申请成功. 举两个简单的例 ...

  7. 苹果手机拦截所有陌生号码,如何解除--请关闭勿扰模式

    如何发现苹果手机拦截所有陌生号码(不在通讯录登记有名子的电话,有时甚至在通讯录电话都阻断掉),拨打的对方只会听到:你拨打的用户忙,请稍后再拨---- 一般是误开打了勿扰模式 勿扰模式,虽然对于那些一般 ...

  8. 勿扰模式代码结构简析

    勿扰模式是Android 7.0开始加入的功能.它的核心思想是屏蔽了通知的铃声.振动和展示. 代码分散在几部分. 1.设置代码在Settings中,ZenMode开头的一系列文件 /packages/ ...

  9. GNOME 3.36正式发布,家长控制、勿扰模式、更加优雅的锁屏界面

    2020年3月11日,GNOME 3.36正式发布,被命名为 "Gresik", 是 GNOME 3 当前的最新版本.它包含了主要的新功能,以及许多小的改进和错误修复.总的来说,这 ...

最新文章

  1. new二维数组的几种方法
  2. 零基础Java学习之初始化块
  3. Split in Java
  4. jvm学习笔记(一)
  5. LeetCode 7 Reverse Integer(反转数字)
  6. html5中如何实现跑马灯效果,h5_实现跑马灯效果
  7. centos搭建git服务
  8. P2770 航空路线问题
  9. 全网最全Linux常用命令
  10. ug链轮设计软件_教你怎么用UG做链轮教程【UG爱好者首发】
  11. 抽象代数学习笔记三《群:对称性变换与对称性群》
  12. 如何将b站上的视频下载到本地?
  13. 计算机 交换机连接设置方法,怎么用串口线连接电脑和交换机 连接步骤教程
  14. 使用Docker容器来搭建LNMP(Nginx+Mysql+php)+Wordpress
  15. raster包—projectRaster函数
  16. Kali下用wifite破解WIFI
  17. 围剿苹果Siri:车载语音争夺移动终端
  18. 数据结构与算法 — 环形队列
  19. SpringBoot+MyBatisPlus+Thymeleaf+AdminLTE增删改查实战
  20. 常见的BeanUtils.populate异常 解决方案

热门文章

  1. python与sql server处理表_如何将python和google图表与microsoft sql server数据连接起来?...
  2. Mybatis源码解析:从基础到源码统统帮你搞定,使用指南
  3. 今日话题:魏则西事件对百度影响---第二季度损失20亿
  4. 努力做一个灵魂画师、Affinity Designer使用(一)
  5. 《拳霸风云》今日上映 杜海涛首次出演功夫片
  6. .jpg图片转化流程详解
  7. 样条线动画制作方法(个人记录)
  8. 华为最新「天才少年」:博士四年21篇论文,却自称是个「低能儿」
  9. Geohash:算法原理
  10. 2022年都要结束了做网站还需要交换友情链接吗?