Simplify initialization and add setValue to support parceling

Bug: 197162116
Test: atest libbattery_test

Change-Id: I4278206eab049d714c5278e6b10ba3155e17142f
diff --git a/libs/battery/LongArrayMultiStateCounter.cpp b/libs/battery/LongArrayMultiStateCounter.cpp
index 68e0883..125cfaf 100644
--- a/libs/battery/LongArrayMultiStateCounter.cpp
+++ b/libs/battery/LongArrayMultiStateCounter.cpp
@@ -62,7 +62,7 @@
 template <>
 std::string LongArrayMultiStateCounter::valueToString(const std::vector<uint64_t>& v) const {
     std::stringstream s;
-    s << "{ ";
+    s << "{";
     bool first = true;
     for (uint64_t n : v) {
         if (!first) {
diff --git a/libs/battery/LongArrayMultiStateCounterTest.cpp b/libs/battery/LongArrayMultiStateCounterTest.cpp
index 24cb437..e4e6b2a 100644
--- a/libs/battery/LongArrayMultiStateCounterTest.cpp
+++ b/libs/battery/LongArrayMultiStateCounterTest.cpp
@@ -24,7 +24,9 @@
 class LongArrayMultiStateCounterTest : public testing::Test {};
 
 TEST_F(LongArrayMultiStateCounterTest, stateChange) {
-    LongArrayMultiStateCounter testCounter(2, 0, std::vector<uint64_t>(4), 1000);
+    LongArrayMultiStateCounter testCounter(2, std::vector<uint64_t>(4));
+    testCounter.updateValue(std::vector<uint64_t>({0, 0, 0, 0}), 1000);
+    testCounter.setState(0, 1000);
     testCounter.setState(1, 2000);
     testCounter.updateValue(std::vector<uint64_t>({100, 200, 300, 400}), 3000);
 
@@ -34,7 +36,9 @@
 }
 
 TEST_F(LongArrayMultiStateCounterTest, accumulation) {
-    LongArrayMultiStateCounter testCounter(2, 0, std::vector<uint64_t>(4), 1000);
+    LongArrayMultiStateCounter testCounter(2, std::vector<uint64_t>(4));
+    testCounter.updateValue(std::vector<uint64_t>({0, 0, 0, 0}), 1000);
+    testCounter.setState(0, 1000);
     testCounter.setState(1, 2000);
     testCounter.updateValue(std::vector<uint64_t>({100, 200, 300, 400}), 3000);
     testCounter.setState(0, 4000);
@@ -50,5 +54,16 @@
     EXPECT_EQ(std::vector<uint64_t>({70, 120, 170, 220}), testCounter.getCount(1));
 }
 
+TEST_F(LongArrayMultiStateCounterTest, toString) {
+    LongArrayMultiStateCounter testCounter(2, std::vector<uint64_t>(4));
+    testCounter.updateValue(std::vector<uint64_t>({0, 0, 0, 0}), 1000);
+    testCounter.setState(0, 1000);
+    testCounter.setState(1, 2000);
+    testCounter.updateValue(std::vector<uint64_t>({100, 200, 300, 400}), 3000);
+
+    EXPECT_STREQ("[0: {50, 100, 150, 200}, 1: {50, 100, 150, 200}] updated: 3000 currentState: 1",
+                 testCounter.toString().c_str());
+}
+
 } // namespace battery
 } // namespace android
diff --git a/libs/battery/MultiStateCounter.h b/libs/battery/MultiStateCounter.h
index 9f56b29..40de068 100644
--- a/libs/battery/MultiStateCounter.h
+++ b/libs/battery/MultiStateCounter.h
@@ -51,15 +51,18 @@
     State* states;
 
 public:
-    MultiStateCounter(uint16_t stateCount, state_t initialState, const T& emptyValue,
-                      time_t timestamp);
+    MultiStateCounter(uint16_t stateCount, const T& emptyValue);
 
     virtual ~MultiStateCounter();
 
     void setState(state_t state, time_t timestamp);
 
+    void setValue(state_t state, const T& value);
+
     void updateValue(const T& value, time_t timestamp);
 
+    uint16_t getStateCount();
+
     const T& getCount(state_t state);
 
     std::string toString();
@@ -86,14 +89,13 @@
 // Since MultiStateCounter is a template, the implementation must be inlined.
 
 template <class T>
-MultiStateCounter<T>::MultiStateCounter(uint16_t stateCount, state_t initialState,
-                                        const T& emptyValue, time_t timestamp)
+MultiStateCounter<T>::MultiStateCounter(uint16_t stateCount, const T& emptyValue)
       : stateCount(stateCount),
-        currentState(initialState),
-        lastStateChangeTimestamp(timestamp),
+        currentState(0),
+        lastStateChangeTimestamp(-1),
         emptyValue(emptyValue),
         lastValue(emptyValue),
-        lastUpdateTimestamp(timestamp),
+        lastUpdateTimestamp(-1),
         deltaValue(emptyValue) {
     states = new State[stateCount];
     for (int i = 0; i < stateCount; i++) {
@@ -109,17 +111,19 @@
 
 template <class T>
 void MultiStateCounter<T>::setState(state_t state, time_t timestamp) {
-    if (timestamp >= lastStateChangeTimestamp) {
-        states[currentState].timeInStateSinceUpdate += timestamp - lastStateChangeTimestamp;
-    } else {
-        ALOGE("setState is called with an earlier timestamp: %lu, previous timestamp: %lu\n",
-              (unsigned long)timestamp, (unsigned long)lastStateChangeTimestamp);
-        // The accumulated durations have become unreliable. For example, if the timestamp
-        // sequence was 1000, 2000, 1000, 3000, if we accumulated the positive deltas,
-        // we would get 4000, which is greater than (last - first). This could lead to
-        // counts exceeding 100%.
-        for (int i = 0; i < stateCount; i++) {
-            states[i].timeInStateSinceUpdate = 0;
+    if (lastStateChangeTimestamp >= 0) {
+        if (timestamp >= lastStateChangeTimestamp) {
+            states[currentState].timeInStateSinceUpdate += timestamp - lastStateChangeTimestamp;
+        } else {
+            ALOGE("setState is called with an earlier timestamp: %lu, previous timestamp: %lu\n",
+                  (unsigned long)timestamp, (unsigned long)lastStateChangeTimestamp);
+            // The accumulated durations have become unreliable. For example, if the timestamp
+            // sequence was 1000, 2000, 1000, 3000, if we accumulated the positive deltas,
+            // we would get 4000, which is greater than (last - first). This could lead to
+            // counts exceeding 100%.
+            for (int i = 0; i < stateCount; i++) {
+                states[i].timeInStateSinceUpdate = 0;
+            }
         }
     }
     currentState = state;
@@ -127,36 +131,49 @@
 }
 
 template <class T>
+void MultiStateCounter<T>::setValue(state_t state, const T& value) {
+    states[state].counter = value;
+}
+
+template <class T>
 void MultiStateCounter<T>::updateValue(const T& value, time_t timestamp) {
     // Confirm the current state for the side-effect of updating the time-in-state
     // counter for the current state.
     setState(currentState, timestamp);
 
-    if (timestamp > lastUpdateTimestamp) {
-        if (delta(lastValue, value, &deltaValue)) {
-            time_t timeSinceUpdate = timestamp - lastUpdateTimestamp;
-            for (int i = 0; i < stateCount; i++) {
-                time_t timeInState = states[i].timeInStateSinceUpdate;
-                if (timeInState) {
-                    add(&states[i].counter, deltaValue, timeInState, timeSinceUpdate);
-                    states[i].timeInStateSinceUpdate = 0;
+    if (lastUpdateTimestamp >= 0) {
+        if (timestamp > lastUpdateTimestamp) {
+            if (delta(lastValue, value, &deltaValue)) {
+                time_t timeSinceUpdate = timestamp - lastUpdateTimestamp;
+                for (int i = 0; i < stateCount; i++) {
+                    time_t timeInState = states[i].timeInStateSinceUpdate;
+                    if (timeInState) {
+                        add(&states[i].counter, deltaValue, timeInState, timeSinceUpdate);
+                        states[i].timeInStateSinceUpdate = 0;
+                    }
                 }
+            } else {
+                std::stringstream str;
+                str << "updateValue is called with a value " << valueToString(value)
+                    << ", which is lower than the previous value " << valueToString(lastValue)
+                    << "\n";
+                ALOGE("%s", str.str().c_str());
             }
-        } else {
-            std::stringstream str;
-            str << "updateValue is called with a value " << valueToString(value)
-                << ", which is lower than the previous value " << valueToString(lastValue) << "\n";
-            ALOGE("%s", str.str().c_str());
+        } else if (timestamp < lastUpdateTimestamp) {
+            ALOGE("updateValue is called with an earlier timestamp: %lu, previous timestamp: %lu\n",
+                  (unsigned long)timestamp, (unsigned long)lastUpdateTimestamp);
         }
-    } else if (timestamp < lastUpdateTimestamp) {
-        ALOGE("updateValue is called with an earlier timestamp: %lu, previous timestamp: %lu\n",
-              (unsigned long)timestamp, (unsigned long)lastUpdateTimestamp);
     }
     lastValue = value;
     lastUpdateTimestamp = timestamp;
 }
 
 template <class T>
+uint16_t MultiStateCounter<T>::getStateCount() {
+    return stateCount;
+}
+
+template <class T>
 const T& MultiStateCounter<T>::getCount(state_t state) {
     return states[state].counter;
 }
@@ -164,17 +181,29 @@
 template <class T>
 std::string MultiStateCounter<T>::toString() {
     std::stringstream str;
-    str << "currentState: " << currentState
-        << " lastStateChangeTimestamp: " << lastStateChangeTimestamp
-        << " lastUpdateTimestamp: " << lastUpdateTimestamp << " states: [";
+    str << "[";
     for (int i = 0; i < stateCount; i++) {
         if (i != 0) {
             str << ", ";
         }
-        str << i << ": time: " << states[i].timeInStateSinceUpdate
-            << " counter: " << valueToString(states[i].counter);
+        str << i << ": " << valueToString(states[i].counter);
+        if (states[i].timeInStateSinceUpdate > 0) {
+            str << " timeInStateSinceUpdate: " << states[i].timeInStateSinceUpdate;
+        }
     }
     str << "]";
+    if (lastUpdateTimestamp >= 0) {
+        str << " updated: " << lastUpdateTimestamp;
+    }
+    if (lastStateChangeTimestamp >= 0) {
+        str << " currentState: " << currentState;
+        if (lastStateChangeTimestamp > lastUpdateTimestamp) {
+            str << " stateChanged: " << lastStateChangeTimestamp;
+        }
+    } else {
+        str << " currentState: none";
+    }
+
     return str.str();
 }
 
diff --git a/libs/battery/MultiStateCounterTest.cpp b/libs/battery/MultiStateCounterTest.cpp
index 942d5ca..87c80c5 100644
--- a/libs/battery/MultiStateCounterTest.cpp
+++ b/libs/battery/MultiStateCounterTest.cpp
@@ -49,8 +49,9 @@
 class MultiStateCounterTest : public testing::Test {};
 
 TEST_F(MultiStateCounterTest, constructor) {
-    DoubleMultiStateCounter testCounter(3, 1, 0, 1000);
-    testCounter.setState(1, 2000);
+    DoubleMultiStateCounter testCounter(3, 0);
+    testCounter.updateValue(0, 0);
+    testCounter.setState(1, 0);
     testCounter.updateValue(3.14, 3000);
 
     EXPECT_DOUBLE_EQ(0, testCounter.getCount(0));
@@ -59,7 +60,9 @@
 }
 
 TEST_F(MultiStateCounterTest, stateChange) {
-    DoubleMultiStateCounter testCounter(3, 1, 0, 0);
+    DoubleMultiStateCounter testCounter(3, 0);
+    testCounter.updateValue(0, 0);
+    testCounter.setState(1, 0);
     testCounter.setState(2, 1000);
     testCounter.updateValue(6.0, 3000);
 
@@ -69,7 +72,9 @@
 }
 
 TEST_F(MultiStateCounterTest, timeAdjustment_setState) {
-    DoubleMultiStateCounter testCounter(3, 1, 0, 0);
+    DoubleMultiStateCounter testCounter(3, 0);
+    testCounter.updateValue(0, 0);
+    testCounter.setState(1, 0);
     testCounter.setState(2, 2000);
 
     // Time moves back
@@ -88,7 +93,9 @@
 }
 
 TEST_F(MultiStateCounterTest, timeAdjustment_updateValue) {
-    DoubleMultiStateCounter testCounter(1, 0, 0, 0);
+    DoubleMultiStateCounter testCounter(1, 0);
+    testCounter.updateValue(0, 0);
+    testCounter.setState(0, 0);
     testCounter.updateValue(6.0, 2000);
 
     // Time moves back. The negative delta from 2000 to 1000 is ignored
@@ -101,5 +108,23 @@
     EXPECT_DOUBLE_EQ(9.0, testCounter.getCount(0));
 }
 
+TEST_F(MultiStateCounterTest, toString) {
+    DoubleMultiStateCounter testCounter(2, 0);
+
+    EXPECT_STREQ("[0: 0.000000, 1: 0.000000] currentState: none", testCounter.toString().c_str());
+
+    testCounter.updateValue(0, 0);
+    testCounter.setState(1, 0);
+    testCounter.setState(1, 2000);
+    EXPECT_STREQ("[0: 0.000000, 1: 0.000000 timeInStateSinceUpdate: 2000]"
+                 " updated: 0 currentState: 1 stateChanged: 2000",
+                 testCounter.toString().c_str());
+
+    testCounter.updateValue(3.14, 3000);
+
+    EXPECT_STREQ("[0: 0.000000, 1: 3.140000] updated: 3000 currentState: 1",
+                 testCounter.toString().c_str());
+}
+
 } // namespace battery
 } // namespace android