summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHector Tellez <htellez@google.com>2016-03-04 19:56:20 -0800
committerHector Tellez <htellez@google.com>2016-03-09 17:07:51 -0800
commite952089725398c8fa8b617ca7bdde840a38849fd (patch)
tree99028f4322d29b98ebc4dd40962484f4b98d2d7d
parent61a8a07e6770a403ebdb2d55dffcb33409573357 (diff)
downloadloganalysis-e952089725398c8fa8b617ca7bdde840a38849fd.tar.gz
Adds projected battery life analysis.
Change-Id: I25bcb84f5d62802dcb51d9a3ceae60929eb89606
-rw-r--r--src/com/android/loganalysis/item/BatteryDischargeStatsInfoItem.java119
-rw-r--r--src/com/android/loganalysis/item/DumpsysBatteryStatsItem.java19
-rw-r--r--src/com/android/loganalysis/parser/BatteryDischargeStatsInfoParser.java112
-rw-r--r--src/com/android/loganalysis/parser/DumpsysBatteryStatsParser.java16
-rw-r--r--tests/src/com/android/loganalysis/parser/BatteryDischargeStatsInfoParserTest.java166
5 files changed, 429 insertions, 3 deletions
diff --git a/src/com/android/loganalysis/item/BatteryDischargeStatsInfoItem.java b/src/com/android/loganalysis/item/BatteryDischargeStatsInfoItem.java
new file mode 100644
index 0000000..8c15b92
--- /dev/null
+++ b/src/com/android/loganalysis/item/BatteryDischargeStatsInfoItem.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.loganalysis.item;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * An {@link IItem} used to store information of the battery discharge.
+ */
+public class BatteryDischargeStatsInfoItem extends GenericItem {
+
+ /** Constant for JSON output */
+ public static final String MAX_PERCENTAGE = "MAX_PERCENTAGE";
+ /** Constant for JSON output */
+ public static final String MIN_PERCENTAGE = "MIN_PERCENTAGE";
+ /** Constant for JSON output */
+ public static final String DISCHARGE_PERCENTAGE = "DISCHARGE_PERCENTAGE";
+ /** Constant for JSON output */
+ public static final String DISCHARGE_DURATION = "DISCHARGE_DURATION";
+ /** Constant for JSON output */
+ public static final String PROJECTED_BATTERY_LIFE = "PROJECTED_BATTERY_LIFE";
+
+ private static final Set<String> ATTRIBUTES = new HashSet<>(Arrays.asList(MAX_PERCENTAGE,
+ MIN_PERCENTAGE, DISCHARGE_PERCENTAGE, DISCHARGE_DURATION, PROJECTED_BATTERY_LIFE));
+
+ /**
+ * The constructor for {@link BatteryDischargeStatsInfoItem}.
+ */
+ public BatteryDischargeStatsInfoItem() {
+ super(ATTRIBUTES);
+ }
+
+ /**
+ * Set the maximum percentage.
+ */
+ public void setMaxPercentage(int percentage) {
+ setAttribute(MAX_PERCENTAGE, percentage);
+ }
+
+ /**
+ * Set the minimum percentage.
+ */
+ public void setMinPercentage(int percentage) {
+ setAttribute(MIN_PERCENTAGE, percentage);
+ }
+
+ /**
+ * Set the discharge percentage.
+ */
+ public void setDischargePercentage(int dischargePercentage) {
+ setAttribute(DISCHARGE_PERCENTAGE, dischargePercentage);
+ }
+
+ /**
+ * Set the discharge duration.
+ */
+ public void setDischargeDuration(long dischargeDuration) {
+ setAttribute(DISCHARGE_DURATION, dischargeDuration);
+ }
+
+ /**
+ * Set the projected battery life.
+ */
+ public void setProjectedBatteryLife(long projectedBatteryLife) {
+ setAttribute(PROJECTED_BATTERY_LIFE, projectedBatteryLife);
+ }
+
+ /**
+ * Get the maximum percentage.
+ */
+ public int getMaxPercentage() {
+ return (int) getAttribute(MAX_PERCENTAGE);
+ }
+
+ /**
+ * Get the minimum percentage.
+ */
+ public int getMinPercentage() {
+ return (int) getAttribute(MIN_PERCENTAGE);
+ }
+
+ /**
+ * Get the discharge percentage.
+ */
+ public int getDischargePercentage() {
+ return (int) getAttribute(DISCHARGE_PERCENTAGE);
+ }
+
+ /**
+ * Get the discharge duration.
+ */
+ public long getDischargeDuration() {
+ return (long) getAttribute(DISCHARGE_DURATION);
+ }
+
+ /**
+ * Get the projected battery life.
+ */
+ public long getProjectedBatteryLife() {
+ return (long) getAttribute(PROJECTED_BATTERY_LIFE);
+ }
+
+}
diff --git a/src/com/android/loganalysis/item/DumpsysBatteryStatsItem.java b/src/com/android/loganalysis/item/DumpsysBatteryStatsItem.java
index 1039324..8b7a800 100644
--- a/src/com/android/loganalysis/item/DumpsysBatteryStatsItem.java
+++ b/src/com/android/loganalysis/item/DumpsysBatteryStatsItem.java
@@ -27,9 +27,12 @@ public class DumpsysBatteryStatsItem implements IItem {
public static final String SUMMARY = "SUMMARY";
/** Constant for JSON output */
public static final String DETAILED_STATS = "DETAILED_STATS";
+ /** Constant for JSON output */
+ public static final String DISCHARGE_STATS = "DISCHARGE_STATS";
private BatteryStatsSummaryInfoItem mBatteryStatsSummaryItem;
private BatteryStatsDetailedInfoItem mDetailedBatteryStatsItem;
+ private BatteryDischargeStatsInfoItem mDischargeStatsItem;
/**
* Set the battery stats summary {@link BatteryStatsSummaryInfoItem}
@@ -46,6 +49,13 @@ public class DumpsysBatteryStatsItem implements IItem {
}
/**
+ * Set the battery steps info item {@link BatteryDischargeStatsInfoItem}
+ */
+ public void setBatteryDischargeStatsItem(BatteryDischargeStatsInfoItem item){
+ mDischargeStatsItem = item;
+ }
+
+ /**
* Get the battery stats summary {@link BatteryStatsSummaryInfoItem}
*/
public BatteryStatsSummaryInfoItem getBatteryStatsSummaryItem() {
@@ -59,6 +69,12 @@ public class DumpsysBatteryStatsItem implements IItem {
return mDetailedBatteryStatsItem;
}
+ /**
+ * Get the battery steps info item {@link BatteryDischargeStatsInfoItem}
+ */
+ public BatteryDischargeStatsInfoItem getBatteryDischargeStatsItem() {
+ return mDischargeStatsItem;
+ }
/**
* {@inheritDoc}
@@ -89,6 +105,9 @@ public class DumpsysBatteryStatsItem implements IItem {
if (mDetailedBatteryStatsItem != null) {
batteryStatsComponent.put(DETAILED_STATS, mDetailedBatteryStatsItem.toJson());
}
+ if (mDischargeStatsItem != null) {
+ batteryStatsComponent.put(DISCHARGE_STATS, mDischargeStatsItem.toJson());
+ }
} catch (JSONException e) {
// ignore
}
diff --git a/src/com/android/loganalysis/parser/BatteryDischargeStatsInfoParser.java b/src/com/android/loganalysis/parser/BatteryDischargeStatsInfoParser.java
new file mode 100644
index 0000000..00e0527
--- /dev/null
+++ b/src/com/android/loganalysis/parser/BatteryDischargeStatsInfoParser.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.loganalysis.parser;
+
+import com.android.loganalysis.item.BatteryDischargeStatsInfoItem;
+import com.android.loganalysis.item.BatteryStatsSummaryInfoItem;
+import com.android.loganalysis.util.NumberFormattingUtil;
+
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * A {@link IParser} to parse the battery discharge section.
+ */
+public class BatteryDischargeStatsInfoParser extends AbstractSectionParser {
+
+ /**
+ * Matches; #47: +5m5s105ms to 47 (screen-on, power-save-off, device-idle-off)
+ */
+ private static Pattern DISCHARGE_STEP_PATTERN = Pattern
+ .compile("^.*: \\+((\\d+)h)?((\\d+)m)?((\\d+)s)?(\\d+)ms.* to (\\d+).*");
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return The {@link BatteryDischargeStatsInfoItem}.
+ */
+ @Override
+ public BatteryDischargeStatsInfoItem parse(List<String> lines) {
+ long totalDuration = 0;
+ long projectionDuration = 0;
+ Integer minPercent = null;
+ Integer maxPercent = null;
+ Integer minProjectionPercent = null;
+ Integer maxProjectionPercent = null;
+
+ for (String line : lines) {
+ Matcher m = DISCHARGE_STEP_PATTERN.matcher(line);
+
+ if (m.matches()) {
+ int percent = Integer.parseInt(m.group(8));
+
+ if (minPercent == null || percent < minPercent) {
+ minPercent = percent;
+ }
+
+ if (maxPercent == null || maxPercent < percent) {
+ maxPercent = percent;
+ }
+
+ long duration = NumberFormattingUtil.getMs(
+ NumberFormattingUtil.parseIntOrZero(m.group(2)),
+ NumberFormattingUtil.parseIntOrZero(m.group(4)),
+ NumberFormattingUtil.parseIntOrZero(m.group(6)),
+ NumberFormattingUtil.parseIntOrZero(m.group(7)));
+
+ totalDuration += duration;
+
+ // For computing the projected battery life we drop the first 5% of the battery
+ // charge because these discharge 'slower' and are not reliable for the projection.
+ if (percent > 94) {
+ continue;
+ }
+
+ if (minProjectionPercent == null || percent < minProjectionPercent) {
+ minProjectionPercent = percent;
+ }
+
+ if (maxProjectionPercent == null || maxProjectionPercent < percent) {
+ maxProjectionPercent = percent;
+ }
+
+ projectionDuration += duration;
+ }
+ }
+
+ if (minPercent == null) {
+ return null;
+ }
+
+ int dischargePercent = maxPercent - minPercent + 1;
+
+ BatteryDischargeStatsInfoItem item = new BatteryDischargeStatsInfoItem();
+ item.setDischargeDuration(totalDuration);
+ item.setDischargePercentage(dischargePercent);
+ item.setMaxPercentage(maxPercent);
+ item.setMinPercentage(minPercent);
+
+ if (minProjectionPercent == null) {
+ return item;
+ }
+
+ int projectionDischargePercent = maxProjectionPercent - minProjectionPercent + 1;
+ item.setProjectedBatteryLife((projectionDuration * 100) / projectionDischargePercent);
+ return item;
+ }
+}
diff --git a/src/com/android/loganalysis/parser/DumpsysBatteryStatsParser.java b/src/com/android/loganalysis/parser/DumpsysBatteryStatsParser.java
index 8a995e8..a93c892 100644
--- a/src/com/android/loganalysis/parser/DumpsysBatteryStatsParser.java
+++ b/src/com/android/loganalysis/parser/DumpsysBatteryStatsParser.java
@@ -16,6 +16,7 @@
package com.android.loganalysis.parser;
+import com.android.loganalysis.item.BatteryDischargeStatsInfoItem;
import com.android.loganalysis.item.BatteryStatsDetailedInfoItem;
import com.android.loganalysis.item.DumpsysBatteryStatsItem;
import com.android.loganalysis.item.BatteryStatsSummaryInfoItem;
@@ -31,11 +32,17 @@ public class DumpsysBatteryStatsParser extends AbstractSectionParser {
private static final String SUMMARY_INFO_SECTION_REGEX =
"Battery History \\(\\d+% used, \\d+(KB)? used of \\d+KB, \\d+ strings using "
+ "\\d+(KB)?\\):$";
+ private static final String DISCHARGE_STATS_INFO_SECTION_REGEX = "^Discharge step durations:$";
private static final String DETAILED_INFO_SECTION_REGEX = "^Statistics since last charge:$";
- private static final String NOOP_SECTION_REGEX = "^Statistics since last unplugged:$";
+
+ // We are not using this sections and will be ignored.
+ private static final String NOOP_SECTION_REGEX =
+ "^(Statistics since last unplugged:|Daily stats:)$";
private BatteryStatsSummaryInfoParser mSummaryParser = new BatteryStatsSummaryInfoParser();
private BatteryStatsDetailedInfoParser mDetailedParser = new BatteryStatsDetailedInfoParser();
+ private BatteryDischargeStatsInfoParser mDischargeStepsParser = new
+ BatteryDischargeStatsInfoParser();
private DumpsysBatteryStatsItem mDumpsysBatteryStatsItem = null;
private boolean mParsedInput = false;
@@ -64,6 +71,7 @@ public class DumpsysBatteryStatsParser extends AbstractSectionParser {
protected void setup() {
addSectionParser(mSummaryParser, SUMMARY_INFO_SECTION_REGEX);
addSectionParser(mDetailedParser, DETAILED_INFO_SECTION_REGEX);
+ addSectionParser(mDischargeStepsParser, DISCHARGE_STATS_INFO_SECTION_REGEX);
addSectionParser(new NoopParser(), NOOP_SECTION_REGEX);
}
@@ -82,9 +90,11 @@ public class DumpsysBatteryStatsParser extends AbstractSectionParser {
if (mDumpsysBatteryStatsItem != null) {
mDumpsysBatteryStatsItem.setBatteryStatsSummarytem(
- (BatteryStatsSummaryInfoItem) getSection(mSummaryParser));
+ (BatteryStatsSummaryInfoItem) getSection(mSummaryParser));
mDumpsysBatteryStatsItem.setDetailedBatteryStatsItem(
- (BatteryStatsDetailedInfoItem) getSection(mDetailedParser));
+ (BatteryStatsDetailedInfoItem) getSection(mDetailedParser));
+ mDumpsysBatteryStatsItem.setBatteryDischargeStatsItem(
+ (BatteryDischargeStatsInfoItem) getSection(mDischargeStepsParser));
}
}
}
diff --git a/tests/src/com/android/loganalysis/parser/BatteryDischargeStatsInfoParserTest.java b/tests/src/com/android/loganalysis/parser/BatteryDischargeStatsInfoParserTest.java
new file mode 100644
index 0000000..983e3aa
--- /dev/null
+++ b/tests/src/com/android/loganalysis/parser/BatteryDischargeStatsInfoParserTest.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.loganalysis.parser;
+
+import com.android.loganalysis.item.BatteryDischargeStatsInfoItem;
+
+import junit.framework.TestCase;
+
+import org.json.JSONException;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Unit tests for {@link BatteryDischargeStatsInfoParser}
+ */
+public class BatteryDischargeStatsInfoParserTest extends TestCase {
+
+ /**
+ * Test that normal input is parsed correctly.
+ */
+ public void testBatteryDischargeStats() {
+ List<String> input = Arrays.asList(
+ " #0: +4m53s738ms to 0 (screen-on, power-save-off, device-idle-off)",
+ " #1: +4m5s586ms to 1 (screen-on, power-save-off, device-idle-off)",
+ " #2: +3m0s157ms to 2 (screen-on, power-save-off, device-idle-off)",
+ " #3: +2m52s243ms to 3 (screen-on, power-save-off, device-idle-off)",
+ " #4: +2m27s599ms to 4 (screen-on, power-save-off, device-idle-off)",
+ " #5: +5m0s172ms to 5 (screen-on, power-save-off, device-idle-off)",
+ " #6: +2m21s664ms to 6 (screen-on, power-save-off, device-idle-off)",
+ " #7: +5m18s811ms to 7 (screen-on, power-save-off, device-idle-off)",
+ " #8: +3m35s622ms to 8 (screen-on, power-save-off, device-idle-off)",
+ " #9: +4m52s605ms to 9 (screen-on, power-save-off, device-idle-off)",
+ " #10: +4m46s779ms to 10 (screen-on, power-save-off, device-idle-off)",
+ " #11: +4m0s200ms to 11 (screen-on, power-save-off, device-idle-off)",
+ " #12: +4m44s941ms to 12 (screen-on, power-save-off, device-idle-off)",
+ " #13: +3m31s163ms to 13 (screen-on, power-save-off, device-idle-off)",
+ " #14: +4m17s293ms to 14 (screen-on, power-save-off, device-idle-off)",
+ " #15: +3m11s584ms to 15 (screen-on, power-save-off, device-idle-off)",
+ " #16: +5m52s923ms to 16 (screen-on, power-save-off, device-idle-off)",
+ " #17: +3m7s34ms to 17 (screen-on, power-save-off, device-idle-off)",
+ " #18: +5m59s810ms to 18 (screen-on, power-save-off, device-idle-off)",
+ " #19: +6m15s275ms to 19 (screen-on, power-save-off, device-idle-off)",
+ " #20: +4m0s55ms to 20 (screen-on, power-save-off, device-idle-off)",
+ " #21: +5m21s911ms to 21 (screen-on, power-save-off, device-idle-off)",
+ " #22: +4m0s171ms to 22 (screen-on, power-save-off, device-idle-off)",
+ " #23: +5m22s820ms to 23 (screen-on, power-save-off, device-idle-off)",
+ " #24: +3m44s752ms to 24 (screen-on, power-save-off, device-idle-off)",
+ " #25: +4m15s130ms to 25 (screen-on, power-save-off, device-idle-off)",
+ " #26: +3m48s654ms to 26 (screen-on, power-save-off, device-idle-off)",
+ " #27: +5m0s294ms to 27 (screen-on, power-save-off, device-idle-off)",
+ " #28: +3m11s169ms to 28 (screen-on, power-save-off, device-idle-off)",
+ " #29: +4m48s194ms to 29 (screen-on, power-save-off, device-idle-off)",
+ " #30: +5m0s319ms to 30 (screen-on, power-save-off, device-idle-off)",
+ " #31: +2m42s209ms to 31 (screen-on, power-save-off, device-idle-off)",
+ " #32: +5m29s187ms to 32 (screen-on, power-save-off, device-idle-off)",
+ " #33: +3m32s392ms to 33 (screen-on, power-save-off, device-idle-off)",
+ " #34: +5m27s578ms to 34 (screen-on, power-save-off, device-idle-off)",
+ " #35: +3m47s37ms to 35 (screen-on, power-save-off, device-idle-off)",
+ " #36: +5m18s916ms to 36 (screen-on, power-save-off, device-idle-off)",
+ " #37: +2m54s111ms to 37 (screen-on, power-save-off, device-idle-off)",
+ " #38: +6m32s480ms to 38 (screen-on, power-save-off, device-idle-off)",
+ " #39: +5m24s906ms to 39 (screen-on, power-save-off, device-idle-off)",
+ " #40: +3m2s451ms to 40 (screen-on, power-save-off, device-idle-off)",
+ " #41: +6m29s762ms to 41 (screen-on, power-save-off, device-idle-off)",
+ " #42: +3m31s933ms to 42 (screen-on, power-save-off, device-idle-off)",
+ " #43: +4m58s520ms to 43 (screen-on, power-save-off, device-idle-off)",
+ " #44: +4m31s130ms to 44 (screen-on, power-save-off, device-idle-off)",
+ " #45: +5m28s870ms to 45 (screen-on, power-save-off, device-idle-off)",
+ " #46: +3m54s809ms to 46 (screen-on, power-save-off, device-idle-off)",
+ " #47: +5m5s105ms to 47 (screen-on, power-save-off, device-idle-off)",
+ " #48: +3m50s427ms to 48 (screen-on, power-save-off, device-idle-off)",
+ " #49: +6m0s344ms to 49 (screen-on, power-save-off, device-idle-off)",
+ " #50: +5m2s952ms to 50 (screen-on, power-save-off, device-idle-off)",
+ " #51: +3m6s120ms to 51 (screen-on, power-save-off, device-idle-off)",
+ " #52: +5m34s839ms to 52 (screen-on, power-save-off, device-idle-off)",
+ " #53: +2m33s473ms to 53 (screen-on, power-save-off, device-idle-off)",
+ " #54: +4m51s873ms to 54 (screen-on, power-save-off, device-idle-off)",
+ " #55: +3m30s41ms to 55 (screen-on, power-save-off, device-idle-off)",
+ " #56: +4m29s879ms to 56 (screen-on, power-save-off, device-idle-off)",
+ " #57: +3m41s722ms to 57 (screen-on, power-save-off, device-idle-off)",
+ " #58: +4m29s72ms to 58 (screen-on, power-save-off, device-idle-off)",
+ " #59: +4m49s351ms to 59 (screen-on, power-save-off, device-idle-off)",
+ " #60: +3m51s605ms to 60 (screen-on, power-save-off, device-idle-off)",
+ " #61: +5m8s334ms to 61 (screen-on, power-save-off, device-idle-off)",
+ " #62: +2m53s153ms to 62 (screen-on, power-save-off, device-idle-off)",
+ " #63: +6m0s234ms to 63 (screen-on, power-save-off, device-idle-off)",
+ " #64: +3m20s345ms to 64 (screen-on, power-save-off, device-idle-off)",
+ " #65: +5m46s211ms to 65 (screen-on, power-save-off, device-idle-off)",
+ " #66: +3m40s147ms to 66 (screen-on, power-save-off, device-idle-off)",
+ " #67: +5m14s559ms to 67 (screen-on, power-save-off, device-idle-off)",
+ " #68: +4m0s183ms to 68 (screen-on, power-save-off, device-idle-off)",
+ " #69: +5m23s334ms to 69 (screen-on, power-save-off, device-idle-off)",
+ " #70: +5m45s493ms to 70 (screen-on, power-save-off, device-idle-off)",
+ " #71: +4m0s179ms to 71 (screen-on, power-save-off, device-idle-off)",
+ " #72: +5m45s462ms to 72 (screen-on, power-save-off, device-idle-off)",
+ " #73: +3m10s449ms to 73 (screen-on, power-save-off, device-idle-off)",
+ " #74: +6m29s370ms to 74 (screen-on, power-save-off, device-idle-off)",
+ " #75: +3m20s414ms to 75 (screen-on, power-save-off, device-idle-off)",
+ " #76: +5m10s462ms to 76 (screen-on, power-save-off, device-idle-off)",
+ " #77: +4m20s500ms to 77 (screen-on, power-save-off, device-idle-off)",
+ " #78: +5m39s504ms to 78 (screen-on, power-save-off, device-idle-off)",
+ " #79: +5m59s819ms to 79 (screen-on, power-save-off, device-idle-off)",
+ " #80: +3m0s126ms to 80 (screen-on, power-save-off, device-idle-off)",
+ " #81: +6m20s912ms to 81 (screen-on, power-save-off, device-idle-off)",
+ " #82: +4m0s199ms to 82 (screen-on, power-save-off, device-idle-off)",
+ " #83: +5m23s470ms to 83 (screen-on, power-save-off, device-idle-off)",
+ " #84: +3m15s368ms to 84 (screen-on, power-save-off, device-idle-off)",
+ " #85: +6m18s625ms to 85 (screen-on, power-save-off, device-idle-off)",
+ " #86: +3m41s417ms to 86 (screen-on, power-save-off, device-idle-off)",
+ " #87: +5m32s257ms to 87 (screen-on, power-save-off, device-idle-off)",
+ " #88: +4m0s212ms to 88 (screen-on, power-save-off, device-idle-off)",
+ " #89: +5m41s218ms to 89 (screen-on, power-save-off, device-idle-off)",
+ " #90: +5m46s333ms to 90 (screen-on, power-save-off, device-idle-off)",
+ " #91: +3m58s362ms to 91 (screen-on, power-save-off, device-idle-off)",
+ " #92: +5m1s593ms to 92 (screen-on, power-save-off, device-idle-off)",
+ " #93: +4m47s33ms to 93 (screen-on, power-save-off, device-idle-off)",
+ " #94: +6m0s417ms to 94 (screen-on, power-save-off, device-idle-off)",
+ " #95: +3m9s77ms to 95 (screen-on, power-save-off, device-idle-off)",
+ " #96: +7m0s308ms to 96 (screen-on, power-save-off, device-idle-off)",
+ " #97: +3m29s741ms to 97 (screen-on, power-save-off, device-idle-off)",
+ " #98: +7m12s748ms to 98 (screen-on, power-save-off, device-idle-off)",
+ " Estimated screen on time: 7h 36m 13s 0ms ");
+
+ BatteryDischargeStatsInfoItem infoItem = new BatteryDischargeStatsInfoParser().parse(input);
+ assertEquals(99, infoItem.getDischargePercentage());
+ assertEquals(27099330, infoItem.getDischargeDuration());
+ assertEquals(27207848, infoItem.getProjectedBatteryLife());
+ }
+
+ /**
+ * Test that input with only a few discharge stats.
+ */
+ public void testBatteryDischargeStatsWithTop5Percentages() throws JSONException {
+ List<String> input = Arrays.asList(
+ " #95: +3m9s77ms to 95 (screen-on, power-save-off, device-idle-off)",
+ " #96: +7m0s308ms to 96 (screen-on, power-save-off, device-idle-off)",
+ " #97: +3m29s741ms to 97 (screen-on, power-save-off, device-idle-off)",
+ " #98: +7m12s748ms to 98 (screen-on, power-save-off, device-idle-off)",
+ " Estimated screen on time: 7h 36m 13s 0ms ");
+
+ BatteryDischargeStatsInfoItem infoItem = new BatteryDischargeStatsInfoParser().parse(input);
+
+ try {
+ infoItem.getProjectedBatteryLife();
+ fail("Projected battery life is expected to be undefined when there are not enough" +
+ " samples of battery discharge below 95 percent.");
+ } catch (NullPointerException e) {
+ // NullPointerException expected.
+ }
+ }
+}