diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java index 4597b16568849..b33424c563a38 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java @@ -33,6 +33,7 @@ import com.android.keyguard.AlphaOptimizedLinearLayout; import com.android.systemui.R; import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.collection.NotificationEntry.OnSensitivityChangedListener; import java.util.List; @@ -159,20 +160,30 @@ public class HeadsUpStatusBarView extends AlphaOptimizedLinearLayout { } public void setEntry(NotificationEntry entry) { - if (entry != null) { - mShowingEntry = entry; + if (mShowingEntry != null) { + mShowingEntry.removeOnSensitivityChangedListener(mOnSensitivityChangedListener); + } + mShowingEntry = entry; + + if (mShowingEntry != null) { CharSequence text = entry.headsUpStatusBarText; if (entry.isSensitive()) { text = entry.headsUpStatusBarTextPublic; } mTextView.setText(text); - mShowingEntry.setOnSensitiveChangedListener(() -> setEntry(entry)); - } else if (mShowingEntry != null){ - mShowingEntry.setOnSensitiveChangedListener(null); - mShowingEntry = null; + mShowingEntry.addOnSensitivityChangedListener(mOnSensitivityChangedListener); } } + private final OnSensitivityChangedListener mOnSensitivityChangedListener = entry -> { + if (entry != mShowingEntry) { + throw new IllegalStateException("Got a sensitivity change for " + entry + + " but mShowingEntry is " + mShowingEntry); + } + // Update the text + setEntry(entry); + }; + @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java index 8632969264912..d8fdf928f6add 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java @@ -263,11 +263,11 @@ public class NotificationMediaManager implements Dumpable { synchronized (mEntryManager) { NotificationEntry entry = mEntryManager .getActiveNotificationUnfiltered(mMediaNotificationKey); - if (entry == null || entry.expandedIcon == null) { + if (entry == null || entry.getIcons().getShelfIcon() == null) { return null; } - return entry.expandedIcon.getSourceIcon(); + return entry.getIcons().getShelfIcon().getSourceIcon(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java index 1a8454cfa1138..d7f2ae43cf9ee 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java @@ -329,7 +329,7 @@ public class NotificationShelf extends ActivatableNotificationView implements expandableRow.setAboveShelf(false); } if (notGoneIndex == 0) { - StatusBarIconView icon = expandableRow.getEntry().expandedIcon; + StatusBarIconView icon = expandableRow.getEntry().getIcons().getShelfIcon(); NotificationIconContainer.IconState iconState = getIconState(icon); // The icon state might be null in rare cases where the notification is actually // added to the layout, but not to the shelf. An example are replied messages, @@ -432,7 +432,7 @@ public class NotificationShelf extends ActivatableNotificationView implements // if the shelf is clipped, lets make sure we also clip the icon maxTop = Math.max(maxTop, getTranslationY() + getClipTopAmount()); } - StatusBarIconView icon = row.getEntry().expandedIcon; + StatusBarIconView icon = row.getEntry().getIcons().getShelfIcon(); float shelfIconPosition = getTranslationY() + icon.getTop() + icon.getTranslationY(); if (shelfIconPosition < maxTop && !mAmbientState.isFullyHidden()) { int top = (int) (maxTop - shelfIconPosition); @@ -444,7 +444,7 @@ public class NotificationShelf extends ActivatableNotificationView implements } private void updateContinuousClipping(final ExpandableNotificationRow row) { - StatusBarIconView icon = row.getEntry().expandedIcon; + StatusBarIconView icon = row.getEntry().getIcons().getShelfIcon(); boolean needsContinuousClipping = ViewState.isAnimatingY(icon) && !mAmbientState.isDozing(); boolean isContinuousClipping = icon.getTag(TAG_CONTINUOUS_CLIPPING) != null; if (needsContinuousClipping && !isContinuousClipping) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java index 0450e02818756..c6d84ff79bde7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java @@ -841,7 +841,7 @@ public class NotificationEntryManager implements private void dumpEntry(PrintWriter pw, String indent, int i, NotificationEntry e) { pw.print(indent); - pw.println(" [" + i + "] key=" + e.getKey() + " icon=" + e.icon); + pw.println(" [" + i + "] key=" + e.getKey() + " icon=" + e.getIcons().getStatusBarIcon()); StatusBarNotification n = e.getSbn(); pw.print(indent); pw.println(" pkg=" + n.getPackageName() + " id=" + n.getId() + " importance=" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java index 3e9d8a436f38b..7019b5b42cf45 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java @@ -29,8 +29,6 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCRE import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR; -import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC; -import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED; import static com.android.systemui.statusbar.notification.collection.NotifCollection.REASON_NOT_CANCELED; import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING; @@ -44,10 +42,7 @@ import android.app.NotificationManager.Policy; import android.app.Person; import android.app.RemoteInputHistoryItem; import android.content.Context; -import android.content.pm.LauncherApps; -import android.content.pm.LauncherApps.ShortcutQuery; import android.content.pm.ShortcutInfo; -import android.graphics.drawable.Icon; import android.net.Uri; import android.os.Bundle; import android.os.SystemClock; @@ -55,25 +50,20 @@ import android.service.notification.NotificationListenerService.Ranking; import android.service.notification.SnoozeCriterion; import android.service.notification.StatusBarNotification; import android.util.ArraySet; -import android.util.Log; -import android.view.View; -import android.widget.ImageView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.statusbar.StatusBarIcon; import com.android.internal.util.ArrayUtils; import com.android.internal.util.ContrastColorUtil; import com.android.systemui.statusbar.InflationTask; -import com.android.systemui.statusbar.StatusBarIconView; -import com.android.systemui.statusbar.notification.InflationException; import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifDismissInterceptor; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender; +import com.android.systemui.statusbar.notification.icon.IconPack; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController; import com.android.systemui.statusbar.notification.row.NotificationGuts; @@ -81,8 +71,6 @@ import com.android.systemui.statusbar.notification.row.NotificationRowContentBin import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.Objects; @@ -102,15 +90,11 @@ import java.util.Objects; * clean this up in the future. */ public final class NotificationEntry extends ListEntry { - private static final String TAG = "NotificationEntry"; private final String mKey; private StatusBarNotification mSbn; private Ranking mRanking; - private StatusBarIcon mSmallIcon; - private StatusBarIcon mPeopleAvatar; - /* * Bookkeeping members */ @@ -142,10 +126,7 @@ public final class NotificationEntry extends ListEntry { * TODO: Remove every member beneath this line if possible */ - public StatusBarIconView icon; - public StatusBarIconView expandedIcon; - public StatusBarIconView centeredIcon; - public StatusBarIconView aodIcon; + private IconPack mIcons = IconPack.buildEmptyPack(null); private boolean interruption; public int targetSdk; private long lastFullScreenIntentLaunchTime = NOT_LAUNCHED_YET; @@ -191,7 +172,8 @@ public final class NotificationEntry extends ListEntry { private boolean hasSentReply; private boolean mSensitive = true; - private Runnable mOnSensitiveChangedListener; + private List mOnSensitivityChangedListeners = new ArrayList<>(); + private boolean mAutoHeadsUp; private boolean mPulseSupressed; private boolean mAllowFgsDismissal; @@ -347,6 +329,15 @@ public final class NotificationEntry extends ListEntry { * TODO: Remove as many of these as possible */ + @NonNull + public IconPack getIcons() { + return mIcons; + } + + public void setIcons(@NonNull IconPack icons) { + mIcons = icons; + } + public void setInterruption() { interruption = true; } @@ -464,239 +455,6 @@ public final class NotificationEntry extends ListEntry { || SystemClock.elapsedRealtime() > initializationTime + INITIALIZATION_DELAY; } - /** - * Create the icons for a notification - * @param context the context to create the icons with - * @param sbn the notification - * @throws InflationException Exception if required icons are not valid or specified - */ - public void createIcons(Context context, StatusBarNotification sbn) - throws InflationException { - StatusBarIcon ic = getIcon(context, sbn, false /* redact */); - - // Construct the icon. - icon = new StatusBarIconView(context, - sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), sbn); - icon.setScaleType(ImageView.ScaleType.CENTER_INSIDE); - - // Construct the expanded icon. - expandedIcon = new StatusBarIconView(context, - sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), sbn); - expandedIcon.setScaleType(ImageView.ScaleType.CENTER_INSIDE); - - // Construct the expanded icon. - aodIcon = new StatusBarIconView(context, - sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), sbn); - aodIcon.setScaleType(ImageView.ScaleType.CENTER_INSIDE); - aodIcon.setIncreasedSize(true); - - try { - setIcons(ic, Collections.singletonList(icon)); - if (isSensitive()) { - ic = getIcon(context, sbn, true /* redact */); - } - setIcons(ic, Arrays.asList(expandedIcon, aodIcon)); - } catch (InflationException e) { - icon = null; - expandedIcon = null; - centeredIcon = null; - aodIcon = null; - throw e; - } - - expandedIcon.setVisibility(View.INVISIBLE); - expandedIcon.setOnVisibilityChangedListener( - newVisibility -> { - if (row != null) { - row.setIconsVisible(newVisibility != View.VISIBLE); - } - }); - - // Construct the centered icon - if (mSbn.getNotification().isMediaNotification()) { - centeredIcon = new StatusBarIconView(context, - sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), sbn); - centeredIcon.setScaleType(ImageView.ScaleType.CENTER_INSIDE); - try { - setIcons(ic, Collections.singletonList(centeredIcon)); - } catch (InflationException e) { - centeredIcon = null; - throw e; - } - } - } - - /** - * Determines if this icon should be tinted based on the sensitivity of the icon, its context - * and the user's indicated sensitivity preference. - * - * @param ic The icon that should/should not be tinted. - * @return - */ - private boolean shouldTintIcon(StatusBarIconView ic) { - boolean usedInSensitiveContext = (ic == expandedIcon || ic == aodIcon); - return !isImportantConversation() || (usedInSensitiveContext && isSensitive()); - } - - - private void setIcons(StatusBarIcon ic, List icons) - throws InflationException { - for (StatusBarIconView icon: icons) { - if (icon == null) { - continue; - } - icon.setTintIcons(shouldTintIcon(icon)); - if (!icon.set(ic)) { - throw new InflationException("Couldn't create icon" + ic); - } - } - } - - private StatusBarIcon getIcon(Context context, StatusBarNotification sbn, boolean redact) - throws InflationException { - Notification n = sbn.getNotification(); - final boolean showPeopleAvatar = isImportantConversation() && !redact; - - // If cached, return corresponding cached values - if (showPeopleAvatar && mPeopleAvatar != null) { - return mPeopleAvatar; - } else if (!showPeopleAvatar && mSmallIcon != null) { - return mSmallIcon; - } - - Icon icon = showPeopleAvatar ? createPeopleAvatar(context) : n.getSmallIcon(); - if (icon == null) { - throw new InflationException("No icon in notification from " + sbn.getPackageName()); - } - - StatusBarIcon ic = new StatusBarIcon( - sbn.getUser(), - sbn.getPackageName(), - icon, - n.iconLevel, - n.number, - StatusBarIconView.contentDescForNotification(context, n)); - - // Cache if important conversation. - if (isImportantConversation()) { - if (showPeopleAvatar) { - mPeopleAvatar = ic; - } else { - mSmallIcon = ic; - } - } - return ic; - } - - private Icon createPeopleAvatar(Context context) throws InflationException { - // Attempt to extract form shortcut. - String conversationId = getChannel().getConversationId(); - ShortcutQuery query = new ShortcutQuery() - .setPackage(mSbn.getPackageName()) - .setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED) - .setShortcutIds(Collections.singletonList(conversationId)); - List shortcuts = context.getSystemService(LauncherApps.class) - .getShortcuts(query, mSbn.getUser()); - Icon ic = null; - if (shortcuts != null && !shortcuts.isEmpty()) { - ic = shortcuts.get(0).getIcon(); - } - - // Fall back to notification large icon if available - if (ic == null) { - ic = mSbn.getNotification().getLargeIcon(); - } - - // Fall back to extract from message - if (ic == null) { - Bundle extras = mSbn.getNotification().extras; - List messages = Message.getMessagesFromBundleArray( - extras.getParcelableArray(Notification.EXTRA_MESSAGES)); - Person user = extras.getParcelable(Notification.EXTRA_MESSAGING_PERSON); - - for (int i = messages.size() - 1; i >= 0; i--) { - Message message = messages.get(i); - Person sender = message.getSenderPerson(); - if (sender != null && sender != user) { - ic = message.getSenderPerson().getIcon(); - break; - } - } - } - - // Revert to small icon if still not available - if (ic == null) { - ic = mSbn.getNotification().getSmallIcon(); - } - if (ic == null) { - throw new InflationException("No icon in notification from " + mSbn.getPackageName()); - } - return ic; - } - - private void updateSensitiveIconState() { - try { - StatusBarIcon ic = getIcon(getRow().getContext(), mSbn, isSensitive()); - setIcons(ic, Arrays.asList(expandedIcon, aodIcon)); - } catch (InflationException e) { - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "Unable to update icon", e); - } - } - } - - public void setIconTag(int key, Object tag) { - if (icon != null) { - icon.setTag(key, tag); - expandedIcon.setTag(key, tag); - } - - if (centeredIcon != null) { - centeredIcon.setTag(key, tag); - } - - if (aodIcon != null) { - aodIcon.setTag(key, tag); - } - } - - /** - * Update the notification icons. - * - * @param context the context to create the icons with. - * @param sbn the notification to read the icon from. - * @throws InflationException Exception if required icons are not valid or specified - */ - public void updateIcons(Context context, StatusBarNotification sbn) - throws InflationException { - if (icon != null) { - // Update the icon - mSmallIcon = null; - mPeopleAvatar = null; - - StatusBarIcon ic = getIcon(context, sbn, false /* redact */); - - icon.setNotification(sbn); - expandedIcon.setNotification(sbn); - aodIcon.setNotification(sbn); - setIcons(ic, Arrays.asList(icon, expandedIcon)); - - if (isSensitive()) { - ic = getIcon(context, sbn, true /* redact */); - } - setIcons(ic, Collections.singletonList(aodIcon)); - - if (centeredIcon != null) { - centeredIcon.setNotification(sbn); - setIcons(ic, Collections.singletonList(centeredIcon)); - } - } - } - - private boolean isImportantConversation() { - return getChannel() != null && getChannel().isImportantConversation(); - } - public int getContrastedColor(Context context, boolean isLowPriority, int backgroundColor) { int rawColor = isLowPriority ? Notification.COLOR_DEFAULT : @@ -1125,9 +883,8 @@ public final class NotificationEntry extends ListEntry { getRow().setSensitive(sensitive, deviceSensitive); if (sensitive != mSensitive) { mSensitive = sensitive; - updateSensitiveIconState(); - if (mOnSensitiveChangedListener != null) { - mOnSensitiveChangedListener.run(); + for (int i = 0; i < mOnSensitivityChangedListeners.size(); i++) { + mOnSensitivityChangedListeners.get(i).onSensitivityChanged(this); } } } @@ -1136,8 +893,14 @@ public final class NotificationEntry extends ListEntry { return mSensitive; } - public void setOnSensitiveChangedListener(Runnable listener) { - mOnSensitiveChangedListener = listener; + /** Add a listener to be notified when the entry's sensitivity changes. */ + public void addOnSensitivityChangedListener(OnSensitivityChangedListener listener) { + mOnSensitivityChangedListeners.add(listener); + } + + /** Remove a listener that was registered above. */ + public void removeOnSensitivityChangedListener(OnSensitivityChangedListener listener) { + mOnSensitivityChangedListeners.remove(listener); } public boolean isPulseSuppressed() { @@ -1167,6 +930,12 @@ public final class NotificationEntry extends ListEntry { } } + /** Listener interface for {@link #addOnSensitivityChangedListener} */ + public interface OnSensitivityChangedListener { + /** Called when the sensitivity changes */ + void onSensitivityChanged(@NonNull NotificationEntry entry); + } + /** @see #getDismissState() */ public enum DismissState { /** User has not dismissed this notif or its parent */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java index 4beeedecfdf50..7237284888261 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java @@ -16,7 +16,6 @@ package com.android.systemui.statusbar.notification.collection.inflation; -import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME; import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP; import android.annotation.Nullable; @@ -29,8 +28,6 @@ import android.util.Log; import android.view.ViewGroup; import com.android.internal.util.NotificationMessagingUtil; -import com.android.systemui.R; -import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.NotificationRemoteInputManager; @@ -38,25 +35,22 @@ import com.android.systemui.statusbar.NotificationUiAdjustment; import com.android.systemui.statusbar.notification.InflationException; import com.android.systemui.statusbar.notification.NotificationClicker; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.icon.IconManager; import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController; import com.android.systemui.statusbar.notification.row.NotifBindPipeline; -import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder; import com.android.systemui.statusbar.notification.row.RowContentBindParams; import com.android.systemui.statusbar.notification.row.RowContentBindStage; import com.android.systemui.statusbar.notification.row.RowInflaterTask; import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotificationRowComponent; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; -import com.android.systemui.statusbar.phone.KeyguardBypassController; -import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.StatusBar; import java.util.Objects; import javax.inject.Inject; -import javax.inject.Named; import javax.inject.Provider; import javax.inject.Singleton; @@ -66,23 +60,23 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { private static final String TAG = "NotificationViewManager"; - private final NotificationInterruptStateProvider mNotificationInterruptStateProvider; - private final Context mContext; - private final NotifBindPipeline mNotifBindPipeline; - private final RowContentBindStage mRowContentBindStage; private final NotificationMessagingUtil mMessagingUtil; private final NotificationRemoteInputManager mNotificationRemoteInputManager; private final NotificationLockscreenUserManager mNotificationLockscreenUserManager; + private final NotifBindPipeline mNotifBindPipeline; + private final RowContentBindStage mRowContentBindStage; + private final NotificationInterruptStateProvider mNotificationInterruptStateProvider; + private final Provider mRowInflaterTaskProvider; + private final ExpandableNotificationRowComponent.Builder + mExpandableNotificationRowComponentBuilder; + private final IconManager mIconManager; private NotificationPresenter mPresenter; private NotificationListContainer mListContainer; private NotificationRowContentBinder.InflationCallback mInflationCallback; private BindRowCallback mBindRowCallback; private NotificationClicker mNotificationClicker; - private final Provider mRowInflaterTaskProvider; - private final ExpandableNotificationRowComponent.Builder - mExpandableNotificationRowComponentBuilder; @Inject public NotificationRowBinderImpl( @@ -92,14 +86,10 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { NotificationLockscreenUserManager notificationLockscreenUserManager, NotifBindPipeline notifBindPipeline, RowContentBindStage rowContentBindStage, - @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress, - KeyguardBypassController keyguardBypassController, - StatusBarStateController statusBarStateController, - NotificationGroupManager notificationGroupManager, - NotificationGutsManager notificationGutsManager, NotificationInterruptStateProvider notificationInterruptionStateProvider, Provider rowInflaterTaskProvider, - ExpandableNotificationRowComponent.Builder expandableNotificationRowComponentBuilder) { + ExpandableNotificationRowComponent.Builder expandableNotificationRowComponentBuilder, + IconManager iconManager) { mContext = context; mNotifBindPipeline = notifBindPipeline; mRowContentBindStage = rowContentBindStage; @@ -109,6 +99,7 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { mNotificationInterruptStateProvider = notificationInterruptionStateProvider; mRowInflaterTaskProvider = rowInflaterTaskProvider; mExpandableNotificationRowComponentBuilder = expandableNotificationRowComponentBuilder; + mIconManager = iconManager; } /** @@ -120,6 +111,8 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { mPresenter = presenter; mListContainer = listContainer; mBindRowCallback = bindRowCallback; + + mIconManager.attach(); } public void setInflationCallback(NotificationRowContentBinder.InflationCallback callback) { @@ -142,12 +135,12 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { final StatusBarNotification sbn = entry.getSbn(); if (entry.rowExists()) { - entry.updateIcons(mContext, sbn); + mIconManager.updateIcons(entry); entry.reset(); updateNotification(entry, pmUser, sbn, entry.getRow()); entry.getRowController().setOnDismissRunnable(onDismissRunnable); } else { - entry.createIcons(mContext, sbn); + mIconManager.createIcons(entry); mRowInflaterTaskProvider.get().inflate(mContext, parent, entry, row -> { // Setup the controller for the view. @@ -227,8 +220,8 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { row.setLegacy(entry.targetSdk >= Build.VERSION_CODES.GINGERBREAD && entry.targetSdk < Build.VERSION_CODES.LOLLIPOP); - // TODO: should updates to the entry be happening somewhere else? - entry.setIconTag(R.id.icon_is_pre_L, entry.targetSdk < Build.VERSION_CODES.LOLLIPOP); + // TODO: should this be happening somewhere else? + mIconManager.updateIconTags(entry, entry.targetSdk); row.setOnActivatedListener(mPresenter); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconBuilder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconBuilder.kt new file mode 100644 index 0000000000000..afc123faba798 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconBuilder.kt @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.icon + +import android.app.Notification +import android.content.Context +import com.android.systemui.statusbar.StatusBarIconView +import com.android.systemui.statusbar.notification.collection.NotificationEntry +import javax.inject.Inject + +/** + * Testable wrapper around Context. + */ +class IconBuilder @Inject constructor( + private val context: Context +) { + fun createIconView(entry: NotificationEntry): StatusBarIconView { + return StatusBarIconView( + context, + "${entry.sbn.packageName}/0x${Integer.toHexString(entry.sbn.id)}", + entry.sbn) + } + + fun getIconContentDescription(n: Notification): CharSequence { + return StatusBarIconView.contentDescForNotification(context, n) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt new file mode 100644 index 0000000000000..bb0fcafdb354b --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt @@ -0,0 +1,338 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.icon + +import android.app.Notification +import android.app.Person +import android.content.pm.LauncherApps +import android.graphics.drawable.Icon +import android.os.Build +import android.os.Bundle +import android.util.Log +import android.view.View +import android.widget.ImageView +import com.android.internal.statusbar.StatusBarIcon +import com.android.systemui.R +import com.android.systemui.statusbar.StatusBarIconView +import com.android.systemui.statusbar.notification.InflationException +import com.android.systemui.statusbar.notification.collection.NotificationEntry +import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection +import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener +import javax.inject.Inject + +/** + * Inflates and updates icons associated with notifications + * + * Notifications are represented by icons in a few different places -- in the status bar, in the + * notification shelf, in AOD, etc. This class is in charge of inflating the views that hold these + * icons and keeping the icon assets themselves up to date as notifications change. + * + * TODO: Much of this code was copied whole-sale in order to get it out of NotificationEntry. + * Long-term, it should probably live somewhere in the content inflation pipeline. + */ +class IconManager @Inject constructor( + private val notifCollection: CommonNotifCollection, + private val launcherApps: LauncherApps, + private val iconBuilder: IconBuilder +) { + fun attach() { + notifCollection.addCollectionListener(entryListener) + } + + private val entryListener = object : NotifCollectionListener { + override fun onEntryInit(entry: NotificationEntry) { + entry.addOnSensitivityChangedListener(sensitivityListener) + } + + override fun onEntryCleanUp(entry: NotificationEntry) { + entry.removeOnSensitivityChangedListener(sensitivityListener) + } + + override fun onRankingApplied() { + // When the sensitivity changes OR when the isImportantConversation status changes, + // we need to update the icons + for (entry in notifCollection.allNotifs) { + val isImportant = isImportantConversation(entry) + if (entry.icons.areIconsAvailable && + isImportant != entry.icons.isImportantConversation) { + updateIconsSafe(entry) + } + entry.icons.isImportantConversation = isImportant + } + } + } + + private val sensitivityListener = NotificationEntry.OnSensitivityChangedListener { + entry -> updateIconsSafe(entry) + } + + /** + * Inflate icon views for each icon variant and assign appropriate icons to them. Stores the + * result in [NotificationEntry.getIcons]. + * + * @throws InflationException Exception if required icons are not valid or specified + */ + @Throws(InflationException::class) + fun createIcons(entry: NotificationEntry) { + // Construct the status bar icon view. + val sbIcon = iconBuilder.createIconView(entry) + sbIcon.scaleType = ImageView.ScaleType.CENTER_INSIDE + + // Construct the shelf icon view. + val shelfIcon = iconBuilder.createIconView(entry) + shelfIcon.scaleType = ImageView.ScaleType.CENTER_INSIDE + + shelfIcon.visibility = View.INVISIBLE + // TODO: This doesn't belong here + shelfIcon.setOnVisibilityChangedListener { newVisibility: Int -> + if (entry.row != null) { + entry.row.setIconsVisible(newVisibility != View.VISIBLE) + } + } + + // Construct the aod icon view. + val aodIcon = iconBuilder.createIconView(entry) + aodIcon.scaleType = ImageView.ScaleType.CENTER_INSIDE + aodIcon.setIncreasedSize(true) + + // Construct the centered icon view. + val centeredIcon = if (entry.sbn.notification.isMediaNotification) { + iconBuilder.createIconView(entry).apply { + scaleType = ImageView.ScaleType.CENTER_INSIDE + } + } else { + null + } + + // Set the icon views' icons + val (normalIconDescriptor, sensitiveIconDescriptor) = getIconDescriptors(entry) + + try { + setIcon(entry, normalIconDescriptor, sbIcon) + setIcon(entry, sensitiveIconDescriptor, shelfIcon) + setIcon(entry, sensitiveIconDescriptor, aodIcon) + if (centeredIcon != null) { + setIcon(entry, normalIconDescriptor, centeredIcon) + } + entry.icons = IconPack.buildPack(sbIcon, shelfIcon, aodIcon, centeredIcon, entry.icons) + } catch (e: InflationException) { + entry.icons = IconPack.buildEmptyPack(entry.icons) + throw e + } + } + + /** + * Update the notification icons. + * + * @param entry the notification to read the icon from. + * @throws InflationException Exception if required icons are not valid or specified + */ + @Throws(InflationException::class) + fun updateIcons(entry: NotificationEntry) { + if (!entry.icons.areIconsAvailable) { + return + } + entry.icons.smallIconDescriptor = null + entry.icons.peopleAvatarDescriptor = null + + val (normalIconDescriptor, sensitiveIconDescriptor) = getIconDescriptors(entry) + + entry.icons.statusBarIcon?.let { + it.notification = entry.sbn + setIcon(entry, normalIconDescriptor, it) + } + + entry.icons.shelfIcon?.let { + it.notification = entry.sbn + setIcon(entry, normalIconDescriptor, it) + } + + entry.icons.aodIcon?.let { + it.notification = entry.sbn + setIcon(entry, sensitiveIconDescriptor, it) + } + + entry.icons.centeredIcon?.let { + it.notification = entry.sbn + setIcon(entry, sensitiveIconDescriptor, it) + } + } + + /** + * Updates tags on the icon views to match the posting app's target SDK level + * + * Note that this method MUST be called after both [createIcons] and [updateIcons]. + */ + fun updateIconTags(entry: NotificationEntry, targetSdk: Int) { + setTagOnIconViews( + entry.icons, + R.id.icon_is_pre_L, + targetSdk < Build.VERSION_CODES.LOLLIPOP) + } + + private fun updateIconsSafe(entry: NotificationEntry) { + try { + updateIcons(entry) + } catch (e: InflationException) { + // TODO This should mark the entire row as involved in an inflation error + Log.e(TAG, "Unable to update icon", e) + } + } + + @Throws(InflationException::class) + private fun getIconDescriptors( + entry: NotificationEntry + ): Pair { + val iconDescriptor = getIconDescriptor(entry, false /* redact */) + val sensitiveDescriptor = if (entry.isSensitive) { + getIconDescriptor(entry, true /* redact */) + } else { + iconDescriptor + } + return Pair(iconDescriptor, sensitiveDescriptor) + } + + @Throws(InflationException::class) + private fun getIconDescriptor( + entry: NotificationEntry, + redact: Boolean + ): StatusBarIcon { + val n = entry.sbn.notification + val showPeopleAvatar = isImportantConversation(entry) && !redact + + val peopleAvatarDescriptor = entry.icons.peopleAvatarDescriptor + val smallIconDescriptor = entry.icons.smallIconDescriptor + + // If cached, return corresponding cached values + if (showPeopleAvatar && peopleAvatarDescriptor != null) { + return peopleAvatarDescriptor + } else if (!showPeopleAvatar && smallIconDescriptor != null) { + return smallIconDescriptor + } + + val icon = + (if (showPeopleAvatar) { + createPeopleAvatar(entry) + } else { + n.smallIcon + }) ?: throw InflationException( + "No icon in notification from " + entry.sbn.packageName) + + val ic = StatusBarIcon( + entry.sbn.user, + entry.sbn.packageName, + icon, + n.iconLevel, + n.number, + iconBuilder.getIconContentDescription(n)) + + // Cache if important conversation. + if (isImportantConversation(entry)) { + if (showPeopleAvatar) { + entry.icons.peopleAvatarDescriptor = ic + } else { + entry.icons.smallIconDescriptor = ic + } + } + + return ic + } + + @Throws(InflationException::class) + private fun setIcon( + entry: NotificationEntry, + iconDescriptor: StatusBarIcon, + iconView: StatusBarIconView + ) { + iconView.setTintIcons(shouldTintIconView(entry, iconView)) + if (!iconView.set(iconDescriptor)) { + throw InflationException("Couldn't create icon $iconDescriptor") + } + } + + @Throws(InflationException::class) + private fun createPeopleAvatar(entry: NotificationEntry): Icon? { + // Attempt to extract form shortcut. + val conversationId = entry.ranking.channel.conversationId + val query = LauncherApps.ShortcutQuery() + .setPackage(entry.sbn.packageName) + .setQueryFlags( + LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC + or LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED) + .setShortcutIds(listOf(conversationId)) + val shortcuts = launcherApps.getShortcuts(query, entry.sbn.user) + var ic: Icon? = null + if (shortcuts != null && shortcuts.isNotEmpty()) { + ic = shortcuts[0].icon + } + + // Fall back to notification large icon if available + if (ic == null) { + ic = entry.sbn.notification.getLargeIcon() + } + + // Fall back to extract from message + if (ic == null) { + val extras: Bundle = entry.sbn.notification.extras + val messages = Notification.MessagingStyle.Message.getMessagesFromBundleArray( + extras.getParcelableArray(Notification.EXTRA_MESSAGES)) + val user = extras.getParcelable(Notification.EXTRA_MESSAGING_PERSON) + for (i in messages.indices.reversed()) { + val message = messages[i] + val sender = message.senderPerson + if (sender != null && sender !== user) { + ic = message.senderPerson!!.icon + break + } + } + } + + // Revert to small icon if still not available + if (ic == null) { + ic = entry.sbn.notification.smallIcon + } + if (ic == null) { + throw InflationException("No icon in notification from " + entry.sbn.packageName) + } + return ic + } + + /** + * Determines if this icon should be tinted based on the sensitivity of the icon, its context + * and the user's indicated sensitivity preference. + * + * @param iconView The icon that should/should not be tinted. + */ + private fun shouldTintIconView(entry: NotificationEntry, iconView: StatusBarIconView): Boolean { + val usedInSensitiveContext = + iconView === entry.icons.shelfIcon || iconView === entry.icons.aodIcon + return !isImportantConversation(entry) || usedInSensitiveContext && entry.isSensitive + } + + private fun isImportantConversation(entry: NotificationEntry): Boolean { + return entry.ranking.channel != null && entry.ranking.channel.isImportantConversation + } + + private fun setTagOnIconViews(icons: IconPack, key: Int, tag: Any) { + icons.statusBarIcon?.setTag(key, tag) + icons.shelfIcon?.setTag(key, tag) + icons.aodIcon?.setTag(key, tag) + icons.centeredIcon?.setTag(key, tag) + } +} + +private const val TAG = "IconManager" \ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconPack.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconPack.java new file mode 100644 index 0000000000000..054e381f096a7 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconPack.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.icon; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.internal.statusbar.StatusBarIcon; +import com.android.systemui.statusbar.StatusBarIconView; + +/** + * Data class for storing icons associated with a notification + */ +public final class IconPack { + + private final boolean mAreIconsAvailable; + @Nullable private final StatusBarIconView mStatusBarIcon; + @Nullable private final StatusBarIconView mShelfIcon; + @Nullable private final StatusBarIconView mAodIcon; + @Nullable private final StatusBarIconView mCenteredIcon; + + @Nullable private StatusBarIcon mSmallIconDescriptor; + @Nullable private StatusBarIcon mPeopleAvatarDescriptor; + + private boolean mIsImportantConversation; + + /** + * Builds an empty instance of IconPack that doesn't have any icons (because either they + * haven't been inflated yet or there was an error while inflating them). + */ + public static IconPack buildEmptyPack(@Nullable IconPack fromSource) { + return new IconPack(false, null, null, null, null, fromSource); + } + + /** + * Builds an instance of an IconPack that contains successfully-inflated icons + */ + public static IconPack buildPack( + @NonNull StatusBarIconView statusBarIcon, + @NonNull StatusBarIconView shelfIcon, + @NonNull StatusBarIconView aodIcon, + @Nullable StatusBarIconView centeredIcon, + @Nullable IconPack source) { + return new IconPack(true, statusBarIcon, shelfIcon, aodIcon, centeredIcon, source); + } + + private IconPack( + boolean areIconsAvailable, + @Nullable StatusBarIconView statusBarIcon, + @Nullable StatusBarIconView shelfIcon, + @Nullable StatusBarIconView aodIcon, + @Nullable StatusBarIconView centeredIcon, + @Nullable IconPack source) { + mAreIconsAvailable = areIconsAvailable; + mStatusBarIcon = statusBarIcon; + mShelfIcon = shelfIcon; + mCenteredIcon = centeredIcon; + mAodIcon = aodIcon; + if (source != null) { + mIsImportantConversation = source.mIsImportantConversation; + } + } + + /** The version of the notification icon that appears in the status bar. */ + @Nullable + public StatusBarIconView getStatusBarIcon() { + return mStatusBarIcon; + } + + /** + * The version of the icon that appears in the "shelf" at the bottom of the notification shade. + * In general, this icon also appears somewhere on the notification and is "sucked" into the + * shelf as the scrolls beyond it. + */ + @Nullable + public StatusBarIconView getShelfIcon() { + return mShelfIcon; + } + + @Nullable + public StatusBarIconView getCenteredIcon() { + return mCenteredIcon; + } + + /** The version of the icon that's shown when pulsing (in AOD). */ + @Nullable + public StatusBarIconView getAodIcon() { + return mAodIcon; + } + + @Nullable + StatusBarIcon getSmallIconDescriptor() { + return mSmallIconDescriptor; + } + + void setSmallIconDescriptor(@Nullable StatusBarIcon smallIconDescriptor) { + mSmallIconDescriptor = smallIconDescriptor; + } + + @Nullable + StatusBarIcon getPeopleAvatarDescriptor() { + return mPeopleAvatarDescriptor; + } + + void setPeopleAvatarDescriptor(@Nullable StatusBarIcon peopleAvatarDescriptor) { + mPeopleAvatarDescriptor = peopleAvatarDescriptor; + } + + boolean isImportantConversation() { + return mIsImportantConversation; + } + + void setImportantConversation(boolean importantConversation) { + mIsImportantConversation = importantConversation; + } + + public boolean getAreIconsAvailable() { + return mAreIconsAvailable; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/DungeonRow.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/DungeonRow.kt index 373457d4e3366..dbfa27f1f68ef 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/DungeonRow.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/DungeonRow.kt @@ -37,7 +37,7 @@ class DungeonRow(context: Context, attrs: AttributeSet) : LinearLayout(context, } (findViewById(R.id.icon) as StatusBarIconView).apply { - set(entry?.icon?.statusBarIcon) + set(entry?.icons?.statusBarIcon?.statusBarIcon) } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java index f61fe98309397..b1db5b5b4312f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java @@ -579,7 +579,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView @VisibleForTesting void updateShelfIconColor() { - StatusBarIconView expandedIcon = mEntry.expandedIcon; + StatusBarIconView expandedIcon = mEntry.getIcons().getShelfIcon(); boolean isPreL = Boolean.TRUE.equals(expandedIcon.getTag(R.id.icon_is_pre_L)); boolean colorize = !isPreL || NotificationUtils.isGrayscale(expandedIcon, ContrastColorUtil.getInstance(mContext)); @@ -1290,7 +1290,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView setLongPressListener(null); mGroupParentWhenDismissed = mNotificationParent; mChildAfterViewWhenDismissed = null; - mEntry.icon.setDismissed(); + mEntry.getIcons().getStatusBarIcon().setDismissed(); if (isChildInGroup()) { List notificationChildren = mNotificationParent.getNotificationChildren(); @@ -1832,7 +1832,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView mTranslateableViews.get(i).setTranslationX(0); } invalidateOutline(); - getEntry().expandedIcon.setScrollX(0); + getEntry().getIcons().getShelfIcon().setScrollX(0); } if (mMenuRow != null) { @@ -1912,7 +1912,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView // In order to keep the shelf in sync with this swiping, we're simply translating // it's icon by the same amount. The translation is already being used for the normal // positioning, so we can use the scrollX instead. - getEntry().expandedIcon.setScrollX((int) -translationX); + getEntry().getIcons().getShelfIcon().setScrollX((int) -translationX); } if (mMenuRow != null && mMenuRow.getMenuView() != null) { @@ -2111,7 +2111,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView @Override public StatusBarIconView getShelfIcon() { - return getEntry().expandedIcon; + return getEntry().getIcons().getShelfIcon(); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java index 0996ff27e9a33..14442e346db49 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java @@ -453,9 +453,10 @@ public class StackStateAnimator { needsAnimation = false; } NotificationEntry entry = row.getEntry(); - StatusBarIconView icon = entry.icon; - if (entry.centeredIcon != null && entry.centeredIcon.getParent() != null) { - icon = entry.centeredIcon; + StatusBarIconView icon = entry.getIcons().getStatusBarIcon(); + final StatusBarIconView centeredIcon = entry.getIcons().getCenteredIcon(); + if (centeredIcon != null && centeredIcon.getParent() != null) { + icon = centeredIcon; } if (icon.getParent() != null) { icon.getLocationOnScreen(mTmpLocation); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java index c39ee3a902308..51c02c9f93ab2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java @@ -269,7 +269,7 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener, } updateIsolatedIconLocation(false /* requireUpdate */); mNotificationIconAreaController.showIconIsolated(newEntry == null ? null - : newEntry.icon, animateIsolation); + : newEntry.getIcons().getStatusBarIcon(), animateIsolation); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java index b09ccffdc4dec..f58cce58af74d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java @@ -253,8 +253,8 @@ public class NotificationIconAreaController implements DarkReceiver, boolean hidePulsing, boolean onlyShowCenteredIcon) { final boolean isCenteredNotificationIcon = mCenteredIconView != null - && entry.centeredIcon != null - && Objects.equals(entry.centeredIcon, mCenteredIconView); + && entry.getIcons().getCenteredIcon() != null + && Objects.equals(entry.getIcons().getCenteredIcon(), mCenteredIconView); if (onlyShowCenteredIcon) { return isCenteredNotificationIcon; } @@ -307,7 +307,7 @@ public class NotificationIconAreaController implements DarkReceiver, } private void updateShelfIcons() { - updateIconsForLayout(entry -> entry.expandedIcon, mShelfIcons, + updateIconsForLayout(entry -> entry.getIcons().getShelfIcon(), mShelfIcons, true /* showAmbient */, true /* showLowPriority */, false /* hideDismissed */, @@ -319,7 +319,7 @@ public class NotificationIconAreaController implements DarkReceiver, } public void updateStatusBarIcons() { - updateIconsForLayout(entry -> entry.icon, mNotificationIcons, + updateIconsForLayout(entry -> entry.getIcons().getStatusBarIcon(), mNotificationIcons, false /* showAmbient */, mShowLowPriority, true /* hideDismissed */, @@ -331,7 +331,7 @@ public class NotificationIconAreaController implements DarkReceiver, } private void updateCenterIcon() { - updateIconsForLayout(entry -> entry.centeredIcon, mCenteredIcon, + updateIconsForLayout(entry -> entry.getIcons().getCenteredIcon(), mCenteredIcon, false /* showAmbient */, true /* showLowPriority */, false /* hideDismissed */, @@ -343,7 +343,7 @@ public class NotificationIconAreaController implements DarkReceiver, } public void updateAodNotificationIcons() { - updateIconsForLayout(entry -> entry.aodIcon, mAodIcons, + updateIconsForLayout(entry -> entry.getIcons().getAodIcon(), mAodIcons, false /* showAmbient */, true /* showLowPriority */, true /* hideDismissed */, @@ -517,7 +517,7 @@ public class NotificationIconAreaController implements DarkReceiver, * Shows the icon view given in the center. */ public void showIconCentered(NotificationEntry entry) { - StatusBarIconView icon = entry == null ? null : entry.centeredIcon; + StatusBarIconView icon = entry == null ? null : entry.getIcons().getCenteredIcon(); if (!Objects.equals(mCenteredIconView, icon)) { mCenteredIconView = icon; updateNotificationIcons(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java index e960185ebe3a2..c356e0d16512d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java @@ -329,10 +329,10 @@ public class ExpandableNotificationRowTest extends SysuiTestCase { @Test public void testIconScrollXAfterTranslationAndReset() throws Exception { mGroupRow.setTranslation(50); - assertEquals(50, -mGroupRow.getEntry().expandedIcon.getScrollX()); + assertEquals(50, -mGroupRow.getEntry().getIcons().getShelfIcon().getScrollX()); mGroupRow.resetTranslation(); - assertEquals(0, mGroupRow.getEntry().expandedIcon.getScrollX()); + assertEquals(0, mGroupRow.getEntry().getIcons().getShelfIcon().getScrollX()); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java index a21a047d9a70a..cb44703478266 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java @@ -28,6 +28,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.Notification; +import android.content.pm.LauncherApps; import android.os.Handler; import android.service.notification.NotificationListenerService; import android.service.notification.NotificationListenerService.Ranking; @@ -61,6 +62,8 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationRankingManager; import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl; import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider; +import com.android.systemui.statusbar.notification.icon.IconBuilder; +import com.android.systemui.statusbar.notification.icon.IconManager; import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; @@ -245,14 +248,13 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase { mLockscreenUserManager, pipeline, stage, - true, /* allowLongPress */ - mock(KeyguardBypassController.class), - mock(StatusBarStateController.class), - mGroupManager, - mGutsManager, mNotificationInterruptionStateProvider, RowInflaterTask::new, - mExpandableNotificationRowComponentBuilder); + mExpandableNotificationRowComponentBuilder, + new IconManager( + mEntryManager, + mock(LauncherApps.class), + new IconBuilder(mContext))); mEntryManager.setUpWithPresenter(mPresenter); mEntryManager.addNotificationEntryListener(mEntryListener); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java index 5a89fc44f970d..dc3374bd511be 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java @@ -34,6 +34,7 @@ import android.app.NotificationChannel; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; +import android.content.pm.LauncherApps; import android.graphics.drawable.Icon; import android.os.UserHandle; import android.service.notification.StatusBarNotification; @@ -53,6 +54,8 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; +import com.android.systemui.statusbar.notification.icon.IconBuilder; +import com.android.systemui.statusbar.notification.icon.IconManager; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow.ExpansionLogger; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow.OnExpandClickListener; import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag; @@ -93,6 +96,7 @@ public class NotificationTestHelper { private final NotifBindPipeline mBindPipeline; private final NotifCollectionListener mBindPipelineEntryListener; private final RowContentBindStage mBindStage; + private final IconManager mIconManager; private StatusBarStateController mStatusBarStateController; public NotificationTestHelper(Context context, TestableDependency dependency) { @@ -106,6 +110,10 @@ public class NotificationTestHelper { mock(KeyguardBypassController.class), mock(NotificationGroupManager.class), mock(ConfigurationControllerImpl.class)); mGroupManager.setHeadsUpManager(mHeadsUpManager); + mIconManager = new IconManager( + mock(CommonNotifCollection.class), + mock(LauncherApps.class), + new IconBuilder(mContext)); NotificationContentInflater contentBinder = new NotificationContentInflater( mock(NotifRemoteViewCache.class), @@ -377,7 +385,7 @@ public class NotificationTestHelper { .build(); entry.setRow(row); - entry.createIcons(mContext, entry.getSbn()); + mIconManager.createIcons(entry); row.setEntry(entry); mBindPipelineEntryListener.onEntryInit(entry);