android 4.4 电池电量管理底层分析(C\C++层)(http://blog.csdn.net/daweibalang717/article/details/41446993)

先贴一张类与类之间的关系图:


android开机过程中会加载系统BatteryService ,说一下电池电量相关的,本文主要讲述关于JAVA 层代码。文件路径:\frameworks\base\services\java\com\android\server\BatteryService.java 下面贴出源码。我把注释加上。个人理解,仅参考。

[java] view plain copy
  1. /*
  2. *Copyright(C)2006TheAndroidOpenSourceProject
  3. *
  4. *LicensedundertheApacheLicense,Version2.0(the"License");
  5. *youmaynotusethisfileexceptincompliancewiththeLicense.
  6. *YoumayobtainacopyoftheLicenseat
  7. *
  8. *http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. *Unlessrequiredbyapplicablelaworagreedtoinwriting,software
  11. *distributedundertheLicenseisdistributedonan"ASIS"BASIS,
  12. *WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.
  13. *SeetheLicenseforthespecificlanguagegoverningpermissionsand
  14. *limitationsundertheLicense.
  15. */
  16. packagecom.android.server;
  17. importandroid.os.BatteryStats;
  18. importcom.android.internal.app.IBatteryStats;
  19. importcom.android.server.am.BatteryStatsService;
  20. importandroid.app.ActivityManagerNative;
  21. importandroid.content.ContentResolver;
  22. importandroid.content.Context;
  23. importandroid.content.Intent;
  24. importandroid.content.pm.PackageManager;
  25. importandroid.os.BatteryManager;
  26. importandroid.os.BatteryProperties;
  27. importandroid.os.Binder;
  28. importandroid.os.FileUtils;
  29. importandroid.os.Handler;
  30. importandroid.os.IBatteryPropertiesListener;
  31. importandroid.os.IBatteryPropertiesRegistrar;
  32. importandroid.os.IBinder;
  33. importandroid.os.DropBoxManager;
  34. importandroid.os.RemoteException;
  35. importandroid.os.ServiceManager;
  36. importandroid.os.SystemClock;
  37. importandroid.os.UEventObserver;
  38. importandroid.os.UserHandle;
  39. importandroid.provider.Settings;
  40. importandroid.util.EventLog;
  41. importandroid.util.Slog;
  42. importjava.io.File;
  43. importjava.io.FileDescriptor;
  44. importjava.io.FileOutputStream;
  45. importjava.io.IOException;
  46. importjava.io.PrintWriter;
  47. /**
  48. *<p>BatteryServicemonitorsthechargingstatus,andchargelevelofthedevice
  49. *battery.Whenthesevalueschangethisservicebroadcaststhenewvalues
  50. *toall{@linkandroid.content.BroadcastReceiverIntentReceivers}thatare
  51. *watchingthe{@linkandroid.content.Intent#ACTION_BATTERY_CHANGED
  52. *BATTERY_CHANGED}action.</p>
  53. *<p>ThenewvaluesarestoredintheIntentdataandcanberetrievedby
  54. *calling{@linkandroid.content.Intent#getExtraIntent.getExtra}withthe
  55. *followingkeys:</p>
  56. *<p>"scale"-int,themaximumvalueforthechargelevel</p>
  57. *<p>"level"-int,chargelevel,from0through"scale"inclusive</p>
  58. *<p>"status"-String,thecurrentchargingstatus.<br/>
  59. *<p>"health"-String,thecurrentbatteryhealth.<br/>
  60. *<p>"present"-boolean,trueifthebatteryispresent<br/>
  61. *<p>"icon-small"-int,suggestedsmallicontouseforthisstate</p>
  62. *<p>"plugged"-int,0ifthedeviceisnotpluggedin;1ifplugged
  63. *intoanACpoweradapter;2ifpluggedinviaUSB.</p>
  64. *<p>"voltage"-int,currentbatteryvoltageinmillivolts</p>
  65. *<p>"temperature"-int,currentbatterytemperatureintenthsof
  66. *adegreeCentigrade</p>
  67. *<p>"technology"-String,thetypeofbatteryinstalled,e.g."Li-ion"</p>
  68. *
  69. *<p>
  70. *Thebatteryservicemaybecalledbythepowermanagerwhileholdingitslocksso
  71. *wetakecaretopostalloutcallsintotheactivitymanagertoahandler.
  72. *
  73. *FIXME:Ideallythepowermanagerwouldperformallofitscallsintothebattery
  74. *serviceasynchronouslyitself.
  75. *</p>
  76. */
  77. publicfinalclassBatteryServiceextendsBinder{
  78. privatestaticfinalStringTAG=BatteryService.class.getSimpleName();
  79. privatestaticfinalbooleanDEBUG=false;
  80. privatestaticfinalintBATTERY_SCALE=100;//batterycapacityisapercentage
  81. //Usedlocallyfordeterminingwhentomakealastditchefforttolog
  82. //dischargestatsbeforethedevicedies.
  83. privateintmCriticalBatteryLevel;
  84. privatestaticfinalintDUMP_MAX_LENGTH=24*1024;
  85. privatestaticfinalString[]DUMPSYS_ARGS=newString[]{"--checkin","--unplugged"};
  86. privatestaticfinalStringDUMPSYS_DATA_PATH="/data/system/";
  87. //ThisshouldprobablybeexposedintheAPI,thoughit'snotcritical
  88. privatestaticfinalintBATTERY_PLUGGED_NONE=0;
  89. privatefinalContextmContext;
  90. privatefinalIBatteryStatsmBatteryStats;
  91. privatefinalHandlermHandler;
  92. privatefinalObjectmLock=newObject();
  93. privateBatteryPropertiesmBatteryProps;
  94. privatebooleanmBatteryLevelCritical;
  95. privateintmLastBatteryStatus;
  96. privateintmLastBatteryHealth;
  97. privatebooleanmLastBatteryPresent;
  98. privateintmLastBatteryLevel;
  99. privateintmLastBatteryVoltage;
  100. privateintmLastBatteryTemperature;
  101. privatebooleanmLastBatteryLevelCritical;
  102. privateintmInvalidCharger;
  103. privateintmLastInvalidCharger;
  104. privateintmLowBatteryWarningLevel;
  105. privateintmLowBatteryCloseWarningLevel;
  106. privateintmShutdownBatteryTemperature;
  107. privateintmPlugType;
  108. privateintmLastPlugType=-1;//Extrastatesowecandetectfirstrun
  109. privatelongmDischargeStartTime;
  110. privateintmDischargeStartLevel;
  111. privatebooleanmUpdatesStopped;
  112. privateLedmLed;
  113. privatebooleanmSentLowBatteryBroadcast=false;
  114. privateBatteryListenermBatteryPropertiesListener;
  115. privateIBatteryPropertiesRegistrarmBatteryPropertiesRegistrar;
  116. //构造函数
  117. publicBatteryService(Contextcontext,LightsServicelights){
  118. mContext=context;
  119. mHandler=newHandler(true/*async*/);
  120. mLed=newLed(context,lights);//这个应该是指示灯,没实验
  121. mBatteryStats=BatteryStatsService.getService();
  122. //低电量临界值,这个数我看的源码版本值是4(在这个类里只是用来写日志)
  123. mCriticalBatteryLevel=mContext.getResources().getInteger(
  124. com.android.internal.R.integer.config_criticalBatteryWarningLevel);
  125. //低电量告警值,值15,下面会根据这个变量发送低电量的广播Intent.ACTION_BATTERY_LOW(这个跟系统低电量提醒没关系,只是发出去了)
  126. mLowBatteryWarningLevel=mContext.getResources().getInteger(
  127. com.android.internal.R.integer.config_lowBatteryWarningLevel);
  128. //电量告警取消值,值20,就是手机电量大于等于20的话发送Intent.ACTION_BATTERY_OKAY
  129. mLowBatteryCloseWarningLevel=mContext.getResources().getInteger(
  130. com.android.internal.R.integer.config_lowBatteryCloseWarningLevel);
  131. //值是680,温度过高,超过这个值就发送广播,跳转到将要关机提醒。
  132. mShutdownBatteryTemperature=mContext.getResources().getInteger(
  133. com.android.internal.R.integer.config_shutdownBatteryTemperature);
  134. //watchforinvalidchargermessagesiftheinvalid_chargerswitchexists
  135. if(newFile("/sys/devices/virtual/switch/invalid_charger/state").exists()){
  136. mInvalidChargerObserver.startObserving(
  137. "DEVPATH=/devices/virtual/switch/invalid_charger");
  138. }
  139. //电池监听,这个应该是注册到底层去了。当底层电量改变会调用此监听。然后执行update(BatteryPropertiesprops);
  140. mBatteryPropertiesListener=newBatteryListener();
  141. IBinderb=ServiceManager.getService("batterypropreg");
  142. mBatteryPropertiesRegistrar=IBatteryPropertiesRegistrar.Stub.asInterface(b);
  143. try{
  144. //这里注册
  145. mBatteryPropertiesRegistrar.registerListener(mBatteryPropertiesListener);
  146. }catch(RemoteExceptione){
  147. //Shouldneverhappen.
  148. }
  149. }
  150. //开机后先去看看是否没电了或者温度太高了。如果是,就关机提示(关机提示我等会介绍)。
  151. voidsystemReady(){
  152. //checkourpowersituationnowthatitissafetodisplaytheshutdowndialog.
  153. synchronized(mLock){
  154. shutdownIfNoPowerLocked();
  155. shutdownIfOverTempLocked();
  156. }
  157. }
  158. //返回是否在充电,这个函数在PowerManagerService.java中调用
  159. /**
  160. *Returnstrueifthedeviceispluggedintoanyofthespecifiedplugtypes.
  161. */
  162. publicbooleanisPowered(intplugTypeSet){
  163. synchronized(mLock){
  164. returnisPoweredLocked(plugTypeSet);
  165. }
  166. }
  167. //就是这里,通过充电器类型判断是否充电
  168. privatebooleanisPoweredLocked(intplugTypeSet){
  169. //我这英语小白猜着翻译下:就是开机后,电池状态不明了,那我们就认为就在充电,以便设备正常工作。
  170. //assumewearepoweredifbatterystateisunknownso
  171. //the"stayonwhilepluggedin"optionwillwork.
  172. if(mBatteryProps.batteryStatus==BatteryManager.BATTERY_STATUS_UNKNOWN){
  173. returntrue;
  174. }
  175. //充电器
  176. if((plugTypeSet&BatteryManager.BATTERY_PLUGGED_AC)!=0&&mBatteryProps.chargerAcOnline){
  177. returntrue;
  178. }
  179. //USB,插电脑上充电
  180. if((plugTypeSet&BatteryManager.BATTERY_PLUGGED_USB)!=0&&mBatteryProps.chargerUsbOnline){
  181. returntrue;
  182. }
  183. //电源是无线的。(我没见过...)
  184. if((plugTypeSet&BatteryManager.BATTERY_PLUGGED_WIRELESS)!=0&&mBatteryProps.chargerWirelessOnline){
  185. returntrue;
  186. }
  187. returnfalse;
  188. }
  189. /**
  190. *Returnsthecurrentplugtype.
  191. */
  192. //充电器类型
  193. publicintgetPlugType(){
  194. synchronized(mLock){
  195. returnmPlugType;
  196. }
  197. }
  198. /**
  199. *Returnsbatterylevelasapercentage.
  200. */
  201. //电池属性:电量等级(0-100)
  202. publicintgetBatteryLevel(){
  203. synchronized(mLock){
  204. returnmBatteryProps.batteryLevel;
  205. }
  206. }
  207. /**
  208. *Returnstrueifbatterylevelisbelowthefirstwarningthreshold.
  209. */
  210. //低电量
  211. publicbooleanisBatteryLow(){
  212. synchronized(mLock){
  213. returnmBatteryProps.batteryPresent&&mBatteryProps.batteryLevel<=mLowBatteryWarningLevel;
  214. }
  215. }
  216. /**
  217. *Returnsanon-zerovalueifanunsupportedchargerisattached.
  218. */
  219. //不支持的充电器类型
  220. publicintgetInvalidCharger(){
  221. synchronized(mLock){
  222. returnmInvalidCharger;
  223. }
  224. }
  225. //这里就是没电了,要关机的提示。
  226. privatevoidshutdownIfNoPowerLocked(){
  227. //shutdowngracefullyifourbatteryiscriticallylowandwearenotpowered.
  228. //waituntilthesystemhasbootedbeforeattemptingtodisplaytheshutdowndialog.
  229. if(mBatteryProps.batteryLevel==0&&(mBatteryProps.batteryStatus==BatteryManager.BATTERY_STATUS_DISCHARGING)){
  230. mHandler.post(newRunnable(){
  231. @Override
  232. publicvoidrun(){
  233. if(ActivityManagerNative.isSystemReady()){
  234. Intentintent=newIntent("android.intent.action.ACTION_REQUEST_SHUTDOWN_LOWBATTERY");//ACTION_REQUEST_SHUTDOWN
  235. intent.putExtra(Intent.EXTRA_KEY_CONFIRM,false);
  236. intent.putExtra("cant_be_cancel_by_button",true);
  237. intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  238. mContext.startActivityAsUser(intent,UserHandle.CURRENT);
  239. }
  240. }
  241. });
  242. }
  243. }
  244. //温度过高,关机提示(个人感觉这里有问题,温度过高为啥子跳转到没电关机提示界面)
  245. privatevoidshutdownIfOverTempLocked(){
  246. //shutdowngracefullyiftemperatureistoohigh(>68.0Cbydefault)
  247. //waituntilthesystemhasbootedbeforeattemptingtodisplaythe
  248. //shutdowndialog.
  249. if(mBatteryProps.batteryTemperature>mShutdownBatteryTemperature){
  250. mHandler.post(newRunnable(){
  251. @Override
  252. publicvoidrun(){
  253. if(ActivityManagerNative.isSystemReady()){
  254. Intentintent=newIntent("android.intent.action.ACTION_REQUEST_SHUTDOWN_LOWBATTERY");//ACTION_REQUEST_SHUTDOWN
  255. intent.putExtra(Intent.EXTRA_KEY_CONFIRM,false);
  256. intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  257. mContext.startActivityAsUser(intent,UserHandle.CURRENT);
  258. }
  259. }
  260. });
  261. }
  262. }
  263. //这个方法就是被JNI回调的。用来更新上层状态的方法。
  264. privatevoidupdate(BatteryPropertiesprops){
  265. synchronized(mLock){
  266. if(!mUpdatesStopped){
  267. mBatteryProps=props;
  268. //Processthenewvalues.
  269. processValuesLocked();
  270. }
  271. }
  272. }
  273. //嗯。这个就是最主要的方法了。
  274. privatevoidprocessValuesLocked(){
  275. booleanlogOutlier=false;
  276. longdischargeDuration=0;
  277. mBatteryLevelCritical=(mBatteryProps.batteryLevel<=mCriticalBatteryLevel);
  278. //充电器类型
  279. if(mBatteryProps.chargerAcOnline){
  280. mPlugType=BatteryManager.BATTERY_PLUGGED_AC;
  281. }elseif(mBatteryProps.chargerUsbOnline){
  282. mPlugType=BatteryManager.BATTERY_PLUGGED_USB;
  283. }elseif(mBatteryProps.chargerWirelessOnline){
  284. mPlugType=BatteryManager.BATTERY_PLUGGED_WIRELESS;
  285. }else{
  286. mPlugType=BATTERY_PLUGGED_NONE;
  287. }
  288. if(DEBUG){//日志,略过
  289. Slog.d(TAG,"Processingnewvalues:"
  290. +"chargerAcOnline="+mBatteryProps.chargerAcOnline
  291. +",chargerUsbOnline="+mBatteryProps.chargerUsbOnline
  292. +",chargerWirelessOnline="+mBatteryProps.chargerWirelessOnline
  293. +",batteryStatus="+mBatteryProps.batteryStatus
  294. +",batteryHealth="+mBatteryProps.batteryHealth
  295. +",batteryPresent="+mBatteryProps.batteryPresent
  296. +",batteryLevel="+mBatteryProps.batteryLevel
  297. +",batteryTechnology="+mBatteryProps.batteryTechnology
  298. +",batteryVoltage="+mBatteryProps.batteryVoltage
  299. +",batteryCurrentNow="+mBatteryProps.batteryCurrentNow
  300. +",batteryChargeCounter="+mBatteryProps.batteryChargeCounter
  301. +",batteryTemperature="+mBatteryProps.batteryTemperature
  302. +",mBatteryLevelCritical="+mBatteryLevelCritical
  303. +",mPlugType="+mPlugType);
  304. }
  305. //Letthebatterystatskeeptrackofthecurrentlevel.
  306. try{
  307. //把电池属性放到状态里面
  308. mBatteryStats.setBatteryState(mBatteryProps.batteryStatus,mBatteryProps.batteryHealth,
  309. mPlugType,mBatteryProps.batteryLevel,mBatteryProps.batteryTemperature,
  310. mBatteryProps.batteryVoltage);
  311. }catch(RemoteExceptione){
  312. //Shouldneverhappen.
  313. }
  314. //没电了
  315. shutdownIfNoPowerLocked();
  316. //温度过高了
  317. shutdownIfOverTempLocked();
  318. if(mBatteryProps.batteryStatus!=mLastBatteryStatus||
  319. mBatteryProps.batteryHealth!=mLastBatteryHealth||
  320. mBatteryProps.batteryPresent!=mLastBatteryPresent||
  321. mBatteryProps.batteryLevel!=mLastBatteryLevel||
  322. mPlugType!=mLastPlugType||
  323. mBatteryProps.batteryVoltage!=mLastBatteryVoltage||
  324. mBatteryProps.batteryTemperature!=mLastBatteryTemperature||
  325. mInvalidCharger!=mLastInvalidCharger){
  326. if(mPlugType!=mLastPlugType){//当前充电器类型与上次的不一样
  327. //并且上次充电器类型是noone,那就可以知道,现在是插上充电器了。
  328. if(mLastPlugType==BATTERY_PLUGGED_NONE){
  329. //discharging->charging
  330. //There'snovalueinthisdataunlesswe'vedischargedatleastonceandthe
  331. //batterylevelhaschanged;sodon'tloguntilitdoes.
  332. if(mDischargeStartTime!=0&&mDischargeStartLevel!=mBatteryProps.batteryLevel){
  333. dischargeDuration=SystemClock.elapsedRealtime()-mDischargeStartTime;
  334. logOutlier=true;
  335. EventLog.writeEvent(EventLogTags.BATTERY_DISCHARGE,dischargeDuration,
  336. mDischargeStartLevel,mBatteryProps.batteryLevel);
  337. //makesureweseeadischargeeventbeforeloggingagain
  338. mDischargeStartTime=0;
  339. }
  340. //并且本次充电器类型是noone,那就可以知道,现在是拔掉充电器了。
  341. }elseif(mPlugType==BATTERY_PLUGGED_NONE){
  342. //charging->dischargingorwejustpoweredup
  343. mDischargeStartTime=SystemClock.elapsedRealtime();
  344. mDischargeStartLevel=mBatteryProps.batteryLevel;
  345. }
  346. }
  347. if(mBatteryProps.batteryStatus!=mLastBatteryStatus||//写日志,略过
  348. mBatteryProps.batteryHealth!=mLastBatteryHealth||
  349. mBatteryProps.batteryPresent!=mLastBatteryPresent||
  350. mPlugType!=mLastPlugType){
  351. EventLog.writeEvent(EventLogTags.BATTERY_STATUS,
  352. mBatteryProps.batteryStatus,mBatteryProps.batteryHealth,mBatteryProps.batteryPresent?1:0,
  353. mPlugType,mBatteryProps.batteryTechnology);
  354. }
  355. if(mBatteryProps.batteryLevel!=mLastBatteryLevel){
  356. //Don'tdothisjustfromvoltageortemperaturechanges,thatis
  357. //toonoisy.
  358. EventLog.writeEvent(EventLogTags.BATTERY_LEVEL,
  359. mBatteryProps.batteryLevel,mBatteryProps.batteryVoltage,mBatteryProps.batteryTemperature);
  360. }
  361. if(mBatteryLevelCritical&&!mLastBatteryLevelCritical&&
  362. mPlugType==BATTERY_PLUGGED_NONE){
  363. //Wewanttomakesurewelogdischargecycleoutliers
  364. //ifthebatteryisabouttodie.
  365. dischargeDuration=SystemClock.elapsedRealtime()-mDischargeStartTime;
  366. logOutlier=true;
  367. }
  368. //本次调用,当前的充电状态
  369. finalbooleanplugged=mPlugType!=BATTERY_PLUGGED_NONE;
  370. //本次调用,上次调用的充电状态
  371. finalbooleanoldPlugged=mLastPlugType!=BATTERY_PLUGGED_NONE;
  372. /*TheACTION_BATTERY_LOWbroadcastissentinthesesituations:
  373. *-isjustun-plugged(previouslywasplugged)andbatterylevelis
  374. *lessthanorequaltoWARNING,or
  375. *-isnotpluggedandbatterylevelfallstoWARNINGboundary
  376. *(becomes<=mLowBatteryWarningLevel).
  377. */
  378. //用于发送低电量广播的判断
  379. finalbooleansendBatteryLow=!plugged//(按sendBatteryLow=true来说)当前没有充电
  380. &&mBatteryProps.batteryStatus!=BatteryManager.BATTERY_STATUS_UNKNOWN//充电状态不是UNKNOWN
  381. &&mBatteryProps.batteryLevel<=mLowBatteryWarningLevel//当前电量小于告警值15
  382. &&(oldPlugged||mLastBatteryLevel>mLowBatteryWarningLevel);//上次状态是充电或者上次电量等级大于告警值15
  383. sendIntentLocked();//发送电池电量改变的广播Intent.ACTION_BATTERY_CHANGED
  384. //Separatebroadcastissentforpowerconnected/notconnected
  385. //sincethestandardintentwillnotwakeanyapplicationsandsome
  386. //applicationsmaywanttohavesmartbehaviorbasedonthis.
  387. if(mPlugType!=0&&mLastPlugType==0){//插上充电器了
  388. mHandler.post(newRunnable(){
  389. @Override
  390. publicvoidrun(){
  391. IntentstatusIntent=newIntent(Intent.ACTION_POWER_CONNECTED);
  392. statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
  393. mContext.sendBroadcastAsUser(statusIntent,UserHandle.ALL);
  394. }
  395. });
  396. }
  397. elseif(mPlugType==0&&mLastPlugType!=0){//断开充电器了
  398. mHandler.post(newRunnable(){
  399. @Override
  400. publicvoidrun(){
  401. IntentstatusIntent=newIntent(Intent.ACTION_POWER_DISCONNECTED);
  402. statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
  403. mContext.sendBroadcastAsUser(statusIntent,UserHandle.ALL);
  404. }
  405. });
  406. }
  407. //发送低电量提醒(这个跟系统低电量提醒没关系,只是发出去了)
  408. if(sendBatteryLow){
  409. mSentLowBatteryBroadcast=true;
  410. mHandler.post(newRunnable(){
  411. @Override
  412. publicvoidrun(){
  413. IntentstatusIntent=newIntent(Intent.ACTION_BATTERY_LOW);
  414. statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
  415. mContext.sendBroadcastAsUser(statusIntent,UserHandle.ALL);
  416. }
  417. });
  418. }elseif(mSentLowBatteryBroadcast&&mLastBatteryLevel>=mLowBatteryCloseWarningLevel){//电量超过20了。电池状态OK了
  419. mSentLowBatteryBroadcast=false;
  420. mHandler.post(newRunnable(){
  421. @Override
  422. publicvoidrun(){
  423. IntentstatusIntent=newIntent(Intent.ACTION_BATTERY_OKAY);
  424. statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
  425. mContext.sendBroadcastAsUser(statusIntent,UserHandle.ALL);
  426. }
  427. });
  428. }
  429. //UpdatethebatteryLED
  430. mLed.updateLightsLocked();
  431. //ThisneedstobedoneaftersendIntent()sothatwegetthelastestbatterystats.
  432. if(logOutlier&&dischargeDuration!=0){
  433. logOutlierLocked(dischargeDuration);
  434. }
  435. mLastBatteryStatus=mBatteryProps.batteryStatus;
  436. mLastBatteryHealth=mBatteryProps.batteryHealth;
  437. mLastBatteryPresent=mBatteryProps.batteryPresent;
  438. mLastBatteryLevel=mBatteryProps.batteryLevel;
  439. mLastPlugType=mPlugType;
  440. mLastBatteryVoltage=mBatteryProps.batteryVoltage;
  441. mLastBatteryTemperature=mBatteryProps.batteryTemperature;
  442. mLastBatteryLevelCritical=mBatteryLevelCritical;
  443. mLastInvalidCharger=mInvalidCharger;
  444. }
  445. }
  446. //电池电量改变,把属性发出去(系统低电量提醒接收的是这个广播)
  447. privatevoidsendIntentLocked(){
  448. //Packupthevaluesandbroadcastthemtoeveryone
  449. finalIntentintent=newIntent(Intent.ACTION_BATTERY_CHANGED);
  450. intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
  451. |Intent.FLAG_RECEIVER_REPLACE_PENDING);
  452. inticon=getIconLocked(mBatteryProps.batteryLevel);
  453. intent.putExtra(BatteryManager.EXTRA_STATUS,mBatteryProps.batteryStatus);
  454. intent.putExtra(BatteryManager.EXTRA_HEALTH,mBatteryProps.batteryHealth);
  455. intent.putExtra(BatteryManager.EXTRA_PRESENT,mBatteryProps.batteryPresent);
  456. intent.putExtra(BatteryManager.EXTRA_LEVEL,mBatteryProps.batteryLevel);
  457. intent.putExtra(BatteryManager.EXTRA_SCALE,BATTERY_SCALE);
  458. intent.putExtra(BatteryManager.EXTRA_ICON_SMALL,icon);
  459. intent.putExtra(BatteryManager.EXTRA_PLUGGED,mPlugType);
  460. intent.putExtra(BatteryManager.EXTRA_VOLTAGE,mBatteryProps.batteryVoltage);
  461. intent.putExtra(BatteryManager.EXTRA_TEMPERATURE,mBatteryProps.batteryTemperature);
  462. intent.putExtra(BatteryManager.EXTRA_TECHNOLOGY,mBatteryProps.batteryTechnology);
  463. intent.putExtra(BatteryManager.EXTRA_INVALID_CHARGER,mInvalidCharger);
  464. if(DEBUG){
  465. Slog.d(TAG,"SendingACTION_BATTERY_CHANGED.level:"+mBatteryProps.batteryLevel+
  466. ",scale:"+BATTERY_SCALE+",status:"+mBatteryProps.batteryStatus+
  467. ",health:"+mBatteryProps.batteryHealth+",present:"+mBatteryProps.batteryPresent+
  468. ",voltage:"+mBatteryProps.batteryVoltage+
  469. ",temperature:"+mBatteryProps.batteryTemperature+
  470. ",technology:"+mBatteryProps.batteryTechnology+
  471. ",ACpowered:"+mBatteryProps.chargerAcOnline+",USBpowered:"+mBatteryProps.chargerUsbOnline+
  472. ",Wirelesspowered:"+mBatteryProps.chargerWirelessOnline+
  473. ",icon:"+icon+",invalidcharger:"+mInvalidCharger);
  474. }
  475. mHandler.post(newRunnable(){
  476. @Override
  477. publicvoidrun(){
  478. ActivityManagerNative.broadcastStickyIntent(intent,null,UserHandle.USER_ALL);
  479. }
  480. });
  481. }
  482. privatevoidlogBatteryStatsLocked(){
  483. IBinderbatteryInfoService=ServiceManager.getService(BatteryStats.SERVICE_NAME);
  484. if(batteryInfoService==null)return;
  485. DropBoxManagerdb=(DropBoxManager)mContext.getSystemService(Context.DROPBOX_SERVICE);
  486. if(db==null||!db.isTagEnabled("BATTERY_DISCHARGE_INFO"))return;
  487. FiledumpFile=null;
  488. FileOutputStreamdumpStream=null;
  489. try{
  490. //dumptheservicetoafile
  491. dumpFile=newFile(DUMPSYS_DATA_PATH+BatteryStats.SERVICE_NAME+".dump");
  492. dumpStream=newFileOutputStream(dumpFile);
  493. batteryInfoService.dump(dumpStream.getFD(),DUMPSYS_ARGS);
  494. FileUtils.sync(dumpStream);
  495. //adddumpfiletodropbox
  496. db.addFile("BATTERY_DISCHARGE_INFO",dumpFile,DropBoxManager.IS_TEXT);
  497. }catch(RemoteExceptione){
  498. Slog.e(TAG,"failedtodumpbatteryservice",e);
  499. }catch(IOExceptione){
  500. Slog.e(TAG,"failedtowritedumpsysfile",e);
  501. }finally{
  502. //makesurewecleanup
  503. if(dumpStream!=null){
  504. try{
  505. dumpStream.close();
  506. }catch(IOExceptione){
  507. Slog.e(TAG,"failedtoclosedumpsysoutputstream");
  508. }
  509. }
  510. if(dumpFile!=null&&!dumpFile.delete()){
  511. Slog.e(TAG,"failedtodeletetemporarydumpsysfile:"
  512. +dumpFile.getAbsolutePath());
  513. }
  514. }
  515. }
  516. privatevoidlogOutlierLocked(longduration){
  517. ContentResolvercr=mContext.getContentResolver();
  518. StringdischargeThresholdString=Settings.Global.getString(cr,
  519. Settings.Global.BATTERY_DISCHARGE_THRESHOLD);
  520. StringdurationThresholdString=Settings.Global.getString(cr,
  521. Settings.Global.BATTERY_DISCHARGE_DURATION_THRESHOLD);
  522. if(dischargeThresholdString!=null&&durationThresholdString!=null){
  523. try{
  524. longdurationThreshold=Long.parseLong(durationThresholdString);
  525. intdischargeThreshold=Integer.parseInt(dischargeThresholdString);
  526. if(duration<=durationThreshold&&
  527. mDischargeStartLevel-mBatteryProps.batteryLevel>=dischargeThreshold){
  528. //Ifthedischargecycleisbadenoughwewanttoknowaboutit.
  529. logBatteryStatsLocked();
  530. }
  531. if(DEBUG)Slog.v(TAG,"durationthreshold:"+durationThreshold+
  532. "dischargethreshold:"+dischargeThreshold);
  533. if(DEBUG)Slog.v(TAG,"duration:"+duration+"discharge:"+
  534. (mDischargeStartLevel-mBatteryProps.batteryLevel));
  535. }catch(NumberFormatExceptione){
  536. Slog.e(TAG,"InvalidDischargeThresholdsGServicestring:"+
  537. durationThresholdString+"or"+dischargeThresholdString);
  538. return;
  539. }
  540. }
  541. }
  542. privateintgetIconLocked(intlevel){
  543. if(mBatteryProps.batteryStatus==BatteryManager.BATTERY_STATUS_CHARGING){
  544. returncom.android.internal.R.drawable.stat_sys_battery_charge;
  545. }elseif(mBatteryProps.batteryStatus==BatteryManager.BATTERY_STATUS_DISCHARGING){
  546. returncom.android.internal.R.drawable.stat_sys_battery;
  547. }elseif(mBatteryProps.batteryStatus==BatteryManager.BATTERY_STATUS_NOT_CHARGING
  548. ||mBatteryProps.batteryStatus==BatteryManager.BATTERY_STATUS_FULL){
  549. if(isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)
  550. &&mBatteryProps.batteryLevel>=100){
  551. returncom.android.internal.R.drawable.stat_sys_battery_charge;
  552. }else{
  553. returncom.android.internal.R.drawable.stat_sys_battery;
  554. }
  555. }else{
  556. returncom.android.internal.R.drawable.stat_sys_battery_unknown;
  557. }
  558. }
  559. @Override
  560. protectedvoiddump(FileDescriptorfd,PrintWriterpw,String[]args){
  561. if(mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
  562. !=PackageManager.PERMISSION_GRANTED){
  563. pw.println("PermissionDenial:can'tdumpBatteryservicefromfrompid="
  564. +Binder.getCallingPid()
  565. +",uid="+Binder.getCallingUid());
  566. return;
  567. }
  568. synchronized(mLock){
  569. if(args==null||args.length==0||"-a".equals(args[0])){
  570. pw.println("CurrentBatteryServicestate:");
  571. if(mUpdatesStopped){
  572. pw.println("(UPDATESSTOPPED--use'reset'torestart)");
  573. }
  574. pw.println("ACpowered:"+mBatteryProps.chargerAcOnline);
  575. pw.println("USBpowered:"+mBatteryProps.chargerUsbOnline);
  576. pw.println("Wirelesspowered:"+mBatteryProps.chargerWirelessOnline);
  577. pw.println("status:"+mBatteryProps.batteryStatus);
  578. pw.println("health:"+mBatteryProps.batteryHealth);
  579. pw.println("present:"+mBatteryProps.batteryPresent);
  580. pw.println("level:"+mBatteryProps.batteryLevel);
  581. pw.println("scale:"+BATTERY_SCALE);
  582. pw.println("voltage:"+mBatteryProps.batteryVoltage);
  583. if(mBatteryProps.batteryCurrentNow!=Integer.MIN_VALUE){
  584. pw.println("currentnow:"+mBatteryProps.batteryCurrentNow);
  585. }
  586. if(mBatteryProps.batteryChargeCounter!=Integer.MIN_VALUE){
  587. pw.println("chargecounter:"+mBatteryProps.batteryChargeCounter);
  588. }
  589. pw.println("temperature:"+mBatteryProps.batteryTemperature);
  590. pw.println("technology:"+mBatteryProps.batteryTechnology);
  591. }elseif(args.length==3&&"set".equals(args[0])){
  592. Stringkey=args[1];
  593. Stringvalue=args[2];
  594. try{
  595. booleanupdate=true;
  596. if("ac".equals(key)){
  597. mBatteryProps.chargerAcOnline=Integer.parseInt(value)!=0;
  598. }elseif("usb".equals(key)){
  599. mBatteryProps.chargerUsbOnline=Integer.parseInt(value)!=0;
  600. }elseif("wireless".equals(key)){
  601. mBatteryProps.chargerWirelessOnline=Integer.parseInt(value)!=0;
  602. }elseif("status".equals(key)){
  603. mBatteryProps.batteryStatus=Integer.parseInt(value);
  604. }elseif("level".equals(key)){
  605. mBatteryProps.batteryLevel=Integer.parseInt(value);
  606. }elseif("invalid".equals(key)){
  607. mInvalidCharger=Integer.parseInt(value);
  608. }else{
  609. pw.println("Unknownsetoption:"+key);
  610. update=false;
  611. }
  612. if(update){
  613. longident=Binder.clearCallingIdentity();
  614. try{
  615. mUpdatesStopped=true;
  616. processValuesLocked();
  617. }finally{
  618. Binder.restoreCallingIdentity(ident);
  619. }
  620. }
  621. }catch(NumberFormatExceptionex){
  622. pw.println("Badvalue:"+value);
  623. }
  624. }elseif(args.length==1&&"reset".equals(args[0])){
  625. longident=Binder.clearCallingIdentity();
  626. try{
  627. mUpdatesStopped=false;
  628. }finally{
  629. Binder.restoreCallingIdentity(ident);
  630. }
  631. }else{
  632. pw.println("Dumpcurrentbatterystate,or:");
  633. pw.println("setac|usb|wireless|status|level|invalid<value>");
  634. pw.println("reset");
  635. }
  636. }
  637. }
  638. privatefinalUEventObservermInvalidChargerObserver=newUEventObserver(){
  639. @Override
  640. publicvoidonUEvent(UEventObserver.UEventevent){
  641. finalintinvalidCharger="1".equals(event.get("SWITCH_STATE"))?1:0;
  642. synchronized(mLock){
  643. if(mInvalidCharger!=invalidCharger){
  644. mInvalidCharger=invalidCharger;
  645. }
  646. }
  647. }
  648. };
  649. privatefinalclassLed{
  650. privatefinalLightsService.LightmBatteryLight;
  651. privatefinalintmBatteryLowARGB;
  652. privatefinalintmBatteryMediumARGB;
  653. privatefinalintmBatteryFullARGB;
  654. privatefinalintmBatteryLedOn;
  655. privatefinalintmBatteryLedOff;
  656. publicLed(Contextcontext,LightsServicelights){
  657. mBatteryLight=lights.getLight(LightsService.LIGHT_ID_BATTERY);
  658. mBatteryLowARGB=context.getResources().getInteger(
  659. com.android.internal.R.integer.config_notificationsBatteryLowARGB);
  660. mBatteryMediumARGB=context.getResources().getInteger(
  661. com.android.internal.R.integer.config_notificationsBatteryMediumARGB);
  662. mBatteryFullARGB=context.getResources().getInteger(
  663. com.android.internal.R.integer.config_notificationsBatteryFullARGB);
  664. mBatteryLedOn=context.getResources().getInteger(
  665. com.android.internal.R.integer.config_notificationsBatteryLedOn);
  666. mBatteryLedOff=context.getResources().getInteger(
  667. com.android.internal.R.integer.config_notificationsBatteryLedOff);
  668. }
  669. /**
  670. *SynchronizeonBatteryService.
  671. */
  672. publicvoidupdateLightsLocked(){
  673. finalintlevel=mBatteryProps.batteryLevel;
  674. finalintstatus=mBatteryProps.batteryStatus;
  675. if(level<mLowBatteryWarningLevel){
  676. if(status==BatteryManager.BATTERY_STATUS_CHARGING){
  677. //Solidredwhenbatteryischarging
  678. mBatteryLight.setColor(mBatteryLowARGB);
  679. }else{
  680. //Flashredwhenbatteryislowandnotcharging
  681. mBatteryLight.setFlashing(mBatteryLowARGB,LightsService.LIGHT_FLASH_TIMED,
  682. mBatteryLedOn,mBatteryLedOff);
  683. }
  684. }elseif(status==BatteryManager.BATTERY_STATUS_CHARGING
  685. ||status==BatteryManager.BATTERY_STATUS_FULL){
  686. if(status==BatteryManager.BATTERY_STATUS_FULL||level>=90){
  687. //Solidgreenwhenfullorchargingandnearlyfull
  688. mBatteryLight.setColor(mBatteryFullARGB);
  689. }else{
  690. //Solidorangewhenchargingandhalfwayfull
  691. mBatteryLight.setColor(mBatteryMediumARGB);
  692. }
  693. }else{
  694. //Nolightsifnotchargingandnotlow
  695. mBatteryLight.turnOff();
  696. }
  697. }
  698. }
  699. privatefinalclassBatteryListenerextendsIBatteryPropertiesListener.Stub{
  700. publicvoidbatteryPropertiesChanged(BatteryPropertiesprops){
  701. BatteryService.this.update(props);
  702. }
  703. }
  704. }



  总结如下:  此服务构造时会注册监听到系统JNI层。 当电池电量改变的时候会调用update(BatteryProperties props) -----》processValuesLocked() 。 而processValuesLocked() 函数会把电池状态把广播发送出去。其他类再接收广播进行处理    

