Android 4.4 电池电量显示相关

最近遇到个新的需求,当电池温度过高以及OVP状态的时候,在用户界面提示信息。

电池电源信息相关在Framework层/

与电池电量信息等相关类:

1.BatteryManager.Java

2.BatteryProperties.java

3.BatteryStates.java

4.PowerUI.java

5.LightService.java

6.PowerManager.java

7.BatteryService.java


这里先分析BatteryService.java。

源码路径: 

***/framework/base/services/java/com/Android/server/BatteryService.java

BatteryService.java代码,必要的地方做了处理。

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. /* 
  2.  * Copyright (C) 2006 The Android Open Source Project 
  3.  * 
  4.  * Licensed under the Apache License, Version 2.0 (the "License"); 
  5.  * you may not use this file except in compliance with the License. 
  6.  * You may obtain a copy of the License at 
  7.  * 
  8.  *      http://www.apache.org/licenses/LICENSE-2.0 
  9.  * 
  10.  * Unless required by applicable law or agreed to in writing, software 
  11.  * distributed under the License is distributed on an "AS IS" BASIS, 
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  13.  * See the License for the specific language governing permissions and 
  14.  * limitations under the License. 
  15.  */  
  16.   
  17. package com.android.server;  
  18.   
  19. import android.os.BatteryStats;  
  20. import com.android.internal.app.IBatteryStats;  
  21. import com.android.server.am.BatteryStatsService;  
  22.   
  23. import android.app.ActivityManagerNative;  
  24. import android.content.ContentResolver;  
  25. import android.content.Context;  
  26. import android.content.Intent;  
  27. import android.content.pm.PackageManager;  
  28. import android.os.BatteryManager;  
  29. import android.os.BatteryProperties;  
  30. import android.os.Binder;  
  31. import android.os.FileUtils;  
  32. import android.os.Handler;  
  33. import android.os.IBatteryPropertiesListener;  
  34. import android.os.IBatteryPropertiesRegistrar;  
  35. import android.os.IBinder;  
  36. import android.os.DropBoxManager;  
  37. import android.os.RemoteException;  
  38. import android.os.ServiceManager;  
  39. import android.os.SystemClock;  
  40. import android.os.UEventObserver;  
  41. import android.os.UserHandle;  
  42. import android.provider.Settings;  
  43. import android.util.EventLog;  
  44. import android.util.Slog;  
  45.   
  46. import java.io.File;  
  47. import java.io.FileDescriptor;  
  48. import java.io.FileOutputStream;  
  49. import java.io.IOException;  
  50. import java.io.PrintWriter;  
  51.   
  52.   
  53. /** 
  54.  * <p>BatteryService monitors the charging status, and charge level of the device 
  55.  * battery.  When these values change this service broadcasts the new values 
  56.  * to all {@link android.content.BroadcastReceiver IntentReceivers} that are 
  57.  * watching the {@link android.content.Intent#ACTION_BATTERY_CHANGED 
  58.  * BATTERY_CHANGED} action.</p> 
  59.  * <p>The new values are stored in the Intent data and can be retrieved by 
  60.  * calling {@link android.content.Intent#getExtra Intent.getExtra} with the 
  61.  * following keys:</p> 
  62.  * <p>"scale" - int, the maximum value for the charge level</p> 
  63.  * <p>"level" - int, charge level, from 0 through "scale" inclusive</p> 
  64.  * <p>"status" - String, the current charging status.<br /> 
  65.  * <p>"health" - String, the current battery health.<br /> 
  66.  * <p>"present" - boolean, true if the battery is present<br /> 
  67.  * <p>"icon-small" - int, suggested small icon to use for this state</p> 
  68.  * <p>"plugged" - int, 0 if the device is not plugged in; 1 if plugged 
  69.  * into an AC power adapter; 2 if plugged in via USB.</p> 
  70.  * <p>"voltage" - int, current battery voltage in millivolts</p> 
  71.  * <p>"temperature" - int, current battery temperature in tenths of 
  72.  * a degree Centigrade</p> 
  73.  * <p>"technology" - String, the type of battery installed, e.g. "Li-ion"</p> 
  74.  * 
  75.  * <p> 
  76.  * The battery service may be called by the power manager while holding its locks so 
  77.  * we take care to post all outcalls into the activity manager to a handler. 
  78.  * 
  79.  * FIXME: Ideally the power manager would perform all of its calls into the battery 
  80.  * service asynchronously itself. 
  81.  * </p> 
  82.  */  
  83. public final class BatteryService extends Binder {  
  84.     private static final String TAG = BatteryService.class.getSimpleName();  
  85.   
  86.     private static final boolean DEBUG = false;  
  87.   
  88.     //电量百分比显示  
  89.     private static final int BATTERY_SCALE = 100;    // battery capacity is a percentage  
  90.   
  91.     // Used locally for determining when to make a last ditch effort to log  
  92.     // discharge stats before the device dies.  
  93.     private int mCriticalBatteryLevel;  
  94.   
  95.     private static final int DUMP_MAX_LENGTH = 24 * 1024;  
  96.     private static final String[] DUMPSYS_ARGS = new String[] { "--checkin""--unplugged" };  
  97.   
  98.     private static final String DUMPSYS_DATA_PATH = "/data/system/";  
  99.   
  100.     // This should probably be exposed in the API, though it's not critical  
  101.     //没有充电状态则显示0  
  102.     private static final int BATTERY_PLUGGED_NONE = 0;  
  103.   
  104.     private final Context mContext;  
  105.     private final IBatteryStats mBatteryStats;  
  106.     private final Handler mHandler;  
  107.   
  108.     private final Object mLock = new Object();  
  109.   
  110.     private BatteryProperties mBatteryProps;  
  111.     private boolean mBatteryLevelCritical;  
  112.     private int mLastBatteryStatus;  
  113.     private int mLastBatteryHealth;  
  114.     private boolean mLastBatteryPresent;  
  115.     private int mLastBatteryLevel;  
  116.     private int mLastBatteryVoltage;  
  117.     private int mLastBatteryTemperature;  
  118.     private boolean mLastBatteryLevelCritical;  
  119.   
  120.     private int mInvalidCharger;  
  121.     private int mLastInvalidCharger;  
  122.   
  123.     private int mLowBatteryWarningLevel;  
  124.     private int mLowBatteryCloseWarningLevel;  
  125.     private int mShutdownBatteryTemperature;  
  126.   
  127.     private int mPlugType;  
  128.     private int mLastPlugType = -1// Extra state so we can detect first run  
  129.   
  130.     private long mDischargeStartTime;  
  131.     private int mDischargeStartLevel;  
  132.   
  133.     private boolean mUpdatesStopped;  
  134.   
  135.     private Led mLed;  
  136.   
  137.     private boolean mSentLowBatteryBroadcast = false;  
  138.   
  139.     private BatteryListener mBatteryPropertiesListener;  
  140.     private IBatteryPropertiesRegistrar mBatteryPropertiesRegistrar;  
  141.   
  142.     public BatteryService(Context context, LightsService lights) {  
  143.         mContext = context;  
  144.         mHandler = new Handler(true /*async*/);  
  145.         mLed = new Led(context, lights);  
  146.         mBatteryStats = BatteryStatsService.getService();  
  147.   
  148.         mCriticalBatteryLevel = mContext.getResources().getInteger(  
  149.                 com.android.internal.R.integer.config_criticalBatteryWarningLevel);  
  150.         //res/res/values/config.xml:547:    <integer name="config_lowBatteryWarningLevel">15</integer>  
  151.         mLowBatteryWarningLevel = mContext.getResources().getInteger(  
  152.                 com.android.internal.R.integer.config_lowBatteryWarningLevel);  
  153.         //res/res/values/config.xml:550:    <integer name="config_lowBatteryCloseWarningLevel">20</integer> 接近警戒值。  
  154.         mLowBatteryCloseWarningLevel = mContext.getResources().getInteger(  
  155.                 com.android.internal.R.integer.config_lowBatteryCloseWarningLevel);  
  156.         //res/res/values/config.xml:544:    <integer name="config_shutdownBatteryTemperature">680</integer>//68度?为什么?  
  157.         mShutdownBatteryTemperature = mContext.getResources().getInteger(  
  158.                 com.android.internal.R.integer.config_shutdownBatteryTemperature);  
  159.   
  160.         // watch for invalid charger messages if the invalid_charger switch exists  
  161.         if (new File("/sys/devices/virtual/switch/invalid_charger/state").exists()) {  
  162.             mInvalidChargerObserver.startObserving(  
  163.                     "DEVPATH=/devices/virtual/switch/invalid_charger");  
  164.         }  
  165.   
  166.         //注册监听。实时更新电池电量信息,底层传递上来的电池信息有变化时,则上层会做响应的处理。  
  167.         //从这里可以看出回调接口中调用的update()方法应该是比较频繁的。  
  168.         mBatteryPropertiesListener = new BatteryListener();  
  169.   
  170.         IBinder b = ServiceManager.getService("batterypropreg");  
  171.         mBatteryPropertiesRegistrar = IBatteryPropertiesRegistrar.Stub.asInterface(b);  
  172.   
  173.         try {  
  174.             mBatteryPropertiesRegistrar.registerListener(mBatteryPropertiesListener);  
  175.         } catch (RemoteException e) {  
  176.             // Should never happen.  
  177.         }  
  178.     }  
  179.   
  180.     //该方法在SystemServer.java中调用。开机过程。  
  181.     void systemReady() {  
  182.         // check our power situation now that it is safe to display the shutdown dialog.  
  183.         synchronized (mLock) {  
  184.             shutdownIfNoPowerLocked();  
  185.             shutdownIfOverTempLocked();  
  186.         }  
  187.     }  
  188.   
  189.     /** 
  190.      * Returns true if the device is plugged into any of the specified plug types. 
  191.      */  
  192.     public boolean isPowered(int plugTypeSet) {  
  193.         synchronized (mLock) {  
  194.             return isPoweredLocked(plugTypeSet);  
  195.         }  
  196.     }  
  197.   
  198.     //当前手机是否正在充电。这里面查查&的相关用法。  
  199.     private boolean isPoweredLocked(int plugTypeSet) {  
  200.         // assume we are powered if battery state is unknown so  
  201.         // the "stay on while plugged in" option will work.  
  202.         if (mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN) {  
  203.             return true;  
  204.         }  
  205.         if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_AC) != 0 && mBatteryProps.chargerAcOnline) {  
  206.             return true;  
  207.         }  
  208.         if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_USB) != 0 && mBatteryProps.chargerUsbOnline) {  
  209.             return true;  
  210.         }  
  211.         if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_WIRELESS) != 0 && mBatteryProps.chargerWirelessOnline) {  
  212.             return true;  
  213.         }  
  214.         return false;  
  215.     }  
  216.   
  217.     /** 
  218.      * Returns the current plug type. 
  219.      */  
  220.     public int getPlugType() {  
  221.         synchronized (mLock) {  
  222.             return mPlugType;  
  223.         }  
  224.     }  
  225.   
  226.     /** 
  227.      * Returns battery level as a percentage. 
  228.      */  
  229.     public int getBatteryLevel() {  
  230.         synchronized (mLock) {  
  231.             return mBatteryProps.batteryLevel;  
  232.         }  
  233.     }  
  234.   
  235.     /** 
  236.      * Returns true if battery level is below the first warning threshold. 
  237.      */  
  238.     public boolean isBatteryLow() {  
  239.         synchronized (mLock) {  
  240.             return mBatteryProps.batteryPresent && mBatteryProps.batteryLevel <= mLowBatteryWarningLevel;  
  241.         }  
  242.     }  
  243.   
  244.     /** 
  245.      * Returns a non-zero value if an  unsupported charger is attached. 
  246.      */  
  247.     public int getInvalidCharger() {  
  248.         synchronized (mLock) {  
  249.             return mInvalidCharger;  
  250.         }  
  251.     }  
  252.   
  253.     private void shutdownIfNoPowerLocked() {  
  254.         // shut down gracefully if our battery is critically low and we are not powered.  
  255.         // wait until the system has booted before attempting to display the shutdown dialog.  
  256.         if (mBatteryProps.batteryLevel == 0 && !isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)) {  
  257.             mHandler.post(new Runnable() {  
  258.                 @Override  
  259.                 public void run() {  
  260.                     if (ActivityManagerNative.isSystemReady()) {  
  261.                         Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);  
  262.                         intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);  
  263.                         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
  264.                         mContext.startActivityAsUser(intent, UserHandle.CURRENT);  
  265.                     }  
  266.                 }  
  267.             });  
  268.         }  
  269.     }  
  270.   
  271.     private void shutdownIfOverTempLocked() {  
  272.         // shut down gracefully if temperature is too high (> 68.0C by default)  
  273.         // wait until the system has booted before attempting to display the  
  274.         // shutdown dialog.  
  275.         if (mBatteryProps.batteryTemperature > mShutdownBatteryTemperature) {  
  276.             mHandler.post(new Runnable() {  
  277.                 @Override  
  278.                 public void run() {  
  279.                     if (ActivityManagerNative.isSystemReady()) {  
  280.                         Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);  
  281.                         intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);  
  282.                         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
  283.                         mContext.startActivityAsUser(intent, UserHandle.CURRENT);  
  284.                     }  
  285.                 }  
  286.             });  
  287.         }  
  288.     }  
  289.   
  290.     private void update(BatteryProperties props) {  
  291.         synchronized (mLock) {  
  292.             if (!mUpdatesStopped) {  
  293.                 //mBatteryProps即BatteryProperties,该类封装了电量信息的一些参数。实现了Parcelable接口。  
  294.                 mBatteryProps = props;  
  295.                 // Process the new values.  
  296.                 processValuesLocked();  
  297.             }  
  298.         }  
  299.     }  
  300.   
  301.     //这里是处理电量等逻辑的主要位置。  
  302.     private void processValuesLocked() {  
  303.         boolean logOutlier = false;  
  304.         long dischargeDuration = 0;  
  305.   
  306.         mBatteryLevelCritical = (mBatteryProps.batteryLevel <= mCriticalBatteryLevel);  
  307.         //当前的充电方式。AC,USB,WIRELESS(第三种有点高大上)  
  308.         if (mBatteryProps.chargerAcOnline) {  
  309.             mPlugType = BatteryManager.BATTERY_PLUGGED_AC;  
  310.         } else if (mBatteryProps.chargerUsbOnline) {  
  311.             mPlugType = BatteryManager.BATTERY_PLUGGED_USB;  
  312.         } else if (mBatteryProps.chargerWirelessOnline) {  
  313.             mPlugType = BatteryManager.BATTERY_PLUGGED_WIRELESS;  
  314.         } else {  
  315.             mPlugType = BATTERY_PLUGGED_NONE;  
  316.         }  
  317.           
  318.         //打印日志,可以忽略。  
  319.         if (DEBUG) {  
  320.             Slog.d(TAG, "Processing new values: "  
  321.                     + "chargerAcOnline=" + mBatteryProps.chargerAcOnline  
  322.                     + ", chargerUsbOnline=" + mBatteryProps.chargerUsbOnline  
  323.                     + ", chargerWirelessOnline=" + mBatteryProps.chargerWirelessOnline  
  324.                     + ", batteryStatus=" + mBatteryProps.batteryStatus  
  325.                     + ", batteryHealth=" + mBatteryProps.batteryHealth  
  326.                     + ", batteryPresent=" + mBatteryProps.batteryPresent  
  327.                     + ", batteryLevel=" + mBatteryProps.batteryLevel  
  328.                     + ", batteryTechnology=" + mBatteryProps.batteryTechnology  
  329.                     + ", batteryVoltage=" + mBatteryProps.batteryVoltage  
  330.                     + ", batteryCurrentNow=" + mBatteryProps.batteryCurrentNow  
  331.                     + ", batteryChargeCounter=" + mBatteryProps.batteryChargeCounter  
  332.                     + ", batteryTemperature=" + mBatteryProps.batteryTemperature  
  333.                     + ", mBatteryLevelCritical=" + mBatteryLevelCritical  
  334.                     + ", mPlugType=" + mPlugType);  
  335.         }  
  336.   
  337.         // Let the battery stats keep track of the current level.  
  338.         try {  
  339.             mBatteryStats.setBatteryState(mBatteryProps.batteryStatus, mBatteryProps.batteryHealth,  
  340.                     mPlugType, mBatteryProps.batteryLevel, mBatteryProps.batteryTemperature,  
  341.                     mBatteryProps.batteryVoltage);  
  342.         } catch (RemoteException e) {  
  343.             // Should never happen.  
  344.         }  
  345.   
  346.         //电池电量耗尽以及温度过高。  
  347.         shutdownIfNoPowerLocked();  
  348.         shutdownIfOverTempLocked();  
  349.   
  350.         //mBatteryProps保存之前的电量信息,这里做对比当数据信息有变化的时候则表示电池状态有变化。  
  351.         if (mBatteryProps.batteryStatus != mLastBatteryStatus ||  
  352.                 mBatteryProps.batteryHealth != mLastBatteryHealth ||  
  353.                 mBatteryProps.batteryPresent != mLastBatteryPresent ||  
  354.                 mBatteryProps.batteryLevel != mLastBatteryLevel ||  
  355.                 mPlugType != mLastPlugType ||  
  356.                 mBatteryProps.batteryVoltage != mLastBatteryVoltage ||  
  357.                 mBatteryProps.batteryTemperature != mLastBatteryTemperature ||  
  358.                 mInvalidCharger != mLastInvalidCharger) {  
  359.   
  360.             if (mPlugType != mLastPlugType) {  
  361.                 //plugType前后变化,充电状态--->非充电状态,非充电状态---->充电状态  
  362.                 if (mLastPlugType == BATTERY_PLUGGED_NONE) {  
  363.                     // discharging -> charging  
  364.   
  365.                     // There's no value in this data unless we've discharged at least once and the  
  366.                     // battery level has changed; so don't log until it does.  
  367.                     if (mDischargeStartTime != 0 && mDischargeStartLevel != mBatteryProps.batteryLevel) {  
  368.                         dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime;  
  369.                         logOutlier = true;  
  370.                         EventLog.writeEvent(EventLogTags.BATTERY_DISCHARGE, dischargeDuration,  
  371.                                 mDischargeStartLevel, mBatteryProps.batteryLevel);  
  372.                         // make sure we see a discharge event before logging again  
  373.                         mDischargeStartTime = 0;  
  374.                     }  
  375.                 } else if (mPlugType == BATTERY_PLUGGED_NONE) {  
  376.                     // charging -> discharging or we just powered up  
  377.                     mDischargeStartTime = SystemClock.elapsedRealtime();  
  378.                     mDischargeStartLevel = mBatteryProps.batteryLevel;  
  379.                 }  
  380.             }  
  381.             //打印Log,忽略++++++++++++++++++begin  
  382.             if (mBatteryProps.batteryStatus != mLastBatteryStatus ||  
  383.                     mBatteryProps.batteryHealth != mLastBatteryHealth ||  
  384.                     mBatteryProps.batteryPresent != mLastBatteryPresent ||  
  385.                     mPlugType != mLastPlugType) {  
  386.                 EventLog.writeEvent(EventLogTags.BATTERY_STATUS,  
  387.                         mBatteryProps.batteryStatus, mBatteryProps.batteryHealth, mBatteryProps.batteryPresent ? 1 : 0,  
  388.                         mPlugType, mBatteryProps.batteryTechnology);  
  389.             }  
  390.             if (mBatteryProps.batteryLevel != mLastBatteryLevel) {  
  391.                 // Don't do this just from voltage or temperature changes, that is  
  392.                 // too noisy.  
  393.                 EventLog.writeEvent(EventLogTags.BATTERY_LEVEL,  
  394.                         mBatteryProps.batteryLevel, mBatteryProps.batteryVoltage, mBatteryProps.batteryTemperature);  
  395.             }  
  396.             if (mBatteryLevelCritical && !mLastBatteryLevelCritical &&  
  397.                     mPlugType == BATTERY_PLUGGED_NONE) {  
  398.                 // We want to make sure we log discharge cycle outliers  
  399.                 // if the battery is about to die.  
  400.                 dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime;  
  401.                 logOutlier = true;  
  402.             }  
  403.   
  404.             ///打印Log,忽略++++++++++++++++++end  
  405.               
  406.             final boolean plugged = mPlugType != BATTERY_PLUGGED_NONE;//当前的充电状态  
  407.             final boolean oldPlugged = mLastPlugType != BATTERY_PLUGGED_NONE;//上次的充电状态  
  408.   
  409.             //处理低电量状态。发送广播,弹出AlertDialog,提示用户电池电量低。  
  410.             /* The ACTION_BATTERY_LOW broadcast is sent in these situations: 
  411.              * - is just un-plugged (previously was plugged) and battery level is 
  412.              *   less than or equal to WARNING, or 
  413.              * - is not plugged and battery level falls to WARNING boundary 
  414.              *   (becomes <= mLowBatteryWarningLevel). 
  415.              */  
  416.             final boolean sendBatteryLow = !plugged//当前没有充电  
  417.                     && mBatteryProps.batteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN  
  418.                     && mBatteryProps.batteryLevel <= mLowBatteryWarningLevel//当前电量小于警戒值  
  419.                     && (oldPlugged || mLastBatteryLevel > mLowBatteryWarningLevel);//上次在充或者上次的电量大于警戒值。  
  420.   
  421.             //更新电池电量显示  
  422.             sendIntentLocked();  
  423.   
  424.             //++++++++++++++++power connected / not connected begin+++++++++++++++++++++++++++++++++++++++++++++  
  425.             //充电电源连接与充电电源拔出。  
  426.             // Separate broadcast is sent for power connected / not connected  
  427.             // since the standard intent will not wake any applications and some  
  428.             // applications may want to have smart behavior based on this.  
  429.             if (mPlugType != 0 && mLastPlugType == 0) {  
  430.                 mHandler.post(new Runnable() {  
  431.                     @Override  
  432.                     public void run() {  
  433.                         //android4.4/framework/base/services/java/com/android/server/EntropyMixer.java:100  
  434.                         Intent statusIntent = new Intent(Intent.ACTION_POWER_CONNECTED);  
  435.                         statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);  
  436.                         mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);  
  437.                     }  
  438.                 });  
  439.             }  
  440.             else if (mPlugType == 0 && mLastPlugType != 0) {  
  441.                 mHandler.post(new Runnable() {  
  442.                     @Override  
  443.                     public void run() {  
  444.                         //么有找到该广播处理。  
  445.                         Intent statusIntent = new Intent(Intent.ACTION_POWER_DISCONNECTED);  
  446.                         statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);  
  447.                         mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);  
  448.                     }  
  449.                 });  
  450.             }  
  451.             //++++++++++++++power connected / not connected end+++++++++++++++++++++++++++++++++++++++++++++++  
  452.   
  453.             //当前是否处于低电量状态  
  454.             //这两个中ACTION_BATTERY_LOW和ACTION_BATTERY_OKAY没有找到对应的处理,因此先忽略。这里的ACTION_BATTERY_LOW  
  455.             //与低电量的显示没有多大关系.  
  456.             if (sendBatteryLow) {  
  457.                 //当前处于低电量状态,发送该广播  
  458.                 mSentLowBatteryBroadcast = true;  
  459.                 mHandler.post(new Runnable() {  
  460.                     @Override  
  461.                     public void run() {  
  462.                         Intent statusIntent = new Intent(Intent.ACTION_BATTERY_LOW);  
  463.                         statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);  
  464.                         mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);  
  465.                     }  
  466.                 });  
  467.             } else if (mSentLowBatteryBroadcast && mLastBatteryLevel >= mLowBatteryCloseWarningLevel) {  
  468.                 //当处于低电量时发送ACTION_BATTERY_LOW广播后,用户插上了电源充电,此时,电池电量增加变化,如果变化到大于了20%,则会发送该广播电池状态正常OK状态。  
  469.                 mSentLowBatteryBroadcast = false;  
  470.                 mHandler.post(new Runnable() {  
  471.                     @Override  
  472.                     public void run() {  
  473.                         Intent statusIntent = new Intent(Intent.ACTION_BATTERY_OKAY);  
  474.                         statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);  
  475.                         mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);  
  476.                     }  
  477.                 });  
  478.             }  
  479.   
  480.             // Update the battery LED  
  481.             mLed.updateLightsLocked();  
  482.   
  483.             // This needs to be done after sendIntent() so that we get the lastest battery stats.  
  484.             if (logOutlier && dischargeDuration != 0) {  
  485.                 logOutlierLocked(dischargeDuration);  
  486.             }  
  487.   
  488.             //当前的电量信息更新完毕,保存为最新状态与下一次更新比较。  
  489.             mLastBatteryStatus = mBatteryProps.batteryStatus;  
  490.             mLastBatteryHealth = mBatteryProps.batteryHealth;  
  491.             mLastBatteryPresent = mBatteryProps.batteryPresent;  
  492.             mLastBatteryLevel = mBatteryProps.batteryLevel;  
  493.             mLastPlugType = mPlugType;  
  494.             mLastBatteryVoltage = mBatteryProps.batteryVoltage;  
  495.             mLastBatteryTemperature = mBatteryProps.batteryTemperature;  
  496.             mLastBatteryLevelCritical = mBatteryLevelCritical;  
  497.             mLastInvalidCharger = mInvalidCharger;  
  498.         }  
  499.     }  
  500.   
  501.     //发送广播ACTION:ACTION_BATTERY_CHANGED,发送当前电量信息,更新UI显示,该广播的处理在SystemUI中的PowerUI.java中。  
  502.     private void sendIntentLocked() {  
  503.         //  Pack up the values and broadcast them to everyone  
  504.         final Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);  
  505.         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY  
  506.                 | Intent.FLAG_RECEIVER_REPLACE_PENDING);  
  507.   
  508.         int icon = getIconLocked(mBatteryProps.batteryLevel);  
  509.   
  510.         //将最新的电池电量信息封装到intent中,主动发送给SystemUI,让其显示。  
  511.         intent.putExtra(BatteryManager.EXTRA_STATUS, mBatteryProps.batteryStatus);  
  512.         intent.putExtra(BatteryManager.EXTRA_HEALTH, mBatteryProps.batteryHealth);  
  513.         intent.putExtra(BatteryManager.EXTRA_PRESENT, mBatteryProps.batteryPresent);//这个表示啥意思?  
  514.         intent.putExtra(BatteryManager.EXTRA_LEVEL, mBatteryProps.batteryLevel);  
  515.         intent.putExtra(BatteryManager.EXTRA_SCALE, BATTERY_SCALE);  
  516.         intent.putExtra(BatteryManager.EXTRA_ICON_SMALL, icon);  
  517.         intent.putExtra(BatteryManager.EXTRA_PLUGGED, mPlugType);  
  518.         intent.putExtra(BatteryManager.EXTRA_VOLTAGE, mBatteryProps.batteryVoltage);  
  519.         intent.putExtra(BatteryManager.EXTRA_TEMPERATURE, mBatteryProps.batteryTemperature);  
  520.         intent.putExtra(BatteryManager.EXTRA_TECHNOLOGY, mBatteryProps.batteryTechnology);  
  521.         intent.putExtra(BatteryManager.EXTRA_INVALID_CHARGER, mInvalidCharger);  
  522.           
  523.         //日志打印,可以忽略。  
  524.         if (DEBUG) {  
  525.             Slog.d(TAG, "Sending ACTION_BATTERY_CHANGED.  level:" + mBatteryProps.batteryLevel +  
  526.                     ", scale:" + BATTERY_SCALE + ", status:" + mBatteryProps.batteryStatus +  
  527.                     ", health:" + mBatteryProps.batteryHealth +  ", present:" + mBatteryProps.batteryPresent +  
  528.                     ", voltage: " + mBatteryProps.batteryVoltage +  
  529.                     ", temperature: " + mBatteryProps.batteryTemperature +  
  530.                     ", technology: " + mBatteryProps.batteryTechnology +  
  531.                     ", AC powered:" + mBatteryProps.chargerAcOnline + ", USB powered:" + mBatteryProps.chargerUsbOnline +  
  532.                     ", Wireless powered:" + mBatteryProps.chargerWirelessOnline +  
  533.                     ", icon:" + icon  + ", invalid charger:" + mInvalidCharger);  
  534.         }  
  535.   
  536.         mHandler.post(new Runnable() {  
  537.             @Override  
  538.             public void run() {  
  539.                 ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);  
  540.             }  
  541.         });  
  542.     }  
  543.   
  544.     private void logBatteryStatsLocked() {  
  545.         IBinder batteryInfoService = ServiceManager.getService(BatteryStats.SERVICE_NAME);  
  546.         if (batteryInfoService == nullreturn;  
  547.   
  548.         DropBoxManager db = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE);  
  549.         if (db == null || !db.isTagEnabled("BATTERY_DISCHARGE_INFO")) return;  
  550.   
  551.         File dumpFile = null;  
  552.         FileOutputStream dumpStream = null;  
  553.         try {  
  554.             // dump the service to a file  
  555.             dumpFile = new File(DUMPSYS_DATA_PATH + BatteryStats.SERVICE_NAME + ".dump");  
  556.             dumpStream = new FileOutputStream(dumpFile);  
  557.             batteryInfoService.dump(dumpStream.getFD(), DUMPSYS_ARGS);  
  558.             FileUtils.sync(dumpStream);  
  559.   
  560.             // add dump file to drop box  
  561.             db.addFile("BATTERY_DISCHARGE_INFO", dumpFile, DropBoxManager.IS_TEXT);  
  562.         } catch (RemoteException e) {  
  563.             Slog.e(TAG, "failed to dump battery service", e);  
  564.         } catch (IOException e) {  
  565.             Slog.e(TAG, "failed to write dumpsys file", e);  
  566.         } finally {  
  567.             // make sure we clean up  
  568.             if (dumpStream != null) {  
  569.                 try {  
  570.                     dumpStream.close();  
  571.                 } catch (IOException e) {  
  572.                     Slog.e(TAG, "failed to close dumpsys output stream");  
  573.                 }  
  574.             }  
  575.             if (dumpFile != null && !dumpFile.delete()) {  
  576.                 Slog.e(TAG, "failed to delete temporary dumpsys file: "  
  577.                         + dumpFile.getAbsolutePath());  
  578.             }  
  579.         }  
  580.     }  
  581.   
  582.     private void logOutlierLocked(long duration) {  
  583.         ContentResolver cr = mContext.getContentResolver();  
  584.         String dischargeThresholdString = Settings.Global.getString(cr,  
  585.                 Settings.Global.BATTERY_DISCHARGE_THRESHOLD);  
  586.         String durationThresholdString = Settings.Global.getString(cr,  
  587.                 Settings.Global.BATTERY_DISCHARGE_DURATION_THRESHOLD);  
  588.   
  589.         if (dischargeThresholdString != null && durationThresholdString != null) {  
  590.             try {  
  591.                 long durationThreshold = Long.parseLong(durationThresholdString);  
  592.                 int dischargeThreshold = Integer.parseInt(dischargeThresholdString);  
  593.                 if (duration <= durationThreshold &&  
  594.                         mDischargeStartLevel - mBatteryProps.batteryLevel >= dischargeThreshold) {  
  595.                     // If the discharge cycle is bad enough we want to know about it.  
  596.                     logBatteryStatsLocked();  
  597.                 }  
  598.                 if (DEBUG) Slog.v(TAG, "duration threshold: " + durationThreshold +  
  599.                         " discharge threshold: " + dischargeThreshold);  
  600.                 if (DEBUG) Slog.v(TAG, "duration: " + duration + " discharge: " +  
  601.                         (mDischargeStartLevel - mBatteryProps.batteryLevel));  
  602.             } catch (NumberFormatException e) {  
  603.                 Slog.e(TAG, "Invalid DischargeThresholds GService string: " +  
  604.                         durationThresholdString + " or " + dischargeThresholdString);  
  605.                 return;  
  606.             }  
  607.         }  
  608.     }  
  609.   
  610.     //获取当前电池图标显示的drawableID  
  611.     //BATTERY_STATUS_DISCHARGING和BATTERY_STATUS_NOT_CHARGING应该差不多,因为从逻辑里面看两者状态下都是用了相同的drawable资源。  
  612.     private int getIconLocked(int level) {  
  613.         if (mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_CHARGING) {//充电  
  614.             return com.android.internal.R.drawable.stat_sys_battery_charge;  
  615.         } else if (mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_DISCHARGING) {  
  616.             return com.android.internal.R.drawable.stat_sys_battery;  
  617.         } else if (mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_NOT_CHARGING  
  618.                 || mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_FULL) {  
  619.             if (isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)  
  620.                     && mBatteryProps.batteryLevel >= 100) {  
  621.                 return com.android.internal.R.drawable.stat_sys_battery_charge;  
  622.             } else {  
  623.                 return com.android.internal.R.drawable.stat_sys_battery;  
  624.             }  
  625.         } else {  
  626.             return com.android.internal.R.drawable.stat_sys_battery_unknown;  
  627.         }  
  628.     }  
  629.   
  630.     @Override  
  631.     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {  
  632.         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)  
  633.                 != PackageManager.PERMISSION_GRANTED) {  
  634.   
  635.             pw.println("Permission Denial: can't dump Battery service from from pid="  
  636.                     + Binder.getCallingPid()  
  637.                     + ", uid=" + Binder.getCallingUid());  
  638.             return;  
  639.         }  
  640.   
  641.         synchronized (mLock) {  
  642.             if (args == null || args.length == 0 || "-a".equals(args[0])) {  
  643.                 pw.println("Current Battery Service state:");  
  644.                 if (mUpdatesStopped) {  
  645.                     pw.println("  (UPDATES STOPPED -- use 'reset' to restart)");  
  646.                 }  
  647.                 pw.println("  AC powered: " + mBatteryProps.chargerAcOnline);  
  648.                 pw.println("  USB powered: " + mBatteryProps.chargerUsbOnline);  
  649.                 pw.println("  Wireless powered: " + mBatteryProps.chargerWirelessOnline);  
  650.                 pw.println("  status: " + mBatteryProps.batteryStatus);  
  651.                 pw.println("  health: " + mBatteryProps.batteryHealth);  
  652.                 pw.println("  present: " + mBatteryProps.batteryPresent);  
  653.                 pw.println("  level: " + mBatteryProps.batteryLevel);  
  654.                 pw.println("  scale: " + BATTERY_SCALE);  
  655.                 pw.println("  voltage: " + mBatteryProps.batteryVoltage);  
  656.   
  657.                 if (mBatteryProps.batteryCurrentNow != Integer.MIN_VALUE) {  
  658.                     pw.println("  current now: " + mBatteryProps.batteryCurrentNow);  
  659.                 }  
  660.   
  661.                 if (mBatteryProps.batteryChargeCounter != Integer.MIN_VALUE) {  
  662.                     pw.println("  charge counter: " + mBatteryProps.batteryChargeCounter);  
  663.                 }  
  664.   
  665.                 pw.println("  temperature: " + mBatteryProps.batteryTemperature);  
  666.                 pw.println("  technology: " + mBatteryProps.batteryTechnology);  
  667.             } else if (args.length == 3 && "set".equals(args[0])) {  
  668.                 String key = args[1];  
  669.                 String value = args[2];  
  670.                 try {  
  671.                     boolean update = true;  
  672.                     if ("ac".equals(key)) {  
  673.                         mBatteryProps.chargerAcOnline = Integer.parseInt(value) != 0;  
  674.                     } else if ("usb".equals(key)) {  
  675.                         mBatteryProps.chargerUsbOnline = Integer.parseInt(value) != 0;  
  676.                     } else if ("wireless".equals(key)) {  
  677.                         mBatteryProps.chargerWirelessOnline = Integer.parseInt(value) != 0;  
  678.                     } else if ("status".equals(key)) {  
  679.                         mBatteryProps.batteryStatus = Integer.parseInt(value);  
  680.                     } else if ("level".equals(key)) {  
  681.                         mBatteryProps.batteryLevel = Integer.parseInt(value);  
  682.                     } else if ("invalid".equals(key)) {  
  683.                         mInvalidCharger = Integer.parseInt(value);  
  684.                     } else {  
  685.                         pw.println("Unknown set option: " + key);  
  686.                         update = false;  
  687.                     }  
  688.                     if (update) {  
  689.                         long ident = Binder.clearCallingIdentity();  
  690.                         try {  
  691.                             mUpdatesStopped = true;  
  692.                             processValuesLocked();  
  693.                         } finally {  
  694.                             Binder.restoreCallingIdentity(ident);  
  695.                         }  
  696.                     }  
  697.                 } catch (NumberFormatException ex) {  
  698.                     pw.println("Bad value: " + value);  
  699.                 }  
  700.             } else if (args.length == 1 && "reset".equals(args[0])) {  
  701.                 long ident = Binder.clearCallingIdentity();  
  702.                 try {  
  703.                     mUpdatesStopped = false;  
  704.                 } finally {  
  705.                     Binder.restoreCallingIdentity(ident);  
  706.                 }  
  707.             } else {  
  708.                 pw.println("Dump current battery state, or:");  
  709.                 pw.println("  set ac|usb|wireless|status|level|invalid <value>");  
  710.                 pw.println("  reset");  
  711.             }  
  712.         }  
  713.     }  
  714.   
  715.     private final UEventObserver mInvalidChargerObserver = new UEventObserver() {  
  716.         @Override  
  717.         public void onUEvent(UEventObserver.UEvent event) {  
  718.             final int invalidCharger = "1".equals(event.get("SWITCH_STATE")) ? 1 : 0;  
  719.             synchronized (mLock) {  
  720.                 if (mInvalidCharger != invalidCharger) {  
  721.                     mInvalidCharger = invalidCharger;  
  722.                 }  
  723.             }  
  724.         }  
  725.     };  
  726.   
  727.     private final class Led {  
  728.         private final LightsService.Light mBatteryLight;  
  729.   
  730.         private final int mBatteryLowARGB;  
  731.         private final int mBatteryMediumARGB;  
  732.         private final int mBatteryFullARGB;  
  733.         private final int mBatteryLedOn;  
  734.         private final int mBatteryLedOff;  
  735.   
  736.         public Led(Context context, LightsService lights) {  
  737.             mBatteryLight = lights.getLight(LightsService.LIGHT_ID_BATTERY);  
  738.   
  739.             //./core/res/res/values/config.xml:562:    <integer name="config_notificationsBatteryLowARGB">0xFFFF0000</integer>  
  740.             mBatteryLowARGB = context.getResources().getInteger(  
  741.                     com.android.internal.R.integer.config_notificationsBatteryLowARGB);  
  742.             //./core/res/res/values/config.xml:565:    <integer name="config_notificationsBatteryMediumARGB">0xFFFFFF00</integer>  
  743.             mBatteryMediumARGB = context.getResources().getInteger(  
  744.                     com.android.internal.R.integer.config_notificationsBatteryMediumARGB);  
  745.             //./core/res/res/values/config.xml:568:    <integer name="config_notificationsBatteryFullARGB">0xFF00FF00</integer>  
  746.             mBatteryFullARGB = context.getResources().getInteger(  
  747.                     com.android.internal.R.integer.config_notificationsBatteryFullARGB);  
  748.             //./core/res/res/values/config.xml:571:    <integer name="config_notificationsBatteryLedOn">125</integer>  
  749.             mBatteryLedOn = context.getResources().getInteger(  
  750.                     com.android.internal.R.integer.config_notificationsBatteryLedOn);  
  751.             //./core/res/res/values/config.xml:577:    <integer name="config_notificationsBatteryLedOff">2875</integer>  
  752.             mBatteryLedOff = context.getResources().getInteger(  
  753.                     com.android.internal.R.integer.config_notificationsBatteryLedOff);  
  754.         }  
  755.   
  756.         /** 
  757.          * Synchronize on BatteryService. 
  758.          */  
  759.         public void updateLightsLocked() {  
  760.             final int level = mBatteryProps.batteryLevel;  
  761.             final int status = mBatteryProps.batteryStatus;  
  762.             if (level < mLowBatteryWarningLevel) { //当前电量处于低电量状态  
  763.                 if (status == BatteryManager.BATTERY_STATUS_CHARGING) {//处于低电量状态,并且正在充电  
  764.                     // Solid red when battery is charging  
  765.                     mBatteryLight.setColor(mBatteryLowARGB);  
  766.                 } else {//低电量状态但是没有充电  
  767.                     // Flash red when battery is low and not charging  
  768.                     mBatteryLight.setFlashing(mBatteryLowARGB, LightsService.LIGHT_FLASH_TIMED,  
  769.                             mBatteryLedOn, mBatteryLedOff);  
  770.                 }  
  771.             } else if (status == BatteryManager.BATTERY_STATUS_CHARGING//当前属于充电状态  
  772.                     || status == BatteryManager.BATTERY_STATUS_FULL) {  
  773.                 if (status == BatteryManager.BATTERY_STATUS_FULL || level >= 90) {  
  774.                     // Solid green when full or charging and nearly full  
  775.                     mBatteryLight.setColor(mBatteryFullARGB);  
  776.                 } else {  
  777.                     // Solid orange when charging and halfway full  
  778.                     mBatteryLight.setColor(mBatteryMediumARGB);  
  779.                 }  
  780.             } else {  
  781.                 // No lights if not charging and not low  
  782.                 mBatteryLight.turnOff();  
  783.             }  
  784.         }  
  785.     }  
  786.   
  787.     private final class BatteryListener extends IBatteryPropertiesListener.Stub {  
  788.         public void batteryPropertiesChanged(BatteryProperties props) {  
  789.             BatteryService.this.update(props);  
  790.        }  
  791.     }  
  792. }  

