一:快捷开关功能以及开关状态的实现
第一步:
首先看一下原生的下拉菜单按键的布局在哪里。打开这个路径的文件:frameworks/base/packages/SystemUI/res/values/config.xml
1 | <string name="quick_settings_tiles_default" translatable="false"> |
对!自适应的布局,这些快捷按键的定义都在这里。要是想换成自己定义的按键开关,只要在这里替换就行,但这只是第一步。
我这里暂且换成自己定义的布局:wifi,蓝牙,无线麦克,FM
1 | <string name="quick_settings_tiles_default" translatable="false"> |
第二步:
在config.xml文件中定义我们想要的开关名称之后,还需要打开如下路径来添加相关的内容:
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
在如下方法里面添加:
1 | /** |
这里主要是获取到预定义好的各个快捷图标的QSTile。其中FMTile文件是什么的,接着往下看
第三步:
这一步很重要,首先看一下这个路径:frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tiles
这个路径下面就是你定义的开关实现功能的地方,这里新添加的FM在原有的快捷开关里面是没有的,所以要在这里新添加一个文件,咱们这里暂且起名为FMTile.java,也就是之前所说的FMTile文件。
新建好类之后要继承 QSTile<QSTile.BooleanState>
这样会生成一些方法,下面就来看一下这个文件各个方法的作用:
1 | public class FMTile extends QSTile<QSTile.BooleanState>{ |
其中Settings.System.FM_SYSTEMUI 是我们在settingProvader中定义的值,主要是控制与外界开关同步的问题,这个我们后面会有详细的介绍,这些方法中最重要的是handleClick()和handleUpdateState(…),每次点击开关会先走handleclick()方法,然后去刷新页面,刷新页面的处理就是在handleUpdateState(..)中处理。
这个方法里面有图片状态的改变,以及功能的实现。这个时候开关默认的是关闭,要是默认打开的话只要在两个方法中把mstate = Settings.System.getInt(*, *, 1); 把1改为0即可。
这里还要注意的方法首先是FMTile(..)这个方法是初始化用的,也就是开机之后只走一次,也就相当我Activity里面的Oncreate()方法,如果你有什么要初始化的东西可以在这里面定义。还有特别注意的两个方法setFmModeUpdate()和getQSTileViewMarkBit()。这两个方法不是文件自动生成的,需要你手动添加,那么这两个方法有什么作用呢,其实这两个方法也很重要,要是没有这两个方法的话点击开关是没有作用的,也就是没有起到刷新页面的作用,那这两个方法在那实现的呢,来接着看下面的解释:
第四步:
结合第三步最后的疑问我们来看一下这个文件:frameworks/base/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
1 | protected QSTile(Host host) { |
这些添加之后你的开关状态就能其作用了,但到这里如果你编译工程的时候会发现编译报错,如下图:
这是怎么回事呢,这是因为你添加的FMTile.java文件里面的方法是从一个超类型实现的。
这个时候你还需有在QSTile.java文件中添加getQSTileViewMarkBit()方法,如下:
1 | // |
到这里FM开关的添加就结束了。同样的方法添加其它快捷按键开关原理都是一样的。
二:下拉FM开关与外界开关同步
其实刚才我们已经有所了解了,主要就是Settings值的作用,但这里面还涉及到一个重要的知识点,先不着急,我们先打开FM的应用代码,看怎么实现同步更新:
首先在你应用里面控制开关的地方加上Settings.System.putInt(MainActivity.this.getContentResolver(), Settings.System.FM_SYSTEMUI, 0); //0代表打开 关闭的时候调用Settings.System.putInt(MainActivity.this.getContentResolver(), Settings.System.FM_SYSTEMUI, 1); //1代表关闭
关键的代码来了:也就是我们之前说的实现同步更新的 ContentObserver 内容观察者
首先看一下代码:
1 | private void registerContentObserver() { |
在onChange方法里面主要是观察Settings值的变化,然后根据值的变化控制你应用的开关。我们定义的这个值在状态栏快捷开关里面也有所控制,这个刚才已经介绍。那么这个时候你会问,我们在应用里面添加观察者可是没有在下拉状态栏里添加,这样能同步吗?其实SystemUi里面已经添加过了,你只需要在你的应用里添加内容观察者即可。注意在初始化的地方要注册registerContentObserver() ,在退出的时候调用unregisterContentObserver()方法即可。这样以来就能实现应用开关和状态栏下拉快捷开关的同步。
这里还涉及到一个知识点:就是打开开关,不管是在你的应用里还是在状态栏快捷开关里,打开FM后在状态栏顶部需要有一个图标显示你打开了FM,关闭时图片消失。这个功能的实现我会在后续的文章中介绍。这里就不做说明了。
相信看到这里你会对SystemUi状态栏的开发有新的帮助。