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

Commit 3ce6a828 authored by Ioana Alexandru's avatar Ioana Alexandru Committed by Android (Google) Code Review
Browse files

Merge changes Ic23f2c41,I09370146,Iad9f6887 into main

* changes:
  Notif redesign: Account for low ram icon size
  Set inflater factory for group summary header
  Notif redesign: Use launcher app icons for notification rows
parents f89706d2 0023b25c
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -5,6 +5,14 @@ container: "system"
# when appropriate, as it's not currently part of the namespace so it may not be obvious what the
# flag relates to.

flag {
  name: "notifications_redesign_app_icons"
  namespace: "systemui"
  description: "Notifications Redesign: Use app icons in notification rows (not to be confused with"
    " notifications_use_app_icons, notifications_use_app_icon_in_row which are just experiments)."
  bug: "371174789"
}

flag {
  name: "modes_api"
  is_exported: true
+198 −26
Original line number Diff line number Diff line
@@ -39,17 +39,24 @@ import com.android.internal.R;

/**
 * An image view that holds the icon displayed at the start of a notification row.
 * This can generally either display the "small icon" of a notification set via
 * {@link this#setImageIcon(Icon)}, or an app icon controlled and fetched by the provider set
 * through {@link this#setIconProvider(NotificationIconProvider)}.
 */
@RemoteViews.RemoteView
public class NotificationRowIconView extends CachingIconView {
    private NotificationIconProvider mIconProvider;

    private boolean mApplyCircularCrop = false;
    private boolean mShouldShowAppIcon = false;
    private Drawable mAppIcon = null;

    // Padding and background set on the view prior to being changed by setShouldShowAppIcon(true),
    // to be restored if shouldShowAppIcon becomes false again.
    // Padding, background and colors set on the view prior to being overridden when showing the app
    // icon, to be restored if we're showing the small icon again.
    private Rect mOriginalPadding = null;
    private Drawable mOriginalBackground = null;

    private int mOriginalBackgroundColor = ColoredIconHelper.COLOR_INVALID;
    private int mOriginalIconColor = ColoredIconHelper.COLOR_INVALID;

    public NotificationRowIconView(Context context) {
        super(context);
@@ -81,6 +88,71 @@ public class NotificationRowIconView extends CachingIconView {
        super.onFinishInflate();
    }

    /**
     * Sets the icon provider for this view. This is used to determine whether we should show the
     * app icon instead of the small icon, and to fetch the app icon if needed.
     */
    public void setIconProvider(NotificationIconProvider iconProvider) {
        mIconProvider = iconProvider;
    }

    private Drawable loadAppIcon() {
        if (mIconProvider != null && mIconProvider.shouldShowAppIcon()) {
            return mIconProvider.getAppIcon();
        }
        return null;
    }

    @RemotableViewMethod(asyncImpl = "setImageIconAsync")
    @Override
    public void setImageIcon(Icon icon) {
        if (Flags.notificationsRedesignAppIcons()) {
            if (mAppIcon != null) {
                // We already know that we should be using the app icon, and we already loaded it.
                // We assume that cannot change throughout the lifetime of a notification, so
                // there's nothing to do here.
                return;
            }
            mAppIcon = loadAppIcon();
            if (mAppIcon != null) {
                setImageDrawable(mAppIcon);
                adjustViewForAppIcon();
            } else {
                super.setImageIcon(icon);
                restoreViewForSmallIcon();
            }
            return;
        }
        super.setImageIcon(icon);
    }

    @RemotableViewMethod
    @Override
    public Runnable setImageIconAsync(Icon icon) {
        if (Flags.notificationsRedesignAppIcons()) {
            if (mAppIcon != null) {
                // We already know that we should be using the app icon, and we already loaded it.
                // We assume that cannot change throughout the lifetime of a notification, so
                // there's nothing to do here.
                return () -> {
                };
            }
            mAppIcon = loadAppIcon();
            if (mAppIcon != null) {
                return () -> {
                    setImageDrawable(mAppIcon);
                    adjustViewForAppIcon();
                };
            } else {
                return () -> {
                    super.setImageIcon(icon);
                    restoreViewForSmallIcon();
                };
            }
        }
        return super.setImageIconAsync(icon);
    }

    /** Whether the icon represents the app icon (instead of the small icon). */
    @RemotableViewMethod
    public void setShouldShowAppIcon(boolean shouldShowAppIcon) {
@@ -91,13 +163,68 @@ public class NotificationRowIconView extends CachingIconView {

            mShouldShowAppIcon = shouldShowAppIcon;
            if (mShouldShowAppIcon) {
                if (mOriginalPadding == null && mOriginalBackground == null) {
                adjustViewForAppIcon();
            } else {
                // Restore original padding and background if needed
                restoreViewForSmallIcon();
            }
        }
    }

    /**
     * Override padding and background from the view to display the app icon.
     */
    private void adjustViewForAppIcon() {
        removePadding();

        if (Flags.notificationsUseAppIconInRow()) {
            addWhiteBackground();
        } else {
            // No need to set the background for notification redesign, since the icon
            // factory already does that for us.
            removeBackground();
        }
    }

    /**
     * Restore padding and background overridden by {@link this#adjustViewForAppIcon}.
     * Does nothing if they were not overridden.
     */
    private void restoreViewForSmallIcon() {
        restorePadding();
        restoreBackground();
        restoreColors();
    }

    private void removePadding() {
        if (mOriginalPadding == null) {
            mOriginalPadding = new Rect(getPaddingLeft(), getPaddingTop(),
                    getPaddingRight(), getPaddingBottom());
        }
        setPadding(0, 0, 0, 0);
    }

    private void restorePadding() {
        if (mOriginalPadding != null) {
            setPadding(mOriginalPadding.left, mOriginalPadding.top,
                    mOriginalPadding.right,
                    mOriginalPadding.bottom);
            mOriginalPadding = null;
        }
    }

    private void removeBackground() {
        if (mOriginalBackground == null) {
            mOriginalBackground = getBackground();
        }

                setPadding(0, 0, 0, 0);
        setBackground(null);
    }

    private void addWhiteBackground() {
        if (mOriginalBackground == null) {
            mOriginalBackground = getBackground();
        }

        // Make the background white in case the icon itself doesn't have one.
        ColorFilter colorFilter = new PorterDuffColorFilter(Color.WHITE,
@@ -107,17 +234,49 @@ public class NotificationRowIconView extends CachingIconView {
            setBackground(getContext().getDrawable(R.drawable.notification_icon_circle));
        }
        getBackground().mutate().setColorFilter(colorFilter);
            } else {
                // Restore original padding and background if needed
                if (mOriginalPadding != null) {
                    setPadding(mOriginalPadding.left, mOriginalPadding.top, mOriginalPadding.right,
                            mOriginalPadding.bottom);
                    mOriginalPadding = null;
    }

    private void restoreBackground() {
        // NOTE: This will not work if the original background was null, but that's better than
        //  accidentally clearing the background. We expect that there's generally going to be one
        //  anyway unless we manually clear it.
        if (mOriginalBackground != null) {
            setBackground(mOriginalBackground);
            mOriginalBackground = null;
        }
    }

    private void restoreColors() {
        if (mOriginalBackgroundColor != ColoredIconHelper.COLOR_INVALID) {
            super.setBackgroundColor(mOriginalBackgroundColor);
            mOriginalBackgroundColor = ColoredIconHelper.COLOR_INVALID;
        }
        if (mOriginalIconColor != ColoredIconHelper.COLOR_INVALID) {
            super.setOriginalIconColor(mOriginalIconColor);
            mOriginalIconColor = ColoredIconHelper.COLOR_INVALID;
        }
    }

    @RemotableViewMethod
    @Override
    public void setBackgroundColor(int color) {
        // Ignore color overrides if we're showing the app icon.
        if (mAppIcon == null) {
            super.setBackgroundColor(color);
        } else {
            mOriginalBackgroundColor = color;
        }
    }

    @RemotableViewMethod
    @Override
    public void setOriginalIconColor(int color) {
        // Ignore color overrides if we're showing the app icon.
        if (mAppIcon == null) {
            super.setOriginalIconColor(color);
        } else {
            mOriginalIconColor = color;
        }
    }

    @Nullable
@@ -197,4 +356,17 @@ public class NotificationRowIconView extends CachingIconView {

        return bitmap;
    }

    /**
     * A provider that allows this view to verify whether it should use the app icon instead of the
     * icon provided to it via setImageIcon, as well as actually fetching the app icon. It should
     * primarily be called on the background thread.
     */
    public interface NotificationIconProvider {
        /** Whether this notification should use the app icon instead of the small icon. */
        boolean shouldShowAppIcon();

        /** Get the app icon for this notification. */
        Drawable getAppIcon();
    }
}
+5 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.notification.row
import android.widget.flags.Flags.notifLinearlayoutOptimized
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.statusbar.notification.row.icon.NotificationRowIconViewInflaterFactory
import com.android.systemui.statusbar.notification.shared.NotificationViewFlipperPausing
import javax.inject.Inject
import javax.inject.Provider
@@ -35,6 +36,7 @@ constructor(
    bigPictureLayoutInflaterFactory: BigPictureLayoutInflaterFactory,
    optimizedLinearLayoutFactory: NotificationOptimizedLinearLayoutFactory,
    notificationViewFlipperFactory: Provider<NotificationViewFlipperFactory>,
    notificationRowIconViewInflaterFactory: NotificationRowIconViewInflaterFactory,
) : NotifRemoteViewsFactoryContainer {
    override val factories: Set<NotifRemoteViewsFactory> = buildSet {
        add(precomputedTextViewFactory)
@@ -47,5 +49,8 @@ constructor(
        if (NotificationViewFlipperPausing.isEnabled) {
            add(notificationViewFlipperFactory.get())
        }
        if (android.app.Flags.notificationsRedesignAppIcons()) {
            add(notificationRowIconViewInflaterFactory)
        }
    }
}
+10 −1
Original line number Diff line number Diff line
@@ -478,6 +478,13 @@ public class NotificationContentInflater implements NotificationRowContentBinder
                notifLayoutInflaterFactoryProvider.provide(row, FLAG_CONTENT_VIEW_HEADS_UP));
        setRemoteViewsInflaterFactory(result.newPublicView,
                notifLayoutInflaterFactoryProvider.provide(row, FLAG_CONTENT_VIEW_PUBLIC));
        if (android.app.Flags.notificationsRedesignAppIcons()) {
            setRemoteViewsInflaterFactory(result.mNewGroupHeaderView,
                    notifLayoutInflaterFactoryProvider.provide(row, FLAG_GROUP_SUMMARY_HEADER));
            setRemoteViewsInflaterFactory(result.mNewMinimizedGroupHeaderView,
                    notifLayoutInflaterFactoryProvider.provide(row,
                            FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER));
        }
    }

    private static void setRemoteViewsInflaterFactory(RemoteViews remoteViews,
@@ -516,6 +523,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder
                    logger.logAsyncTaskProgress(entry, "contracted view applied");
                    result.inflatedContentView = v;
                }

                @Override
                public RemoteViews getRemoteView() {
                    return result.newContentView;
@@ -1406,6 +1414,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder
    @VisibleForTesting
    abstract static class ApplyCallback {
        public abstract void setResultView(View v);

        public abstract RemoteViews getRemoteView();
    }

+2 −1
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.notification.row;

import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.statusbar.notification.row.icon.AppIconProviderModule;
import com.android.systemui.statusbar.notification.row.shared.NotificationRowContentBinderRefactor;

import dagger.Binds;
@@ -28,7 +29,7 @@ import javax.inject.Provider;
/**
 * Dagger Module containing notification row and view inflation implementations.
 */
@Module
@Module(includes = {AppIconProviderModule.class})
public abstract class NotificationRowModule {

    /**
Loading