Android电池管理

1:Android电池管理结构

 Android-statuabar电池管理_第1张图片


 Android-statuabar电池管理_第2张图片

相关代码路径:

java代码:

 frameworks/frameworks/base/services/java/com/android/server/BatteryService.java

frameworks/frameworks/base/core/java/android/os//BatteryManager.javaframeworks/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java

 

JNI代码:

    frameworks/base/services/jni/com_android_server_BatteryService.cpp

kerneldriver 代码:

    drivers/power/xx_battery.c

2:在SystemServer.java中可以看到启动BatteryService的代码:

SystemServer.java

@Override

    public void run() {

……………………………….

Slog.i(TAG,"Battery Service");

            battery = newBatteryService(context, lights);

       ServiceManager.addService("battery", battery);

……………………………….

}

 

 

 

BatteryManager.java电池的各个状态:

 

信息

类型

状态

Status

电池状态

 

int

BATTERY_STATUS_UNKNOWN

未知

1

BATTERY_STATUS_CHARGING

充电状态

2

BATTERY_STATUS_DISCHARGING

放电中

3

BATTERY_STATUS_NOT_CHARGING

未充电

4

BATTERY_STATUS_FULL

电池满

5

 

 

 

Health

电池健康情况

 

 

 

int

 

BATTERY_HEALTH_UNKNOWN

未知

1

BATTERY_HEALTH_GOOD

良好

2

BATTERY_HEALTH_OVERHEAT

过热

3

BATTERY_HEALTH_DEAD

没电

4

BATTERY_HEALTH_OVER_VOLTAGE

过电压

5

BATTERY_HEALTH_UNSPECIFIED_FAILURE

未知错误

6

BATTERY_HEALTH_COLD

 

7

 

Plugged

充电类型

 

int

 

BATTERY_PLUGGED_AC

充电器

1

BATTERY_PLUGGED_USB

USB

2

BATTERY_PLUGGED_UNKNOWN

未知

3

level

int

电池电量,数字

 

 

scale

int

电池最大容量

 

 

present

boolean

使用状态

 

 

icon-small

int

图标ID

 

 

voltage

int

电池伏数

 

 

temperature

int

电池温度,0.1度单位。

 

 

Technology

String

电池技术

 

 

invalid_charger

String

无效的充电器

 

 

 

3、BatteryService

 BatteryService 作为电池及充电相关的服务: 监听Uevent、读取 sysfs

里中的状态 、广播 Intent.ACTION_BATTERY_CHANGED。

(1)、mPowerSupplyObserver

   BatteryService 实现了一个 UevenObserver  mPowerSupplyObserver。

   uevent 是 Linux 内核用来向用户空间主动上报事件的机制,对于 JAVA 程

序来说,只实现 UEventObserver 的虚函数 onUEvent,然后注册即可。

   private UEventObserver mPowerSupplyObserver= new UEventObserver()

    {

        @Override

        public voidonUEvent(UEventObserver.UEvent event)

        {

            update();

        }

    };

BatteryService只关注 power_supply 的事件,所以在构造函数注册:

    public BatteryService(Context context,LightsService lights)

    {

        mContext = context;

        mLed = new Led(context, lights);

        mBatteryStats =BatteryStatsService.getService();

 

        mCriticalBatteryLevel =mContext.getResources().getInteger(

               com.android.internal.R.integer.config_criticalBatteryWarningLevel);

        mLowBatteryWarningLevel =mContext.getResources().getInteger(

               com.android.internal.R.integer.config_lowBatteryWarningLevel);

        mLowBatteryCloseWarningLevel =mContext.getResources().getInteger(

               com.android.internal.R.integer.config_lowBatteryCloseWarningLevel);

        mFullBatteryLevel =mContext.getResources().getInteger(

                com.android.internal.R.integer.config_fullBatteryLevel);

 

       mPowerSupplyObserver.startObserving("SUBSYSTEM=power_supply");

 

        // watch for invalid charger messagesif the invalid_charger switch

        // exists

        if (newFile("/sys/devices/virtual/switch/invalid_charger/state").exists())

        {

           mInvalidChargerObserver.startObserving("DEVPATH=/devices/virtual/switch/invalid_charger");

        }

 

        // set initial status

        update();

}

 

(2)、update()

   update 读取 jni做到同步取得电池信息, 然后根据读到的状态更新

BatteryService的成员变量,并广播一个 Intent 来通知其它关注电源状态的

组件。

   当 kernel 有 power_supply 事 件 上 报 时 ,mPowerSupplyObserver调 用

update()函数,然后 update 调用 native_update 从 jni处读取相关状态

(com_android_server_BatteryService.cpp):

   

 

    private synchronized final void update()

    {

  

        native_update();

        processValues();

     

    }

然后:

privatenative void native_update();

 

 

