diff options
| author | 2014-04-29 11:23:16 -0700 | |
|---|---|---|
| committer | 2014-04-29 11:23:16 -0700 | |
| commit | 260c5020ae65ddd14668b8ae496c169082aa13f6 (patch) | |
| tree | e69168f593b191849c2c0ca34499349988b84558 | |
| parent | 21cc57319953e018c29876bab68a283600596ddd (diff) | |
Implement better computing of battery drain time, actual charge time.
Also move time formatter in to framework for use elsewhere.
Change-Id: I42b6a44414b68754af65c522bef5591da5643909
| -rw-r--r-- | core/java/android/text/format/Formatter.java | 65 | ||||
| -rw-r--r-- | core/java/com/android/internal/os/BatteryStatsImpl.java | 155 | ||||
| -rw-r--r-- | core/res/res/values/strings.xml | 39 | ||||
| -rw-r--r-- | core/res/res/values/symbols.xml | 11 |
4 files changed, 268 insertions, 2 deletions
diff --git a/core/java/android/text/format/Formatter.java b/core/java/android/text/format/Formatter.java index 9c98b98dedf4..b0cbcd224c87 100644 --- a/core/java/android/text/format/Formatter.java +++ b/core/java/android/text/format/Formatter.java @@ -106,4 +106,69 @@ public final class Formatter { public static String formatIpAddress(int ipv4Address) { return NetworkUtils.intToInetAddress(ipv4Address).getHostAddress(); } + + private static final int SECONDS_PER_MINUTE = 60; + private static final int SECONDS_PER_HOUR = 60 * 60; + private static final int SECONDS_PER_DAY = 24 * 60 * 60; + + /** + * Returns elapsed time for the given millis, in the following format: + * 1 day 5 hrs; will include at most two units, can go down to seconds precision. + * @param context the application context + * @param millis the elapsed time in milli seconds + * @return the formatted elapsed time + * @hide + */ + public static String formatShortElapsedTime(Context context, long millis) { + long secondsLong = millis / 1000; + + int days = 0, hours = 0, minutes = 0; + if (secondsLong >= SECONDS_PER_DAY) { + days = (int)(secondsLong / SECONDS_PER_DAY); + secondsLong -= days * SECONDS_PER_DAY; + } + if (secondsLong >= SECONDS_PER_HOUR) { + hours = (int)(secondsLong / SECONDS_PER_HOUR); + secondsLong -= hours * SECONDS_PER_HOUR; + } + if (secondsLong >= SECONDS_PER_MINUTE) { + minutes = (int)(secondsLong / SECONDS_PER_MINUTE); + secondsLong -= minutes * SECONDS_PER_MINUTE; + } + int seconds = (int)secondsLong; + + if (days >= 2) { + days += (hours+12)/24; + return context.getString(com.android.internal.R.string.durationDays, days); + } else if (days > 0) { + if (hours == 1) { + return context.getString(com.android.internal.R.string.durationDayHour, days, hours); + } + return context.getString(com.android.internal.R.string.durationDayHours, days, hours); + } else if (hours >= 2) { + hours += (minutes+30)/60; + return context.getString(com.android.internal.R.string.durationHours, hours); + } else if (hours > 0) { + if (minutes == 1) { + return context.getString(com.android.internal.R.string.durationHourMinute, hours, + minutes); + } + return context.getString(com.android.internal.R.string.durationHourMinutes, hours, + minutes); + } else if (minutes >= 2) { + minutes += (seconds+30)/60; + return context.getString(com.android.internal.R.string.durationMinutes, minutes); + } else if (minutes > 0) { + if (seconds == 1) { + return context.getString(com.android.internal.R.string.durationMinuteSecond, minutes, + seconds); + } + return context.getString(com.android.internal.R.string.durationMinuteSeconds, minutes, + seconds); + } else if (seconds == 1) { + return context.getString(com.android.internal.R.string.durationSecond, seconds); + } else { + return context.getString(com.android.internal.R.string.durationSeconds, seconds); + } + } } diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 343c507c03ea..93d2297ce2cb 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -88,7 +88,7 @@ public final class BatteryStatsImpl extends BatteryStats { private static final int MAGIC = 0xBA757475; // 'BATSTATS' // Current on-disk Parcel version - private static final int VERSION = 103 + (USE_OLD_HISTORY ? 1000 : 0); + private static final int VERSION = 104 + (USE_OLD_HISTORY ? 1000 : 0); // Maximum number of items we will record in the history. private static final int MAX_HISTORY_ITEMS = 2000; @@ -319,6 +319,18 @@ public final class BatteryStatsImpl extends BatteryStats { int mDischargeAmountScreenOff; int mDischargeAmountScreenOffSinceCharge; + static final int MAX_LEVEL_STEPS = 100; + + int mLastDischargeStepLevel; + long mLastDischargeStepTime; + int mNumDischargeStepDurations; + final long[] mDischargeStepDurations = new long[MAX_LEVEL_STEPS]; + + int mLastChargeStepLevel; + long mLastChargeStepTime; + int mNumChargeStepDurations; + final long[] mChargeStepDurations = new long[MAX_LEVEL_STEPS]; + long mLastWriteTime = 0; // Milliseconds private int mBluetoothPingCount; @@ -5721,6 +5733,10 @@ public final class BatteryStatsImpl extends BatteryStats { mDischargeAmountScreenOnSinceCharge = 0; mDischargeAmountScreenOff = 0; mDischargeAmountScreenOffSinceCharge = 0; + mLastDischargeStepTime = -1; + mNumDischargeStepDurations = 0; + mLastChargeStepTime = -1; + mNumChargeStepDurations = 0; } public void resetAllStatsCmdLocked() { @@ -5885,7 +5901,10 @@ public final class BatteryStatsImpl extends BatteryStats { resetAllStatsLocked(); mDischargeStartLevel = level; reset = true; + mNumDischargeStepDurations = 0; } + mLastDischargeStepLevel = level; + mLastDischargeStepTime = -1; pullPendingStateUpdatesLocked(); mHistoryCur.batteryLevel = (byte)level; mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG; @@ -5921,6 +5940,9 @@ public final class BatteryStatsImpl extends BatteryStats { } updateDischargeScreenLevelsLocked(mScreenOn, mScreenOn); updateTimeBasesLocked(false, !mScreenOn, uptime, realtime); + mNumChargeStepDurations = 0; + mLastChargeStepLevel = level; + mLastChargeStepTime = -1; } if (doWrite || (mLastWriteTime + (60 * 1000)) < mSecRealtime) { if (mFile != null) { @@ -5944,6 +5966,24 @@ public final class BatteryStatsImpl extends BatteryStats { // This should probably be exposed in the API, though it's not critical private static final int BATTERY_PLUGGED_NONE = 0; + private static int addLevelSteps(long[] steps, int stepCount, long lastStepTime, + int numStepLevels, long elapsedRealtime) { + if (lastStepTime >= 0 && numStepLevels > 0) { + long duration = elapsedRealtime - lastStepTime; + for (int i=0; i<numStepLevels; i++) { + System.arraycopy(steps, 0, steps, 1, steps.length-1); + long thisDuration = duration / (numStepLevels-i); + duration -= thisDuration; + steps[0] = thisDuration; + } + stepCount += numStepLevels; + if (stepCount > steps.length) { + stepCount = steps.length; + } + } + return stepCount; + } + public void setBatteryState(int status, int health, int plugType, int level, int temp, int volt) { synchronized(this) { @@ -6021,6 +6061,23 @@ public final class BatteryStatsImpl extends BatteryStats { if (changed) { addHistoryRecordLocked(elapsedRealtime, uptime); } + if (onBattery) { + if (mLastDischargeStepLevel != level) { + mNumDischargeStepDurations = addLevelSteps(mDischargeStepDurations, + mNumDischargeStepDurations, mLastDischargeStepTime, + mLastDischargeStepLevel - level, elapsedRealtime); + mLastDischargeStepLevel = level; + mLastDischargeStepTime = elapsedRealtime; + } + } else { + if (mLastChargeStepLevel != level) { + mNumChargeStepDurations = addLevelSteps(mChargeStepDurations, + mNumChargeStepDurations, mLastChargeStepTime, + level - mLastChargeStepLevel, elapsedRealtime); + mLastChargeStepLevel = level; + mLastChargeStepTime = elapsedRealtime; + } + } } if (!onBattery && status == BatteryManager.BATTERY_STATUS_FULL) { // We don't record history while we are plugged in and fully charged. @@ -6235,11 +6292,51 @@ public final class BatteryStatsImpl extends BatteryStats { return mOnBatteryScreenOffTimeBase.computeRealtime(curTime, which); } + private 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]; + } + return total / numSteps; + /* + long[] buckets = new long[numSteps]; + int numBuckets = 0; + int numToAverage = 4; + int i = 0; + while (i < numSteps) { + long totalTime = 0; + int num = 0; + for (int j=0; j<numToAverage && (i+j)<numSteps; j++) { + totalTime += steps[i+j]; + num++; + } + buckets[numBuckets] = totalTime / num; + numBuckets++; + numToAverage *= 2; + i += num; + } + if (numBuckets < 1) { + return -1; + } + long averageTime = buckets[numBuckets-1]; + for (i=numBuckets-2; i>=0; i--) { + averageTime = (averageTime + buckets[i]) / 2; + } + return averageTime; + */ + } + @Override public long computeBatteryTimeRemaining(long curTime) { if (!mOnBattery) { return -1; } + /* Simple implementation just looks at the average discharge per level across the + entire sample period. int discharge = (getLowDischargeAmountSinceCharge()+getHighDischargeAmountSinceCharge())/2; if (discharge < 2) { return -1; @@ -6250,14 +6347,24 @@ public final class BatteryStatsImpl extends BatteryStats { } long usPerLevel = duration/discharge; return usPerLevel * mCurrentBatteryLevel; + */ + if (mNumDischargeStepDurations < 1) { + return -1; + } + long msPerLevel = computeTimePerLevel(mDischargeStepDurations, mNumDischargeStepDurations); + if (msPerLevel <= 0) { + return -1; + } + return (msPerLevel * mCurrentBatteryLevel) * 1000; } @Override public long computeChargeTimeRemaining(long curTime) { - if (true || mOnBattery) { + if (mOnBattery) { // Not yet working. return -1; } + /* Broken int curLevel = mCurrentBatteryLevel; int plugLevel = mDischargePlugLevel; if (plugLevel < 0 || curLevel < (plugLevel+1)) { @@ -6269,6 +6376,15 @@ public final class BatteryStatsImpl extends BatteryStats { } long usPerLevel = duration/(curLevel-plugLevel); return usPerLevel * (100-curLevel); + */ + if (mNumChargeStepDurations < 1) { + return -1; + } + long msPerLevel = computeTimePerLevel(mChargeStepDurations, mNumChargeStepDurations); + if (msPerLevel <= 0) { + return -1; + } + return (msPerLevel * (100-mCurrentBatteryLevel)) * 1000; } long getBatteryUptimeLocked() { @@ -6776,6 +6892,10 @@ public final class BatteryStatsImpl extends BatteryStats { mHighDischargeAmountSinceCharge = in.readInt(); mDischargeAmountScreenOnSinceCharge = in.readInt(); mDischargeAmountScreenOffSinceCharge = in.readInt(); + mNumDischargeStepDurations = in.readInt(); + in.readLongArray(mDischargeStepDurations); + mNumChargeStepDurations = in.readInt(); + in.readLongArray(mChargeStepDurations); mStartCount++; @@ -7030,6 +7150,10 @@ public final class BatteryStatsImpl extends BatteryStats { out.writeInt(getHighDischargeAmountSinceCharge()); out.writeInt(getDischargeAmountScreenOnSinceCharge()); out.writeInt(getDischargeAmountScreenOffSinceCharge()); + out.writeInt(mNumDischargeStepDurations); + out.writeLongArray(mDischargeStepDurations); + out.writeInt(mNumChargeStepDurations); + out.writeLongArray(mChargeStepDurations); mScreenOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS); for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) { @@ -7344,6 +7468,10 @@ public final class BatteryStatsImpl extends BatteryStats { mDischargeAmountScreenOnSinceCharge = in.readInt(); mDischargeAmountScreenOff = in.readInt(); mDischargeAmountScreenOffSinceCharge = in.readInt(); + mNumDischargeStepDurations = in.readInt(); + in.readLongArray(mDischargeStepDurations); + mNumChargeStepDurations = in.readInt(); + in.readLongArray(mChargeStepDurations); mLastWriteTime = in.readLong(); mBluetoothPingCount = in.readInt(); @@ -7464,6 +7592,10 @@ public final class BatteryStatsImpl extends BatteryStats { out.writeInt(mDischargeAmountScreenOnSinceCharge); out.writeInt(mDischargeAmountScreenOff); out.writeInt(mDischargeAmountScreenOffSinceCharge); + out.writeInt(mNumDischargeStepDurations); + out.writeLongArray(mDischargeStepDurations); + out.writeInt(mNumChargeStepDurations); + out.writeLongArray(mChargeStepDurations); out.writeLong(mLastWriteTime); out.writeInt(getBluetoothPingCount()); @@ -7573,6 +7705,25 @@ public final class BatteryStatsImpl extends BatteryStats { pr.println("*** Bluetooth active type #" + i + ":"); mBluetoothStateTimer[i].logState(pr, " "); } + StringBuilder sb = new StringBuilder(128); + if (mNumDischargeStepDurations > 0) { + pr.println("*** Discharge step durations:"); + for (int i=0; i<mNumDischargeStepDurations; i++) { + sb.setLength(0); + sb.append(" #"); sb.append(i); sb.append(": "); + formatTimeMs(sb, mDischargeStepDurations[i]); + pr.println(sb.toString()); + } + } + if (mNumChargeStepDurations > 0) { + pr.println("*** Charge step durations:"); + for (int i=0; i<mNumChargeStepDurations; i++) { + sb.setLength(0); + sb.append(" #"); sb.append(i); sb.append(": "); + formatTimeMs(sb, mChargeStepDurations[i]); + pr.println(sb.toString()); + } + } } super.dumpLocked(context, pw, flags, reqUid, histStart); } diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index cb52db291e84..57b2c01b476a 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -36,6 +36,45 @@ the placeholders. --> <string name="fileSizeSuffix"><xliff:g id="number" example="123">%1$s</xliff:g><xliff:g id="unit" example="KB">%2$s</xliff:g></string> + <!-- [CHAR_LIMIT=10] Suffix added to signify duration in days --> + <string name="durationDays"><xliff:g id="days">%1$d</xliff:g> days</string> + + <!-- [CHAR_LIMIT=10] Suffix added to signify duration of one day with hours --> + <string name="durationDayHours"><xliff:g id="days">%1$d</xliff:g> day + <xliff:g id="hours">%2$d</xliff:g> hrs</string> + + <!-- [CHAR_LIMIT=10] Suffix added to signify duration of one day with one hours --> + <string name="durationDayHour"><xliff:g id="days">%1$d</xliff:g> day + <xliff:g id="hours">%2$d</xliff:g> hr</string> + + <!-- [CHAR_LIMIT=10] Suffix added to signify duration in hours --> + <string name="durationHours"><xliff:g id="hours">%1$d</xliff:g> hrs</string> + + <!-- [CHAR_LIMIT=10] Suffix added to signify duration of one hour with minutes --> + <string name="durationHourMinutes"><xliff:g id="hours">%1$d</xliff:g> hr + <xliff:g id="minutes">%2$d</xliff:g> mins</string> + + <!-- [CHAR_LIMIT=10] Suffix added to signify duration of one hour with one minute --> + <string name="durationHourMinute"><xliff:g id="hours">%1$d</xliff:g> hr + <xliff:g id="minutes">%2$d</xliff:g> min</string> + + <!-- [CHAR_LIMIT=10] Suffix added to signify duration in minutes --> + <string name="durationMinutes"><xliff:g id="minutes">%1$d</xliff:g> mins</string> + + <!-- [CHAR_LIMIT=10] Suffix added to signify duration of one minute with seconds --> + <string name="durationMinuteSeconds"><xliff:g id="minutes">%1$d</xliff:g> min + <xliff:g id="seconds">%2$d</xliff:g> secs</string> + + <!-- [CHAR_LIMIT=10] Suffix added to signify duration of one minute with one second --> + <string name="durationMinuteSecond"><xliff:g id="minutes">%1$d</xliff:g> min + <xliff:g id="seconds">%2$d</xliff:g> sec</string> + + <!-- [CHAR_LIMIT=10] Suffix added to signify duration in seconds --> + <string name="durationSeconds"><xliff:g id="seconds">%1$d</xliff:g> secs</string> + + <!-- [CHAR_LIMIT=10] Suffix added to signify duration of one second --> + <string name="durationSecond"><xliff:g id="seconds">%1$d</xliff:g> sec</string> + <!-- Used in Contacts for a field that has no label and in Note Pad for a note with no name. --> <string name="untitled"><Untitled></string> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 431dab83c0f3..22708109e678 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -506,6 +506,17 @@ <java-symbol type="string" name="display_manager_overlay_display_secure_suffix" /> <java-symbol type="string" name="display_manager_overlay_display_title" /> <java-symbol type="string" name="double_tap_toast" /> + <java-symbol type="string" name="durationDays" /> + <java-symbol type="string" name="durationDayHours" /> + <java-symbol type="string" name="durationDayHour" /> + <java-symbol type="string" name="durationHours" /> + <java-symbol type="string" name="durationHourMinutes" /> + <java-symbol type="string" name="durationHourMinute" /> + <java-symbol type="string" name="durationMinutes" /> + <java-symbol type="string" name="durationMinuteSeconds" /> + <java-symbol type="string" name="durationMinuteSecond" /> + <java-symbol type="string" name="durationSeconds" /> + <java-symbol type="string" name="durationSecond" /> <java-symbol type="string" name="elapsed_time_short_format_h_mm_ss" /> <java-symbol type="string" name="elapsed_time_short_format_mm_ss" /> <java-symbol type="string" name="emailTypeCustom" /> |