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

Commit 17834277 authored by Matías Hernández's avatar Matías Hernández Committed by Android (Google) Code Review
Browse files

Merge changes from topic "apply-night" into main

* changes:
  Fix BroadcastReceiver registration in DefaultDeviceEffectsApplier
  Apply Night Mode as part of ZenDeviceEffects
parents 09802a75 901ec941
Loading
Loading
Loading
Loading
+10 −1
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package android.service.notification;

import android.service.notification.ZenModeConfig.ConfigChangeOrigin;

/**
 * Responsible for making any service calls needed to apply the set of {@link ZenDeviceEffects} that
 * make sense for the current platform.
@@ -33,6 +35,13 @@ public interface DeviceEffectsApplier {
     *
     * <p>This will be called whenever the set of consolidated effects changes (normally through
     * the activation or deactivation of zen rules).
     *
     * @param effects The effects that should be active and inactive.
     * @param source The origin of the change. Because the application of specific effects can be
     *               disruptive (e.g. lead to Activity recreation), that operation can in some
     *               cases be deferred (e.g. until screen off). However, if the effects are
     *               changing as a result of an explicit user action, then it makes sense to
     *               apply them immediately regardless.
     */
    void apply(ZenDeviceEffects effects);
    void apply(ZenDeviceEffects effects, @ConfigChangeOrigin int source);
}
+63 −1
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;

import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.AlarmManager;
@@ -61,6 +62,8 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
@@ -79,7 +82,66 @@ import java.util.UUID;
 * @hide
 */
public class ZenModeConfig implements Parcelable {
    private static String TAG = "ZenModeConfig";
    private static final String TAG = "ZenModeConfig";

    /**
     * The {@link ZenModeConfig} is being updated because of an unknown reason.
     */
    public static final int UPDATE_ORIGIN_UNKNOWN = 0;

    /**
     * The {@link ZenModeConfig} is being updated because of system initialization (i.e. load from
     * storage, on device boot).
     */
    public static final int UPDATE_ORIGIN_INIT = 1;

    /** The {@link ZenModeConfig} is being updated (replaced) because of a user switch or unlock. */
    public static final int UPDATE_ORIGIN_INIT_USER = 2;

    /** The {@link ZenModeConfig} is being updated because of a user action, for example:
     * <ul>
     *     <li>{@link NotificationManager#setAutomaticZenRuleState} with a
     *     {@link Condition#source} equal to {@link Condition#SOURCE_USER_ACTION}.</li>
     *     <li>Adding, updating, or removing a rule from Settings.</li>
     *     <li>Directly activating or deactivating/snoozing a rule through some UI affordance (e.g.
     *     Quick Settings).</li>
     * </ul>
     */
    public static final int UPDATE_ORIGIN_USER = 3;

    /**
     * The {@link ZenModeConfig} is being "independently" updated by an app, and not as a result of
     * a user's action inside that app (for example, activating an {@link AutomaticZenRule} based on
     * a previously set schedule).
     */
    public static final int UPDATE_ORIGIN_APP = 4;

    /**
     * The {@link ZenModeConfig} is being updated by the System or SystemUI. Note that this only
     * includes cases where the call is coming from the System/SystemUI but the change is not due to
     * a user action (e.g. automatically activating a schedule-based rule). If the change is a
     * result of a user action (e.g. activating a rule by tapping on its QS tile) then
     * {@link #UPDATE_ORIGIN_USER} is used instead.
     */
    public static final int UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI = 5;

    /**
     * The {@link ZenModeConfig} is being updated (replaced) because the user's DND configuration
     * is being restored from a backup.
     */
    public static final int UPDATE_ORIGIN_RESTORE_BACKUP = 6;