(3)、sysfs

   Linux 驱动 driver 维护着保存电池信息的一组文件 sysfs,供应用程序获

取电源相关状态.

当电池状态发生变化时,driver 会更新这些文件。

 

 

4:数据传送: processValues()里有调用sendIntent():

    private final void sendIntent()

    {       // Pack up the values and broadcast them to everyone

        Intent intent = newIntent(Intent.ACTION_BATTERY_CHANGED);

       intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY |Intent.FLAG_RECEIVER_REPLACE_PENDING);

 

        int icon = getIcon(mBatteryLevel);

 

       intent.putExtra(BatteryManager.EXTRA_STATUS, mBatteryStatus);

       intent.putExtra(BatteryManager.EXTRA_HEALTH, mBatteryHealth);

       intent.putExtra(BatteryManager.EXTRA_PRESENT, mBatteryPresent);

       intent.putExtra(BatteryManager.EXTRA_LEVEL, mBatteryLevel);

       intent.putExtra(BatteryManager.EXTRA_SCALE, BATTERY_SCALE);

       intent.putExtra(BatteryManager.EXTRA_ICON_SMALL, icon);

        intent.putExtra(BatteryManager.EXTRA_PLUGGED,mPlugType);

       intent.putExtra(BatteryManager.EXTRA_VOLTAGE, mBatteryVoltage);

       intent.putExtra(BatteryManager.EXTRA_TEMPERATURE, mBatteryTemperature);

       intent.putExtra(BatteryManager.EXTRA_TECHNOLOGY, mBatteryTechnology);

       intent.putExtra(BatteryManager.EXTRA_INVALID_CHARGER, mInvalidCharger);

 

        if (false)

        {

            Slog.d(TAG, "level:" +mBatteryLevel + " scale:" + BATTERY_SCALE + " status:"

                    + mBatteryStatus + "health:" + mBatteryHealth + " present:" + mBatteryPresent

                    + " voltage: " +mBatteryVoltage + " temperature: " + mBatteryTemperature

                    + " technology: "+ mBatteryTechnology + " AC powered:" + mAcOnline

                    + " USB powered:"+ mUsbOnline + " Unknown powered: " + mUnknownOnline

                    + " icon:" + icon+ " invalid charger:" + mInvalidCharger);

        }

 

       ActivityManagerNative.broadcastStickyIntent(intent, null);

      

    }

 

5:数据接收:

BatteryController.Java里:

   public BatteryController(Context context) {

        mContext = context;

 

        IntentFilter filter = newIntentFilter();

       filter.addAction(Intent.ACTION_BATTERY_CHANGED);

        context.registerReceiver(this, filter);

    }

 

接着:

 

    public void onReceive(Context context,Intent intent) {

        final String action =intent.getAction();

        if(action.equals(Intent.ACTION_BATTERY_CHANGED)) {

            final int level =intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);

            final boolean plugged =intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0;

            final int status =intent.getIntExtra(BatteryManager.EXTRA_STATUS,BatteryManager.BATTERY_STATUS_UNKNOWN);

 

            // @ { QIA-1189,update status baricon when battery state changed.

            final int icon;

            final boolean isBartteryPresent =intent.getBooleanExtra(BatteryManager.EXTRA_PRESENT,

                    false);

            if (isBartteryPresent) {

                icon =(BatteryManager.BATTERY_STATUS_CHARGING == status) ?R.drawable.stat_sys_battery_charge

                        :R.drawable.stat_sys_battery;

            } else {

                icon =R.drawable.stat_sys_battery_absent;

            }

            // @ }

 

            int N = mIconViews.size();

            for (int i=0; i

                ImageView v =mIconViews.get(i);

                v.setImageResource(icon);

                v.setImageLevel(level);

                v.setContentDescription(mContext.getString(R.string.accessibility_battery_level,

                        level));

            }

            N = mLabelViews.size();

            for (int i=0; i

                TextView v =mLabelViews.get(i);

                v.setText(mContext.getString(R.string.status_bar_settings_battery_meter_format,

                        level));

            }

            mIcon = icon;

            mLevel = level;

        }

    }

6:控制显示

PhoneStatusBar.java

    // ================================================================================

    //Constructing the view

    //================================================================================

    protected ViewmakeStatusBarView() {

                ………………..

             mBatteryController =newBatteryController(mContext);

        mBatteryController.addIconView((ImageView)sb.findViewById(R.id.battery));

 

               ………………



问题一:电量过低自动关机流程
1: BatteryService.java
update() /processValues() /shutdownIfNoPower():
条件:
(mBatteryLevel <= 0 && !isPowered() && ActivityManagerNative.isSystemReady())  
执行:
Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
            intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);          mContext.startActivity(intent);