上面看完了,BatteryService.java的源码,感觉不多, 因此这里就平时使用手机的体验来看看相关的一些具体实现吧。反正源码在手,随便你看。

1.手机电量过低,弹出来的dialog信息框是从哪里实现的?

低电量时的广播实际上就是BatteryService的sendIntentLocked() 方法中ACTION为ACTION_BATTERY_CHANGED的广播,在SystemUI里面接收参数判断处理。


这个直接在PowerUI.java中查看。从接收广播,到解析数据,然后针对数据的各个情况做处理。


[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {  
  2.         @Override  
  3.         public void onReceive(Context context, Intent intent) {  
  4.             String action = intent.getAction();  
  5.             if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {  
  6.                 //上一次电量  
  7.                 final int oldBatteryLevel = mBatteryLevel;  
  8.                 //最新电量  
  9.                 mBatteryLevel = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 100);  
  10.                 //上一次电池状态  
  11.                 final int oldBatteryStatus = mBatteryStatus;  
  12.                 //最新电池状态  
  13.                 mBatteryStatus = intent.getIntExtra(BatteryManager.EXTRA_STATUS,  
  14.                         BatteryManager.BATTERY_STATUS_UNKNOWN);  
  15.                 //充电类型。AC,USB,WIRELESS  
  16.                 final int oldPlugType = mPlugType;  
  17.                 mPlugType = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 1);  
  18.                   
  19.                 final int oldInvalidCharger = mInvalidCharger;  
  20.                 mInvalidCharger = intent.getIntExtra(BatteryManager.EXTRA_INVALID_CHARGER, 0);  
  21.   
  22.                 //当前是否在充电  
  23.                 final boolean plugged = mPlugType != 0;  
  24.                 //上一次刷新,是否在充电状态。  
  25.                 final boolean oldPlugged = oldPlugType != 0;  
  26.   
  27.                 //从方法来看,貌似就是电池的状态是Ok的呢还是电量过低,  
  28.                 int oldBucket = findBatteryLevelBucket(oldBatteryLevel);  
  29.                 int bucket = findBatteryLevelBucket(mBatteryLevel);  
  30.   
  31.                 if (DEBUG) {  
  32.                     Slog.d(TAG, "buckets   ....." + mLowBatteryAlertCloseLevel  
  33.                             + " .. " + mLowBatteryReminderLevels[0]  
  34.                             + " .. " + mLowBatteryReminderLevels[1]);  
  35.                     Slog.d(TAG, "level          " + oldBatteryLevel + " --> " + mBatteryLevel);  
  36.                     Slog.d(TAG, "status         " + oldBatteryStatus + " --> " + mBatteryStatus);  
  37.                     Slog.d(TAG, "plugType       " + oldPlugType + " --> " + mPlugType);  
  38.                     Slog.d(TAG, "invalidCharger " + oldInvalidCharger + " --> " + mInvalidCharger);  
  39.                     Slog.d(TAG, "bucket         " + oldBucket + " --> " + bucket);  
  40.                     Slog.d(TAG, "plugged        " + oldPlugged + " --> " + plugged);  
  41.                 }  
  42.   
  43.                 if (oldInvalidCharger == 0 && mInvalidCharger != 0) {  
  44.                     Slog.d(TAG, "showing invalid charger warning");  
  45.                     showInvalidChargerDialog();  
  46.                     return;  
  47.                 } else if (oldInvalidCharger != 0 && mInvalidCharger == 0) {  
  48.                     dismissInvalidChargerDialog();  
  49.                 } else if (mInvalidChargerDialog != null) {  
  50.                     // if invalid charger is showing, don't show low battery  
  51.                     return;  
  52.                 }  
  53.   
  54.                   
  55.                 if (!plugged  
  56.                         && (bucket < oldBucket || oldPlugged)  
  57.                         && mBatteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN  
  58.                         && bucket < 0) {  
  59.                     showLowBatteryWarning();  
  60.   
  61.                     // only play SFX when the dialog comes up or the bucket changes  
  62.                     if (bucket != oldBucket || oldPlugged) {//可以体会到,当我们手机没电了,恰好我们把充电拔了,就会有提示音。  
  63.                         playLowBatterySound();  
  64.                     }  
  65.                 } else if (plugged || (bucket > oldBucket && bucket > 0)) {  
  66.                     //充电状态  
  67.                     dismissLowBatteryWarning();  
  68.                 } else if (mBatteryLevelTextView != null) {  
  69.                     //显示低电量dialog  
  70.                     showLowBatteryWarning();  
  71.                 }  
  72.             } else if (Intent.ACTION_SCREEN_OFF.equals(action)) {  
  73.                 mScreenOffTime = SystemClock.elapsedRealtime();  
  74.             } else if (Intent.ACTION_SCREEN_ON.equals(action)) {  
  75.                 mScreenOffTime = -1;  
  76.             } else {  
  77.                 Slog.w(TAG, "unknown intent: " + intent);  
  78.             }  
  79.         }  
  80.     };  