    @IntDef(prefix = { "UPDATE_ORIGIN_" }, value = {
            UPDATE_ORIGIN_UNKNOWN,
            UPDATE_ORIGIN_INIT,
            UPDATE_ORIGIN_INIT_USER,
            UPDATE_ORIGIN_USER,
            UPDATE_ORIGIN_APP,
            UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI,
            UPDATE_ORIGIN_RESTORE_BACKUP
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface ConfigChangeOrigin {}

    public static final int SOURCE_ANYONE = Policy.PRIORITY_SENDERS_ANY;
    public static final int SOURCE_CONTACT = Policy.PRIORITY_SENDERS_CONTACTS;
+98 −12
Original line number Diff line number Diff line
@@ -16,14 +16,23 @@

package com.android.server.notification;

import static android.app.UiModeManager.MODE_NIGHT_CUSTOM_TYPE_BEDTIME;

import android.app.UiModeManager;
import android.app.WallpaperManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.display.ColorDisplayManager;
import android.os.Binder;
import android.os.PowerManager;
import android.service.notification.DeviceEffectsApplier;
import android.service.notification.ZenDeviceEffects;
import android.service.notification.ZenModeConfig;
import android.service.notification.ZenModeConfig.ConfigChangeOrigin;

import com.android.internal.annotations.GuardedBy;

/** Default implementation for {@link DeviceEffectsApplier}. */
class DefaultDeviceEffectsApplier implements DeviceEffectsApplier {
@@ -34,13 +43,24 @@ class DefaultDeviceEffectsApplier implements DeviceEffectsApplier {
    private static final int SATURATION_LEVEL_FULL_COLOR = 100;
    private static final float WALLPAPER_DIM_AMOUNT_DIMMED = 0.6f;
    private static final float WALLPAPER_DIM_AMOUNT_NORMAL = 0f;
    private static final IntentFilter SCREEN_OFF_INTENT_FILTER = new IntentFilter(
            Intent.ACTION_SCREEN_OFF);

    private final Context mContext;
    private final ColorDisplayManager mColorDisplayManager;
    private final PowerManager mPowerManager;
    private final UiModeManager mUiModeManager;
    private final WallpaperManager mWallpaperManager;

    private final Object mRegisterReceiverLock = new Object();
    @GuardedBy("mRegisterReceiverLock")
    private boolean mIsScreenOffReceiverRegistered;

    private ZenDeviceEffects mLastAppliedEffects = new ZenDeviceEffects.Builder().build();
    private boolean mPendingNightMode;

    DefaultDeviceEffectsApplier(Context context) {
        mContext = context;
        mColorDisplayManager = context.getSystemService(ColorDisplayManager.class);
        mPowerManager = context.getSystemService(PowerManager.class);
        mUiModeManager = context.getSystemService(UiModeManager.class);
@@ -48,24 +68,90 @@ class DefaultDeviceEffectsApplier implements DeviceEffectsApplier {
    }

    @Override
    public void apply(ZenDeviceEffects effects) {
    public void apply(ZenDeviceEffects effects, @ConfigChangeOrigin int origin) {
        Binder.withCleanCallingIdentity(() -> {
            if (mLastAppliedEffects.shouldSuppressAmbientDisplay()
                    != effects.shouldSuppressAmbientDisplay()) {
                mPowerManager.suppressAmbientDisplay(SUPPRESS_AMBIENT_DISPLAY_TOKEN,
                        effects.shouldSuppressAmbientDisplay());
            }

            if (mLastAppliedEffects.shouldDisplayGrayscale() != effects.shouldDisplayGrayscale()) {
                if (mColorDisplayManager != null) {
                    mColorDisplayManager.setSaturationLevel(
                            effects.shouldDisplayGrayscale() ? SATURATION_LEVEL_GRAYSCALE
                                    : SATURATION_LEVEL_FULL_COLOR);
                }
            }

            if (mLastAppliedEffects.shouldDimWallpaper() != effects.shouldDimWallpaper()) {
                if (mWallpaperManager != null) {
                    mWallpaperManager.setWallpaperDimAmount(
                            effects.shouldDimWallpaper() ? WALLPAPER_DIM_AMOUNT_DIMMED
                                    : WALLPAPER_DIM_AMOUNT_NORMAL);
                }
            }

            if (mLastAppliedEffects.shouldUseNightMode() != effects.shouldUseNightMode()) {
                updateOrScheduleNightMode(effects.shouldUseNightMode(), origin);
            }
        });

        mLastAppliedEffects = effects;
    }

    private void updateOrScheduleNightMode(boolean useNightMode, @ConfigChangeOrigin int origin) {
        mPendingNightMode = useNightMode;

        // Changing the theme can be disruptive for the user (Activities are likely recreated, may
        // lose some state). Therefore we only apply the change immediately if the rule was
        // activated manually, or we are initializing, or the screen is currently off/dreaming.
        if (origin == ZenModeConfig.UPDATE_ORIGIN_INIT
                || origin == ZenModeConfig.UPDATE_ORIGIN_INIT_USER
                || origin == ZenModeConfig.UPDATE_ORIGIN_USER
                || origin == ZenModeConfig.UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI
                || !mPowerManager.isInteractive()) {
            unregisterScreenOffReceiver();
            updateNightModeImmediately(useNightMode);
        } else {
            registerScreenOffReceiver();
        }
    }

            // TODO: b/308673343 - Apply dark theme (via UiModeManager) when screen is off.
    @GuardedBy("mRegisterReceiverLock")
    private final BroadcastReceiver mNightModeWhenScreenOff = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            unregisterScreenOffReceiver();
            updateNightModeImmediately(mPendingNightMode);
        }
    };

    private void updateNightModeImmediately(boolean useNightMode) {
        Binder.withCleanCallingIdentity(() -> {
            // TODO: b/314285749 - Placeholder; use real APIs when available.
            mUiModeManager.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
            mUiModeManager.setNightModeActivatedForCustomMode(MODE_NIGHT_CUSTOM_TYPE_BEDTIME,
                    useNightMode);
        });
    }

    private void registerScreenOffReceiver() {
        synchronized (mRegisterReceiverLock) {
            if (!mIsScreenOffReceiverRegistered) {
                mContext.registerReceiver(mNightModeWhenScreenOff, SCREEN_OFF_INTENT_FILTER,
                        Context.RECEIVER_NOT_EXPORTED);
                mIsScreenOffReceiverRegistered = true;
            }
        }
    }

    private void unregisterScreenOffReceiver() {
        synchronized (mRegisterReceiverLock) {
            if (mIsScreenOffReceiverRegistered) {
                mIsScreenOffReceiverRegistered = false;
                mContext.unregisterReceiver(mNightModeWhenScreenOff);
            }
        }
    }
}
+37 −20
Original line number Diff line number Diff line
@@ -5299,11 +5299,11 @@ public class NotificationManagerService extends SystemService {
        public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
            enforceSystemOrSystemUI("INotificationManager.setZenMode");
            final int callingUid = Binder.getCallingUid();
            final boolean isSystemOrSystemUi = isCallerSystemOrSystemUi();
            final long identity = Binder.clearCallingIdentity();
            try {
                mZenModeHelper.setManualZenMode(mode, conditionId, null, reason, callingUid,
                        isSystemOrSystemUi);
                mZenModeHelper.setManualZenMode(mode, conditionId,
                        ZenModeConfig.UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, // Checked by enforce()
                        reason, /* caller= */ null, callingUid);
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
@@ -5360,10 +5360,11 @@ public class NotificationManagerService extends SystemService {
            }
            return mZenModeHelper.addAutomaticZenRule(rulePkg, automaticZenRule,
                    "addAutomaticZenRule", Binder.getCallingUid(),
                    // TODO: b/308670715: Distinguish FROM_APP from FROM_USER
                    isCallerSystemOrSystemUi() ? ZenModeHelper.FROM_SYSTEM_OR_SYSTEMUI
                            : ZenModeHelper.FROM_APP);
                    // TODO: b/308670715: Distinguish origin properly (e.g. USER if creating a rule
                    //  manually in Settings).
                    isCallerSystemOrSystemUi() ? ZenModeConfig.UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI
                            : ZenModeConfig.UPDATE_ORIGIN_APP,
                    "addAutomaticZenRule", Binder.getCallingUid());
        }
        @Override
@@ -5379,11 +5380,12 @@ public class NotificationManagerService extends SystemService {
            Objects.requireNonNull(automaticZenRule.getConditionId(), "ConditionId is null");
            enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
            // TODO: b/308670715: Distinguish origin properly (e.g. USER if updating a rule
            //  manually in Settings).
            return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
                    "updateAutomaticZenRule", Binder.getCallingUid(),
                    // TODO: b/308670715: Distinguish FROM_APP from FROM_USER
                    isCallerSystemOrSystemUi() ? ZenModeHelper.FROM_SYSTEM_OR_SYSTEMUI
                            : ZenModeHelper.FROM_APP);
                    isCallerSystemOrSystemUi() ? ZenModeConfig.UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI
                            : ZenModeConfig.UPDATE_ORIGIN_APP,
                    "updateAutomaticZenRule", Binder.getCallingUid());
        }
        @Override
@@ -5392,8 +5394,12 @@ public class NotificationManagerService extends SystemService {
            // Verify that they can modify zen rules.
            enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
            return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule",
                    Binder.getCallingUid(), isCallerSystemOrSystemUi());
            // TODO: b/308670715: Distinguish origin properly (e.g. USER if removing a rule
            //  manually in Settings).
            return mZenModeHelper.removeAutomaticZenRule(id,
                    isCallerSystemOrSystemUi() ? ZenModeConfig.UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI
                            : ZenModeConfig.UPDATE_ORIGIN_APP,
                    "removeAutomaticZenRule", Binder.getCallingUid());
        }
        @Override
@@ -5402,8 +5408,9 @@ public class NotificationManagerService extends SystemService {
            enforceSystemOrSystemUI("removeAutomaticZenRules");
            return mZenModeHelper.removeAutomaticZenRules(packageName,
                    packageName + "|removeAutomaticZenRules", Binder.getCallingUid(),
                    isCallerSystemOrSystemUi());
                    isCallerSystemOrSystemUi() ? ZenModeConfig.UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI
                            : ZenModeConfig.UPDATE_ORIGIN_APP,
                    packageName + "|removeAutomaticZenRules", Binder.getCallingUid());
        }
        @Override