下一个类就是低电量提醒了,文件目录:\frameworks\base\packages\SystemUI\src\com\android\systemui\power\PowerUI.java

[java] view plain copy
  1. /*
  2. *Copyright(C)2008TheAndroidOpenSourceProject
  3. *
  4. *LicensedundertheApacheLicense,Version2.0(the"License");
  5. *youmaynotusethisfileexceptincompliancewiththeLicense.
  6. *YoumayobtainacopyoftheLicenseat
  7. *
  8. *http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. *Unlessrequiredbyapplicablelaworagreedtoinwriting,software
  11. *distributedundertheLicenseisdistributedonan"ASIS"BASIS,
  12. *WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.
  13. *SeetheLicenseforthespecificlanguagegoverningpermissionsand
  14. *limitationsundertheLicense.
  15. */
  16. packagecom.android.systemui.power;
  17. importandroid.app.AlertDialog;
  18. importandroid.content.BroadcastReceiver;
  19. importandroid.content.ContentResolver;
  20. importandroid.content.Context;
  21. importandroid.content.DialogInterface;
  22. importandroid.content.Intent;
  23. importandroid.content.IntentFilter;
  24. importandroid.media.AudioManager;
  25. importandroid.media.Ringtone;
  26. importandroid.media.RingtoneManager;
  27. importandroid.net.Uri;
  28. importandroid.os.BatteryManager;
  29. importandroid.os.Handler;
  30. importandroid.os.PowerManager;
  31. importandroid.os.SystemClock;
  32. importandroid.os.UserHandle;
  33. importandroid.provider.Settings;
  34. importandroid.util.Slog;
  35. importandroid.view.View;
  36. importandroid.view.WindowManager;
  37. importandroid.widget.TextView;
  38. importcom.android.systemui.R;
  39. importcom.android.systemui.SystemUI;
  40. importjava.io.FileDescriptor;
  41. importjava.io.PrintWriter;
  42. importjava.util.Arrays;
  43. publicclassPowerUIextendsSystemUI{//总体说一下,这里才是处理低电量提醒的地方,他接收的广播是Intent.ACTION_BATTERY_CHANGED
  44. staticfinalStringTAG="PowerUI";
  45. staticfinalbooleanDEBUG=false;
  46. HandlermHandler=newHandler();
  47. intmBatteryLevel=100;
  48. intmBatteryStatus=BatteryManager.BATTERY_STATUS_UNKNOWN;
  49. intmPlugType=0;
  50. intmInvalidCharger=0;
  51. intmLowBatteryAlertCloseLevel;
  52. int[]mLowBatteryReminderLevels=newint[2];
  53. AlertDialogmInvalidChargerDialog;
  54. AlertDialogmLowBatteryDialog;
  55. TextViewmBatteryLevelTextView;
  56. privatelongmScreenOffTime=-1;
  57. publicvoidstart(){//这个类会在手机启动后,在SystemUI里启动(就是系统界面)。
  58. mLowBatteryAlertCloseLevel=mContext.getResources().getInteger(//电量告警取消值,值20
  59. com.android.internal.R.integer.config_lowBatteryCloseWarningLevel);
  60. mLowBatteryReminderLevels[0]=mContext.getResources().getInteger(//低电量提醒15
  61. com.android.internal.R.integer.config_lowBatteryWarningLevel);
  62. mLowBatteryReminderLevels[1]=mContext.getResources().getInteger(//低电量临界值4
  63. com.android.internal.R.integer.config_criticalBatteryWarningLevel);
  64. finalPowerManagerpm=(PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
  65. mScreenOffTime=pm.isScreenOn()?-1:SystemClock.elapsedRealtime();
  66. //RegisterforIntentbroadcastsfor...
  67. IntentFilterfilter=newIntentFilter();
  68. filter.addAction(Intent.ACTION_BATTERY_CHANGED);
  69. filter.addAction(Intent.ACTION_SCREEN_OFF);
  70. filter.addAction(Intent.ACTION_SCREEN_ON);
  71. mContext.registerReceiver(mIntentReceiver,filter,null,mHandler);
  72. }
  73. /**
  74. *Bucketsthebatterylevel.
  75. *
  76. *ThecodeinthisfunctionisalittleweirdbecauseIcouldn'tcomprehend
  77. *thebucketgoingupwhenthebatterylevelwasgoingdown.--joeo
  78. *
  79. *1meansthatthebatteryis"ok"
  80. *0meansthatthebatteryisbetween"ok"andwhatweshouldwarnabout.
  81. *lessthan0meansthatthebatteryislow
  82. */
  83. privateintfindBatteryLevelBucket(intlevel){//这个方法是用来警告判断用的。
  84. if(level>=mLowBatteryAlertCloseLevel){
  85. return1;
  86. }
  87. if(level>=mLowBatteryReminderLevels[0]){
  88. return0;
  89. }
  90. finalintN=mLowBatteryReminderLevels.length;
  91. for(inti=N-1;i>=0;i--){
  92. if(level<=mLowBatteryReminderLevels[i]){
  93. return-1-i;
  94. }
  95. }
  96. thrownewRuntimeException("notpossible!");
  97. }
  98. privateBroadcastReceivermIntentReceiver=newBroadcastReceiver(){//重点,广播接收处理
  99. @Override
  100. publicvoidonReceive(Contextcontext,Intentintent){
  101. Stringaction=intent.getAction();
  102. if(action.equals(Intent.ACTION_BATTERY_CHANGED)){//电池电量改变
  103. finalintoldBatteryLevel=mBatteryLevel;//下边就是根据Intent获取BatteryService传过来的电池属性
  104. mBatteryLevel=intent.getIntExtra(BatteryManager.EXTRA_LEVEL,100);/
  105. finalintoldBatteryStatus=mBatteryStatus;
  106. mBatteryStatus=intent.getIntExtra(BatteryManager.EXTRA_STATUS,
  107. BatteryManager.BATTERY_STATUS_UNKNOWN);
  108. finalintoldPlugType=mPlugType;
  109. mPlugType=intent.getIntExtra(BatteryManager.EXTRA_PLUGGED,1);
  110. finalintoldInvalidCharger=mInvalidCharger;
  111. mInvalidCharger=intent.getIntExtra(BatteryManager.EXTRA_INVALID_CHARGER,0);
  112. finalbooleanplugged=mPlugType!=0;
  113. finalbooleanoldPlugged=oldPlugType!=0;
  114. intoldBucket=findBatteryLevelBucket(oldBatteryLevel);//这两个值特别有意思,就是说记录下老的电量,记录一下新的电量,比较电量是增加了,还是减小了
  115. intbucket=findBatteryLevelBucket(mBatteryLevel);
  116. if(DEBUG){
  117. Slog.d(TAG,"buckets....."+mLowBatteryAlertCloseLevel
  118. +".."+mLowBatteryReminderLevels[0]
  119. +".."+mLowBatteryReminderLevels[1]);
  120. Slog.d(TAG,"level"+oldBatteryLevel+"-->"+mBatteryLevel);
  121. Slog.d(TAG,"status"+oldBatteryStatus+"-->"+mBatteryStatus);
  122. Slog.d(TAG,"plugType"+oldPlugType+"-->"+mPlugType);
  123. Slog.d(TAG,"invalidCharger"+oldInvalidCharger+"-->"+mInvalidCharger);
  124. Slog.d(TAG,"bucket"+oldBucket+"-->"+bucket);
  125. Slog.d(TAG,"plugged"+oldPlugged+"-->"+plugged);
  126. }
  127. if(oldInvalidCharger==0&&mInvalidCharger!=0){
  128. Slog.d(TAG,"showinginvalidchargerwarning");
  129. showInvalidChargerDialog();//就是充电器不识别的弹窗
  130. return;
  131. }elseif(oldInvalidCharger!=0&&mInvalidCharger==0){
  132. dismissInvalidChargerDialog();
  133. }elseif(mInvalidChargerDialog!=null){
  134. //ifinvalidchargerisshowing,don'tshowlowbattery
  135. return;
  136. }
  137. if(!plugged
  138. &&(bucket<oldBucket||oldPlugged)
  139. &&mBatteryStatus!=BatteryManager.BATTERY_STATUS_UNKNOWN
  140. &&bucket<0){
  141. showLowBatteryWarning();<spanstyle="color:#FF0000;">//这里哈,低电量提醒的弹窗</span>
  142. //onlyplaySFXwhenthedialogcomesuporthebucketchanges
  143. if(bucket!=oldBucket||oldPlugged){
  144. playLowBatterySound();
  145. }
  146. }elseif(plugged||(bucket>oldBucket&&bucket>0)){//插上充电器或者充电电池电量超过20取消弹窗
  147. dismissLowBatteryWarning();
  148. }elseif(mBatteryLevelTextView!=null){
  149. showLowBatteryWarning();
  150. }
  151. }elseif(Intent.ACTION_SCREEN_OFF.equals(action)){
  152. mScreenOffTime=SystemClock.elapsedRealtime();
  153. }elseif(Intent.ACTION_SCREEN_ON.equals(action)){
  154. mScreenOffTime=-1;
  155. }else{
  156. Slog.w(TAG,"unknownintent:"+intent);
  157. }
  158. }
  159. };
  160. voiddismissLowBatteryWarning(){
  161. if(mLowBatteryDialog!=null){
  162. Slog.i(TAG,"closinglowbatterywarning:level="+mBatteryLevel);
  163. mLowBatteryDialog.dismiss();
  164. }
  165. }
  166. voidshowLowBatteryWarning(){
  167. Slog.i(TAG,
  168. ((mBatteryLevelTextView==null)?"showing":"updating")
  169. +"lowbatterywarning:level="+mBatteryLevel
  170. +"["+findBatteryLevelBucket(mBatteryLevel)+"]");
  171. CharSequencelevelText=mContext.getString(
  172. R.string.battery_low_percent_format,mBatteryLevel);
  173. if(mBatteryLevelTextView!=null){
  174. mBatteryLevelTextView.setText(levelText);
  175. }else{
  176. Viewv=View.inflate(mContext,R.layout.battery_low,null);
  177. mBatteryLevelTextView=(TextView)v.findViewById(R.id.level_percent);
  178. mBatteryLevelTextView.setText(levelText);
  179. AlertDialog.Builderb=newAlertDialog.Builder(mContext);
  180. b.setCancelable(true);
  181. b.setTitle(R.string.battery_low_title);
  182. b.setView(v);
  183. b.setIconAttribute(android.R.attr.alertDialogIcon);
  184. b.setPositiveButton(android.R.string.ok,null);
  185. finalIntentintent=newIntent(Intent.ACTION_POWER_USAGE_SUMMARY);
  186. intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
  187. |Intent.FLAG_ACTIVITY_MULTIPLE_TASK
  188. |Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
  189. |Intent.FLAG_ACTIVITY_NO_HISTORY);
  190. if(intent.resolveActivity(mContext.getPackageManager())!=null){
  191. b.setNegativeButton(R.string.battery_low_why,
  192. newDialogInterface.OnClickListener(){
  193. @Override
  194. publicvoidonClick(DialogInterfacedialog,intwhich){
  195. mContext.startActivityAsUser(intent,UserHandle.CURRENT);
  196. dismissLowBatteryWarning();
  197. }
  198. });
  199. }
  200. AlertDialogd=b.create();
  201. d.setOnDismissListener(newDialogInterface.OnDismissListener(){
  202. @Override
  203. publicvoidonDismiss(DialogInterfacedialog){
  204. mLowBatteryDialog=null;
  205. mBatteryLevelTextView=null;
  206. }
  207. });
  208. d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
  209. d.getWindow().getAttributes().privateFlags|=
  210. WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
  211. d.show();
  212. mLowBatteryDialog=d;
  213. }
  214. }
  215. voidplayLowBatterySound(){
  216. finalContentResolvercr=mContext.getContentResolver();
  217. finalintsilenceAfter=Settings.Global.getInt(cr,
  218. Settings.Global.LOW_BATTERY_SOUND_TIMEOUT,0);
  219. finallongoffTime=SystemClock.elapsedRealtime()-mScreenOffTime;
  220. if(silenceAfter>0
  221. &&mScreenOffTime>0
  222. &&offTime>silenceAfter){
  223. Slog.i(TAG,"screenofftoolong("+offTime+"ms,limit"+silenceAfter
  224. +"ms):notwakinguptheuserwithlowbatterysound");
  225. return;
  226. }
  227. if(DEBUG){
  228. Slog.d(TAG,"playinglowbatterysound.pick-a-doop!");//WOMP-WOMPisdeprecated
  229. }
  230. if(Settings.Global.getInt(cr,Settings.Global.POWER_SOUNDS_ENABLED,1)==1){
  231. finalStringsoundPath=Settings.Global.getString(cr,
  232. Settings.Global.LOW_BATTERY_SOUND);
  233. if(soundPath!=null){
  234. finalUrisoundUri=Uri.parse("file://"+soundPath);
  235. if(soundUri!=null){
  236. finalRingtonesfx=RingtoneManager.getRingtone(mContext,soundUri);
  237. if(sfx!=null){
  238. sfx.setStreamType(AudioManager.STREAM_SYSTEM);
  239. sfx.play();
  240. }
  241. }
  242. }
  243. }
  244. }
  245. voiddismissInvalidChargerDialog(){
  246. if(mInvalidChargerDialog!=null){
  247. mInvalidChargerDialog.dismiss();
  248. }
  249. }
  250. voidshowInvalidChargerDialog(){
  251. Slog.d(TAG,"showinginvalidchargerdialog");
  252. dismissLowBatteryWarning();
  253. AlertDialog.Builderb=newAlertDialog.Builder(mContext);
  254. b.setCancelable(true);
  255. b.setMessage(R.string.invalid_charger);
  256. b.setIconAttribute(android.R.attr.alertDialogIcon);
  257. b.setPositiveButton(android.R.string.ok,null);
  258. AlertDialogd=b.create();
  259. d.setOnDismissListener(newDialogInterface.OnDismissListener(){
  260. publicvoidonDismiss(DialogInterfacedialog){
  261. mInvalidChargerDialog=null;
  262. mBatteryLevelTextView=null;
  263. }
  264. });
  265. d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
  266. d.show();
  267. mInvalidChargerDialog=d;
  268. }
  269. publicvoiddump(FileDescriptorfd,PrintWriterpw,String[]args){
  270. pw.print("mLowBatteryAlertCloseLevel=");
  271. pw.println(mLowBatteryAlertCloseLevel);
  272. pw.print("mLowBatteryReminderLevels=");
  273. pw.println(Arrays.toString(mLowBatteryReminderLevels));
  274. pw.print("mInvalidChargerDialog=");
  275. pw.println(mInvalidChargerDialog==null?"null":mInvalidChargerDialog.toString());
  276. pw.print("mLowBatteryDialog=");
  277. pw.println(mLowBatteryDialog==null?"null":mLowBatteryDialog.toString());
  278. pw.print("mBatteryLevel=");
  279. pw.println(Integer.toString(mBatteryLevel));
  280. pw.print("mBatteryStatus=");
  281. pw.println(Integer.toString(mBatteryStatus));
  282. pw.print("mPlugType=");
  283. pw.println(Integer.toString(mPlugType));
  284. pw.print("mInvalidCharger=");
  285. pw.println(Integer.toString(mInvalidCharger));
  286. pw.print("mScreenOffTime=");
  287. pw.print(mScreenOffTime);
  288. if(mScreenOffTime>=0){
  289. pw.print("(");
  290. pw.print(SystemClock.elapsedRealtime()-mScreenOffTime);
  291. pw.print("ago)");
  292. }
  293. pw.println();
  294. pw.print("soundTimeout=");
  295. pw.println(Settings.Global.getInt(mContext.getContentResolver(),
  296. Settings.Global.LOW_BATTERY_SOUND_TIMEOUT,0));
  297. pw.print("bucket:");
  298. pw.println(Integer.toString(findBatteryLevelBucket(mBatteryLevel)));
  299. }
  300. }

