Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 091a0573 authored by Fan Zhang's avatar Fan Zhang
Browse files

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
parent 478923bd
Loading
Loading
Loading
Loading
+40 −12
Original line number Diff line number Diff line
@@ -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 @@ public class PowerWhitelistBackend {

    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 class PowerWhitelistBackend {
    }

    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 @@ public class PowerWhitelistBackend {
        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 class PowerWhitelistBackend {
        }
    }

    public static PowerWhitelistBackend getInstance() {
    public static PowerWhitelistBackend getInstance(Context context) {
        if (sInstance == null) {
            sInstance = new PowerWhitelistBackend();
            sInstance = new PowerWhitelistBackend(context);
        }
        return sInstance;
    }
+43 −10
Original line number Diff line number Diff line
@@ -23,35 +23,52 @@ import static org.mockito.Mockito.doNothing;
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
@@ -89,6 +106,22 @@ public class PowerWhitelistBackendTest {
                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
    public void testIsSystemWhitelisted() throws Exception {
        doReturn(new String[] {PACKAGE_ONE}).when(mDeviceIdleService).getSystemPowerWhitelist();
+44 −0
Original line number Diff line number Diff line
/*
 * 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
+46 −0
Original line number Diff line number Diff line
/*
 * 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