代码比较清晰,主要是电池信息的一些情况判断,需要多多琢磨一下为啥是这样的。

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. //显示低电量Dialog  
  2.     void showLowBatteryWarning() {  
  3.         Slog.i(TAG,  
  4.                 ((mBatteryLevelTextView == null) ? "showing" : "updating")  
  5.                 + " low battery warning: level=" + mBatteryLevel  
  6.                 + " [" + findBatteryLevelBucket(mBatteryLevel) + "]");  
  7.   
  8.         CharSequence levelText = mContext.getString(  
  9.                 R.string.battery_low_percent_format, mBatteryLevel);  
  10.   
  11.         //这里的第一个if:因为电池的刷新频率比较高,因此如果此时dialog还在显示状态中,直接刷新电量信息即可。  
  12.         if (mBatteryLevelTextView != null) {  
  13.             mBatteryLevelTextView.setText(levelText);  
  14.         } else {  
  15.             View v = View.inflate(mContext, R.layout.battery_low, null);  
  16.             mBatteryLevelTextView = (TextView)v.findViewById(R.id.level_percent);  
  17.   
  18.             mBatteryLevelTextView.setText(levelText);  
  19.   
  20.             AlertDialog.Builder b = new AlertDialog.Builder(mContext);  
  21.                 b.setCancelable(true);  
  22.                 b.setTitle(R.string.battery_low_title);  
  23.                 b.setView(v);  
  24.                 b.setIconAttribute(android.R.attr.alertDialogIcon);  
  25.                 b.setPositiveButton(android.R.string.ok, null);  
  26.   
  27.             final Intent intent = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);  
  28.             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK  
  29.                     | Intent.FLAG_ACTIVITY_MULTIPLE_TASK  
  30.                     | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS  
  31.                     | Intent.FLAG_ACTIVITY_NO_HISTORY);  
  32.             if (intent.resolveActivity(mContext.getPackageManager()) != null) {  
  33.                 b.setNegativeButton(R.string.battery_low_why,  
  34.                         new DialogInterface.OnClickListener() {  
  35.                     @Override  
  36.                     public void onClick(DialogInterface dialog, int which) {  
  37.                         mContext.startActivityAsUser(intent, UserHandle.CURRENT);  
  38.                         dismissLowBatteryWarning();  
  39.                     }  
  40.                 });  
  41.             }  
  42.   
  43.             AlertDialog d = b.create();  
  44.             d.setOnDismissListener(new DialogInterface.OnDismissListener() {  
  45.                     @Override  
  46.                     public void onDismiss(DialogInterface dialog) {  
  47.                         mLowBatteryDialog = null;  
  48.                         mBatteryLevelTextView = null;  
  49.                     }  
  50.                 });  
  51.             //dialog属性  
  52.             d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);  
  53.             d.getWindow().getAttributes().privateFlags |=  
  54.                     WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;  
  55.             d.show();  
  56.             mLowBatteryDialog = d;  
  57.         }  
  58.     }  

