Merge "Turn battery charging into a test signal"
diff --git a/src/com/android/tradefed/testtype/DeviceBatteryLevelChecker.java b/src/com/android/tradefed/testtype/DeviceBatteryLevelChecker.java
index 7cf18f5..c5777e0 100644
--- a/src/com/android/tradefed/testtype/DeviceBatteryLevelChecker.java
+++ b/src/com/android/tradefed/testtype/DeviceBatteryLevelChecker.java
@@ -24,13 +24,19 @@
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.invoker.TestInformation;
 import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.metrics.proto.MetricMeasurement.Metric;
+import com.android.tradefed.result.FailureDescription;
 import com.android.tradefed.result.ITestInvocationListener;
+import com.android.tradefed.result.ITestLifeCycleReceiver;
+import com.android.tradefed.result.TestDescription;
 import com.android.tradefed.util.IRunUtil;
 import com.android.tradefed.util.RunUtil;
 import com.android.tradefed.util.TimeUtil;
 
 import org.junit.Assert;
 
+import java.util.HashMap;
+
 /**
  * An {@link IRemoteTest} that checks for a minimum battery charge, and waits for the battery to
  * reach a second charging threshold if the minimum charge isn't present.
@@ -39,6 +45,7 @@
 public class DeviceBatteryLevelChecker implements IRemoteTest {
 
     private ITestDevice mTestDevice = null;
+    private TestDescription mTestDescription = new TestDescription("BatteryCharging", "charge");
 
     /**
      * We use max-battery here to coincide with a {@link DeviceSelectionOptions} option of the same
@@ -103,11 +110,31 @@
         mTestDevice = testInfo.getDevice();
         Assert.assertNotNull(mTestDevice);
 
+        long startTime = System.currentTimeMillis();
+        listener.testRunStarted("BatteryCharging", 1);
+        listener.testStarted(mTestDescription);
+        try {
+            runTest(testInfo, listener);
+        } finally {
+            listener.testEnded(mTestDescription, new HashMap<String, Metric>());
+            listener.testRunEnded(
+                    System.currentTimeMillis() - startTime, new HashMap<String, Metric>());
+        }
+    }
+
+    private void runTest(TestInformation testInfo, ITestInvocationListener listener)
+            throws DeviceNotAvailableException {
+        mTestDevice = testInfo.getDevice();
+        Assert.assertNotNull(mTestDevice);
+
         Integer batteryLevel = checkBatteryLevel(mTestDevice);
 
         if (batteryLevel == null) {
             CLog.w("Failed to determine battery level for device %s.",
                     mTestDevice.getSerialNumber());
+            listener.testFailed(
+                    mTestDescription,
+                    FailureDescription.create("Failed to determine battery level"));
             return;
         } else if (batteryLevel < mMaxBattery) {
             // Time-out.  Send the device to the corner
@@ -130,39 +157,68 @@
         // turn screen off
         turnScreenOff(mTestDevice);
 
-        if (mStopRuntime) {
-            stopDeviceRuntime();
-        }
-        // Stop our logcat receiver
-        if (mStopLogcat) {
-            mTestDevice.stopLogcat();
+        try {
+            if (mStopRuntime) {
+                stopDeviceRuntime();
+            }
+            // Stop our logcat receiver
+            if (mStopLogcat) {
+                mTestDevice.stopLogcat();
+            }
+
+            runBatteryCharging(listener, mTestDescription);
+            // TODO: Check the charging speed
+        } finally {
+            if (mStopRuntime) {
+                // Restart runtime if it was stopped
+                startDeviceRuntime();
+            }
         }
 
+        CLog.i(
+                "Device %s is now charged to battery level %d; releasing.",
+                mTestDevice.getSerialNumber(), batteryLevel);
+    }
+
+    private void turnScreenOff(ITestDevice device) throws DeviceNotAvailableException {
+        // TODO: Handle the case where framework is not working, both command below require it.
+        // disable always on
+        device.executeShellCommand("svc power stayon false");
+        // set screen timeout to 1s
+        device.executeShellCommand("settings put system screen_off_timeout 1000");
+        // pause for 5s to ensure that screen would be off
+        getRunUtil().sleep(5000);
+    }
+
+    private Integer runBatteryCharging(ITestLifeCycleReceiver listener, TestDescription test) {
         // If we're down here, it's time to hold the device until it reaches mResumeLevel
         Long lastReportTime = System.currentTimeMillis();
-        Integer newLevel = checkBatteryLevel(mTestDevice);
+        Integer batteryLevel = checkBatteryLevel(mTestDevice);
 
         long startTime = System.currentTimeMillis();
         while (batteryLevel != null && batteryLevel < mResumeLevel) {
             if (System.currentTimeMillis() - lastReportTime > mLoggingPollTime * 60 * 1000) {
                 // Log the battery level status every mLoggingPollTime minutes
-                CLog.w("Battery level for device %s is currently %d", mTestDevice.getSerialNumber(),
-                        newLevel);
+                CLog.i(
+                        "Battery level for device %s is currently %d",
+                        mTestDevice.getSerialNumber(), batteryLevel);
                 lastReportTime = System.currentTimeMillis();
             }
             if (System.currentTimeMillis() - startTime > mMaxRunTime) {
-                CLog.w(
+                CLog.i(
                         "DeviceBatteryLevelChecker has been running for %s. terminating.",
                         TimeUtil.formatElapsedTime(mMaxRunTime));
                 break;
             }
 
             getRunUtil().sleep((long) (mChargingPollTime * 60 * 1000));
-            newLevel = checkBatteryLevel(mTestDevice);
+            Integer newLevel = checkBatteryLevel(mTestDevice);
             if (newLevel == null) {
                 // weird
                 CLog.w("Breaking out of wait loop because battery level read failed for device %s",
                         mTestDevice.getSerialNumber());
+                listener.testFailed(
+                        test, FailureDescription.create("Failed to read battery level"));
                 break;
             } else if (newLevel < batteryLevel) {
                 // also weird
@@ -175,23 +231,7 @@
             }
             batteryLevel = newLevel;
         }
-
-        if (mStopRuntime) {
-            // Restart runtime if it was stopped
-            startDeviceRuntime();
-        }
-
-        CLog.w("Device %s is now charged to battery level %d; releasing.",
-                mTestDevice.getSerialNumber(), batteryLevel);
-    }
-
-    private void turnScreenOff(ITestDevice device) throws DeviceNotAvailableException {
-        // disable always on
-        device.executeShellCommand("svc power stayon false");
-        // set screen timeout to 1s
-        device.executeShellCommand("settings put system screen_off_timeout 1000");
-        // pause for 5s to ensure that screen would be off
-        getRunUtil().sleep(5000);
+        return batteryLevel;
     }
 
     /**
diff --git a/tests/src/com/android/tradefed/testtype/DeviceBatteryLevelCheckerTest.java b/tests/src/com/android/tradefed/testtype/DeviceBatteryLevelCheckerTest.java
index 01aa9c6..0e99b3e 100644
--- a/tests/src/com/android/tradefed/testtype/DeviceBatteryLevelCheckerTest.java
+++ b/tests/src/com/android/tradefed/testtype/DeviceBatteryLevelCheckerTest.java
@@ -26,6 +26,10 @@
 import com.android.tradefed.invoker.InvocationContext;
 import com.android.tradefed.invoker.TestInformation;
 import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.metrics.proto.MetricMeasurement.Metric;
+import com.android.tradefed.result.FailureDescription;
+import com.android.tradefed.result.ITestInvocationListener;
+import com.android.tradefed.result.TestDescription;
 import com.android.tradefed.util.IRunUtil;
 
 import org.easymock.EasyMock;
@@ -34,6 +38,8 @@
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
+import java.util.HashMap;
+
 /** Unit tests for {@link DeviceBatteryLevelChecker}. */
 @RunWith(JUnit4.class)
 public class DeviceBatteryLevelCheckerTest {
@@ -42,10 +48,12 @@
     private TestInformation mTestInfo = null;
     private ITestDevice mFakeTestDevice = null;
     public Integer mBatteryLevel = 10;
+    private TestDescription mTestDescription = new TestDescription("BatteryCharging", "charge");
 
     private IDevice mMockIDevice;
     private IDeviceStateMonitor mMockStateMonitor;
     private IDeviceMonitor mMockDvcMonitor;
+    private ITestInvocationListener mMockListener;
 
     /** A {@link TestDevice} that is suitable for running tests against */
     private class TestableTestDevice extends TestDevice {
@@ -80,6 +88,7 @@
         mMockStateMonitor = EasyMock.createMock(IDeviceStateMonitor.class);
         mMockDvcMonitor = EasyMock.createMock(IDeviceMonitor.class);
         mFakeTestDevice = EasyMock.createMock(ITestDevice.class);
+        mMockListener = EasyMock.createMock(ITestInvocationListener.class);
 
         mDevice = new TestableTestDevice();
         mChecker = new DeviceBatteryLevelChecker() {
@@ -97,9 +106,16 @@
     @Test
     public void testNull() throws Exception {
         expectBattLevel(null);
+        mMockListener.testRunStarted("BatteryCharging", 1);
+        mMockListener.testStarted(mTestDescription);
+        mMockListener.testFailed(
+                mTestDescription, FailureDescription.create("Failed to determine battery level"));
+        mMockListener.testEnded(mTestDescription, new HashMap<String, Metric>());
+        mMockListener.testRunEnded(
+                EasyMock.anyLong(), EasyMock.<HashMap<String, Metric>>anyObject());
         replayDevices();
 
-        mChecker.run(mTestInfo, null);
+        mChecker.run(mTestInfo, mMockListener);
         // expect this to return immediately without throwing an exception.  Should log a warning.
         verifyDevices();
     }
@@ -107,9 +123,14 @@
     @Test
     public void testNormal() throws Exception {
         expectBattLevel(45);
+        mMockListener.testRunStarted("BatteryCharging", 1);
+        mMockListener.testStarted(mTestDescription);
+        mMockListener.testEnded(mTestDescription, new HashMap<String, Metric>());
+        mMockListener.testRunEnded(
+                EasyMock.anyLong(), EasyMock.<HashMap<String, Metric>>anyObject());
         replayDevices();
 
-        mChecker.run(mTestInfo, null);
+        mChecker.run(mTestInfo, mMockListener);
         verifyDevices();
     }
 
@@ -123,9 +144,14 @@
                 .andStubReturn("");
         EasyMock.expect(mFakeTestDevice.executeShellCommand(
                 "settings put system screen_off_timeout 1000")).andStubReturn("");
+        mMockListener.testRunStarted("BatteryCharging", 1);
+        mMockListener.testStarted(mTestDescription);
+        mMockListener.testEnded(mTestDescription, new HashMap<String, Metric>());
+        mMockListener.testRunEnded(
+                EasyMock.anyLong(), EasyMock.<HashMap<String, Metric>>anyObject());
         replayDevices();
         mChecker.setResumeLevel(5);
-        mChecker.run(mTestInfo, null);
+        mChecker.run(mTestInfo, mMockListener);
         verifyDevices();
     }
 
@@ -139,6 +165,11 @@
                 .andStubReturn("");
         EasyMock.expect(mFakeTestDevice.executeShellCommand(
                 "settings put system screen_off_timeout 1000")).andStubReturn("");
+        mMockListener.testRunStarted("BatteryCharging", 1);
+        mMockListener.testStarted(mTestDescription);
+        mMockListener.testEnded(mTestDescription, new HashMap<String, Metric>());
+        mMockListener.testRunEnded(
+                EasyMock.anyLong(), EasyMock.<HashMap<String, Metric>>anyObject());
         replayDevices();
         Thread raise = new Thread(new Runnable() {
             @Override
@@ -152,7 +183,7 @@
             }
         });
         raise.start();
-        mChecker.run(mTestInfo, null);
+        mChecker.run(mTestInfo, mMockListener);
         verifyDevices();
     }
 
