android高低溫報警

         一般來講手機都會有高低溫報警,每個廠商都有自己的不同需求,所以這方面便會有很多定製;而因爲平臺不同,雖然說殊途同歸,實現方式一樣,但是代碼方面也會有些區別。

         我寫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;

區別就是自加或者自減,這樣的話就可以模擬高低溫報警的情況。

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章