Add UI for camera + flashlight battery reporting.

Bug: 11694505
Change-Id: Ieefa78a1d641851f4141fe666dae7b9fde394f09
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 1f2ad5f..becd0c8 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -1940,6 +1940,15 @@
      */
     public abstract long getFlashlightOnCount(int which);
 
+    /**
+     * Returns the time in microseconds that the camera has been on while the device was
+     * running on battery.
+     *
+     * {@hide}
+     */
+    public abstract long getCameraOnTime(long elapsedRealtimeUs, int which);
+
+
     public static final int NETWORK_MOBILE_RX_DATA = 0;
     public static final int NETWORK_MOBILE_TX_DATA = 1;
     public static final int NETWORK_WIFI_RX_DATA = 2;
@@ -2735,6 +2744,9 @@
                     case OVERCOUNTED:
                         label = "over";
                         break;
+                    case CAMERA:
+                        label = "camera";
+                        break;
                     default:
                         label = "???";
                 }
@@ -3522,6 +3534,10 @@
                         pw.print(prefix); pw.print("    Over-counted: "); printmAh(pw, bs.totalPowerMah);
                         pw.println();
                         break;
+                    case CAMERA:
+                        pw.print(prefix); pw.print("    Camera: "); printmAh(pw, bs.totalPowerMah);
+                        pw.println();
+                        break;
                 }
             }
             pw.println();
diff --git a/core/java/com/android/internal/os/BatterySipper.java b/core/java/com/android/internal/os/BatterySipper.java
index 056b0aa..049d3eb 100644
--- a/core/java/com/android/internal/os/BatterySipper.java
+++ b/core/java/com/android/internal/os/BatterySipper.java
@@ -42,6 +42,8 @@
     public long wifiRunningTimeMs;
     public long cpuFgTimeMs;
     public long wakeLockTimeMs;
+    public long cameraTimeMs;
+    public long flashlightTimeMs;
 
     public long mobileRxPackets;
     public long mobileTxPackets;
@@ -67,6 +69,8 @@
     public double mobileRadioPowerMah;
     public double gpsPowerMah;
     public double sensorPowerMah;
+    public double cameraPowerMah;
+    public double flashlightPowerMah;
 
     public enum DrainType {
         IDLE,
@@ -79,7 +83,8 @@
         APP,
         USER,
         UNACCOUNTED,
-        OVERCOUNTED
+        OVERCOUNTED,
+        CAMERA
     }
 
     public BatterySipper(DrainType drainType, Uid uid, double value) {
@@ -135,6 +140,8 @@
         wifiRunningTimeMs += other.wifiRunningTimeMs;
         cpuFgTimeMs += other.cpuFgTimeMs;
         wakeLockTimeMs += other.wakeLockTimeMs;
+        cameraTimeMs += other.cameraTimeMs;
+        flashlightTimeMs += other.flashlightTimeMs;
         mobileRxPackets += other.mobileRxPackets;
         mobileTxPackets += other.mobileTxPackets;
         mobileActive += other.mobileActive;
@@ -151,6 +158,8 @@
         sensorPowerMah += other.sensorPowerMah;
         mobileRadioPowerMah += other.mobileRadioPowerMah;
         wakeLockPowerMah += other.wakeLockPowerMah;
+        cameraPowerMah += other.cameraPowerMah;
+        flashlightPowerMah += other.flashlightPowerMah;
     }
 
     /**
@@ -158,7 +167,8 @@
      * @return the sum of all the power in this BatterySipper.
      */
     public double sumPower() {
-        return totalPowerMah = usagePowerMah + wifiPowerMah + gpsPowerMah + cpuPowerMah + sensorPowerMah
-                + mobileRadioPowerMah + wakeLockPowerMah;
+        return totalPowerMah = usagePowerMah + wifiPowerMah + gpsPowerMah + cpuPowerMah +
+                sensorPowerMah + mobileRadioPowerMah + wakeLockPowerMah + cameraPowerMah +
+                flashlightPowerMah;
     }
 }
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index fbe87c5..e6165a1 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -122,6 +122,8 @@
     PowerCalculator mWifiPowerCalculator;
     PowerCalculator mBluetoothPowerCalculator;
     PowerCalculator mSensorPowerCalculator;