@@ -166,6 +197,13 @@
                 .andStubReturn("");
         EasyMock.expect(mFakeTestDevice.executeShellCommand(
                 "settings put system screen_off_timeout 1000")).andStubReturn("");
+        mMockListener.testRunStarted("BatteryCharging", 1);
+        mMockListener.testStarted(mTestDescription);
+        mMockListener.testFailed(
+                mTestDescription, FailureDescription.create("Failed to read battery level"));
+        mMockListener.testEnded(mTestDescription, new HashMap<String, Metric>());
+        mMockListener.testRunEnded(
+                EasyMock.anyLong(), EasyMock.<HashMap<String, Metric>>anyObject());
         replayDevices();
         Thread raise = new Thread(new Runnable() {
             @Override
@@ -179,7 +217,7 @@
             }
         });
         raise.start();
-        mChecker.run(mTestInfo, null);
+        mChecker.run(mTestInfo, mMockListener);
         verifyDevices();
     }
 
@@ -188,11 +226,11 @@
     }
 
     private void replayDevices() {
-        EasyMock.replay(mFakeTestDevice);
+        EasyMock.replay(mFakeTestDevice, mMockListener);
     }
 
     private void verifyDevices() {
-        EasyMock.verify(mFakeTestDevice);
+        EasyMock.verify(mFakeTestDevice, mMockListener);
     }
 }