`
quanminchaoren
  • 浏览: 923031 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Android中低电量的处理方法

阅读更多

前段时间解了个Bug:Android系统在低电时充电,StatusBar上的充电图标不会变化,始终显示的是同一个图标

当时没有来得及整理,现在补一下

 

电池电量信息是从BatteryService中通过Intent发送出去的,在上一篇有讲到

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

其中函数update负责读具体信息并发送

208     private synchronized final void update() {

 

 

1、发送:Intent.ACTION_BATTERY_LOW && Intent.ACTION_BATTERY_OKAY)

首先需要判断是否需要发送低电量信息:Intent.ACTION_BATTERY_LOW

288             /* The ACTION_BATTERY_LOW broadcast is sent in these situations:
289              * - is just un-plugged (previously was plugged) and battery level is
290              *   less than or equal to WARNING, or
291              * - is not plugged and battery level falls to WARNING boundary
292              *   (becomes <= mLowBatteryWarningLevel).
293              */
294             final boolean sendBatteryLow = !plugged
295                 && mBatteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
296                 && mBatteryLevel <= mLowBatteryWarningLevel
297                 && (oldPlugged || mLastBatteryLevel > mLowBatteryWarningLevel);
可以看到发送低电量信息会有两个条件,
1)当前不在充电状态,上次update时处于充电状态,并且电池电量小于等于mLowBatteryWarningLevel(低电量警告值)
2)当前不在充电状态,电池电量小于等于mLowBatteryWarningLevel(低电量警告值),并且上次update时,电量大于mLowBatteryWarningLevel(低电量警告值)
 
但是mLowBatteryWarningLevel这个值具体是多少呢?
127         mLowBatteryWarningLevel = mContext.getResources().getInteger(
128                 com.android.internal.R.integer.config_lowBatteryWarningLevel);
从以上可以看出,是通过config.xml读取到的
文件位于frameworks/base/core/res/res/values/config.xml
261     <!-- Display low battery warning when battery level dips to this value -->
262     <integer name="config_lowBatteryWarningLevel">15</integer>
 
下面代码是具体发送
315             if (sendBatteryLow) {
316                 mSentLowBatteryBroadcast = true;
317                 statusIntent.setAction(Intent.ACTION_BATTERY_LOW);
318                 mContext.sendBroadcast(statusIntent);
319             } else if (mSentLowBatteryBroadcast && mLastBatteryLevel >= mLowBatteryCloseWarningLevel) {
320                 mSentLowBatteryBroadcast = false;
321                 statusIntent.setAction(Intent.ACTION_BATTERY_OKAY);
322                 mContext.sendBroadcast(statusIntent);
323             }
其中if分支是发送Intent.ACTION_BATTERY_LOW,else分析负责发送Intent.ACTION_BATTERY_OKAY);
if 分支只要满足上面两个条件就回发送,而else什么时候发送呢?
根据代码可以这么理解:当发送Intent.ACTION_BATTERY_LOW时,会把mSentLowBatteryBroadcast 置为true,
同时mBatteryLevel 会小于15;由于电池更新较快,也就是此update函数较频繁,可以推断 mLastBatteryLevel 将会略大约else分支用到mBatteryLevel 的值(可能为16),是否会满足else分支的 mLastBatteryLevel >= mLowBatteryCloseWarningLevel条件呢?
此时就需要我们来查看mLowBatteryCloseWarningLevel的值具体是多少,定义方式与mLowBatteryWarningLevel类似,如下
129         mLowBatteryCloseWarningLevel = mContext.getResources().getInteger(
130                 com.android.internal.R.integer.config_lowBatteryCloseWarningLevel);
也是通过config.xml读取到的
文件位于frameworks/base/core/res/res/values/config.xml
264     <!-- Close low battery warning when battery level reaches this value -->
265     <integer name="config_lowBatteryCloseWarningLevel">20</integer>
 
按照如上分析,貌似else分析永远都不会执行,也就是Intent.ACTION_BATTERY_OKAY不会发出
但其实有一种情况会执行的,当电池电量小于mLowBatteryWarningLevel,并且已经成功发送了 Intent.ACTION_BATTERY_LOW信息,此时用户插上USB或充电器充电,当电池电量达到 mLowBatteryCloseWarningLevel,此时才会发送Intent.ACTION_BATTERY_OKAY信息
 
 

2、接收:Intent.ACTION_BATTERY_LOW && Intent.ACTION_BATTERY_OKAY)

1)StatusBarPolicy.java

frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java

这个类在2.3之前的版本中放在frameworks/base/services/java/com/android/server/status/目录下,现在做了代码归整

首先需要注册

671         IntentFilter filter = new IntentFilter();

672
673         // Register for Intent broadcasts for...
674         filter.addAction(Intent.ACTION_BATTERY_CHANGED);
675         filter.addAction(Intent.ACTION_BATTERY_LOW);
676         filter.addAction(Intent.ACTION_BATTERY_OKAY);
700         mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
 
接收部分
529         public void onReceive(Context context, Intent intent) {
530             String action = intent.getAction();
531             if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
532                 updateBattery(intent);
533             }
534             else if (action.equals(Intent.ACTION_ALARM_CHANGED)) {
535                 updateAlarm(intent);
536             }
537             else if (action.equals(Intent.ACTION_SYNC_STATE_CHANGED)) {
538                 updateSyncState(intent);
539             }
540             else if (action.equals(Intent.ACTION_BATTERY_LOW)) {
541                 onBatteryLow(intent);
542             }
543             else if (action.equals(Intent.ACTION_BATTERY_OKAY)
544                     || action.equals(Intent.ACTION_POWER_CONNECTED)) {
545                 onBatteryOkay(intent);
546             }
 
当收到Intent.ACTION_BATTERY_LOW时,做如下处理
759     private void onBatteryLow(Intent intent) {
760         if (SHOW_LOW_BATTERY_WARNING) {
761             if (false) {
762                 Slog.d(TAG, "mPhoneState=" + mPhoneState
763                       + " mLowBatteryDialog=" + mLowBatteryDialog
764                       + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall);
765             }
766
767             if (SHOW_BATTERY_WARNINGS_IN_CALL || mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
768                 showLowBatteryWarning();
769             } else {
770                 mBatteryShowLowOnEndCall = true;
771             }
772         }
773     }
其中SHOW_LOW_BATTERY_WARNING和SHOW_BATTERY_WARNINGS_IN_CALL 定义为常量 
115     private static final boolean SHOW_LOW_BATTERY_WARNING = true;
116     private static final boolean SHOW_BATTERY_WARNINGS_IN_CALL = true;
1.1) 可以看到当此时电话状态为TelephonyManager.CALL_STATE_IDLE状态时,做如下处理,否则标记mBatteryShowLowOnEndCall为true
794     private void showLowBatteryWarning() {
795         closeLastBatteryView();
796
797         // Show exact battery level.
798         CharSequence levelText = mContext.getString(
799                     R.string.battery_low_percent_format, mBatteryLevel);
800
801         if (mBatteryLevelTextView != null ) {
802             mBatteryLevelTextView.setText(levelText);
803         } else {
804             View v = View.inflate(mContext, R.layout.battery_low, null);
805             mBatteryLevelTextView=(TextView)v.findViewById(R.id.level_percent);
806
807             mBatteryLevelTextView.setText(levelText);
808
809             AlertDialog.Builder b = new AlertDialog.Builder(mContext);
810                 b.setCancelable(true);
811                 b.setTitle(R.string.battery_low_title);
812                 b.setView(v);
813                 b.setIcon(android.R.drawable.ic_dialog_alert);
814                 b.setPositiveButton(android.R.string.ok, null);
815
816                 final Intent intent = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
817                 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
818                         | Intent.FLAG_ACTIVITY_MULTIPLE_TASK
819                         | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
820                         | Intent.FLAG_ACTIVITY_NO_HISTORY);
821                 if (intent.resolveActivity(mContext.getPackageManager()) != null) {
822                     b.setNegativeButton(R.string.battery_low_why,
823                             new DialogInterface.OnClickListener() {
824                         public void onClick(DialogInterface dialog, int which) {
825                             mContext.startActivity(intent);
826                             if (mLowBatteryDialog != null) {
827                                 mLowBatteryDialog.dismiss();
828                             }
829                         }
830                     });
831                 }
832
833             AlertDialog d = b.create();
834             d.setOnDismissListener(mLowBatteryListener);
835             d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
836             d.show();
837             mLowBatteryDialog = d;
838         }
839
840         final ContentResolver cr = mContext.getContentResolver();
841         if (Settings.System.getInt(cr,
842                 Settings.System.POWER_SOUNDS_ENABLED, 1) == 1)
843         {
844             final String soundPath = Settings.System.getString(cr,
845                 Settings.System.LOW_BATTERY_SOUND);
846             if (soundPath != null) {
847                 final Uri soundUri = Uri.parse("file://" + soundPath);
848                 if (soundUri != null) {
849                     final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
850                     if (sfx != null) {
851                         sfx.setStreamType(AudioManager.STREAM_SYSTEM);
852                         sfx.play();
853                     }
854                 }
855             }
856         }
857     }
此函数主要分两部分,第一部分是根据mBatteryLevelTextView是否为null,有选择的创建并显示mLowBatteryDialog,为什么不始终创建呢?
这时候需要看一下mLowBatteryListener
881     private DialogInterface.OnDismissListener mLowBatteryListener
882             = new DialogInterface.OnDismissListener() {
883         public void onDismiss(DialogInterface dialog) {
884             mLowBatteryDialog = null;
885             mBatteryLevelTextView = null;
886         }
887     };
可以看出,如果mLowBatteryDialog已经被Dismiss掉,则选择创建mLowBatteryDialog,如果没有Dismiss,为了节省资源,只需要更新mLowBatteryDialog中的界面就可以了。
 
第二部分则是低电提示音,在网上看帖子,这个功能令很多人恼火啊,特别是学生深受其害,那么是否让用户有选择的打开此功能呢?
实现这部分功能需要两步
POWER_SOUNDS_ENABLED
841         if (Settings.System.getInt(cr,
842                 Settings.System.POWER_SOUNDS_ENABLED, 1) == 1)
我们知道Settings.System.POWER_SOUNDS_ENABLED是一个系统属性,通过在源码中并没有查找到有用此属性的地方
Settings.System.LOW_BATTERY_SOUND
844             final String soundPath = Settings.System.getString(cr,
845                 Settings.System.LOW_BATTERY_SOUND);
846             if (soundPath != null) {
 
定义在文件Settings.java
1656         /**
1657          * Whether to play a sound for low-battery alerts.
1658          * @hide
1659          */
1660         public static final String POWER_SOUNDS_ENABLED = "power_sounds_enabled";
1674         /**
1675          * URI for the low battery sound file.
1676          * @hide
1677          */
1678         public static final String LOW_BATTERY_SOUND = "low_battery_sound";
通过如下方式读取默认值
1081     private void loadUISoundEffectsSettings(SQLiteStatement stmt) {
1082         loadIntegerSetting(stmt, Settings.System.POWER_SOUNDS_ENABLED,
1083             R.integer.def_power_sounds_enabled);
1084         loadStringSetting(stmt, Settings.System.LOW_BATTERY_SOUND,
1085             R.string.def_low_battery_sound);
 
1098         loadIntegerSetting(stmt, Settings.System.LOCKSCREEN_SOUNDS_ENABLED,
1099             R.integer.def_lockscreen_sounds_enabled);
1100         loadStringSetting(stmt, Settings.System.LOCK_SOUND,
1101             R.string.def_lock_sound);
1102         loadStringSetting(stmt, Settings.System.UNLOCK_SOUND,
1103             R.string.def_unlock_sound);
上面包括是否开启解锁屏声音,默认值定义在如下文件中
61     <!-- user interface sound effects -->
62     <integer name="def_power_sounds_enabled">1</integer>
63     <string name="def_low_battery_sound" translatable="false">/system/media/audio/ui/LowBattery.ogg</string>
64     <integer name="def_dock_sounds_enabled">0</integer>
69     <integer name="def_lockscreen_sounds_enabled">0</integer>
70     <string name="def_lock_sound" translatable="false">/system/media/audio/ui/Lock.ogg</string>
71     <string name="def_unlock_sound" translatable="false">/system/media/audio/ui/Unlock.ogg</string>
 
通过以上分析可以知道,低点提示音始终是有的,并且用户不可以定制
有了以上的分析,可以很清楚的知道,可以在Settings应用里加个可以配置低点提示音的功能
如可以在SoundSettings中多定义一个CheckboxPreference用来控制,当用户选中时,操作也很简单
final ContentResolver cr = mContext.getContentResolver();
Settings.System.putInt(cr, Settings.System.POWER_SOUNDS_ENABLED, 0);
 
1.2) 如果此时电话不为TelephonyManager.CALL_STATE_IDLE状态,而是如下两种状态
TelephonyManager. CALL_STATE_OFFHOOK
TelephonyManager. CALL_STATE_RINGING
当电话状态变更为CALL_STATE_IDLE时,会调用如下函数
859     private final void updateCallState(int state) {
860         mPhoneState = state;
861         if (false) {
862             Slog.d(TAG, "mPhoneState=" + mPhoneState
863                     + " mLowBatteryDialog=" + mLowBatteryDialog
864                     + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall);
865         }
866         if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
867             if (mBatteryShowLowOnEndCall) {
868                 if (!mBatteryPlugged) {
869                     showLowBatteryWarning();
870                 }
871                 mBatteryShowLowOnEndCall = false;
872             }
873         } else {
874             if (mLowBatteryDialog != null) {
875                 mLowBatteryDialog.dismiss();
876                 mBatteryShowLowOnEndCall = true;
877             }
878         }
879     }
由于mBatteryShowLowOnEndCall已经被置为true,如果此时没有在充电状态,则也会调到showLowBatteryWarning,与以上的处理方式一样。
 
 
以上知识处理了Intent.ACTION_BATTERY_LOW,下面简单看一下如何处理Intent.ACTION_BATTERY_OKAY
775     private void onBatteryOkay(Intent intent) {
776         if (mLowBatteryDialog != null
777                 && SHOW_LOW_BATTERY_WARNING) {
778              mLowBatteryDialog .dismiss();
779             mBatteryShowLowOnEndCall = false;
780         }
781     }
从以上代码中可以看出只是把mLowBatteryDialog给Dismiss掉,并把mBatteryShowLowOnEndCall 复位
 
 

1)Phone应用

还有Phone应用也会接收Intent.ACTION_BATTERY_LOW消息,但是跟下去,看懂了代码实现者的意图,如果在通话中,电池电量较低时,会给用户一个提示,但是最终并没有真正的实现这一功能。

首先PhoneApp中注册监听Intent.ACTION_BATTERY_LOW

packages/apps/Phone / src / com / android / phone /PhoneApp.java

499             intentFilter.addAction(Intent.ACTION_BATTERY_LOW);
 
1440             } else if (action.equals(Intent.ACTION_BATTERY_LOW)) {
1441                 if (VDBG) Log.d(LOG_TAG, "mReceiver: ACTION_BATTERY_LOW");
1442                 notifier.sendBatteryLow();  // Play a warning tone if in-call
通过CallNotifier来处理信息
packages/apps/Phone / src / com / android / phone / CallNotifier.java
1222     /**
1223      * Posts a PHONE_BATTERY_LOW event, causing us to play a warning
1224      * tone if the user is in-call.
1225      */
1226     /* package */ void sendBatteryLow() {
1227         Message message = Message.obtain(this, PHONE_BATTERY_LOW);
1228         sendMessage(message);
1229     }
通过Handler来处理PHONE_BATTERY_LOW信息
266             case PHONE_BATTERY_LOW:
267                 onBatteryLow();
268                 break;

 

1231     private void onBatteryLow() {
1232         if (DBG) log("onBatteryLow()...");
1234         // A "low battery" warning tone is now played by
1235         // StatusBarPolicy.updateBattery().
1236     }
从以上代码可以看出,Phone中并没有实现此功能,说是通过StatusBarPolicy.updateBattery()来实现
而StatusBarPolicy中的代码非常简单,根本就没有实现此功能

 

 

 PS:

 其实在BatteryService函数update中还会发送如下信息,如果有哪位同学想要研究的话,可以接着研究

1)Intent.ACTION_POWER_CONNECTED

2)Intent.ACTION_POWER_DISCONNECTED

301             // Separate broadcast is sent for power connected / not connected
302             // since the standard intent will not wake any applications and some
303             // applications may want to have smart behavior based on this.
304             Intent statusIntent = new Intent();
305             statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
306             if (mPlugType != 0 && mLastPlugType == 0) {
307                 statusIntent.setAction(Intent.ACTION_POWER_CONNECTED);
308                 mContext.sendBroadcast(statusIntent);
309             }
310             else if (mPlugType == 0 && mLastPlugType != 0) {
311                 statusIntent.setAction(Intent.ACTION_POWER_DISCONNECTED);
312                 mContext.sendBroadcast(statusIntent);
313             }
分享到:
评论

相关推荐

    安卓借中低阶微处理器嵌入“嵌入式”.pdf

    对于不需要复杂用户界面和高级功能的嵌入式系统,采用中低阶微处理器结合优化的操作系统(如Linux或精简版Android)可以实现既经济又实用的解决方案。这样的策略不仅节省成本,而且有助于维持系统的长期可持续性和...

    研究论文-核电厂退役中低放废物量估算方法研究.pdf

    在设计和运行阶段研究和估算退役阶段可能产生的中低放废物总量,可以尽早规划中低放废物的处置场,评估运行阶段所筹集的退役中低放废物的处置费的充足性。文中介绍了利用类比法和统计法计算核电厂退役中低放废物的...

    芯片设计中低功耗设计方法(完整57页PPT)

    内容: 1、CMOS电路的功耗来源 2、影响功耗的因素 3、低功耗设计方法 4、工艺级的优化技术 5、版图和晶体管级的优化技术 6、RTL级和逻辑级的优化技术 7、系统级的优化技术 8、采用HDL的低功耗设计流程

    电信设备-Y信道中低复杂度的干扰消除方法.zip

    "Y信道中低复杂度的干扰消除方法"这一主题涉及到的是如何在特定的信道环境下,通过有效的算法和技术手段降低信号间的相互干扰,从而优化通信性能。下面我们将深入探讨这一话题。 首先,我们需要理解Y信道的概念。在...

    中低轨卫星多普勒数据处理技术研究.pdf

    中低轨卫星多普勒数据处理技术研究 中低轨卫星多普勒数据处理技术研究是指对中低轨卫星多普勒数据进行处理和分析的技术研究,以提高数据的精度和可靠性。这项技术研究的主要目的是为了满足高精度定轨定位的需求。 ...

    煤气中低浓度CO2的收集方法研究

    随着经济的发展,温室气体特别是CO2减排成为各国关注的焦点,而我国煤气之中的CO2的排放量高于世界前列,深入研究...本文分别从燃烧后收集、富氧燃烧以及燃烧前收集等层面对煤气中低浓度CO2的常见收集方法进行总结分析。

    大规模分布式系统中低通信阈值监控方法.pdf

    CEM方法的核心思想是将多个被监控对象视为一个整体进行处理,而不是独立地对待每个对象。通过分析和利用对象间的相对关系,该方法能够更有效地降低通信开销。具体实现上,CEM方法从所有未超过阈值的对象中选出一个...

    基于android字典的查询已修复网上低版本bug

    本项目针对的是一个基于Android开发的字典应用,它已经修复了之前在线上环境中低版本Android系统上出现的闪退问题,这意味着该应用现在具有更广泛的兼容性和稳定性,不仅能在最新的Android版本上运行,也能在较旧的...

    电量传感器选型手册-安科瑞 华楠

    电磁式适用于中低电压测量,电容分压式则适用于高压测量,具有高隔离度和低损耗特性。 3. 功率传感器:如热电偶、热电阻、光电二极管等,用于测量电路的功率消耗。 4. 频率传感器:主要用于检测电网频率,确保电力...

    关于电子功用-依托常规轧制模型控制中低牌号电工钢轧制的方法的说明分析.rar

    标题中的“关于电子功用-依托常规轧制模型控制中低牌号电工钢轧制的方法的说明分析”揭示了本文档的核心内容,它涉及到的是在电子功能材料领域中,特别是电工钢这一关键材料的生产过程中,如何利用常规的轧制模型...

    贵州中低品位铝土矿综合利用分析

    认为贵州铝土矿资源丰富,但属于高铝高硅型,且铝硅比较低,除了少数可以用拜耳法来生产氧化铝外,大部分铝土矿属于中低品位铝土矿,在生产氧化铝方面往往采用联合法来处理。对于中低品位铝土矿,除了用于生产氧化铝外,在...

    电子政务-中低聚合度蓄电池隔板专用聚氯乙烯树脂的生产方法.zip

    在这个特定的案例中,我们关注的是一个与电子政务相关的技术应用——中低聚合度蓄电池隔板专用聚氯乙烯树脂的生产方法。聚氯乙烯(PVC)树脂是电池制造中的关键材料,尤其是在蓄电池隔板的制作中。本文将深入探讨这...

    一种带导流板的中低倍复合消防泡沫炮的制作方法.docx

    本文介绍的是一种带导流板的中低倍复合消防泡沫炮的创新制作方法,该方法旨在解决传统消防泡沫炮在射程和灭火效率之间的平衡问题。泡沫炮在消防领域广泛应用,根据发泡倍率分为低倍、中倍和高倍。低倍泡沫炮射程远,...

    动态无线传感网中低延迟高可靠的数据查询机制.pdf

    同时,可以采用兴趣区域管理(Interest Region Management, IRM)策略,只唤醒和处理与当前查询相关的部分节点,减少不必要的通信开销。 另外,能量效率也是动态无线传感网设计时需要考虑的重要因素。为了延长网络...

    中低比转速离心泵叶轮多目标优化设计.zip

    为提高泵效率、减小汽蚀余量、消除扬程曲线驼峰,本文论述了以中低比转速泵的能量损失最小,汽蚀余量最小及消除扬程曲线驼峰为多目标函数,以叶轮主要参数为设计变量的泵叶轮优化设计方法。通过优化,获得了满足一定...

    论文研究-大规模分布式系统中低通信阈值监控方法.pdf

    面向可用性的对等网络数据分发方法,针对热点数据和节点可用性的分析,通过增加系统中数据的副本数量,提高数据的可用性,同时减小消息扩散的范围,提高系统的效率,克服会话时间异构性。实验结果表明,该方法可以...

    行业资料-电子功用-共存体系中低浓度17β雌二醇的选择性光电催化去除方法的说明分析.rar

    电子功用-共存体系中低浓度17β雌二醇的选择性光电催化去除方法的说明分析”表明,这是一个关于环境科学或化学工程领域的文档,特别是涉及了17β雌二醇(一种常见的环境内分泌干扰物)在水体中的处理技术。...

    中低收入国家私营和公共卫生系统可及性与医疗质量比较.pdf

    中低收入国家私营和公共卫生系统可及性与医疗质量比较 随着我国医药卫生体制改革的推进,如何提高医疗服务的可及性和质量成为关注的焦点。中低收入国家的私营和公共卫生系统在医疗服务可及性和质量方面存在着明显的...

Global site tag (gtag.js) - Google Analytics