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

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

Merge changes I3fc38158,Ied8e53c2 into main

* changes:
  (Almost) display active priority mode icon in status bar
  Prepare the way for showing the active Priority Mode icon instead of the DND icon
parents 4d06f18f fb020458
Loading
Loading
Loading
Loading
+23 −1
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@


package com.android.internal.statusbar;
package com.android.internal.statusbar;


import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.graphics.drawable.Icon;
import android.os.Parcel;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Parcelable;
@@ -23,7 +24,18 @@ import android.os.UserHandle;
import android.text.TextUtils;
import android.text.TextUtils;


import androidx.annotation.NonNull;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;


/**
 * Representation of an icon that should appear in the status bar.
 *
 * <p>This includes notifications, conversations, and icons displayed on the right side (e.g.
 * Wifi, Vibration/Silence, Priority Modes, etc).
 *
 * <p>This class is {@link Parcelable} but the {@link #preloadedIcon} is not (and will be lost if
 * the object is copied through parcelling). If {@link #preloadedIcon} is supplied, it must match
 * the {@link #icon} resource/bitmap.
 */
public class StatusBarIcon implements Parcelable {
public class StatusBarIcon implements Parcelable {
    public enum Type {
    public enum Type {
        // Notification: the sender avatar for important conversations
        // Notification: the sender avatar for important conversations
@@ -34,7 +46,9 @@ public class StatusBarIcon implements Parcelable {
        // Notification: the small icon from the notification
        // Notification: the small icon from the notification
        NotifSmallIcon,
        NotifSmallIcon,
        // The wi-fi, cellular or battery icon.
        // The wi-fi, cellular or battery icon.
        SystemIcon
        SystemIcon,
        // Some other icon, corresponding to a resource (possibly in a different package).
        ResourceIcon
    }
    }


