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