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

Commit ff61d887 authored by Makoto Onuki's avatar Makoto Onuki Committed by Android (Google) Code Review
Browse files

Merge "Implement new BS warning / notification flow (1/2)" into pi-dev

parents b2637dac 16a0dd2d
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -7761,6 +7761,22 @@ public final class Settings {
         */
        public static final String BLUETOOTH_ON_WHILE_DRIVING = "bluetooth_on_while_driving";

        /**
         * The number of times (integer) the user has manually enabled battery saver.
         * @hide
         */
        public static final String LOW_POWER_MANUAL_ACTIVATION_COUNT =
                "low_power_manual_activation_count";

        /**
         * Whether the "first time battery saver warning" dialog needs to be shown (0: default)
         * or not (1).
         *
         * @hide
         */
        public static final String LOW_POWER_WARNING_ACKNOWLEDGED =
                "low_power_warning_acknowledged";

        /**
         * This are the settings to be backed up.
         *
+1 −1
Original line number Diff line number Diff line
@@ -4475,7 +4475,7 @@
    <string name="package_deleted_device_owner">Deleted by your admin</string>

    <!-- [CHAR_LIMIT=NONE] Battery saver: Feature description -->
    <string name="battery_saver_description">To help improve battery life, Battery Saver reduces your devices performance and limits vibration, location services, and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery Saver turns off automatically when your device is charging.</string>
    <string name="battery_saver_description">To extend battery life, Battery Saver reduces your device\'s performance and limits or turns off vibration, location services, and background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery Saver turns off automatically when your device is charging.</string>

    <!-- [CHAR_LIMIT=NONE] Data saver: Feature description -->
    <string name="data_saver_description">To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app you’re currently using can access data, but may do so less frequently. This may mean, for example, that images don’t display until you tap them.</string>
+3 −1
Original line number Diff line number Diff line
@@ -581,7 +581,9 @@ public class SettingsBackupTest {
                 Settings.Secure.KEYGUARD_SLICE_URI,
                 Settings.Secure.PARENTAL_CONTROL_ENABLED,
                 Settings.Secure.PARENTAL_CONTROL_REDIRECT_URL,
                 Settings.Secure.BLUETOOTH_ON_WHILE_DRIVING);
                 Settings.Secure.BLUETOOTH_ON_WHILE_DRIVING,
                 Settings.Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT,
                 Settings.Secure.LOW_POWER_WARNING_ACKNOWLEDGED);

    @Test
    public void systemSettingsBackedUpOrBlacklisted() {
+91 −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.fuelgauge;

import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.os.PowerManager;
import android.provider.Settings.Secure;
import android.util.Log;

/**
 * Utilities related to battery saver.
 */
public class BatterySaverUtils {
    private static final String TAG = "BatterySaverUtils";

    private BatterySaverUtils() {
    }

    private static final boolean DEBUG = false;

    // Broadcast action for SystemUI to show the battery saver confirmation dialog.
    public static final String ACTION_SHOW_START_SAVER_CONFIRMATION = "PNW.startSaverConfirmation";

    /**
     * Enable / disable battery saver by user request.
     * - If it's the first time and needFirstTimeWarning, show the first time dialog.
     * - If it's 4th time through 8th time, show the schedule suggestion notification.
     *
     * @param enable true to disable battery saver.
     *
     * @return true if the request succeeded.
     */
    public static synchronized boolean setPowerSaveMode(Context context,
            boolean enable, boolean needFirstTimeWarning) {
        if (DEBUG) {
            Log.d(TAG, "Battery saver turning " + (enable ? "ON" : "OFF"));
        }
        final ContentResolver cr = context.getContentResolver();

        if (enable && needFirstTimeWarning && maybeShowBatterySaverConfirmation(context)) {
            return false;
        }
        if (enable && !needFirstTimeWarning) {
            setBatterySaverConfirmationAcknowledged(context);
        }

        if (context.getSystemService(PowerManager.class).setPowerSaveMode(enable)) {
            if (enable) {
                Secure.putInt(cr, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT,
                        Secure.getInt(cr, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, 0) + 1);

                // TODO If enabling, and the count is between 4 and 8 (inclusive), then
                // show the "battery saver schedule suggestion" notification.
            }

            return true;
        }
        return false;
    }

    private static boolean maybeShowBatterySaverConfirmation(Context context) {
        if (Secure.getInt(context.getContentResolver(),
                Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 0) != 0) {
            return false; // Already shown.
        }
        final Intent i = new Intent(ACTION_SHOW_START_SAVER_CONFIRMATION);
        context.sendBroadcast(i);

        return true;
    }

    private static void setBatterySaverConfirmationAcknowledged(Context context) {
        Secure.putInt(context.getContentResolver(), Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 1);
    }
}
+152 −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.fuelgauge;

import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.os.PowerManager;
import android.provider.Settings.Secure;

import com.android.settingslib.SettingsLibRobolectricTestRunner;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;


@RunWith(SettingsLibRobolectricTestRunner.class)
public class BatterySaverUtilsTest {
    @Mock
    Context mMockContext;

    @Mock
    ContentResolver mMockResolver;

    @Mock
    PowerManager mMockPowerManager;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);

        when(mMockContext.getContentResolver()).thenReturn(mMockResolver);
        when(mMockContext.getSystemService(eq(PowerManager.class))).thenReturn(mMockPowerManager);
        when(mMockPowerManager.setPowerSaveMode(anyBoolean())).thenReturn(true);
    }

    @Test
    public void testSetPowerSaveMode_enable_firstCall_needWarning() throws Exception {
        Secure.putString(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, "null");
        Secure.putString(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, "null");

        assertEquals(false, BatterySaverUtils.setPowerSaveMode(mMockContext, true, true));

        verify(mMockContext, times(1)).sendBroadcast(any(Intent.class));
        verify(mMockPowerManager, times(0)).setPowerSaveMode(anyBoolean());

        // They shouldn't have changed.
        assertEquals(-1,
                Secure.getInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, -1));
        assertEquals(-2,
                Secure.getInt(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, -2));
    }

    @Test
    public void testSetPowerSaveMode_enable_secondCall_needWarning() throws Exception {
        Secure.putInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 1); // Already acked.
        Secure.putString(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, "null");

        assertEquals(true, BatterySaverUtils.setPowerSaveMode(mMockContext, true, true));

        verify(mMockContext, times(0)).sendBroadcast(any(Intent.class));
        verify(mMockPowerManager, times(1)).setPowerSaveMode(eq(true));

        assertEquals(1, Secure.getInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, -1));
        assertEquals(1, Secure.getInt(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, -2));
    }

    @Test
    public void testSetPowerSaveMode_enable_thridCall_needWarning() throws Exception {
        Secure.putInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 1); // Already acked.
        Secure.putInt(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, 1);

        assertEquals(true, BatterySaverUtils.setPowerSaveMode(mMockContext, true, true));

        verify(mMockContext, times(0)).sendBroadcast(any(Intent.class));
        verify(mMockPowerManager, times(1)).setPowerSaveMode(eq(true));

        assertEquals(1, Secure.getInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, -1));
        assertEquals(2, Secure.getInt(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, -2));
    }

    @Test
    public void testSetPowerSaveMode_enable_firstCall_noWarning() throws Exception {
        Secure.putString(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, "null");
        Secure.putString(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, "null");

        assertEquals(true, BatterySaverUtils.setPowerSaveMode(mMockContext, true, false));

        verify(mMockContext, times(0)).sendBroadcast(any(Intent.class));
        verify(mMockPowerManager, times(1)).setPowerSaveMode(eq(true));

        assertEquals(1, Secure.getInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, -1));
        assertEquals(1, Secure.getInt(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, -2));
    }

    @Test
    public void testSetPowerSaveMode_disable_firstCall_noWarning() throws Exception {
        Secure.putString(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, "null");
        Secure.putString(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, "null");

        // When disabling, needFirstTimeWarning doesn't matter.
        assertEquals(true, BatterySaverUtils.setPowerSaveMode(mMockContext, false, false));

        verify(mMockContext, times(0)).sendBroadcast(any(Intent.class));
        verify(mMockPowerManager, times(1)).setPowerSaveMode(eq(false));

        assertEquals(-1, Secure.getInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, -1));
        assertEquals(-2,
                Secure.getInt(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, -2));
    }

    @Test
    public void testSetPowerSaveMode_disable_firstCall_needWarning() throws Exception {
        Secure.putString(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, "null");
        Secure.putString(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, "null");

        // When disabling, needFirstTimeWarning doesn't matter.
        assertEquals(true, BatterySaverUtils.setPowerSaveMode(mMockContext, false, true));

        verify(mMockContext, times(0)).sendBroadcast(any(Intent.class));
        verify(mMockPowerManager, times(1)).setPowerSaveMode(eq(false));

        assertEquals(-1, Secure.getInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, -1));
        assertEquals(-2,
                Secure.getInt(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, -2));
    }
}
Loading