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

Commit fbb15392 authored by William Xiao's avatar William Xiao Committed by Android (Google) Code Review
Browse files

Merge "Allow dreaming when charge limit is active" into main

parents 5de3c42f 01af8ca1
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -100,3 +100,13 @@ flag {
  bug: "403579494"
  is_fixed_read_only: true
}

flag {
    name: "allow_dream_with_charge_limit"
    namespace: "systemui"
    description: "Allows dreaming even when a charge limit is active"
    bug: "397717022"
    metadata {
        purpose: PURPOSE_BUGFIX
    }
}
 No newline at end of file
+61 −14
Original line number Diff line number Diff line
@@ -20,7 +20,9 @@ import static android.Manifest.permission.BIND_DREAM_SERVICE;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.os.BatteryManager.EXTRA_CHARGING_STATUS;
import static android.service.dreams.Flags.allowDreamWhenPostured;
import static android.service.dreams.Flags.allowDreamWithChargeLimit;
import static android.service.dreams.Flags.cleanupDreamSettingsOnUninstall;
import static android.service.dreams.Flags.dreamHandlesBeingObscured;
import static android.service.dreams.Flags.dreamsV2;
@@ -46,6 +48,7 @@ import android.content.pm.PackageManagerInternal;
import android.content.pm.ServiceInfo;
import android.database.ContentObserver;
import android.hardware.display.AmbientDisplayConfiguration;
import android.hardware.health.BatteryChargingState;
import android.net.Uri;
import android.os.BatteryManager;
import android.os.BatteryManagerInternal;
@@ -120,6 +123,13 @@ public final class DreamManagerService extends SystemService {
    private static final int DREAM_ON_CHARGE = 1 << 1;
    private static final int DREAM_ON_POSTURED = 1 << 2;

    /**
     * Battery percentage at which the device stops charging when the charge limit feature is
     * enabled.
     */
    @VisibleForTesting
    static final int CHARGE_LIMIT_PERCENTAGE = 80;

    private final Object mLock = new Object();

    private final Context mContext;
@@ -206,13 +216,20 @@ public final class DreamManagerService extends SystemService {
                }
            };

    private final BroadcastReceiver mChargingReceiver = new BroadcastReceiver() {
    /**
     * Receiver for the {@link Intent#ACTION_BATTERY_CHANGED} broadcast.
     */
    private final BroadcastReceiver mBatteryChangedReceived = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
        public void onReceive(Context context, Intent batteryChangedIntent) {
            if (allowDreamWithChargeLimit()) {
                updateChargingStatus(batteryChangedIntent);
            } else {
                mIsCharging = mBatteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY);
                mIsWirelessCharging = mBatteryManagerInternal.isPowered(
                        BatteryManager.BATTERY_PLUGGED_WIRELESS);
            }
        }
    };

    private final BroadcastReceiver mDockStateReceiver = new BroadcastReceiver() {
@@ -320,10 +337,11 @@ public final class DreamManagerService extends SystemService {
            mContext.registerReceiver(
                    mDockStateReceiver, new IntentFilter(Intent.ACTION_DOCK_EVENT));

            IntentFilter chargingIntentFilter = new IntentFilter();
            chargingIntentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
            chargingIntentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
            mContext.registerReceiver(mChargingReceiver, chargingIntentFilter);
            // Broadcast is sticky so we don't need to query state directly.
            IntentFilter batteryChangedIntentFilter = new IntentFilter();
            batteryChangedIntentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
            batteryChangedIntentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
            mContext.registerReceiver(mBatteryChangedReceived, batteryChangedIntentFilter);

            mSettingsObserver = new SettingsObserver(mHandler);
            mContext.getContentResolver().registerContentObserver(Settings.Secure.getUriFor(
@@ -342,11 +360,13 @@ public final class DreamManagerService extends SystemService {
                            Settings.Secure.SCREENSAVER_RESTRICT_TO_WIRELESS_CHARGING),
                    false, mSettingsObserver, UserHandle.USER_ALL);

            if (!allowDreamWithChargeLimit()) {
                // We don't get an initial broadcast for the battery state, so we have to initialize
                // directly from BatteryManager.
                mIsCharging = mBatteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY);
                mIsWirelessCharging = mBatteryManagerInternal.isPowered(
                        BatteryManager.BATTERY_PLUGGED_WIRELESS);
            }

            updateWhenToDreamSettings();
        }
@@ -424,6 +444,33 @@ public final class DreamManagerService extends SystemService {
        }
    }

    private void updateChargingStatus(Intent batteryChangedIntent) {
        mIsWirelessCharging = mBatteryManagerInternal.isPowered(
                BatteryManager.BATTERY_PLUGGED_WIRELESS);

        if (mBatteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY)) {
            mIsCharging = true;
        } else {
            // When charge limit is enabled and the device is at the charge limit battery %, the
            // device stops charging entirely and the plug type is reported as BATTERY_PLUGGED_NONE.
            // Check if the feature is enabled so that the device can still dream when charge limit
            // is active.

            final ContentResolver resolver = mContext.getContentResolver();
            final boolean isChargeLimitEnabled = Settings.Secure.getIntForUser(resolver,
                    Settings.Secure.CHARGE_OPTIMIZATION_MODE, /*default=*/ 0,
                    UserHandle.USER_CURRENT) != 0;

            int chargingStatus = batteryChangedIntent.getIntExtra(EXTRA_CHARGING_STATUS,
                    BatteryChargingState.NORMAL);
            final boolean isChargeLimitActive =
                    mBatteryManagerInternal.getBatteryLevel() >= CHARGE_LIMIT_PERCENTAGE
                            && chargingStatus == BatteryChargingState.LONG_LIFE;

            mIsCharging = isChargeLimitEnabled && isChargeLimitActive;
        }
    }

    private void updateWhenToDreamSettings() {
        synchronized (mLock) {
            final ContentResolver resolver = mContext.getContentResolver();
+42 −0
Original line number Diff line number Diff line
@@ -16,11 +16,14 @@

package com.android.server.dreams;

import static android.os.BatteryManager.EXTRA_CHARGING_STATUS;
import static android.service.dreams.Flags.FLAG_DREAMS_V2;
import static android.service.dreams.Flags.FLAG_ALLOW_DREAM_WITH_CHARGE_LIMIT;

import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.server.dreams.DreamManagerService.CHARGE_LIMIT_PERCENTAGE;

import static com.google.common.truth.Truth.assertThat;

@@ -33,6 +36,7 @@ import android.app.ActivityManagerInternal;
import android.content.BroadcastReceiver;
import android.content.ContextWrapper;
import android.content.Intent;
import android.hardware.health.BatteryChargingState;
import android.os.BatteryManager;
import android.os.BatteryManagerInternal;
import android.os.PowerManagerInternal;
@@ -200,6 +204,44 @@ public class DreamManagerServiceTest {
        final DreamManagerService service = createService();
        service.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);

        // Battery changed event is received.
        ArgumentCaptor<BroadcastReceiver> receiverCaptor = ArgumentCaptor.forClass(
                BroadcastReceiver.class);
        verify(mContextSpy).registerReceiver(receiverCaptor.capture(),
                argThat((arg) -> arg.hasAction(Intent.ACTION_BATTERY_CHANGED)));
        receiverCaptor.getValue().onReceive(mContext, new Intent());

        // Dream condition is active.
        assertThat(service.dreamConditionActiveInternal()).isTrue();
    }

    @EnableFlags(FLAG_ALLOW_DREAM_WITH_CHARGE_LIMIT)
    @Test
    public void testDreamConditionActive_chargeLimitActive() {
        // Enable dreaming while charging only.
        Settings.Secure.putIntForUser(mContextSpy.getContentResolver(),
                Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, 1, UserHandle.USER_CURRENT);
        // Enable charge limit setting.
        Settings.Secure.putIntForUser(mContextSpy.getContentResolver(),
                Settings.Secure.CHARGE_OPTIMIZATION_MODE, 1, UserHandle.USER_CURRENT);

        // Device is not considered charging when charge limit is on.
        when(mBatteryManagerInternal.isPowered(anyInt())).thenReturn(false);
        when(mBatteryManagerInternal.getBatteryLevel()).thenReturn(CHARGE_LIMIT_PERCENTAGE);

        // Initialize service so settings are read.
        final DreamManagerService service = createService();
        service.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);

        // Battery changed event is received.
        ArgumentCaptor<BroadcastReceiver> receiverCaptor = ArgumentCaptor.forClass(
                BroadcastReceiver.class);
        verify(mContextSpy).registerReceiver(receiverCaptor.capture(),
                argThat((arg) -> arg.hasAction(Intent.ACTION_BATTERY_CHANGED)));
        Intent intent = new Intent();
        intent.putExtra(EXTRA_CHARGING_STATUS, BatteryChargingState.LONG_LIFE);
        receiverCaptor.getValue().onReceive(mContext, intent);

        // Dream condition is active.
        assertThat(service.dreamConditionActiveInternal()).isTrue();
    }