+    PowerCalculator mCameraPowerCalculator;
+    PowerCalculator mFlashlightPowerCalculator;
 
     public static boolean checkWifiOnly(Context context) {
         ConnectivityManager cm = (ConnectivityManager)context.getSystemService(
@@ -365,6 +367,16 @@
         }
         mSensorPowerCalculator.reset();
 
+        if (mCameraPowerCalculator == null) {
+            mCameraPowerCalculator = new CameraPowerCalculator(mPowerProfile);
+        }
+        mCameraPowerCalculator.reset();
+
+        if (mFlashlightPowerCalculator == null) {
+            mFlashlightPowerCalculator = new FlashlightPowerCalculator(mPowerProfile);
+        }
+        mFlashlightPowerCalculator.reset();
+
         mStatsType = statsType;
         mRawUptime = rawUptimeUs;
         mRawRealtime = rawRealtimeUs;
@@ -480,6 +492,8 @@
             mWifiPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType);
             mBluetoothPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType);
             mSensorPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType);
+            mCameraPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType);
+            mFlashlightPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType);
 
             final double totalPower = app.sumPower();
             if (DEBUG && totalPower != 0) {
@@ -619,15 +633,6 @@
         }
     }
 
-    private void addFlashlightUsage() {
-        long flashlightOnTimeMs = mStats.getFlashlightOnTime(mRawRealtime, mStatsType) / 1000;
-        double flashlightPower = flashlightOnTimeMs
-                * mPowerProfile.getAveragePower(PowerProfile.POWER_FLASHLIGHT) / (60*60*1000);
-        if (flashlightPower != 0) {
-            addEntry(BatterySipper.DrainType.FLASHLIGHT, flashlightOnTimeMs, flashlightPower);
-        }
-    }
-
     private void addUserUsage() {
         for (int i = 0; i < mUserSippers.size(); i++) {
             final int userId = mUserSippers.keyAt(i);
@@ -643,7 +648,6 @@
         addUserUsage();
         addPhoneUsage();
         addScreenUsage();
-        addFlashlightUsage();
         addWiFiUsage();
         addBluetoothUsage();
         addIdleUsage(); // Not including cellular idle power
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 62745d4..c38ab09 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -4337,15 +4337,22 @@
         return 0;
     }
 
-    @Override public long getFlashlightOnTime(long elapsedRealtimeUs, int which) {
+    @Override
+    public long getFlashlightOnTime(long elapsedRealtimeUs, int which) {
         return mFlashlightOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
     }
 
-    @Override public long getFlashlightOnCount(int which) {
+    @Override
+    public long getFlashlightOnCount(int which) {
         return mFlashlightOnTimer.getCountLocked(which);
     }
 
     @Override
+    public long getCameraOnTime(long elapsedRealtimeUs, int which) {
+        return mCameraOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
+    }
+
+    @Override
     public long getNetworkActivityBytes(int type, int which) {
         if (type >= 0 && type < mNetworkByteActivityCounters.length) {
             return mNetworkByteActivityCounters[type].getCountLocked(which);
diff --git a/core/java/com/android/internal/os/CameraPowerCalculator.java b/core/java/com/android/internal/os/CameraPowerCalculator.java
new file mode 100644
index 0000000..3273080
--- /dev/null
+++ b/core/java/com/android/internal/os/CameraPowerCalculator.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2015 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.internal.os;
+
+import android.os.BatteryStats;
+
+/**
+ * Power calculator for the camera subsystem, excluding the flashlight.
+ *
+ * Note: Power draw for the flash unit should be included in the FlashlightPowerCalculator.
+ */
+public class CameraPowerCalculator extends PowerCalculator {
+    private final double mCameraPowerOnAvg;
+
+    public CameraPowerCalculator(PowerProfile profile) {
+        mCameraPowerOnAvg = profile.getAveragePower(PowerProfile.POWER_CAMERA);
+    }
+
+    @Override
+    public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
+                             long rawUptimeUs, int statsType) {
+
+        // Calculate camera power usage.  Right now, this is a (very) rough estimate based on the
+        // average power usage for a typical camera application.
+        final BatteryStats.Timer timer = u.getCameraTurnedOnTimer();
+        if (timer != null) {
+            final long totalTime = timer.getTotalTimeLocked(rawRealtimeUs, statsType) / 1000;
+            app.cameraTimeMs = totalTime;
+            app.cameraPowerMah = (totalTime * mCameraPowerOnAvg) / (1000*60*60);
+        } else {
+            app.cameraTimeMs = 0;
+            app.cameraPowerMah = 0;
+        }
+    }
+}
diff --git a/core/java/com/android/internal/os/FlashlightPowerCalculator.java b/core/java/com/android/internal/os/FlashlightPowerCalculator.java
new file mode 100644
index 0000000..fef66ff
--- /dev/null
+++ b/core/java/com/android/internal/os/FlashlightPowerCalculator.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2015 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.internal.os;
+
+import android.os.BatteryStats;
+
+/**
+ * Power calculator for the flashlight.
+ */
+public class FlashlightPowerCalculator extends PowerCalculator {
+    private final double mFlashlightPowerOnAvg;
+
+    public FlashlightPowerCalculator(PowerProfile profile) {
+        mFlashlightPowerOnAvg = profile.getAveragePower(PowerProfile.POWER_FLASHLIGHT);
+    }
+
+    @Override
+    public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
+                             long rawUptimeUs, int statsType) {
+
+        // Calculate flashlight power usage.  Right now, this is based on the average power draw
+        // of the flash unit when kept on over a short period of time.
+        final BatteryStats.Timer timer = u.getFlashlightTurnedOnTimer();
+        if (timer != null) {
+            final long totalTime = timer.getTotalTimeLocked(rawRealtimeUs, statsType) / 1000;
+            app.flashlightTimeMs = totalTime;
+            app.flashlightPowerMah = (totalTime * mFlashlightPowerOnAvg) / (1000*60*60);
+        } else {
+            app.flashlightTimeMs = 0;
+            app.flashlightPowerMah = 0;
+        }
+    }
+}
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index 1efa5651..4ede8dda 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -152,10 +152,17 @@
     public static final String POWER_VIDEO = "dsp.video";
 
     /**
-     * Power consumption when camera flashlight is on.
+     * Average power consumption when camera flashlight is on.
      */
     public static final String POWER_FLASHLIGHT = "camera.flashlight";
 
+    /**
+     * Average power consumption when the camera is on over all standard use cases.
+     *
+     * TODO: Add more fine-grained camera power metrics.
+     */
+    public static final String POWER_CAMERA = "camera.avg";
+
     public static final String POWER_CPU_SPEEDS = "cpu.speeds";
 
     /**
diff --git a/core/res/res/xml/power_profile.xml b/core/res/res/xml/power_profile.xml
index 3215e17..28d99d8 100644
--- a/core/res/res/xml/power_profile.xml
+++ b/core/res/res/xml/power_profile.xml
@@ -37,6 +37,8 @@
   <item name="wifi.scan">0.1</item>  <!-- WIFI network scanning, ~100mA -->
   <item name="dsp.audio">0.1</item> <!-- ~10mA -->
   <item name="dsp.video">0.1</item> <!-- ~50mA -->
+  <item name="camera.flashlight">0.1</item> <!-- Avg. power for camera flash, ~160mA -->
+  <item name="camera.avg">0.1</item> <!-- Avg. power use of camera in standard usecases, ~550mA -->
   <item name="radio.active">0.1</item> <!-- ~200mA -->
   <item name="radio.scanning">0.1</item> <!-- cellular radio scanning for signal, ~10mA -->
   <item name="gps.on">0.1</item> <!-- ~50mA -->