我要做的需求差不多就可以按照低电量的显示来实现了。这里省略。

2.拔掉充电器或者USB连线,状态栏的电池图标是如何更新的?

当插拔数据线的时候,电池图标的变化,是自定义View Draw出来的。具体在

packages/SystemUI/src/com/android/systemui/BatteryMeterView.java 。

3.低电量关机是如何实现的?

首先我们可以从BatteryService.java中看到有这么个方法:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. private void shutdownIfNoPowerLocked() {  
  2.     // shut down gracefully if our battery is critically low and we are not powered.  
  3.     // wait until the system has booted before attempting to display the shutdown dialog.  
  4.     if (mBatteryProps.batteryLevel == 0 && !isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)) {  
  5.         mHandler.post(new Runnable() {  
  6.             @Override  
  7.             public void run() {  
  8.                 if (ActivityManagerNative.isSystemReady()) {  
  9.                     Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);  
  10.                     intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);  
  11.                     intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
  12.                     mContext.startActivityAsUser(intent, UserHandle.CURRENT);  
  13.                 }  
  14.             }  
  15.         });  
  16.     }  
  17. }  

--->搜索可以找到AndroidMenifest.xml

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. <activity android:name="com.android.server.ShutdownActivity"  
  2.     android:permission="android.permission.SHUTDOWN"  
  3.     android:excludeFromRecents="true">  
  4.     <intent-filter>  
  5.         <action android:name="android.intent.action.ACTION_REQUEST_SHUTDOWN" />  
  6.         <category android:name="android.intent.category.DEFAULT" />  
  7.     </intent-filter>  
  8.     <intent-filter>  
  9.         <action android:name="android.intent.action.REBOOT" />  
  10.         <category android:name="android.intent.category.DEFAULT" />  
  11.     </intent-filter>  
  12. </activity>  

