Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 260c5020 authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

Implement better computing of battery drain time, actual charge time.

Also move time formatter in to framework for use elsewhere.

Change-Id: I42b6a44414b68754af65c522bef5591da5643909
parent 21cc5731
Loading
Loading
Loading
Loading
+65 −0
Original line number Diff line number Diff line
@@ -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);
        }
    }
}
+153 −2
Original line number Diff line number Diff line
@@ -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);
    }
+39 −0
Original line number Diff line number Diff line
@@ -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">&lt;Untitled&gt;</string>
+11 −0
Original line number Diff line number Diff line
@@ -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" />