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

Commit 563d1c29 authored by Bryce Lee's avatar Bryce Lee Committed by Android (Google) Code Review
Browse files

Merge changes from topic "408229468api" into main

* changes:
  Allow granular ambient suppression.
  Low-light dream behavior flag introduction.
parents 2907d1e8 ba5ad9b2
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -146,6 +146,10 @@ interface IPowerManager
    boolean isAmbientDisplayAvailable();
    // suppresses the current ambient display configuration and disables ambient display.
    void suppressAmbientDisplay(String token, boolean suppress);
    // suppresses the current ambient display configuration and disables ambient display based on
    // the specified flags.
    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE)")
    oneway void suppressAmbientDisplayBehavior(String token, int suppressionFlags);
    // returns whether ambient display is suppressed by the calling app with the given token.
    boolean isAmbientDisplaySuppressedForToken(String token);
    // returns whether ambient display is suppressed by any app with any token.
+68 −0
Original line number Diff line number Diff line
@@ -392,6 +392,53 @@ public final class PowerManager {
    @Retention(RetentionPolicy.SOURCE)
    public @interface UserActivityEvent{}

    /**
     * Flag to represent no suppression
     *
     * @hide
     */
    @FlaggedApi(Flags.FLAG_LOW_LIGHT_DREAM_BEHAVIOR)
    public static final int FLAG_AMBIENT_SUPPRESSION_NONE = 0;

    /**
     * Flag to represent dream suppression
     *
     * @hide
     */
    @FlaggedApi(Flags.FLAG_LOW_LIGHT_DREAM_BEHAVIOR)
    public static final int FLAG_AMBIENT_SUPPRESSION_DREAM = 1;

    /**
     * Flag to represent AOD suppression
     *
     * @hide
     */
    @FlaggedApi(Flags.FLAG_LOW_LIGHT_DREAM_BEHAVIOR)
    public static final int FLAG_AMBIENT_SUPPRESSION_AOD = 1 << 1;

    /**
     * Flag to represent suppressing everything
     *
     * @hide
     */
    @FlaggedApi(Flags.FLAG_LOW_LIGHT_DREAM_BEHAVIOR)
    public static final int FLAG_AMBIENT_SUPPRESSION_ALL =
            FLAG_AMBIENT_SUPPRESSION_DREAM
                    | FLAG_AMBIENT_SUPPRESSION_AOD;

    /**
     * @hide
     */
    @IntDef(flag = true, prefix = {"FLAG_AMBIENT_SUPPRESSION_"}, value = {
            FLAG_AMBIENT_SUPPRESSION_NONE,
            FLAG_AMBIENT_SUPPRESSION_DREAM,
            FLAG_AMBIENT_SUPPRESSION_AOD,
            FLAG_AMBIENT_SUPPRESSION_ALL,
    })
    @Retention(RetentionPolicy.SOURCE)
    @FlaggedApi(Flags.FLAG_LOW_LIGHT_DREAM_BEHAVIOR)
    public @interface FlagAmbientSuppression{}

    /**
     *
     * Convert the user activity event to a string for debugging purposes.
@@ -3174,6 +3221,27 @@ public final class PowerManager {
        }
    }

    /**
     * Suppresses the current ambient display configuration and disables ambient display.
     *
     * <p>This method has no effect if {@link #isAmbientDisplayAvailable()} is false.
     *
     * @param token A persistable identifier for the ambient display suppression that is unique
     *              within the calling application.
     * @param suppressionFlags Flags that describe how the ambient display should be suppressed.
     * @hide
     */
    @FlaggedApi(Flags.FLAG_LOW_LIGHT_DREAM_BEHAVIOR)
    @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE)
    public void suppressAmbientDisplay(@NonNull String token,
            @FlagAmbientSuppression  int suppressionFlags) {
        try {
            mService.suppressAmbientDisplayBehavior(token, suppressionFlags);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Returns true if ambient display is suppressed by the calling app with the given
     * {@code token}.
+7 −0
Original line number Diff line number Diff line
@@ -264,6 +264,13 @@ flag {
     is_exported: true
}

flag {
    name: "low_light_dream_behavior"
    namespace: "systemui"
    description: "New low light dream behavior"
    bug: "408229468"
}

flag {
     name: "mainline_vcn_platform_api"
     namespace: "vcn"
+111 −8
Original line number Diff line number Diff line
@@ -20,10 +20,12 @@ import static java.util.Objects.requireNonNull;

import android.annotation.NonNull;
import android.content.Context;
import android.os.Flags;
import android.os.PowerManager;
import android.os.PowerManager.FlagAmbientSuppression;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.ArraySet;
import android.util.Pair;
import android.util.Slog;

import com.android.internal.statusbar.IStatusBarService;
@@ -31,7 +33,9 @@ import com.android.internal.statusbar.IStatusBarService;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
@@ -40,7 +44,20 @@ import java.util.Set;
public class AmbientDisplaySuppressionController {
    private static final String TAG = "AmbientDisplaySuppressionController";

    private final Set<Pair<String, Integer>> mSuppressionTokens;
    /**
     * A {@link SuppressionToken} is a unique identifier for a suppression request. It is unique
     * based on an id (determined by the controller) and a tag (determined by the process).
     */
    private record SuppressionToken(int id, String tag) {
        public boolean belongsToId(int id) {
            return this.id() == id;
        }
    }

    private final Set<SuppressionToken> mSuppressionTokens;

    private final Map<SuppressionToken, Integer> mSuppressions;

    private final AmbientDisplaySuppressionChangedCallback mCallback;
    private IStatusBarService mStatusBarService;

@@ -52,23 +69,33 @@ public class AmbientDisplaySuppressionController {
         * @param isSuppressed Whether ambient is suppressed.
         */
        void onSuppressionChanged(boolean isSuppressed);

        /**
         * Called when the suppression state changes.
         *
         * @param suppressionState the new aggregate suppression state.
         */
        void onSuppressionChanged(@FlagAmbientSuppression int suppressionState);
    }

    AmbientDisplaySuppressionController(
            @NonNull AmbientDisplaySuppressionChangedCallback callback) {
        mSuppressionTokens = Collections.synchronizedSet(new ArraySet<>());
        mSuppressions = Collections.synchronizedMap(new HashMap<>());
        mCallback = requireNonNull(callback);
    }

    /**
     * Suppresses ambient display.
     *
     * @deprecated Use {@link #suppress(String, int, int)} instead.
     * @param token A persistible identifier for the ambient display suppression.
     * @param callingUid The uid of the calling application.
     * @param suppress If true, suppresses the ambient display. Otherwise, unsuppresses it.
     */
    @Deprecated
    public void suppress(@NonNull String token, int callingUid, boolean suppress) {
        Pair<String, Integer> suppressionToken = Pair.create(requireNonNull(token), callingUid);
        SuppressionToken suppressionToken = new SuppressionToken(callingUid, requireNonNull(token));
        final boolean wasSuppressed = isSuppressed();

        if (suppress) {
@@ -91,6 +118,41 @@ public class AmbientDisplaySuppressionController {
        }
    }

    /**
     * Suppresses ambient display.
     *
     * @param token A persistible identifier for the ambient display suppression.
     * @param callingUid The uid of the calling application.
     * @param suppressionFlags flags specifying how to suppress the ambient display.
     */
    public void suppress(@NonNull String token, int callingUid,
            @FlagAmbientSuppression int suppressionFlags) {
        final SuppressionToken suppressionToken =
                new SuppressionToken(callingUid, requireNonNull(token));
        final int existingSuppression = calculateSuppression();

        if (suppressionFlags != PowerManager.FLAG_AMBIENT_SUPPRESSION_NONE) {
            mSuppressions.put(suppressionToken, suppressionFlags);
        } else {
            mSuppressions.remove(suppressionToken);
        }

        final int currentSuppression = calculateSuppression();
        if (existingSuppression != currentSuppression) {
            mCallback.onSuppressionChanged(currentSuppression);
        }

        try {
            synchronized (mSuppressionTokens) {
                getStatusBar().suppressAmbientDisplay(
                        (suppressionFlags & PowerManager.FLAG_AMBIENT_SUPPRESSION_AOD)
                                == PowerManager.FLAG_AMBIENT_SUPPRESSION_AOD);
            }
        } catch (RemoteException e) {
            Slog.e(TAG, "Failed to suppress ambient display", e);
        }
    }

    /**
     * Returns the tokens used to suppress ambient display through
     * {@link #suppress(String, int, boolean)}.
@@ -99,10 +161,21 @@ public class AmbientDisplaySuppressionController {
     */
    List<String> getSuppressionTokens(int callingUid) {
        List<String> result = new ArrayList<>();

        if (Flags.lowLightDreamBehavior()) {
            synchronized (mSuppressions) {
                for (Map.Entry<SuppressionToken, Integer> entry : mSuppressions.entrySet()) {
                    if (entry.getKey().belongsToId(callingUid)) {
                        result.add(entry.getKey().tag);
                    }
                }
            }
        } else {
            synchronized (mSuppressionTokens) {
            for (Pair<String, Integer> token : mSuppressionTokens) {
                if (token.second == callingUid) {
                    result.add(token.first);
                for (SuppressionToken token: mSuppressionTokens) {
                    if (token.belongsToId(callingUid)) {
                        result.add(token.tag);
                    }
                }
            }
        }
@@ -116,13 +189,39 @@ public class AmbientDisplaySuppressionController {
     * @param callingUid The uid of the calling application.
     */
    public boolean isSuppressed(@NonNull String token, int callingUid) {
        return mSuppressionTokens.contains(Pair.create(requireNonNull(token), callingUid));
        if (Flags.lowLightDreamBehavior()) {
            return mSuppressions.containsKey(
                    new SuppressionToken(callingUid, requireNonNull(token)));
        }

        return mSuppressionTokens.contains(new SuppressionToken(callingUid, requireNonNull(token)));
    }

    /**
     * Calculates the current ambient suppression by aggregating the flags across active
     * suppressions.
     * @return the aggregate suppression flags from all active suppressions
     */
    public @FlagAmbientSuppression int calculateSuppression() {
        int suppression = PowerManager.FLAG_AMBIENT_SUPPRESSION_NONE;
        synchronized (mSuppressions) {
            for (Map.Entry<SuppressionToken, Integer> entry : mSuppressions.entrySet()) {
                suppression |= entry.getValue();
            }
        }

        return suppression;
    }

    /**
     * Returns whether ambient display is suppressed.
     */
    public boolean isSuppressed() {
        if (Flags.lowLightDreamBehavior()) {
            return (calculateSuppression() & PowerManager.FLAG_AMBIENT_SUPPRESSION_DREAM)
                    == PowerManager.FLAG_AMBIENT_SUPPRESSION_DREAM;
        }

        return !mSuppressionTokens.isEmpty();
    }

@@ -134,6 +233,10 @@ public class AmbientDisplaySuppressionController {
        pw.println("AmbientDisplaySuppressionController:");
        pw.println(" ambientDisplaySuppressed=" + isSuppressed());
        pw.println(" mSuppressionTokens=" + mSuppressionTokens);

        if (Flags.lowLightDreamBehavior()) {
            pw.println(" mSuppressions=" + mSuppressions);
        }
    }

    private synchronized IStatusBarService getStatusBar() {
+62 −0
Original line number Diff line number Diff line
@@ -75,6 +75,7 @@ import android.os.BatteryManagerInternal;
import android.os.BatterySaverPolicyConfig;
import android.os.Binder;
import android.os.Build;
import android.os.Flags;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.IBinder;
@@ -85,6 +86,7 @@ import android.os.Looper;
import android.os.Message;
import android.os.ParcelDuration;
import android.os.PowerManager;
import android.os.PowerManager.FlagAmbientSuppression;
import android.os.PowerManager.GoToSleepReason;
import android.os.PowerManager.ServiceType;
import android.os.PowerManager.WakeReason;
@@ -3592,6 +3594,27 @@ public final class PowerManagerService extends SystemService
        }
    }

    @GuardedBy("mLock")
    private void onDreamSuppressionChangedLocked(
            @FlagAmbientSuppression final int suppressionFlags) {
        if (!mDreamsDisabledByAmbientModeSuppressionConfig) {
            return;
        }

        final boolean isSuppressed = suppressionFlags != PowerManager.FLAG_AMBIENT_SUPPRESSION_NONE;

        final PowerGroup defaultPowerGroup = mPowerGroups.get(Display.DEFAULT_DISPLAY_GROUP);
        if (!isSuppressed && mIsPowered && mDreamsSupportedConfig && mDreamsEnabledSetting
                && shouldNapAtBedTimeLocked(defaultPowerGroup)
                && isItBedTimeYetLocked(defaultPowerGroup)) {
            napInternal(SystemClock.uptimeMillis(), Process.SYSTEM_UID, /* allowWake= */ true);
        } else if (isSuppressed) {
            mDirty |= DIRTY_SETTINGS;
            updatePowerStateLocked();
        }
    }

    @Deprecated
    @GuardedBy("mLock")
    private void onDreamSuppressionChangedLocked(final boolean isSuppressed) {
        if (!mDreamsDisabledByAmbientModeSuppressionConfig) {
@@ -5438,6 +5461,13 @@ public final class PowerManagerService extends SystemService
                        onDreamSuppressionChangedLocked(isSuppressed);
                    }
                }

                @Override
                public void onSuppressionChanged(int suppressionState) {
                    synchronized (mLock) {
                        onDreamSuppressionChangedLocked(suppressionState);
                    }
                }
            };

    /**
@@ -7044,6 +7074,14 @@ public final class PowerManagerService extends SystemService

        @Override // Binder call
        public void suppressAmbientDisplay(@NonNull String token, boolean suppress) {
            if (Flags.lowLightDreamBehavior()) {
                // Use flagged-based suppression if new behavior is available.
                suppressAmbientDisplayBehavior(token, suppress
                        ? PowerManager.FLAG_AMBIENT_SUPPRESSION_ALL
                        : PowerManager.FLAG_AMBIENT_SUPPRESSION_NONE);
                return;
            }

            mContext.enforceCallingOrSelfPermission(
                    android.Manifest.permission.WRITE_DREAM_STATE, null);

@@ -7056,6 +7094,30 @@ public final class PowerManagerService extends SystemService
            }
        }

        @Override // Binder call
        public void suppressAmbientDisplayBehavior(@NonNull String token,
                @FlagAmbientSuppression int flags) {
            if (!Flags.lowLightDreamBehavior()) {
                throw new IllegalArgumentException("suppressAmbientDisplayBehavior should only"
                        + "be called if lowLightDreamBehavior is enabled");
            }

            // sanitize the input to known flags.
            flags &= PowerManager.FLAG_AMBIENT_SUPPRESSION_ALL;

            mContext.enforceCallingOrSelfPermission(
                    android.Manifest.permission.WRITE_DREAM_STATE, null);

            final int uid = Binder.getCallingUid();
            final long ident = Binder.clearCallingIdentity();
            try {
                mAmbientDisplaySuppressionController.suppress(token, uid, flags);
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
        }


        @Override // Binder call
        public boolean isAmbientDisplaySuppressedForToken(@NonNull String token) {
            mContext.enforceCallingOrSelfPermission(
Loading