Merge "Import translations. DO NOT MERGE" into oc-mr1-dev
diff --git a/src/com/android/settings/fuelgauge/anomaly/AnomalyDetectionPolicy.java b/src/com/android/settings/fuelgauge/anomaly/AnomalyDetectionPolicy.java
index 0c401b5..dd8ebc7 100644
--- a/src/com/android/settings/fuelgauge/anomaly/AnomalyDetectionPolicy.java
+++ b/src/com/android/settings/fuelgauge/anomaly/AnomalyDetectionPolicy.java
@@ -17,12 +17,17 @@
 package com.android.settings.fuelgauge.anomaly;
 
 import android.content.Context;
+import android.net.Uri;
 import android.provider.Settings;
 import android.support.annotation.VisibleForTesting;
 import android.text.format.DateUtils;
 import android.util.KeyValueListParser;
 import android.util.Log;
 
+import java.util.Arrays;
+import java.util.Set;
+import java.util.stream.Collectors;
+
 /**
  * Class to store the policy for anomaly detection, which comes from
  * {@link android.provider.Settings.Global}
@@ -43,6 +48,8 @@
     @VisibleForTesting
     static final String KEY_WAKEUP_ALARM_THRESHOLD = "wakeup_alarm_threshold";
     @VisibleForTesting
+    static final String KEY_WAKEUP_BLACKLISTED_TAGS = "wakeup_blacklisted_tags";
+    @VisibleForTesting
     static final String KEY_BLUETOOTH_SCAN_THRESHOLD = "bluetooth_scan_threshold";
 
     /**
@@ -94,6 +101,14 @@
     public final long wakeupAlarmThreshold;
 
     /**
+     * Array of blacklisted wakeups, by tag.
+     *
+     * @see Settings.Global#ANOMALY_DETECTION_CONSTANTS
+     * @see #KEY_WAKEUP_BLACKLISTED_TAGS
+     */
+    public final Set<String> wakeupBlacklistedTags;
+
+    /**
      * Threshold for bluetooth unoptimized scanning time in milli seconds
      *
      * @see Settings.Global#ANOMALY_DETECTION_CONSTANTS
@@ -119,15 +134,18 @@
             Log.e(TAG, "Bad anomaly detection constants");
         }
 
-        anomalyDetectionEnabled = mParserWrapper.getBoolean(KEY_ANOMALY_DETECTION_ENABLED, true);
-        wakeLockDetectionEnabled = mParserWrapper.getBoolean(KEY_WAKELOCK_DETECTION_ENABLED, true);
-        wakeupAlarmDetectionEnabled = mParserWrapper.getBoolean(KEY_WAKEUP_ALARM_DETECTION_ENABLED,
-                false);
+        anomalyDetectionEnabled =
+                mParserWrapper.getBoolean(KEY_ANOMALY_DETECTION_ENABLED, false);
+        wakeLockDetectionEnabled =
+                mParserWrapper.getBoolean(KEY_WAKELOCK_DETECTION_ENABLED,false);
+        wakeupAlarmDetectionEnabled =
+                mParserWrapper.getBoolean(KEY_WAKEUP_ALARM_DETECTION_ENABLED,false);
         bluetoothScanDetectionEnabled = mParserWrapper.getBoolean(
-                KEY_BLUETOOTH_SCAN_DETECTION_ENABLED, true);
+                KEY_BLUETOOTH_SCAN_DETECTION_ENABLED, false);
         wakeLockThreshold = mParserWrapper.getLong(KEY_WAKELOCK_THRESHOLD,
                 DateUtils.HOUR_IN_MILLIS);
-        wakeupAlarmThreshold = mParserWrapper.getLong(KEY_WAKEUP_ALARM_THRESHOLD, 60);
+        wakeupAlarmThreshold = mParserWrapper.getLong(KEY_WAKEUP_ALARM_THRESHOLD, 10);
+        wakeupBlacklistedTags = parseStringSet(KEY_WAKEUP_BLACKLISTED_TAGS, null);
         bluetoothScanThreshold = mParserWrapper.getLong(KEY_BLUETOOTH_SCAN_THRESHOLD,
                 30 * DateUtils.MINUTE_IN_MILLIS);
     }
@@ -148,4 +166,14 @@
                 return false; // Disabled when no this type
         }
     }
+
+    private Set<String> parseStringSet(final String key, final Set<String> defaultSet) {
+        final String value = mParserWrapper.getString(key, null);
+        if (value != null) {
+            return Arrays.stream(value.split(":"))
+                    .map(String::trim).map(Uri::decode).collect(Collectors.toSet());
+        } else {
+            return defaultSet;
+        }
+    }
 }
diff --git a/src/com/android/settings/fuelgauge/anomaly/KeyValueListParserWrapper.java b/src/com/android/settings/fuelgauge/anomaly/KeyValueListParserWrapper.java
index 4a9c2a9..7d216c5 100644
--- a/src/com/android/settings/fuelgauge/anomaly/KeyValueListParserWrapper.java
+++ b/src/com/android/settings/fuelgauge/anomaly/KeyValueListParserWrapper.java
@@ -44,6 +44,14 @@
     void setString(String str) throws IllegalArgumentException;
 
     /**
+     * Get the value for key as a string.
+     * @param key The key to lookup.
+     * @param defaultValue The value to return if the key was not found.
+     * @return the string value associated with the key.
+     */
+    String getString(String key, String defaultValue);
+
+    /**
      * Get the value for key as a boolean.
      * @param key The key to lookup.
      * @param defaultValue The value to return if the key was not found.
diff --git a/src/com/android/settings/fuelgauge/anomaly/KeyValueListParserWrapperImpl.java b/src/com/android/settings/fuelgauge/anomaly/KeyValueListParserWrapperImpl.java
index f724034..cf3aa95 100644
--- a/src/com/android/settings/fuelgauge/anomaly/KeyValueListParserWrapperImpl.java
+++ b/src/com/android/settings/fuelgauge/anomaly/KeyValueListParserWrapperImpl.java
@@ -39,6 +39,11 @@
     }
 
     @Override
+    public String getString(String key, String defaultValue) {
+        return mParser.getString(key, defaultValue);
+    }
+
+    @Override
     public boolean getBoolean(String key, boolean defaultValue) {
         return mParser.getBoolean(key, defaultValue);
     }
diff --git a/src/com/android/settings/fuelgauge/anomaly/checker/WakeupAlarmAnomalyDetector.java b/src/com/android/settings/fuelgauge/anomaly/checker/WakeupAlarmAnomalyDetector.java
index 8823a17..936fe30 100644
--- a/src/com/android/settings/fuelgauge/anomaly/checker/WakeupAlarmAnomalyDetector.java
+++ b/src/com/android/settings/fuelgauge/anomaly/checker/WakeupAlarmAnomalyDetector.java
@@ -29,10 +29,11 @@
 import com.android.settings.fuelgauge.anomaly.Anomaly;
 import com.android.settings.fuelgauge.anomaly.AnomalyDetectionPolicy;
 import com.android.settings.fuelgauge.anomaly.AnomalyUtils;
-import com.android.settings.fuelgauge.anomaly.action.AnomalyAction;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 /**
  * Check whether apps has too many wakeup alarms
@@ -42,6 +43,7 @@
     @VisibleForTesting
     BatteryUtils mBatteryUtils;
     private long mWakeupAlarmThreshold;
+    private Set<String> mWakeupBlacklistedTags;
     private Context mContext;
     private AnomalyUtils mAnomalyUtils;
 
@@ -56,6 +58,7 @@
         mBatteryUtils = BatteryUtils.getInstance(context);
         mAnomalyUtils = anomalyUtils;
         mWakeupAlarmThreshold = policy.wakeupAlarmThreshold;
+        mWakeupBlacklistedTags = policy.wakeupBlacklistedTags;
     }
 
     @Override
@@ -123,11 +126,14 @@
             final BatteryStats.Uid.Pkg ps = packageStats.valueAt(ipkg);
             final ArrayMap<String, ? extends BatteryStats.Counter> alarms =
                     ps.getWakeupAlarmStats();
-            for (int iwa = alarms.size() - 1; iwa >= 0; iwa--) {
-                int count = alarms.valueAt(iwa).getCountLocked(BatteryStats.STATS_SINCE_CHARGED);
+            for (Map.Entry<String, ? extends BatteryStats.Counter> alarm : alarms.entrySet()) {
+                if (mWakeupBlacklistedTags != null
+                        && mWakeupBlacklistedTags.contains(alarm.getKey())) {
+                    continue;
+                }
+                int count = alarm.getValue().getCountLocked(BatteryStats.STATS_SINCE_CHARGED);
                 wakeups += count;
             }
-
         }
 
         return wakeups;
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/anomaly/AnomalyDetectionPolicyTest.java b/tests/robotests/src/com/android/settings/fuelgauge/anomaly/AnomalyDetectionPolicyTest.java
index 914cc2f..8d07629 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/anomaly/AnomalyDetectionPolicyTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/anomaly/AnomalyDetectionPolicyTest.java
@@ -40,11 +40,13 @@
 @RunWith(SettingsRobolectricTestRunner.class)
 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
 public class AnomalyDetectionPolicyTest {
-    private static final String ANOMALY_DETECTION_CONSTANTS_VALUE = "anomaly_detection_enabled=true"
+    private static final String ANOMALY_DETECTION_CONSTANTS_VALUE =
+            "anomaly_detection_enabled=true"
             + ",wakelock_enabled=false"
             + ",wakelock_threshold=3000"
             + ",wakeup_alarm_enabled=true"
             + ",wakeup_alarm_threshold=100"
+            + ",wakeup_blacklisted_tags=tag1:tag2:with%2Ccomma:with%3Acolon"
             + ",bluetooth_scan_enabled=true"
             + ",bluetooth_scan_threshold=2000";
     private Context mContext;
@@ -58,7 +60,7 @@
     }
 
     @Test
-    public void testInit_containsDataFromSettings() {
+    public void testInit_usesConfigValues() {
         AnomalyDetectionPolicy anomalyDetectionPolicy = createAnomalyPolicyWithConfig();
 
         assertThat(anomalyDetectionPolicy.anomalyDetectionEnabled).isTrue();
@@ -66,12 +68,14 @@
         assertThat(anomalyDetectionPolicy.wakeLockThreshold).isEqualTo(3000);
         assertThat(anomalyDetectionPolicy.wakeupAlarmDetectionEnabled).isTrue();
         assertThat(anomalyDetectionPolicy.wakeupAlarmThreshold).isEqualTo(100);
+        assertThat(anomalyDetectionPolicy.wakeupBlacklistedTags)
+                .containsExactly("tag1", "tag2", "with,comma", "with:colon");
         assertThat(anomalyDetectionPolicy.bluetoothScanDetectionEnabled).isTrue();
         assertThat(anomalyDetectionPolicy.bluetoothScanThreshold).isEqualTo(2000);
     }
 
     @Test
-    public void testInit_containsDefaultData() {
+    public void testInit_defaultValues() {
         Settings.Global.putString(mContext.getContentResolver(),
                 Settings.Global.ANOMALY_DETECTION_CONSTANTS, "");
         // Mock it to avoid noSuchMethodError
@@ -81,18 +85,19 @@
         AnomalyDetectionPolicy anomalyDetectionPolicy = new AnomalyDetectionPolicy(mContext,
                 mKeyValueListParserWrapper);
 
-        assertThat(anomalyDetectionPolicy.anomalyDetectionEnabled).isTrue();
-        assertThat(anomalyDetectionPolicy.wakeLockDetectionEnabled).isTrue();
+        assertThat(anomalyDetectionPolicy.anomalyDetectionEnabled).isFalse();
+        assertThat(anomalyDetectionPolicy.wakeLockDetectionEnabled).isFalse();
         assertThat(anomalyDetectionPolicy.wakeLockThreshold).isEqualTo(DateUtils.HOUR_IN_MILLIS);
         assertThat(anomalyDetectionPolicy.wakeupAlarmDetectionEnabled).isFalse();
-        assertThat(anomalyDetectionPolicy.wakeupAlarmThreshold).isEqualTo(60);
-        assertThat(anomalyDetectionPolicy.bluetoothScanDetectionEnabled).isTrue();
+        assertThat(anomalyDetectionPolicy.wakeupAlarmThreshold).isEqualTo(10);
+        assertThat(anomalyDetectionPolicy.wakeupBlacklistedTags).isNull();
+        assertThat(anomalyDetectionPolicy.bluetoothScanDetectionEnabled).isFalse();
         assertThat(anomalyDetectionPolicy.bluetoothScanThreshold).isEqualTo(
                 30 * DateUtils.MINUTE_IN_MILLIS);
     }
 
     @Test
-    public void testIsAnomalyDetectorEnabled() {
+    public void testIsAnomalyDetectorEnabled_usesConfigValues() {
         AnomalyDetectionPolicy anomalyDetectionPolicy = createAnomalyPolicyWithConfig();
 
         assertThat(anomalyDetectionPolicy.isAnomalyDetectorEnabled(
@@ -103,18 +108,37 @@
                 Anomaly.AnomalyType.BLUETOOTH_SCAN)).isTrue();
     }
 
+    @Test
+    public void testIsAnomalyDetectorEnabled_usesDefaultValues() {
+        Settings.Global.putString(mContext.getContentResolver(),
+                Settings.Global.ANOMALY_DETECTION_CONSTANTS, "");
+        // Mock it to avoid noSuchMethodError
+        doReturn(true).when(mKeyValueListParserWrapper).getBoolean(anyString(), eq(true));
+        doReturn(false).when(mKeyValueListParserWrapper).getBoolean(anyString(), eq(false));
+
+        AnomalyDetectionPolicy anomalyDetectionPolicy = new AnomalyDetectionPolicy(mContext,
+                mKeyValueListParserWrapper);
+
+        assertThat(anomalyDetectionPolicy.isAnomalyDetectorEnabled(
+                Anomaly.AnomalyType.WAKE_LOCK)).isFalse();
+        assertThat(anomalyDetectionPolicy.isAnomalyDetectorEnabled(
+                Anomaly.AnomalyType.WAKEUP_ALARM)).isFalse();
+        assertThat(anomalyDetectionPolicy.isAnomalyDetectorEnabled(
+                Anomaly.AnomalyType.BLUETOOTH_SCAN)).isFalse();
+    }
+
     private AnomalyDetectionPolicy createAnomalyPolicyWithConfig() {
         Settings.Global.putString(mContext.getContentResolver(),
                 Settings.Global.ANOMALY_DETECTION_CONSTANTS, ANOMALY_DETECTION_CONSTANTS_VALUE);
         // Mock it to avoid noSuchMethodError
         doReturn(true).when(mKeyValueListParserWrapper).getBoolean(
-                AnomalyDetectionPolicy.KEY_ANOMALY_DETECTION_ENABLED, true);
+                AnomalyDetectionPolicy.KEY_ANOMALY_DETECTION_ENABLED, false);
         doReturn(false).when(mKeyValueListParserWrapper).getBoolean(
-                AnomalyDetectionPolicy.KEY_WAKELOCK_DETECTION_ENABLED, true);
+                AnomalyDetectionPolicy.KEY_WAKELOCK_DETECTION_ENABLED, false);
         doReturn(true).when(mKeyValueListParserWrapper).getBoolean(
                 AnomalyDetectionPolicy.KEY_WAKEUP_ALARM_DETECTION_ENABLED, false);
         doReturn(true).when(mKeyValueListParserWrapper).getBoolean(
-                AnomalyDetectionPolicy.KEY_BLUETOOTH_SCAN_DETECTION_ENABLED, true);
+                AnomalyDetectionPolicy.KEY_BLUETOOTH_SCAN_DETECTION_ENABLED, false);
 
         return new AnomalyDetectionPolicy(mContext, mKeyValueListParserWrapper);
     }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/anomaly/checker/WakeupAlarmAnomalyDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/anomaly/checker/WakeupAlarmAnomalyDetectorTest.java
index 55be734..13a5ab8 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/anomaly/checker/WakeupAlarmAnomalyDetectorTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/anomaly/checker/WakeupAlarmAnomalyDetectorTest.java
@@ -30,6 +30,7 @@
 import android.os.Build;
 import android.text.format.DateUtils;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 
 import com.android.internal.os.BatterySipper;
 import com.android.internal.os.BatteryStatsHelper;
@@ -52,6 +53,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Set;
 
 @RunWith(SettingsRobolectricTestRunner.class)
 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
@@ -69,6 +71,7 @@
             1 * DateUtils.HOUR_IN_MILLIS + 10 * DateUtils.MINUTE_IN_MILLIS;
     private static final int ANOMALY_WAKEUP_COUNT = 500;
     private static final int NORMAL_WAKEUP_COUNT = 61;
+    private static final int BLACKLISTED_WAKEUP_COUNT = 37;
     private static final int ANOMALY_WAKEUP_FREQUENCY = 428; // count per hour
     @Mock
     private BatteryStatsHelper mBatteryStatsHelper;
@@ -87,12 +90,12 @@
     @Mock
     private BatteryUtils mBatteryUtils;
     @Mock
-    private ApplicationInfo mApplicationInfo;
-    @Mock
     private BatteryStats.Uid.Pkg mPkg;
     @Mock
     private BatteryStats.Counter mCounter;
     @Mock
+    private BatteryStats.Counter mCounter2;
+    @Mock
     private AnomalyDetectionPolicy mPolicy;
     @Mock
     private AnomalyAction mAnomalyAction;
@@ -111,6 +114,9 @@
 
         mContext = spy(RuntimeEnvironment.application);
         ReflectionHelpers.setField(mPolicy, "wakeupAlarmThreshold", 60);
+        final Set<String> blacklistedTags = new ArraySet<>();
+        blacklistedTags.add("blacklistedTag");
+        ReflectionHelpers.setField(mPolicy, "wakeupBlacklistedTags", blacklistedTags);
 
         doReturn(false).when(mBatteryUtils).shouldHideSipper(any());
         doReturn(RUNNING_TIME_MS).when(mBatteryUtils).calculateRunningTimeBasedOnStatsType(any(),
@@ -207,4 +213,20 @@
         assertThat(mWakeupAlarmAnomalyDetector.getWakeupAlarmCountFromUid(mAnomalyUid)).isEqualTo(
                 2 * NORMAL_WAKEUP_COUNT);
     }
+
+    @Test
+    public void testGetWakeupAlarmCountFromUid_filterOutBlacklistedTags() {
+        final ArrayMap<String, BatteryStats.Uid.Pkg> packageStats = new ArrayMap<>();
+        final ArrayMap<String, BatteryStats.Counter> alarms = new ArrayMap<>();
+        doReturn(alarms).when(mPkg).getWakeupAlarmStats();
+        doReturn(NORMAL_WAKEUP_COUNT).when(mCounter).getCountLocked(anyInt());
+        doReturn(BLACKLISTED_WAKEUP_COUNT).when(mCounter2).getCountLocked(anyInt());
+        doReturn(packageStats).when(mAnomalyUid).getPackageStats();
+        packageStats.put("", mPkg);
+        alarms.put("allowedTag", mCounter);
+        alarms.put("blacklistedTag", mCounter2);
+
+        assertThat(mWakeupAlarmAnomalyDetector.getWakeupAlarmCountFromUid(mAnomalyUid)).isEqualTo(
+                NORMAL_WAKEUP_COUNT);
+    }
 }