2:启动ShutdownActivity.java
  ShutdownThread.shutdown(ShutdownActivity.this, mConfirm);
3:调到ShutdownThread.java
shutdown(final Context context, boolean confirm).
根据confirm的boolean值决定是哪种关机方式;电量过低confirm=false,是自动关机。
注:1>:mBatteryLevel赋值:
else if ("level".equals(key)) {
                        mBatteryLevel = Integer.parseInt(value);
    2>:isPowered()
    3>:ActivityManagerNative.isSystemReady()


问题二A:低电量弹出警告对话框

1: BatteryService.java
update() /processValues() /shutdownIfNoPower():
……………………………………………………..
    final boolean sendBatteryLow = !plugged
                    && mBatteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
                    && mBatteryLevel <= mLowBatteryWarningLevel
                    && (oldPlugged || mLastBatteryLevel > mLowBatteryWarningLevel);
…………………………………………………….
   if (sendBatteryLow) {
                mSentLowBatteryBroadcast = true;
                statusIntent.setAction(Intent.ACTION_BATTERY_LOW);
                mContext.sendBroadcast(statusIntent);
            }


2: PhoneApp.java
protected class PhoneAppBroadcastReceiver extends BroadcastReceiver{
……………………
else if (action.equals(Intent.ACTION_BATTERY_LOW)) {
            Log.i("_battery", "PA-----XXX------Recvier:ACTION_BATTERY_LOW+will notifier.sendBatteryLow()--");
           
                if (VDBG) Log.d(LOG_TAG, "mReceiver: ACTION_BATTERY_LOW");
                notifier.sendBatteryLow();  // Play a warning tone if in-call
………………………..


问题二B:低电量弹出警告对话框
通过广播接收处理
PowerUI.java
在start()方法里注册:
……………………………..
        filter.addAction(Intent.ACTION_BATTERY_CHANGED);
       ……………………………
        mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
在接收里处理:
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
                String action = intent.getAction();
            if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
………………………
  if (!plugged
                        && (bucket < oldBucket || oldPlugged)
                        && mBatteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
                        && bucket < 0) {
//弹出低电量请连接充电器对话框,此对话框不会自动消失,必须处理。若连上充电器则调用//dismissLowBatteryWarning()自动消失。
                    showLowBatteryWarning();


                    // only play SFX when the dialog comes up or the bucket changes
                    if (bucket != oldBucket || oldPlugged) {
//弹出低电量请连接充电器对话框的警告声音。
playLowBatterySound();
                    }
                }
………………………
}
}
}

 other:充电100%和充电完成的区别

充电100%是level=100,并不等同于充电完成,充电完成的判断是BATTERY_STATUS_FULL

若要statusbar电池状态图:插线充电满显示充电完成图(未充电图),插线充电充满100%但未充满显示充电100%图(充电图);未插线充电显示未充电图标,则对于4.3,4.4系统需要修改BatteryController。java中接收action时对电池icon的处理:

增加boolean batteryFull 值判断

boolean batteryFull = false;

boolean plugged = false;

 switch (status) {

case BatteryManager.BATTERY_STATUS_CHARGING:

batteryFull = false;

plugged = true;

break;

case BatteryManager.BATTERY_STATUS_FULL:

plugged = true;

batteryFull = true;

break;

}

int icon = (plugged && !batteryFull) ? R.drawable.stat_sys_battery_charge:: R.drawable.stat_sys_battery; 

同时去除level=100的判断

.........................

for (BatteryStateChangeCallback cb : mChangeCallbacks) {

cb.onBatteryLevelChanged(level, (plugged && !batteryFull));

}

.........................


在实现onBatteryLevelChanged处只需调整对应充电字串显示。

对于通知栏电池快捷显示,需改变接口BatteryStateChangeCallback中onBatteryLevelChanged方法

更多相关文章

  1. 安卓隐藏标题栏状态栏 ,实现全屏效果
  2. Android屏幕尺寸、标题栏高度、状态栏高度、当前View尺寸
  3. android button多状态, selector
  4. android 电池(二):android关机充电流程、充电画面显示
  5. android对话框的使用
  6. android 对话框的封装
  7. Android 之 对话框总结
  8. android电池信息简介
  9. TableRow 背景问题以及修改对话框标题高度或者图片

随机推荐

  1. android 混淆时需要注意的地方
  2. android 官方的下拉刷新:SwipeRefreshLay
  3. Android(安卓)谷歌统计
  4. LinearLayout布局中将一个控件放在屏幕的
  5. Android(安卓)之 国际化与资源自适应
  6. Android(安卓)Activity跳转学习笔记
  7. Android(安卓)4.1 Jelly Bean adds Offli
  8. Android: PLEASE DO NOT USE A WAKE LOCK
  9. Android(安卓)内存管理工具
  10. Android(安卓)如何设置网关和路由