最近做个项目用到2个电池的系统,一个内部电池,一个外部电池。内部电池和普通Android系统没什么区别,外部电池实际上是作为AC的形式,但是用了一个CW2015的芯片来读取电量,并且要求能在系统中显示出来。
由于Android原生只支持一个电池,因此需要修改系统才行。此项目选择在原有电池管理系统基础上修改来实现。下面先简单分析下Android电池管理的架构。
Android电池管理分为服务端和客户端,下面做下简单分析。
服务端通过JNI读取Linux 内核电池文件节点,然后更新电池信息,发送一个ACTION,ACTION里就带有电池信息的Intent,客户端注册接收此ACTION的广播接收器,接收处理并显示在状态栏(statusbar)上。
服务端由如下2个文件组成:
JNI 部分:
frameworks/base/services/jni/com_android_server_BatteryService.cpp
Service部分:
frameworks/base/services/java/com/android/server/BatteryService.java
此电池服务是作为系统服务运行的。
客户端由如下文件组成:
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
客户端是SystemUI的一部分。
PS:由于Android系统并不支持双电池系统,不过Linux内核支持UPS,所以在电池的驱动里把类型改为如下,其余的没有需要特别改的地方:
cw_bat->rk_bat.type = POWER_SUPPLY_TYPE_UPS;
这个在后面的Android系统修改中需要用到。
::::下面来一步步增加外部电池的部分。
1:把BatteryController.java文件复制一份,命名为ExtBatteryController.java ,然后按照java类的要去更改ExtBatteryController.java 为合法,不要问我改哪 里, 难道类名和构造函数名不改?
2:在/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/ PhoneStatusBar.java文件 的
BatteryController mBatteryController;
这行下面增加一行:
ExtBatteryController mExtBatteryController;
实际就是在类里增加这个变量。
然后在此文件里的protected PhoneStatusBarView makeStatusBarView()函数的下面3行后面
mLocationController = new LocationController(mContext); // will post a notification
mBatteryController = new BatteryController(mContext);
mBatteryController.addIconView((ImageView)mStatusBarView.findViewById(R.id.battery));
增加如下3行(位于636行左右)
mExtBatteryController = new ExtBatteryController(mContext);
mExtBatteryController.addIconView((ImageView)mStatusBarView.findViewById(R.id.extbattery));
mExtBatteryController.addLabelView((TextView)mStatusBarView.findViewById(R.id.extbattery_label));
这里的R.id.extbattery R.id.extbattery_label 是下面第三步需要在布局文件里定义的。
3:更改布局文件
在如下文件frameworks/base/packages/SystemUI/res/layout/status_bar.xml 的如下内如前面(位于98行左右)
<ImageView
android:id="@+id/battery"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:paddingLeft="4dip"
/>
增加如下内容:
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/extbattery_label"
android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Network"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:layout_gravity="bottom"
android:gravity="center"
/>
<ImageView
android:id="@+id/extbattery"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:paddingLeft="4dip"
/>
看上面的id就是前面在PhoneStatusBar.java文件里用到的。
这个时候保存,然后编译后应该可以看见2个电池图标,并在2个电池图标的左边会有一个显示电池百分比的位置,不过这时显示的还是内部电池的信息。
4:增加服务端
JNI 部分=====================================:
复制frameworks/base/services/jni/com_android_server_BatteryService.cpp 为com_android_server_ExtBatteryService.cpp 并作如下更改
199行:------------------------
static void android_server_BatteryService_update(JNIEnv* env, jobject obj)
改为:static void android_server_ExtBatteryService_update(JNIEnv* env, jobject obj)
228行:------------------------
{"native_ext_update", "()V", (void*)android_server_BatteryService_update},
改为: {"native_ext_update", "()V", (void*)android_server_ExtBatteryService_update},
231行:-------------------------
int register_android_server_BatteryService(JNIEnv* env)
改为: int register_android_server_ExtBatteryService(JNIEnv* env)
271行:--------------------------
else if (strcmp(buf, "battery") == 0) {
改为 : else if (strcmp(buf, "UPS") == 0) {
这里就是因为在Linux驱动里把电池类型定义为UPS的原因了。
335行:---------------------------
jclass clazz = env->FindClass("com/android/server/BatteryService");
改为:jclass clazz = env->FindClass("com/android/server/ExtBatteryService");
PS:这里是为ExtBatteryService类服务的,不是,BatteryService,所以必须改。
/*下面是JNI加载的时候调用的部分*/
然后更改当前路径下的onload.cpp文件里的android命名空间里(25行左右)增加如下语句:
int register_android_server_ExtBatteryService(JNIEnv* env);
再在extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) { 函数里得初始化地方(64行左右)增加如下语句:
register_android_server_ExtBatteryService(env);
最后在当前目录下的Android.mk文件里增加编译刚增加的文件的语句,不要告诉我不会,我也不会。
JAVA 部分==================================
复制frameworks/base/services/java/com/android/server/BatteryService.java 文件为 ExtBatteryService.java,并更改类名。
并更改如下:
146行:---------------------------
private native void native_update();
改为:private native void native_ext_update();
280行:---------------------------
native_update();
改为:native_ext_update();
更改当前目录下得SystemServer.java文件以注册此新服务:
130行左右:----------------------------
增加:ExtBatteryService extbattery = null;
292行左右:----------------------------
增加:Slog.i(TAG, "extBattery Service");
extbattery = new ExtBatteryService(context, lights);
ServiceManager.addService("extbattery", extbattery);
866行左右:------------------------------
增加:final ExtBatteryService extbatteryF = extbattery;
总结:到这里基本上的更改就已经完成了。
不过现在是不能正常工作的,因为内部电池和外部电池的服务端都发送的Intent.ACTION_BATTERY_CHANGED 这个广播,因此肯定会造成冲突,最后内部电池不做更改,外部电池我们新定义一个广播,取名为:"ACTION.EXTBATTERY_CHANGED",然后在外部电池服务里发送这个广播,在外部电池的客户端里接收这个广播,一切都好了,本项目在Android 4.2 Rockchip 3188项目上测试成功。
PS:至于在更改JAVA文件的时候需要导入相应的包的代码没有添加,请自行添加,不要告诉我不会,我也不会。