Add default phone/sms to battery whitelist apps.

This is to prevent essential default apps from being restricted in using
battery in the background.

Change-Id: Iac9db9c425a477680e41f73b2c0e7bc4e161ce9e
Merged-In: Iac9db9c425a477680e41f73b2c0e7bc4e161ce9e
Fixes: 76435804
Bug: 80428049
Test: robotests
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java
index b7699f1..7234788 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java
@@ -16,15 +16,19 @@
 
 package com.android.settingslib.fuelgauge;
 
+import android.content.ComponentName;
+import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.IDeviceIdleController;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.UserHandle;
 import android.support.annotation.VisibleForTesting;
+import android.telecom.DefaultDialerManager;
+import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.Log;
 
+import com.android.internal.telephony.SmsApplication;
 import com.android.internal.util.ArrayUtils;
 
 /**
@@ -38,19 +42,20 @@
 
     private static PowerWhitelistBackend sInstance;
 
+    private final Context mAppContext;
     private final IDeviceIdleController mDeviceIdleService;
     private final ArraySet<String> mWhitelistedApps = new ArraySet<>();
     private final ArraySet<String> mSysWhitelistedApps = new ArraySet<>();
     private final ArraySet<String> mSysWhitelistedAppsExceptIdle = new ArraySet<>();
 
-    public PowerWhitelistBackend() {
-        mDeviceIdleService = IDeviceIdleController.Stub.asInterface(
-                ServiceManager.getService(DEVICE_IDLE_SERVICE));
-        refreshList();
+    public PowerWhitelistBackend(Context context) {
+        this(context, IDeviceIdleController.Stub.asInterface(
+                ServiceManager.getService(DEVICE_IDLE_SERVICE)));
     }
 
     @VisibleForTesting
-    PowerWhitelistBackend(IDeviceIdleController deviceIdleService) {
+    PowerWhitelistBackend(Context context, IDeviceIdleController deviceIdleService) {
+        mAppContext = context.getApplicationContext();
         mDeviceIdleService = deviceIdleService;
         refreshList();
     }
@@ -64,7 +69,27 @@
     }
 
     public boolean isWhitelisted(String pkg) {
-        return mWhitelistedApps.contains(pkg);
+        if (mWhitelistedApps.contains(pkg)) {
+            return true;
+        }
+
+        // Additionally, check if pkg is default dialer/sms. They are considered essential apps and
+        // should be automatically whitelisted (otherwise user may be able to set restriction on
+        // them, leading to bad device behavior.)
+        if (!mAppContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            return false;
+        }
+        final ComponentName defaultSms = SmsApplication.getDefaultSmsApplication(mAppContext,
+                true /* updateIfNeeded */);
+        if (defaultSms != null && TextUtils.equals(pkg, defaultSms.getPackageName())) {
+            return true;
+        }
+
+        final String defaultDialer = DefaultDialerManager.getDefaultDialerApplication(mAppContext);
+        if (TextUtils.equals(pkg, defaultDialer)) {
+            return true;
+        }
+        return false;
     }
 
     public boolean isWhitelisted(String[] pkgs) {
@@ -120,16 +145,19 @@
         mSysWhitelistedApps.clear();
         mSysWhitelistedAppsExceptIdle.clear();
         mWhitelistedApps.clear();
+        if (mDeviceIdleService == null) {
+            return;
+        }
         try {
-            String[] whitelistedApps = mDeviceIdleService.getFullPowerWhitelist();
+            final String[] whitelistedApps = mDeviceIdleService.getFullPowerWhitelist();
             for (String app : whitelistedApps) {
                 mWhitelistedApps.add(app);
             }
-            String[] sysWhitelistedApps = mDeviceIdleService.getSystemPowerWhitelist();
+            final String[] sysWhitelistedApps = mDeviceIdleService.getSystemPowerWhitelist();
             for (String app : sysWhitelistedApps) {
                 mSysWhitelistedApps.add(app);
             }
-            String[] sysWhitelistedAppsExceptIdle =
+            final String[] sysWhitelistedAppsExceptIdle =
                     mDeviceIdleService.getSystemPowerWhitelistExceptIdle();
             for (String app : sysWhitelistedAppsExceptIdle) {
                 mSysWhitelistedAppsExceptIdle.add(app);
@@ -139,9 +167,9 @@
         }
     }
 
-    public static PowerWhitelistBackend getInstance() {
+    public static PowerWhitelistBackend getInstance(Context context) {
         if (sInstance == null) {
-            sInstance = new PowerWhitelistBackend();
+            sInstance = new PowerWhitelistBackend(context);
         }
         return sInstance;
     }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
index 0af2c05..a23eebc 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
@@ -23,35 +23,52 @@
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.verify;
 
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager;
 import android.os.IDeviceIdleController;
 
 import com.android.settingslib.SettingsLibRobolectricTestRunner;
+import com.android.settingslib.testutils.shadow.ShadowDefaultDialerManager;
+import com.android.settingslib.testutils.shadow.ShadowSmsApplication;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadow.api.Shadow;
+import org.robolectric.shadows.ShadowPackageManager;
 
 @RunWith(SettingsLibRobolectricTestRunner.class)
+@Config(shadows = {ShadowDefaultDialerManager.class, ShadowSmsApplication.class})
 public class PowerWhitelistBackendTest {
 
     private static final String PACKAGE_ONE = "com.example.packageone";
     private static final String PACKAGE_TWO = "com.example.packagetwo";
 
-    private PowerWhitelistBackend mPowerWhitelistBackend;
     @Mock
     private IDeviceIdleController mDeviceIdleService;
 
+    private PowerWhitelistBackend mPowerWhitelistBackend;
+    private ShadowPackageManager mPackageManager;
+    private Context mContext;
+
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
+        mContext = RuntimeEnvironment.application;
         doReturn(new String[] {}).when(mDeviceIdleService).getFullPowerWhitelist();
         doReturn(new String[] {}).when(mDeviceIdleService).getSystemPowerWhitelist();
         doReturn(new String[] {}).when(mDeviceIdleService).getSystemPowerWhitelistExceptIdle();
         doNothing().when(mDeviceIdleService).addPowerSaveWhitelistApp(anyString());
         doNothing().when(mDeviceIdleService).removePowerSaveWhitelistApp(anyString());
-        mPowerWhitelistBackend = new PowerWhitelistBackend(mDeviceIdleService);
+        mPackageManager = Shadow.extract(mContext.getPackageManager());
+        mPackageManager.setSystemFeature(PackageManager.FEATURE_TELEPHONY, true);
+
+        mPowerWhitelistBackend = new PowerWhitelistBackend(mContext, mDeviceIdleService);
     }
 
     @Test
@@ -61,8 +78,8 @@
 
         assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isTrue();
         assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_TWO)).isFalse();