之前遇到一个问题,我们像从app上去实现关机,具体做法再研究了。

其中有人做了,但是涉及到一个权限就是

android:permission="android.permission.SHUTDOWN"  

其中,android.excludeFromRecents="true" 表示当前打开的Activity所属应用,不会显示在最近使用的列表里。

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. /* 
  2.          * from BatteryService.java 
  3.          *Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN); 
  4.          *intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false); 
  5.          *intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
  6.          *mContext.startActivityAsUser(intent, UserHandle.CURRENT); 
  7.          * 
  8.          */  
  9.         Intent intent = getIntent();  
  10.         mReboot = Intent.ACTION_REBOOT.equals(intent.getAction());//from BatteryService传递过来的是Intent.ACTION_REQUEST_SHUTDOWN,这里肯定是false。  
  11.         mConfirm = intent.getBooleanExtra(Intent.EXTRA_KEY_CONFIRM, false);  
  12.         Slog.i(TAG, "onCreate(): confirm=" + mConfirm);  
  13.   
  14.         Thread thr = new Thread("ShutdownActivity") {  
  15.             @Override  
  16.             public void run() {  
  17.                 IPowerManager pm = IPowerManager.Stub.asInterface(  
  18.                         ServiceManager.getService(Context.POWER_SERVICE));  
  19.                 try {  
  20.                     //根据Action需求,是重启还是关机。  
  21.                     if (mReboot) {  
  22.                         //接下来。。。。。  
  23.                         pm.reboot(mConfirm, nullfalse);  
  24.                     } else {  
  25.                         pm.shutdown(mConfirm, false);  
  26.                     }  
  27.                 } catch (RemoteException e) {  
  28.                 }  
  29.             }  
  30.         };  
  31.         thr.start();  
  32.         finish();  
  33.         // Wait for us to tell the power manager to shutdown.  
  34.         try {  
  35.        
  36.             thr.join();  
  37.         } catch (InterruptedException e) {  
  38.         }  
  39.     }  

8.app开发过程中,我们需要获取电池电量信息,如何来做?

当我们在开发app的时候需要获取电池信息,可以仿照BatteryService来做。 因为,BatteryService主动把电池电量信息传递给了SystemUI. 

简单的做法就是:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. getApplication().registerReceiver(new BroadcastReceiver() {  
  2.       
  3.     @Override  
  4.     public void onReceive(Context context, Intent intent) {  
  5.         // TODO Auto-generated method stub  
  6.         //这里的intent封装了我们在BatterySerivce.java中sendIntentLocked()  
  7.         //封装的电池电量信息。  
  8.     }  
  9. }, filter) ;  

4.pm.reboot,pm.shutdown 的后续流程是如何实现的?

5.LED灯显示 LightService

6.电池电量管理的底层研究。

7.BatteryService发送广播传递过程如何实现的。

比如这样的

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. Intent statusIntent = new Intent(Intent.ACTION_POWER_CONNECTED);  
  2.                    statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);  
  3.                    mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);  


这里就先源码跟踪到这里,下次继续补充。


原文地址:http://blog.csdn.net/xxm282828/article/details/44926363

没有更多推荐了,返回首页