Android5.1 电池充电剩余时间计算android5.1手机在充电的时候,并且在锁屏界面的时候会显示还剩多少时间电池充满电。
我们就这个机制进行下深入分析:首先对电池的变化都会监听BatteryService发出的Intent.ACTION_BATTERY_CHANGED广播,因此在framework目录下全局搜索,结果发现在./base/packages/Keyguard/src/com/Android/keyguard/KeyguardUpdateMonitor.Java这个目录下,也就是keyguard中有对这个广播的监控在KeyguardUpdateMonitor.java这个文件中[java] view plain copyprivate final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {public void onReceive(Context context, Intent intent) {final String action = intent.getAction();if (DEBUG) Log.d(TAG, "received broadcast " + action);if (Intent.ACTION_TIME_TICK.equals(action)|| Intent.ACTION_TIME_CHANGED.equals(action)|| Intent.ACTION_TIMEZONE_CHANGED.equals(action)) {mHandler.sendEmptyMessage(MSG_TIME_UPDA TE);} else if (Intent.ACTION_BA TTERY_CHANGED.equals(action)) {//监听电池变化的广播final int status = intent.getIntExtra(EXTRA_STA TUS, BA TTERY_STATUS_UNKNOWN);final int plugged = intent.getIntExtra(EXTRA_PLUGGED, 0);final int level = intent.getIntExtra(EXTRA_LEVEL, 0);final int health = intent.getIntExtra(EXTRA_HEALTH, BA TTERY_HEALTH_UNKNOWN);final Message msg = mHandler.obtainMessage(MSG_BA TTERY_UPDATE, new BatteryStatus(status, level, plugged, health));mHandler.sendMessage(msg);//发消息}接下来我们搜索下MSG_BATTERY_UPDATE这个消息,[java] view plain copyprivate void handleBatteryUpdate(BatteryStatus status) {if (DEBUG) Log.d(TAG, "handleBatteryUpdate");final boolean batteryUpdateInteresting = isBatteryUpdateInteresting(mBatteryStatus, status);mBatteryStatus = status;if (batteryUpdateInteresting) {for (int i = 0; i < mCallbacks.size(); i++) {KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();if (cb != null) {cb.onRefreshBatteryInfo(status);//接下来我们就搜一下谁定义了onRefreshBatteryInfo这个接口}}}}结果在KeyguardIndicationController.java这个文件中[java] view plain copyKeyguardUpdateMonitorCallback mUpdateMonitor = new KeyguardUpdateMonitorCallback() { @Overridepublic void onRefreshBatteryInfo(KeyguardUpdateMonitor.BatteryStatus status) { boolean isChargingOrFull = status.status == BatteryManager.BATTERY_STA TUS_CHARGING|| status.status == BatteryManager.BA TTERY_STATUS_FULL;mPowerPluggedIn = status.isPluggedIn() && isChargingOrFull;mPowerCharged = status.isCharged();updateIndication();}};接下来看下updateIndication[java] view plain copyprivate void updateIndication() {if (mVisible) {mTextView.switchIndication(computeIndication());}}接下来就是看下如何计算电池剩余时间的[java] view plain copyprivate String computeIndication() {if (!TextUtils.isEmpty(mTransientIndication)) {return mTransientIndication;}if (mPowerPluggedIn) {//当在充电时return computePowerIndication();}return mRestingIndication;}private String computePowerIndication() {if (mPowerCharged) {return mContext.getResources().getString(R.string.keyguard_charged);}// Try fetching charging time from battery stats.try {//剩余时间通过BatteryStatsService获取long chargingTimeRemaining = puteChargeTimeRemaining();if (chargingTimeRemaining > 0) {String chargingTimeFormatted = Formatter.formatShortElapsedTimeRoundingUpToMinutes(mContext, chargingTimeRemaining);return mContext.getResources().getString(R.string.keyguard_indication_charging_time, chargingTimeFormatted);}} catch (RemoteException e) {Log.e(TAG, "Error calling IBatteryStats: ", e);}// Fall back to simple charging label.return mContext.getResources().getString(R.string.keyguard_plugged_in);}下面是mBatteryInfo的赋值[java] view plain copymBatteryInfo = IBatteryStats.Stub.asInterface(ServiceManager.getService(BatteryStats.SERVICE_NAME));然后看BatteryStatsService中的computeChargeTimeRemaining代码[java] view plain copypublic long computeChargeTimeRemaining() {synchronized (mStats) {long time = puteChargeTimeRemaining(SystemClock.elapsedRealtime());return time >= 0 ? (time/1000) : time;}}其中mStats是在BatteryStatsService构造的时候新建的:[java] view plain copyBatteryStatsService(File systemDir, Handler handler) {mStats = new BatteryStatsImpl(systemDir, handler);}最后我们就来分析下BatteryStatsImpl中的computeChargeTimeRemaining函数:[java] view plain copy@Overridepublic long computeChargeTimeRemaining(long curTime) {if (mOnBattery) {//当处于用电池的状态直接退出// Not yet working.Slog.e(TAG, "mOnBattery");return -1;}/* Brokenint curLevel = mCurrentBatteryLevel;int plugLevel = mDischargePlugLevel;if (plugLevel < 0 || curLevel < (plugLevel+1)) {return -1;}long duration = computeBatteryRealtime(curTime, STATS_SINCE_UNPLUGGED);if (duration < 1000*1000) {return -1;}long usPerLevel = duration/(curLevel-plugLevel);return usPerLevel * (100-curLevel);*/if (mNumChargeStepDurations < 1) {Slog.e(TAG, "mNumChargeStepDurations");return -1;}//mChargeStepDurations是一个数组,保存着每一个level对应的时间,而mNumChargeStepDurations是现在总的一个levellong msPerLevel = computeTimePerLevel(mChargeStepDurations, mNumChargeStepDurations);if (msPerLevel <= 0) {Slog.e(TAG, "msPerLevel");return -1;}Slog.e(TAG, "return time remianing" + (msPerLevel * (100-mCurrentBatteryLevel)) * 1000);return (msPerLevel * (100-mCurrentBatteryLevel)) * 1000;//因此msperlevel代表每一个level需要多少时间,100-mCurrentBatteryLevel代表需要充电的电量}再来看看[java] view plain copyprivate long computeTimePerLevel(long[] steps, int numSteps) {// For now we'll do a simple average across all steps.if (numSteps <= 0) {return -1;}long total = 0;for (int i=0; i<numSteps; i++) {total += steps[i] & STEP_LEVEL_TIME_MASK;//高位保存的别的信息,需要将它去除}return total / numSteps;//所有的level的时间和除以总的level,就是每个level的平均时间但是现在的关键mChargeStepDurations,和mNumChargeStepDurations这两个成员变量如何获得。