-        assertThat(mPowerWhitelistBackend.isWhitelisted(new String[]{PACKAGE_ONE})).isTrue();
-        assertThat(mPowerWhitelistBackend.isWhitelisted(new String[]{PACKAGE_TWO})).isFalse();
+        assertThat(mPowerWhitelistBackend.isWhitelisted(new String[] {PACKAGE_ONE})).isTrue();
+        assertThat(mPowerWhitelistBackend.isWhitelisted(new String[] {PACKAGE_TWO})).isFalse();
 
         mPowerWhitelistBackend.addApp(PACKAGE_TWO);
 
@@ -70,15 +87,15 @@
         assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isTrue();
         assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_TWO)).isTrue();
         assertThat(mPowerWhitelistBackend.isWhitelisted(
-                new String[]{PACKAGE_ONE, PACKAGE_TWO})).isTrue();
+                new String[] {PACKAGE_ONE, PACKAGE_TWO})).isTrue();
 
         mPowerWhitelistBackend.removeApp(PACKAGE_TWO);
 
         verify(mDeviceIdleService, atLeastOnce()).removePowerSaveWhitelistApp(PACKAGE_TWO);
         assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isTrue();
         assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_TWO)).isFalse();
-        assertThat(mPowerWhitelistBackend.isWhitelisted(new String[]{PACKAGE_ONE})).isTrue();
-        assertThat(mPowerWhitelistBackend.isWhitelisted(new String[]{PACKAGE_TWO})).isFalse();
+        assertThat(mPowerWhitelistBackend.isWhitelisted(new String[] {PACKAGE_ONE})).isTrue();
+        assertThat(mPowerWhitelistBackend.isWhitelisted(new String[] {PACKAGE_TWO})).isFalse();
 
         mPowerWhitelistBackend.removeApp(PACKAGE_ONE);
 