    public UserHandle user;
    public UserHandle user;
@@ -46,6 +60,13 @@ public class StatusBarIcon implements Parcelable {
    public CharSequence contentDescription;
    public CharSequence contentDescription;
    public Type type;
    public Type type;


    /**
     * Optional {@link Drawable} corresponding to {@link #icon}. This field is not parcelable, so
     * will be lost if the object is sent to a different process. If you set it, make sure to
     * <em>also</em> set {@link #icon} pointing to the corresponding resource.
     */
    @Nullable public Drawable preloadedIcon;

    public StatusBarIcon(UserHandle user, String resPackage, Icon icon, int iconLevel, int number,
    public StatusBarIcon(UserHandle user, String resPackage, Icon icon, int iconLevel, int number,
            CharSequence contentDescription, Type type) {
            CharSequence contentDescription, Type type) {
        if (icon.getType() == Icon.TYPE_RESOURCE
        if (icon.getType() == Icon.TYPE_RESOURCE
@@ -88,6 +109,7 @@ public class StatusBarIcon implements Parcelable {
        StatusBarIcon that = new StatusBarIcon(this.user, this.pkg, this.icon,
        StatusBarIcon that = new StatusBarIcon(this.user, this.pkg, this.icon,
                this.iconLevel, this.number, this.contentDescription, this.type);
                this.iconLevel, this.number, this.contentDescription, this.type);
        that.visible = this.visible;
        that.visible = this.visible;
        that.preloadedIcon = this.preloadedIcon;
        return that;
        return that;
    }
    }


+47 −10
Original line number Original line Diff line number Diff line
@@ -18,6 +18,8 @@ package com.android.internal.statusbar;


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


import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Parcel;
import android.os.Parcel;
import android.os.UserHandle;
import android.os.UserHandle;


@@ -37,18 +39,55 @@ public class StatusBarIconTest {
     */
     */
    @Test
    @Test
    public void testParcelable() {
    public void testParcelable() {
        final StatusBarIcon original = newStatusBarIcon();

        final StatusBarIcon copy = parcelAndUnparcel(original);

        assertSerializableFieldsEqual(copy, original);
    }

    @Test
    public void testClone_withPreloaded() {
        final StatusBarIcon original = newStatusBarIcon();
        original.preloadedIcon = new ColorDrawable(Color.RED);

        final StatusBarIcon copy = original.clone();

        assertSerializableFieldsEqual(copy, original);
        assertThat(copy.preloadedIcon).isNotNull();
        assertThat(copy.preloadedIcon).isInstanceOf(ColorDrawable.class);
        assertThat(((ColorDrawable) copy.preloadedIcon).getColor()).isEqualTo(Color.RED);
    }

    @Test
    public void testClone_noPreloaded() {
        final StatusBarIcon original = newStatusBarIcon();

        final StatusBarIcon copy = original.clone();

        assertSerializableFieldsEqual(copy, original);
        assertThat(copy.preloadedIcon).isEqualTo(original.preloadedIcon);
    }


    private static StatusBarIcon newStatusBarIcon() {
        final UserHandle dummyUserHandle = UserHandle.of(100);
        final UserHandle dummyUserHandle = UserHandle.of(100);
        final String dummyIconPackageName = "com.android.internal.statusbar.test";
        final String dummyIconPackageName = "com.android.internal.statusbar.test";
        final int dummyIconId = 123;
        final int dummyIconId = 123;
        final int dummyIconLevel = 1;
        final int dummyIconLevel = 1;
        final int dummyIconNumber = 2;
        final int dummyIconNumber = 2;
        final CharSequence dummyIconContentDescription = "dummyIcon";
        final CharSequence dummyIconContentDescription = "dummyIcon";
        final StatusBarIcon original = new StatusBarIcon(dummyIconPackageName, dummyUserHandle,
        return new StatusBarIcon(
                dummyIconId, dummyIconLevel, dummyIconNumber, dummyIconContentDescription,
                dummyIconPackageName,
                dummyUserHandle,
                dummyIconId,
                dummyIconLevel,
                dummyIconNumber,
                dummyIconContentDescription,
                StatusBarIcon.Type.SystemIcon);
                StatusBarIcon.Type.SystemIcon);
    }


        final StatusBarIcon copy = clone(original);
    private static void assertSerializableFieldsEqual(StatusBarIcon copy, StatusBarIcon original) {

        assertThat(copy.user).isEqualTo(original.user);
        assertThat(copy.user).isEqualTo(original.user);
        assertThat(copy.pkg).isEqualTo(original.pkg);
        assertThat(copy.pkg).isEqualTo(original.pkg);
        assertThat(copy.icon.sameAs(original.icon)).isTrue();
        assertThat(copy.icon.sameAs(original.icon)).isTrue();
@@ -56,19 +95,17 @@ public class StatusBarIconTest {
        assertThat(copy.visible).isEqualTo(original.visible);
        assertThat(copy.visible).isEqualTo(original.visible);
        assertThat(copy.number).isEqualTo(original.number);
        assertThat(copy.number).isEqualTo(original.number);
        assertThat(copy.contentDescription).isEqualTo(original.contentDescription);
        assertThat(copy.contentDescription).isEqualTo(original.contentDescription);
        assertThat(copy.type).isEqualTo(original.type);
    }
    }


    private StatusBarIcon clone(StatusBarIcon original) {
    private static StatusBarIcon parcelAndUnparcel(StatusBarIcon original) {
        Parcel parcel = null;
        Parcel parcel = Parcel.obtain();
        try {
        try {
            parcel = Parcel.obtain();
            original.writeToParcel(parcel, 0);
            original.writeToParcel(parcel, 0);
            parcel.setDataPosition(0);
            parcel.setDataPosition(0);
            return StatusBarIcon.CREATOR.createFromParcel(parcel);
            return StatusBarIcon.CREATOR.createFromParcel(parcel);
        } finally {
        } finally {
            if (parcel != null) {
            parcel.recycle();
            parcel.recycle();
        }
        }
    }
    }
}
}
}
+26 −11
Original line number Original line Diff line number Diff line
@@ -471,17 +471,7 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi
     */
     */
    private Drawable getIcon(Context sysuiContext,
    private Drawable getIcon(Context sysuiContext,
            Context context, StatusBarIcon statusBarIcon) {
            Context context, StatusBarIcon statusBarIcon) {
        int userId = statusBarIcon.user.getIdentifier();
        Drawable icon = loadDrawable(context, statusBarIcon);
        if (userId == UserHandle.USER_ALL) {
            userId = UserHandle.USER_SYSTEM;
        }

        // Try to load the monochrome app icon if applicable
        Drawable icon = maybeGetMonochromeAppIcon(context, statusBarIcon);
        // Otherwise, just use the icon normally
        if (icon == null) {
            icon = statusBarIcon.icon.loadDrawableAsUser(context, userId);
        }


        TypedValue typedValue = new TypedValue();
        TypedValue typedValue = new TypedValue();
        sysuiContext.getResources().getValue(R.dimen.status_bar_icon_scale_factor,
        sysuiContext.getResources().getValue(R.dimen.status_bar_icon_scale_factor,
@@ -508,6 +498,26 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi
        return new ScalingDrawableWrapper(icon, scaleFactor);
        return new ScalingDrawableWrapper(icon, scaleFactor);
    }
    }


    @Nullable
    private Drawable loadDrawable(Context context, StatusBarIcon statusBarIcon) {
        if (usesModeIcons() && statusBarIcon.preloadedIcon != null) {
            return statusBarIcon.preloadedIcon.mutate();
        } else {
            int userId = statusBarIcon.user.getIdentifier();
            if (userId == UserHandle.USER_ALL) {
                userId = UserHandle.USER_SYSTEM;
            }

            // Try to load the monochrome app icon if applicable
            Drawable icon = maybeGetMonochromeAppIcon(context, statusBarIcon);
            // Otherwise, just use the icon normally
            if (icon == null) {
                icon = statusBarIcon.icon.loadDrawableAsUser(context, userId);
            }
            return icon;
        }
    }

    @Nullable
    @Nullable
    private Drawable maybeGetMonochromeAppIcon(Context context,
    private Drawable maybeGetMonochromeAppIcon(Context context,
            StatusBarIcon statusBarIcon) {
            StatusBarIcon statusBarIcon) {
@@ -1020,4 +1030,9 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi
    public boolean showsConversation() {
    public boolean showsConversation() {
        return mShowsConversation;
        return mShowsConversation;
    }
    }

    private static boolean usesModeIcons() {
        return android.app.Flags.modesApi() && android.app.Flags.modesUi()
                && android.app.Flags.modesUiIcons();
    }
}
}
+83 −23
Original line number Original line Diff line number Diff line
@@ -44,6 +44,8 @@ import android.view.View;


import androidx.lifecycle.Observer;
import androidx.lifecycle.Observer;


import com.android.settingslib.notification.modes.ZenIconLoader;
import com.android.settingslib.notification.modes.ZenMode;
import com.android.systemui.Flags;
import com.android.systemui.Flags;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.qualifiers.DisplayId;
import com.android.systemui.dagger.qualifiers.DisplayId;
@@ -78,6 +80,7 @@ import com.android.systemui.statusbar.policy.RotationLockController.RotationLock
import com.android.systemui.statusbar.policy.SensorPrivacyController;
import com.android.systemui.statusbar.policy.SensorPrivacyController;
import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.statusbar.policy.domain.interactor.ZenModeInteractor;
import com.android.systemui.util.RingerModeTracker;
import com.android.systemui.util.RingerModeTracker;
import com.android.systemui.util.kotlin.JavaAdapter;
import com.android.systemui.util.kotlin.JavaAdapter;
import com.android.systemui.util.time.DateFormatUtil;
import com.android.systemui.util.time.DateFormatUtil;
@@ -99,7 +102,6 @@ public class PhoneStatusBarPolicy
                CommandQueue.Callbacks,
                CommandQueue.Callbacks,
                RotationLockControllerCallback,
                RotationLockControllerCallback,
                Listener,
                Listener,
                ZenModeController.Callback,
                DeviceProvisionedListener,
                DeviceProvisionedListener,
                KeyguardStateController.Callback,
                KeyguardStateController.Callback,
                PrivacyItemController.Callback,
                PrivacyItemController.Callback,
@@ -161,6 +163,7 @@ public class PhoneStatusBarPolicy
    private final RecordingController mRecordingController;
    private final RecordingController mRecordingController;
    private final RingerModeTracker mRingerModeTracker;
    private final RingerModeTracker mRingerModeTracker;
    private final PrivacyLogger mPrivacyLogger;
    private final PrivacyLogger mPrivacyLogger;
    private final ZenModeInteractor mZenModeInteractor;


    private boolean mZenVisible;
    private boolean mZenVisible;
    private boolean mVibrateVisible;
    private boolean mVibrateVisible;
@@ -193,6 +196,7 @@ public class PhoneStatusBarPolicy
            PrivacyItemController privacyItemController,
            PrivacyItemController privacyItemController,
            PrivacyLogger privacyLogger,
            PrivacyLogger privacyLogger,
            ConnectedDisplayInteractor connectedDisplayInteractor,
            ConnectedDisplayInteractor connectedDisplayInteractor,
            ZenModeInteractor zenModeInteractor,
            JavaAdapter javaAdapter
            JavaAdapter javaAdapter
    ) {
    ) {
        mIconController = iconController;
        mIconController = iconController;
@@ -224,6 +228,7 @@ public class PhoneStatusBarPolicy
        mTelecomManager = telecomManager;
        mTelecomManager = telecomManager;
        mRingerModeTracker = ringerModeTracker;
        mRingerModeTracker = ringerModeTracker;
        mPrivacyLogger = privacyLogger;
        mPrivacyLogger = privacyLogger;
        mZenModeInteractor = zenModeInteractor;
        mJavaAdapter = javaAdapter;
        mJavaAdapter = javaAdapter;


        mSlotCast = resources.getString(com.android.internal.R.string.status_bar_cast);
        mSlotCast = resources.getString(com.android.internal.R.string.status_bar_cast);
@@ -355,7 +360,13 @@ public class PhoneStatusBarPolicy
        mBluetooth.addCallback(this);
        mBluetooth.addCallback(this);
        mProvisionedController.addCallback(this);
        mProvisionedController.addCallback(this);
        mCurrentUserSetup = mProvisionedController.isCurrentUserSetup();
        mCurrentUserSetup = mProvisionedController.isCurrentUserSetup();
        mZenController.addCallback(this);
        if (usesModeIcons()) {
            // Note that we're not fully replacing ZenModeController with ZenModeInteractor, so
            // we listen for the extra event here but still add the ZMC callback.
            mJavaAdapter.alwaysCollectFlow(mZenModeInteractor.getMainActiveMode(),
                    this::onActiveModeChanged);
        }
        mZenController.addCallback(mZenControllerCallback);
        if (!Flags.statusBarScreenSharingChips()) {
        if (!Flags.statusBarScreenSharingChips()) {
            // If the flag is enabled, the cast icon is handled in the new screen sharing chips
            // If the flag is enabled, the cast icon is handled in the new screen sharing chips
            // instead of here so we don't need to listen for events here.
            // instead of here so we don't need to listen for events here.
@@ -385,6 +396,34 @@ public class PhoneStatusBarPolicy
                () -> mResources.getString(R.string.accessibility_managed_profile));
                () -> mResources.getString(R.string.accessibility_managed_profile));
    }
    }


    private void onActiveModeChanged(@Nullable ZenMode mode) {
        if (!usesModeIcons()) {
            Log.wtf(TAG, "onActiveModeChanged shouldn't be called if MODES_UI_ICONS is disabled");
            return;
        }
        boolean visible = mode != null;
        if (visible) {
            // TODO: b/360399800 - Get the resource id, package, and cached drawable from the mode;
            //  this is a shortcut for testing (there should be no direct dependency on
            //  ZenIconLoader here).
            String resPackage = mode.isSystemOwned() ? null : mode.getRule().getPackageName();
            int iconResId = mode.getRule().getIconResId();
            if (iconResId == 0) {
                iconResId = ZenIconLoader.getIconResourceIdFromType(mode.getType());
            }

            mIconController.setResourceIcon(mSlotZen, resPackage, iconResId,
                    /* preloadedIcon= */ null, mode.getName());
        }
        if (visible != mZenVisible) {
            mIconController.setIconVisibility(mSlotZen, visible);
            mZenVisible = visible;
        }
    }

    // TODO: b/308591859 - Should be removed and use the ZenModeInteractor only.
    private final ZenModeController.Callback mZenControllerCallback =
            new ZenModeController.Callback() {
                @Override
                @Override
                public void onZenChanged(int zen) {
                public void onZenChanged(int zen) {
                    updateVolumeZen();
                    updateVolumeZen();
@@ -394,6 +433,7 @@ public class PhoneStatusBarPolicy
                public void onConsolidatedPolicyChanged(NotificationManager.Policy policy) {
                public void onConsolidatedPolicyChanged(NotificationManager.Policy policy) {
                    updateVolumeZen();
                    updateVolumeZen();
                }
                }
            };


    private void updateAlarm() {
    private void updateAlarm() {
        final AlarmClockInfo alarm = mAlarmManager.getNextAlarmClock(mUserTracker.getUserId());
        final AlarmClockInfo alarm = mAlarmManager.getNextAlarmClock(mUserTracker.getUserId());
@@ -417,15 +457,24 @@ public class PhoneStatusBarPolicy
        return mResources.getString(R.string.accessibility_quick_settings_alarm, dateString);
        return mResources.getString(R.string.accessibility_quick_settings_alarm, dateString);
    }
    }


    private final void updateVolumeZen() {
    private void updateVolumeZen() {
        int zen = mZenController.getZen();
        if (!usesModeIcons()) {
            updateZenIcon(zen);
        }
        updateRingerAndAlarmIcons(zen);
    }

    private void updateZenIcon(int zen) {
        if (usesModeIcons()) {
            Log.wtf(TAG, "updateZenIcon shouldn't be called if MODES_UI_ICONS is enabled");
            return;
        }

        boolean zenVisible = false;
        boolean zenVisible = false;
        int zenIconId = 0;
        int zenIconId = 0;
        String zenDescription = null;
        String zenDescription = null;


        boolean vibrateVisible = false;
        boolean muteVisible = false;
        int zen = mZenController.getZen();

        if (DndTile.isVisible(mSharedPreferences) || DndTile.isCombinedIcon(mSharedPreferences)) {
        if (DndTile.isVisible(mSharedPreferences) || DndTile.isCombinedIcon(mSharedPreferences)) {
            zenVisible = zen != Global.ZEN_MODE_OFF;
            zenVisible = zen != Global.ZEN_MODE_OFF;
            zenIconId = R.drawable.stat_sys_dnd;
            zenIconId = R.drawable.stat_sys_dnd;
@@ -440,7 +489,21 @@ public class PhoneStatusBarPolicy
            zenDescription = mResources.getString(R.string.interruption_level_priority);
            zenDescription = mResources.getString(R.string.interruption_level_priority);
        }
        }


        if (!ZenModeConfig.isZenOverridingRinger(zen, mZenController.getConsolidatedPolicy())) {
        if (zenVisible) {
            mIconController.setIcon(mSlotZen, zenIconId, zenDescription);
        }
        if (zenVisible != mZenVisible) {
            mIconController.setIconVisibility(mSlotZen, zenVisible);
            mZenVisible = zenVisible;
        }
    }

    private void updateRingerAndAlarmIcons(int zen) {
        boolean vibrateVisible = false;
        boolean muteVisible = false;

        NotificationManager.Policy consolidatedPolicy = mZenController.getConsolidatedPolicy();
        if (!ZenModeConfig.isZenOverridingRinger(zen, consolidatedPolicy)) {
            final Integer ringerModeInternal =
            final Integer ringerModeInternal =
                    mRingerModeTracker.getRingerModeInternal().getValue();
                    mRingerModeTracker.getRingerModeInternal().getValue();
            if (ringerModeInternal != null) {
            if (ringerModeInternal != null) {
@@ -452,14 +515,6 @@ public class PhoneStatusBarPolicy
            }
            }
        }
        }


        if (zenVisible) {
            mIconController.setIcon(mSlotZen, zenIconId, zenDescription);
        }
        if (zenVisible != mZenVisible) {
            mIconController.setIconVisibility(mSlotZen, zenVisible);
            mZenVisible = zenVisible;
        }

        if (vibrateVisible != mVibrateVisible) {
        if (vibrateVisible != mVibrateVisible) {
            mIconController.setIconVisibility(mSlotVibrate, vibrateVisible);
            mIconController.setIconVisibility(mSlotVibrate, vibrateVisible);
            mVibrateVisible = vibrateVisible;
            mVibrateVisible = vibrateVisible;
@@ -888,4 +943,9 @@ public class PhoneStatusBarPolicy


        mIconController.setIconVisibility(mSlotConnectedDisplay, visible);
        mIconController.setIconVisibility(mSlotConnectedDisplay, visible);
    }
    }

    private static boolean usesModeIcons() {
        return android.app.Flags.modesApi() && android.app.Flags.modesUi()
                && android.app.Flags.modesUiIcons();
    }
}
}
+15 −0
Original line number Original line Diff line number Diff line
@@ -18,9 +18,12 @@ package com.android.systemui.statusbar.phone.ui;


import android.annotation.Nullable;
import android.annotation.Nullable;
import android.content.Context;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.ArraySet;


import androidx.annotation.DrawableRes;

import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.systemui.res.R;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.CallIndicatorIconState;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.CallIndicatorIconState;
@@ -57,6 +60,18 @@ public interface StatusBarIconController {
    /** Adds or updates an icon for the given slot for **internal system icons**. */
    /** Adds or updates an icon for the given slot for **internal system icons**. */
    void setIcon(String slot, int resourceId, CharSequence contentDescription);
    void setIcon(String slot, int resourceId, CharSequence contentDescription);


    /**
     * Adds or updates an icon for the given slot.
     *
     * @param resPackage the package name containing the resource in question. Can be null if the
     *      icon is a system icon (e.g. a resource from {@code android.R.drawable} or
     *      {@code com.android.internal.R.drawable}).
     * @param iconResId id of the drawable resource
     * @param preloadedIcon optional drawable corresponding to {@code iconResId}, if known
     */
    void setResourceIcon(String slot, @Nullable String resPackage, @DrawableRes int iconResId,
            @Nullable Drawable preloadedIcon, CharSequence contentDescription);

    /**
    /**
     * Sets up a wifi icon using the new data pipeline. No effect if the wifi icon has already been
     * Sets up a wifi icon using the new data pipeline. No effect if the wifi icon has already been
     * set up (inflated and added to the view hierarchy).
     * set up (inflated and added to the view hierarchy).
Loading