总结一下:这个类就是接收电池电量改变的广播,然后弹窗提醒。

下一个类就是没电关机界面了,文件目录:\frameworks\base\services\java\com\android\server\ShutdownLowBatteryActivity.java

这个Activity的配置文件是这样的(\frameworks\base\core\res\AndroidManifest.xml):

[html] view plain copy
  1. <activityandroid:name="com.android.server.ShutdownLowBatteryActivity"
  2. android:theme="@android:style/Theme.Translucent.NoTitleBar"
  3. android:configChanges="orientation|keyboardHidden|screenSize"
  4. android:windowSoftInputMode="stateHidden"
  5. android:permission="android.permission.SHUTDOWN"
  6. android:excludeFromRecents="true">
  7. <intent-filter>
  8. <actionandroid:name="android.intent.action.ACTION_REQUEST_SHUTDOWN_LOWBATTERY"/>
  9. <categoryandroid:name="android.intent.category.DEFAULT"/>
  10. </intent-filter>
  11. </activity>

android:theme="@android:style/Theme.Translucent.NoTitleBar"API小于11的透明主题。这样弹出的dialog会是老版本的主题。(这个Activity是透明的)

对于Theme,因为是4.4,我更倾向于:android:theme="@android:style/Theme.Holo.Panel"


ShutdownLowBatteryActivity.java:

