平台:RK3288 Android5.1
需求:Android原生的系统下拉通知栏的快捷方式中有一个sim卡的图标,点击会进入流量使用详情界面,客户想将这个图标换成手机那样直接开关数据流量的按钮。
思路:下拉通知栏属于systemUI,所以要修改需要去到SystemUI的源码位置(frameworks/base/packages/SystemUI/)去修改,因为实现的是开关的功能,所以可以参考gps开关的方式,点击响应事件部分和显示部分做对应的修改就行了。
步骤:
(1)
先来看看下拉状态栏快捷方式的布局,查资料找到是在frameworks/base/packages/SystemUI/res/values/config.xml
中:
<string name="quick_settings_tiles_default_bt" translatable="false">
wifi,bt,inversion,cell,airplane,rotation,flashlight,location,cast,hotspot
</string>
可见有好几个选项,我们要改的是cell对应的选项,我们可以选择在这里替换掉它,改成networkdata
(2)
然后再看是哪里会读取这个xml文件,找到是在frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
的loadTileSpecs方法中调用了,在createTile方法中会对这个属性中的值做匹配,找到:
else if (tileSpec.equals("cell")) return new CellularTileForSlot(this, PhoneConstants.SIM_ID_1);
可见当解析到cell这个项的时候,会构造一个CellularTileForSlot类,因为上一步中把cell值替换为了networkdata,所以在这里也要添加一个case:
else if (tileSpec.equals("networkdata")) return new xxx;
当然从这一步看,我们也可以选择在上一步中选择不替换cell,而是在这里这个case中选择替换掉return后面的类。因为代码需要兼容不同的项目,在xml文件中兼容比在java文件中兼容难度大的做,所以笔者选择不做(1)中的替换,而是在
else if (tileSpec.equals("cell")) return new CellularTileForSlot(this, PhoneConstants.SIM_ID_1);
中选择替换了return后面的类。
(3)
因为我们要做的功能与gps开关类似,作为参考,找到这个开关的实现:
else if (tileSpec.equals("location")) return new LocationTile(this);
搜索这个类,位置为:
frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
所以在同一个目录下,复制此文件,并且更名为NetworkDataTile.java,与类名相关的比如构造函数等都做修改,其他先不变,(2)中的
else if (tileSpec.equals("cell")) return new CellularTileForSlot(this, PhoneConstants.SIM_ID_1);
修改为:
else if (tileSpec.equals("cell")) return new NetworkDataTile(this);
并且import对应的类。
编译,没有出现问题,将生成的apk导入系统对应位置,重启,下拉通知栏发现果然原来sim卡的标志已经变成了location的标志。
这样就成功迈出第一步。
(4)
接下来先不管UI,先搞定功能,这是一个类似按钮的控件,所以需要找到点击事件,通过对比LocationTile.java,发现了其中点击事件的逻辑都是在handleClick这个函数之中,所以只要修改这里就可以修改点击功能。先看LocationTile里面的逻辑:
@Override
protected void handleClick() {
final boolean wasEnabled = (Boolean) mState.value;
mController.setLocationEnabled(!