一般来讲手机都会有高低温报警,每个厂商都有自己的不同需求,所以这方面便会有很多定制;而因为平台不同,虽然说殊途同归,实现方式一样,但是代码方面也会有些区别。
我写java的,所以从java代码入手,讲述一下整个流程。
1.首先是BatteryWarning这个apk,在kk平台和后面的平台这个apk位置是不一样的,在kk中apk位于alps/mediatek/packages/apps/BatteryWarning,而在后面的平台这个apk则是在alps/vendor/mediatek/proprietary/packages/apps/BatteryWarning。
在java代码这一层其实很简单,kk中只有2个类:BatteryWarningActivity.java,BatteryWarningReceiver.java。而后面的平台中也只有3个类:BatteryWarningActivity.java,BatteryWarningReceiver.java,ThermalWarningActivity.java。多出来的ThermalWarningActivity.java是关于手机通信模块过热的,相较于BatteryWarningActivity.java中的警告要轻一些,两者逻辑相同。BatteryWarningActivity.java会受到广播,然后根据广播携带的信息来判断是哪种情况,这其中有一个地方要注意:
type = (int)(Math.log(type) / Math.log(2));
举个例子当传过来的type= 2时,这个是对应温度过高的情况, 经过转换后 type = 1
当传过来的type= 32时,这个是对应温度过低的情况,转换后 type = 5
然后广播通过
activityIntent.putExtra("type", type);
mContext.startActivity(activityIntent);
或者:
thermalIntent.putExtra(ThermalWarningActivity.KEY_TYPE, typeValue);
mContext.startActivity(thermalIntent);
将这个值传给BatteryWarningActivity.java或者ThermalWarningActivity.java,接下来不同平台的区别就出来了,kk是没有低温报警的,而之后的平台是有的,kk中我们可以通过如下方式加入低温报警:
//我加的
private static final int BATTERY_LOW_TEMPERATURE_TYPE = 5;
static final int[] sWarningTitle = new int[] {
R.string.title_charger_over_voltage,
R.string.title_battery_over_temperature,
R.string.title_over_current_protection,
R.string.title_battery_over_voltage,
R.string.title_safety_timer_timeout,
//我加的
R.string.title_battery_low_temperature};
private static final int[] sWarningMsg = new int[] {
R.string.msg_charger_over_voltage,
R.string.msg_battery_over_temperature,
R.string.msg_over_current_protection,
R.string.msg_battery_over_voltage,
R.string.msg_safety_timer_timeout,
//我加的
R.string.msg_battery_low_temperature };
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (Intent.ACTION_POWER_DISCONNECTED.equals(action)) {
if (mType == CHARGER_OVER_VOLTAGE_TYPE
|| mType == SAFETY_OVER_TIMEOUT_TYPE || mType == BATTERY_LOW_TEMPERATURE_TYPE/*我加的*/) {
Xlog.d(TAG, "receive ACTION_POWER_DISCONNECTED broadcast, finish");
finish();
}
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
mType = intent.getIntExtra("type", -1);
Xlog.d(TAG, "onCreate, mType is " + mType);
if (mType >= CHARGER_OVER_VOLTAGE_TYPE && mType <= BATTERY_LOW_TEMPERATURE_TYPE/*我加的*/) {
showWarningDialog(mType);
registerReceiver(mReceiver, new IntentFilter(
Intent.ACTION_POWER_DISCONNECTED));
} else {
finish();
}
}
protected void onDestroy() {
super.onDestroy();
if (mType >= CHARGER_OVER_VOLTAGE_TYPE && mType <= BATTERY_LOW_TEMPERATURE_TYPE/*我加的*/) {
unregisterReceiver(mReceiver);
}
}
代码中有“我加的”注释就是要修改的地方,至于字符串就按照需求放了。
2.说了这么多java代码的,但是有没有发现一个问题,广播哪里发过来的呢?广播多少从java中发过来的,但是这次不一样了,发广播的地方kk中:alps/mediatek/external/batterywarning/batterywarning.c
void readType(char* buffer) {
FILE * pFile;
pFile = fopen(FILE_NAME, "r");
if(pFile == NULL) {
LOGE("error opening file");
return;
} else {
if(fgets(buffer, MAX_CHAR, pFile) == NULL) {
LOGE("can not get the string from the file");
return;
}
}
int type = atoi(buffer);
if (type > 0 && systemServerStarted(CMD))
{
LOGD("start activity by send intent to BatteryWarningReceiver, type = %s", buffer);
char ps[MAX_LENGTH] = INTENT;
strcat(ps,buffer);
LOGD("os.system: %s", ps);
system(ps);
}
fclose(pFile);
}
其中FILE_NAME:#define FILE_NAME "/sys/devices/platform/mt-battery/BatteryNotify"
INTENT:#define INTENT "am broadcast -n com.mediatek.batterywarning/com.mediatek.batterywarning.BatteryWarningReceiver -a android.intent.action.BATTERY_WARNING --ei type "
在之后的平台则是在:alps/vendor/mediatek/proprietary/frameworks/opt/batterywarning/batterywarning.cpp
void readType(char* buffer) {
FILE * pFile;
pFile = fopen(FILE_NAME, "r");
if (pFile == NULL) {
ALOGE("error opening file");
return;
} else {
if (fgets(buffer, MAX_CHAR, pFile) == NULL) {
fclose(pFile);
ALOGE("can not get the string from the file");
return;
}
}
fclose(pFile);
int type = atoi(buffer);
if (type > 0)
{
ALOGD("start activity by send intent to BatteryWarningReceiver, type = %d\n", type);
sendBroadcastMessage(String16(ACTION), type);
}
}
FILE_NAME:这个地方和kk就有不同了:
#ifdef MTK_GM_30
#define FILE_NAME "/sys/devices/platform/charger/BatteryNotify"
#else
#define FILE_NAME "/sys/devices/platform/mt-battery/BatteryNotify"
至于怎么判断的呢?可以看alps/kernel-3.18/drivers/power/mediatek/battery_common.c文件(kk平台则是alps/mediatek/kernel/drivers/power/battery_common.c):
struct platform_device MT_batteryNotify_device = {
.name = "mt-battery",
.id = -1,
};
那就很明显是mt-battery咯,
ACTION则为:#define ACTION "mediatek.intent.action.BATTERY_WARNING"
可以看的出来后面平台的代码还是要出色的多的。
可以看出具体哪个type和BatteryNotify这个文件有关,那么哪个地方是写这个文件的呢?
这是我们首先要看该文件怎么创建出来的:
static DEVICE_ATTR(BatteryNotify, 0664, show_BatteryNotify, store_BatteryNotify);
这里就是将BatteryNotify文件创建出来的地方,然后我们可以看到里面有show_BatteryNotify这一句,找到这个代码:
static ssize_t show_BatteryNotify(struct device *dev,struct device_attribute *attr, char *buf)
{
battery_xlog_printk(BAT_LOG_CRTI, "[Battery] show_BatteryNotify : %x\n", g_BatteryNotifyCode);
return sprintf(buf, "%u\n", g_BatteryNotifyCode);
}
哦,原来BatteryNotify里的值是和g_BatteryNotifyCode一样,而在battery_common.c有无数关于g_BatteryNotifyCode的赋值操作,不同情况赋予不同的值,比如温度过高:
if(BMT_status.temperature >= MAX_CHARGE_TEMPERATURE)
{
g_BatteryNotifyCode |= 0x0002;
battery_xlog_printk(BAT_LOG_CRTI, "[BATTERY] bat_temp(%d) out of range(too high)\n", BMT_status.temperature);
}
温度过低:
#if defined(MTK_JEITA_STANDARD_SUPPORT)
else if (BMT_status.temperature < TEMP_NEG_10_THRESHOLD)
{
g_BatteryNotifyCode |= 0x0020;
battery_xlog_printk(BAT_LOG_CRTI, "[BATTERY] bat_temp(%d) out of range(too low)\n", BMT_status.temperature);
}
那么整个代码流程就已经完毕了,接下来说一个调试技巧。
我们如果要做高温测试的话需要去实验室,来来回回很耽误时间,那么我们调试的时候便可以找到battery_common.c同级目录下的battery_meter.c文件,其中有一个int force_get_tbat(void)方法,将其改成低温报警:
int abcd = 30;//我加的低温报警
int force_get_tbat(void)
{
abcd -= 1;//我加的低温报警
return abcd;//我加的低温报警
#if defined(CONFIG_POWER_EXT) || defined(FIXED_TBAT_25)
bm_print(BM_LOG_CRTI, "[force_get_tbat] fixed TBAT=25 t\n");
return 25;
或者高温报警:
int abcd = 30;//我加的低温报警
int force_get_tbat(void)
{
abcd += 1;//我加的低温报警
return abcd;//我加的低温报警
#if defined(CONFIG_POWER_EXT) || defined(FIXED_TBAT_25)
bm_print(BM_LOG_CRTI, "[force_get_tbat] fixed TBAT=25 t\n");
return 25;
区别就是自加或者自减,这样的话就可以模拟高低温报警的情况。