@@ -86,7 +103,23 @@
         assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isFalse();
         assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_TWO)).isFalse();
         assertThat(mPowerWhitelistBackend.isWhitelisted(
-                new String[]{PACKAGE_ONE, PACKAGE_TWO})).isFalse();
+                new String[] {PACKAGE_ONE, PACKAGE_TWO})).isFalse();
+    }
+
+    @Test
+    public void isWhitelisted_shouldWhitelistDefaultSms() {
+        final String testSms = "com.android.test.defaultsms";
+        ShadowSmsApplication.setDefaultSmsApplication(new ComponentName(testSms, "receiver"));
+
+        assertThat(mPowerWhitelistBackend.isWhitelisted(testSms)).isTrue();
+    }
+
+    @Test
+    public void isWhitelisted_shouldWhitelistDefaultDialer() {
+        final String testDialer = "com.android.test.defaultdialer";
+        ShadowDefaultDialerManager.setDefaultDialerApplication(testDialer);
+
+        assertThat(mPowerWhitelistBackend.isWhitelisted(testDialer)).isTrue();
     }
 
     @Test
@@ -101,7 +134,7 @@
 
     @Test
     public void testIsSystemWhitelistedExceptIdle_onePackage() throws Exception {
-        doReturn(new String[]{PACKAGE_TWO}).when(
+        doReturn(new String[] {PACKAGE_TWO}).when(
                 mDeviceIdleService).getSystemPowerWhitelistExceptIdle();
         mPowerWhitelistBackend.refreshList();
 
@@ -111,7 +144,7 @@
 
     @Test
     public void testIsSystemWhitelistedExceptIdle_packageArray() throws Exception {
-        doReturn(new String[]{PACKAGE_TWO}).when(
+        doReturn(new String[] {PACKAGE_TWO}).when(
                 mDeviceIdleService).getSystemPowerWhitelistExceptIdle();
         mPowerWhitelistBackend.refreshList();
 
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowDefaultDialerManager.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowDefaultDialerManager.java
new file mode 100644
index 0000000..f4afdb1
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowDefaultDialerManager.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2018 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.settingslib.testutils.shadow;
+
+import android.content.Context;
+import android.telecom.DefaultDialerManager;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.Resetter;
+
+@Implements(DefaultDialerManager.class)
+public class ShadowDefaultDialerManager {
+
+    private static String sDefaultDailer;
+
+    @Resetter
+    public void reset() {
+        sDefaultDailer = null;
+    }
+
+    @Implementation
+    public static String getDefaultDialerApplication(Context context) {
+        return sDefaultDailer;
+    }
+
+    public static void setDefaultDialerApplication(String dialer) {
+        sDefaultDailer = dialer;
+    }
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowSmsApplication.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowSmsApplication.java
new file mode 100644
index 0000000..dd7b007
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowSmsApplication.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018 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.settingslib.testutils.shadow;
+
+import android.content.ComponentName;
+import android.content.Context;
+
+import com.android.internal.telephony.SmsApplication;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.Resetter;
+
+@Implements(SmsApplication.class)
+public class ShadowSmsApplication {
+
+    private static ComponentName sDefaultSmsApplication;
+
+    @Resetter
+    public void reset() {
+        sDefaultSmsApplication = null;
+    }
+
+    @Implementation
+    public static ComponentName getDefaultSmsApplication(Context context, boolean updateIfNeeded) {
+        return sDefaultSmsApplication;
+    }
+
+    public static void setDefaultSmsApplication(ComponentName cn) {
+        sDefaultSmsApplication = cn;
+    }
+}
\ No newline at end of file