@@ -5421,8 +5428,12 @@ public class NotificationManagerService extends SystemService {
            enforcePolicyAccess(Binder.getCallingUid(), "setAutomaticZenRuleState");
            mZenModeHelper.setAutomaticZenRuleState(id, condition, Binder.getCallingUid(),
                    isCallerSystemOrSystemUi());
            // TODO: b/308670715: Distinguish origin properly (e.g. USER if toggling a rule
            //  manually in Settings).
            mZenModeHelper.setAutomaticZenRuleState(id, condition,
                    isCallerSystemOrSystemUi() ? ZenModeConfig.UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI
                            : ZenModeConfig.UPDATE_ORIGIN_APP,
                    Binder.getCallingUid());
        }
        @Override
@@ -5440,8 +5451,11 @@ public class NotificationManagerService extends SystemService {
            final long identity = Binder.clearCallingIdentity();
            try {
                mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter",
                        callingUid, isSystemOrSystemUi);
                mZenModeHelper.setManualZenMode(zen, null,
                        isSystemOrSystemUi ? ZenModeConfig.UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI
                                : ZenModeConfig.UPDATE_ORIGIN_APP,
                        /* reason= */ "setInterruptionFilter", /* caller= */ pkg,
                        callingUid);
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
@@ -5806,7 +5820,10 @@ public class NotificationManagerService extends SystemService {
                } else {
                    ZenLog.traceSetNotificationPolicy(pkg, applicationInfo.targetSdkVersion,
                            policy);
                    mZenModeHelper.setNotificationPolicy(policy, callingUid, isSystemOrSystemUi);
                    mZenModeHelper.setNotificationPolicy(policy,
                            isSystemOrSystemUi ? ZenModeConfig.UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI
                                    : ZenModeConfig.UPDATE_ORIGIN_APP,
                            callingUid);
                }
            } catch (RemoteException e) {
                Slog.e(TAG, "Failed to set notification policy", e);
+11 −6
Original line number Diff line number Diff line
@@ -59,6 +59,7 @@ import android.provider.Settings;
import android.service.notification.ConversationChannelWrapper;
import android.service.notification.NotificationListenerService;
import android.service.notification.RankingHelperProto;
import android.service.notification.ZenModeConfig;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.ArrayMap;
@@ -1862,12 +1863,16 @@ public class PreferencesHelper implements RankingConfig {
    public void updateZenPolicy(boolean areChannelsBypassingDnd, int callingUid,
            boolean fromSystemOrSystemUi) {
        NotificationManager.Policy policy = mZenModeHelper.getNotificationPolicy();
        mZenModeHelper.setNotificationPolicy(new NotificationManager.Policy(
        mZenModeHelper.setNotificationPolicy(
                new NotificationManager.Policy(
                        policy.priorityCategories, policy.priorityCallSenders,
                        policy.priorityMessageSenders, policy.suppressedVisualEffects,
                (areChannelsBypassingDnd ? NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND
                        : 0),
                policy.priorityConversationSenders), callingUid, fromSystemOrSystemUi);
                        (areChannelsBypassingDnd
                                ? NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND : 0),
                        policy.priorityConversationSenders),
                fromSystemOrSystemUi ? ZenModeConfig.UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI
                        : ZenModeConfig.UPDATE_ORIGIN_APP,
                callingUid);
    }

    // TODO: b/310620812 - rename to hasPriorityChannels() when modes_api is inlined.
Loading