[java] view plain copy
  1. /*
  2. *Copyright(C)2009TheAndroidOpenSourceProject
  3. *
  4. *LicensedundertheApacheLicense,Version2.0(the"License");
  5. *youmaynotusethisfileexceptincompliancewiththeLicense.
  6. *YoumayobtainacopyoftheLicenseat
  7. *
  8. *http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. *Unlessrequiredbyapplicablelaworagreedtoinwriting,software
  11. *distributedundertheLicenseisdistributedonan"ASIS"BASIS,
  12. *WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.
  13. *SeetheLicenseforthespecificlanguagegoverningpermissionsand
  14. *limitationsundertheLicense.
  15. */
  16. packagecom.android.server;
  17. importandroid.app.Activity;
  18. importandroid.app.AlertDialog;
  19. importandroid.app.KeyguardManager;
  20. importandroid.content.BroadcastReceiver;
  21. importandroid.content.Context;
  22. importandroid.content.DialogInterface;
  23. importandroid.content.Intent;
  24. importandroid.content.IntentFilter;
  25. importandroid.os.Bundle;
  26. importandroid.os.Handler;
  27. importandroid.util.Slog;
  28. importandroid.view.Window;
  29. importandroid.view.WindowManager;
  30. importandroid.view.View;
  31. //importcom.android.internal.app.ShutdownThread;
  32. importcom.android.server.power.ShutdownThread;
  33. importandroid.telephony.TelephonyManager;
  34. importandroid.telephony.PhoneStateListener;
  35. importandroid.media.MediaPlayer;
  36. importandroid.media.MediaPlayer.OnCompletionListener;
  37. importandroid.content.ContentResolver;
  38. importandroid.provider.Settings;
  39. importjava.io.IOException;
  40. publicclassShutdownLowBatteryActivityextendsActivity{
  41. privatestaticfinalStringTAG="ShutdownLowBatteryActivity";
  42. privatebooleanmConfirm;
  43. privateintmSeconds=15;//电池电量等于015秒内不插充电器就自动关机
  44. privateAlertDialogmDialog;
  45. privateHandlermyHandler=newHandler();
  46. privateRunnablemyRunnable=newRunnable(){//这里数秒关机
  47. @Override
  48. publicvoidrun(){
  49. mSeconds--;
  50. if(mSeconds<1)
  51. mSeconds=0;
  52. mDialog.setMessage(getString(com.android.internal.R.string.low_battery_shutdown_after_seconds,mSeconds));
  53. if(mSeconds<=1){
  54. myHandler.removeCallbacks(myRunnable);
  55. Handlerh=newHandler();
  56. h.post(newRunnable(){
  57. publicvoidrun(){
  58. ShutdownThread.shutdown(ShutdownLowBatteryActivity.this,mConfirm);
  59. }
  60. });
  61. }
  62. myHandler.postDelayed(myRunnable,1000);
  63. }
  64. };
  65. privateBroadcastReceivermReceiver;
  66. privateMediaPlayermplayer;
  67. @Override
  68. protectedvoidonCreate(BundlesavedInstanceState){
  69. super.onCreate(savedInstanceState);
  70. mConfirm=getIntent().getBooleanExtra(Intent.EXTRA_KEY_CONFIRM,false);
  71. Slog.i(TAG,"onCreate():confirm="+mConfirm);
  72. //if(getIntent().getBooleanExtra("can_be_cancel",false)){//这行注释掉了:然后当连上充电器后或者电量涨到20的时候,就取消倒计时关机
  73. mReceiver=newBroadcastReceiver(){
  74. @Override
  75. publicvoidonReceive(Contextcontext,Intentintent){
  76. if(Intent.ACTION_BATTERY_OKAY.equals(intent.getAction())|
  77. Intent.ACTION_POWER_CONNECTED.equals(intent.getAction())){
  78. ShutDownWakeLock.releaseCpuLock();
  79. myHandler.removeCallbacks(myRunnable);
  80. if(mReceiver!=null)
  81. unregisterReceiver(mReceiver);
  82. finish();
  83. }
  84. }
  85. };
  86. IntentFilterfilter=newIntentFilter(Intent.ACTION_POWER_CONNECTED);
  87. filter.addAction(Intent.ACTION_BATTERY_OKAY);
  88. registerReceiver(mReceiver,filter);
  89. //}
  90. PhoneStateListenermPhoneStateListener=newPhoneStateListener(){//如果正数秒呢,电话呼入了。取消自动关机
  91. @Override
  92. publicvoidonCallStateChanged(intstate,Stringignored){
  93. if(state==TelephonyManager.CALL_STATE_RINGING){
  94. ShutDownWakeLock.releaseCpuLock();
  95. myHandler.removeCallbacks(myRunnable);
  96. finish();
  97. }
  98. }
  99. };
  100. TelephonyManagermTelephonyManager=(TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
  101. mTelephonyManager.listen(mPhoneStateListener,
  102. PhoneStateListener.LISTEN_CALL_STATE);
  103. requestWindowFeature(android.view.Window.FEATURE_NO_TITLE);
  104. Windowwin=getWindow();
  105. win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
  106. |WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
  107. win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
  108. |WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
  109. setContentView(newView(this));
  110. mDialog=newAlertDialog.Builder(this).create();
  111. mDialog.setTitle(com.android.internal.R.string.low_battery_shutdown_title);
  112. mDialog.setMessage(getString(com.android.internal.R.string.low_battery_shutdown_after_seconds,mSeconds));
  113. if(!getIntent().getBooleanExtra("cant_be_cancel_by_button",false)){//读取配置文件,是否运行取消,然后根据这个显示取消自动关机按钮
  114. mDialog.setButton(DialogInterface.BUTTON_NEUTRAL,getText(com.android.internal.R.string.cancel),newDialogInterface.OnClickListener(){
  115. @Override
  116. publicvoidonClick(DialogInterfacedialog,intwhich){
  117. myHandler.removeCallbacks(myRunnable);
  118. dialog.cancel();
  119. if(mReceiver!=null)
  120. unregisterReceiver(mReceiver);
  121. finish();
  122. }});
  123. }
  124. mDialog.setCancelable(false);
  125. //mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
  126. mDialog.show();
  127. if(mConfirm==false){
  128. myHandler.postDelayed(myRunnable,1000);
  129. }
  130. myHandler.post(newRunnable(){
  131. publicvoidrun(){
  132. finalContentResolvercr=getContentResolver();
  133. Stringpath=Settings.System.getString(cr,Settings.System.NOTIFICATION_SOUND);
  134. mplayer=newMediaPlayer();
  135. try{
  136. mplayer.reset();
  137. mplayer.setDataSource("system/media/audio/ui/LowBattery.ogg");
  138. mplayer.prepare();
  139. mplayer.start();
  140. mplayer.setOnCompletionListener(newOnCompletionListener(){
  141. @Override
  142. publicvoidonCompletion(MediaPlayermp){
  143. if(null!=mplayer){
  144. mplayer.stop();
  145. mplayer.release();
  146. mplayer=null;
  147. }
  148. }
  149. });
  150. }
  151. catch(IOExceptione){
  152. }
  153. }
  154. });
  155. }
  156. }
总结如下:这个类就是弹窗计时,提醒不连充电器就要关机了。

最后一个相关的类,文件路径:\frameworks\base\packages\SystemUI\src\com\android\systemui\BatteryMeterView.java

这个类是自定义控件,定义在手机状态栏里:

[java] view plain copy
  1. /*
  2. *Copyright(C)2013TheAndroidOpenSourceProject
  3. *
  4. *LicensedundertheApacheLicense,Version2.0(the"License");
  5. *youmaynotusethisfileexceptincompliancewiththeLicense.
  6. *YoumayobtainacopyoftheLicenseat
  7. *
  8. *http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. *Unlessrequiredbyapplicablelaworagreedtoinwriting,software
  11. *distributedundertheLicenseisdistributedonan"ASIS"BASIS,
  12. *WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.
  13. *SeetheLicenseforthespecificlanguagegoverningpermissionsand
  14. *limitationsundertheLicense.
  15. */
  16. packagecom.android.systemui;
  17. importandroid.content.BroadcastReceiver;
  18. importandroid.content.Context;
  19. importandroid.content.Intent;
  20. importandroid.content.IntentFilter;
  21. importandroid.content.res.Resources;
  22. importandroid.content.res.TypedArray;
  23. importandroid.graphics.Canvas;
  24. importandroid.graphics.Paint;
  25. importandroid.graphics.Path;
  26. importandroid.graphics.PorterDuff;
  27. importandroid.graphics.PorterDuffXfermode;
  28. importandroid.graphics.Rect;
  29. importandroid.graphics.RectF;
  30. importandroid.graphics.Typeface;
  31. importandroid.os.BatteryManager;
  32. importandroid.os.Bundle;
  33. importandroid.provider.Settings;
  34. importandroid.util.AttributeSet;
  35. importandroid.view.View;
  36. publicclassBatteryMeterViewextendsViewimplementsDemoMode{
  37. publicstaticfinalStringTAG=BatteryMeterView.class.getSimpleName();
  38. publicstaticfinalStringACTION_LEVEL_TEST="com.android.systemui.BATTERY_LEVEL_TEST";
  39. publicstaticfinalbooleanENABLE_PERCENT=true;
  40. publicstaticfinalbooleanSINGLE_DIGIT_PERCENT=false;
  41. publicstaticfinalbooleanSHOW_100_PERCENT=false;
  42. publicstaticfinalintFULL=96;
  43. publicstaticfinalintEMPTY=4;
  44. publicstaticfinalfloatSUBPIXEL=0.4f;//insetrectsforsofteredges
  45. int[]mColors;
  46. booleanmShowPercent=true;
  47. PaintmFramePaint,mBatteryPaint,mWarningTextPaint,mTextPaint,mBoltPaint;
  48. intmButtonHeight;
  49. privatefloatmTextHeight,mWarningTextHeight;
  50. privateintmHeight;
  51. privateintmWidth;
  52. privateStringmWarningString;
  53. privatefinalintmChargeColor;
  54. privatefinalfloat[]mBoltPoints;
  55. privatefinalPathmBoltPath=newPath();
  56. privatefinalRectFmFrame=newRectF();
  57. privatefinalRectFmButtonFrame=newRectF();
  58. privatefinalRectFmClipFrame=newRectF();
  59. privatefinalRectFmBoltFrame=newRectF();
  60. privateclassBatteryTrackerextendsBroadcastReceiver{
  61. publicstaticfinalintUNKNOWN_LEVEL=-1;
  62. //currentbatterystatus
  63. intlevel=UNKNOWN_LEVEL;
  64. StringpercentStr;
  65. intplugType;
  66. booleanplugged;
  67. inthealth;
  68. intstatus;
  69. Stringtechnology;
  70. intvoltage;
  71. inttemperature;
  72. booleantestmode=false;
  73. @Override
  74. publicvoidonReceive(Contextcontext,Intentintent){
  75. finalStringaction=intent.getAction();
  76. if(action.equals(Intent.ACTION_BATTERY_CHANGED)){//接收电量改变的广播,取电池状态的属性
  77. if(testmode&&!intent.getBooleanExtra("testmode",false))return;
  78. level=(int)(100f
  79. *intent.getIntExtra(BatteryManager.EXTRA_LEVEL,0)
  80. /intent.getIntExtra(BatteryManager.EXTRA_SCALE,100));
  81. plugType=intent.getIntExtra(BatteryManager.EXTRA_PLUGGED,0);
  82. plugged=plugType!=0;
  83. health=intent.getIntExtra(BatteryManager.EXTRA_HEALTH,
  84. BatteryManager.BATTERY_HEALTH_UNKNOWN);
  85. status=intent.getIntExtra(BatteryManager.EXTRA_STATUS,
  86. BatteryManager.BATTERY_STATUS_UNKNOWN);
  87. technology=intent.getStringExtra(BatteryManager.EXTRA_TECHNOLOGY);
  88. voltage=intent.getIntExtra(BatteryManager.EXTRA_VOLTAGE,0);
  89. temperature=intent.getIntExtra(BatteryManager.EXTRA_TEMPERATURE,0);
  90. setContentDescription(
  91. context.getString(R.string.accessibility_battery_level,level));
  92. postInvalidate();
  93. }elseif(action.equals(ACTION_LEVEL_TEST)){
  94. testmode=true;
  95. post(newRunnable(){
  96. intcurLevel=0;
  97. intincr=1;
  98. intsaveLevel=level;
  99. intsavePlugged=plugType;
  100. Intentdummy=newIntent(Intent.ACTION_BATTERY_CHANGED);
  101. @Override
  102. publicvoidrun(){
  103. if(curLevel<0){
  104. testmode=false;
  105. dummy.putExtra("level",saveLevel);
  106. dummy.putExtra("plugged",savePlugged);
  107. dummy.putExtra("testmode",false);
  108. }else{
  109. dummy.putExtra("level",curLevel);
  110. dummy.putExtra("plugged",incr>0?BatteryManager.BATTERY_PLUGGED_AC:0);
  111. dummy.putExtra("testmode",true);
  112. }
  113. getContext().sendBroadcast(dummy);
  114. if(!testmode)return;
  115. curLevel+=incr;
  116. if(curLevel==100){
  117. incr*=-1;
  118. }
  119. postDelayed(this,200);
  120. }
  121. });
  122. }
  123. }
  124. }
  125. BatteryTrackermTracker=newBatteryTracker();
  126. @Override
  127. publicvoidonAttachedToWindow(){
  128. super.onAttachedToWindow();
  129. IntentFilterfilter=newIntentFilter();
  130. filter.addAction(Intent.ACTION_BATTERY_CHANGED);
  131. filter.addAction(ACTION_LEVEL_TEST);
  132. finalIntentsticky=getContext().registerReceiver(mTracker,filter);
  133. if(sticky!=null){
  134. //preloadthebatterylevel
  135. mTracker.onReceive(getContext(),sticky);
  136. }
  137. }
  138. @Override
  139. publicvoidonDetachedFromWindow(){
  140. super.onDetachedFromWindow();
  141. getContext().unregisterReceiver(mTracker);

更多相关文章

  1. Android(安卓)实现定时开关机另类实现--BSP级
  2. unity android获取电量和wifi信号强度
  3. 蓝牙遥控器获取电量GATT
  4. Android(安卓)优化电池使用时间 ——监控电池电量和充电状态
  5. Android实现电量控制降低耗电
  6. 展讯android LEDS模块分析----一个bug
  7. [置顶] Android(安卓)显示手机电池的当前电量
  8. 降低android应用程序耗电量的解决方案
  9. Android功耗测试小工具集锦

随机推荐

  1. 在腾讯云上创建您的 SQL Cluster (2)
  2. 双栏模型Hurdle远超Tobit, 对于归并数据
  3. 向量自回归VAR模型操作指南针,为微观面板
  4. 有限混合模型FMM,异质性分组分析的新筹码
  5. 条件Logit绝对不输多项Logit,而混合模型
  6. 广义PSM,连续政策变量因果识别的不二利器
  7. 政策评估中"中介效应"因果分析, 有趣的前
  8. 腾讯云 TDSQL 审计原理揭秘
  9. JavaScript基础之 变量与常量的声明、函
  10. Jupyter Notebook主题设置