diff options
2 files changed, 180 insertions, 32 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java index 9c626f7b877d..12add8c8d9cc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java @@ -159,6 +159,7 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi private boolean mDismissed; private Runnable mOnDismissListener; private boolean mIncreasedSize; + private boolean mTintIcons = true; public StatusBarIconView(Context context, String slot, StatusBarNotification sbn) { this(context, slot, sbn, false); @@ -612,6 +613,11 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi } private void updateIconColor() { + if (!mTintIcons) { + setColorFilter(null); + return; + } + if (mCurrentSetColor != NO_COLOR) { if (mMatrixColorFilter == null) { mMatrix = new float[4 * 5]; @@ -953,6 +959,19 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi maybeUpdateIconScaleDimens(); } + /** + * Sets whether the icon should be tinted. If the state differs from the supplied setting, this + * will update the icon colors. + * + * @param shouldTint Whether the icon should be tinted. + */ + public void setTintIcons(boolean shouldTint) { + if (mTintIcons != shouldTint) { + mTintIcons = shouldTint; + updateIconColor(); + } + } + public interface OnVisibilityChangedListener { void onVisibilityChanged(int newVisibility); } 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 f482d37deb55..25a832d8da5e 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,6 +29,8 @@ 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; @@ -42,6 +44,9 @@ 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; @@ -50,6 +55,7 @@ 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; @@ -75,6 +81,8 @@ 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; @@ -94,11 +102,15 @@ 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 */ @@ -459,12 +471,7 @@ public final class NotificationEntry extends ListEntry { */ public void createIcons(Context context, StatusBarNotification sbn) throws InflationException { - Notification n = sbn.getNotification(); - final Icon smallIcon = n.getSmallIcon(); - if (smallIcon == null) { - throw new InflationException("No small icon in notification from " - + sbn.getPackageName()); - } + StatusBarIcon ic = getIcon(context, sbn, false /* redact */); // Construct the icon. icon = new StatusBarIconView(context, @@ -482,21 +489,20 @@ public final class NotificationEntry extends ListEntry { aodIcon.setScaleType(ImageView.ScaleType.CENTER_INSIDE); aodIcon.setIncreasedSize(true); - final StatusBarIcon ic = new StatusBarIcon( - sbn.getUser(), - sbn.getPackageName(), - smallIcon, - n.iconLevel, - n.number, - StatusBarIconView.contentDescForNotification(context, n)); - - if (!icon.set(ic) || !expandedIcon.set(ic) || !aodIcon.set(ic)) { + 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 new InflationException("Couldn't create icon: " + ic); + throw e; } + expandedIcon.setVisibility(View.INVISIBLE); expandedIcon.setOnVisibilityChangedListener( newVisibility -> { @@ -510,10 +516,130 @@ public final class NotificationEntry extends ListEntry { centeredIcon = new StatusBarIconView(context, sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), sbn); centeredIcon.setScaleType(ImageView.ScaleType.CENTER_INSIDE); - - if (!centeredIcon.set(ic)) { + try { + setIcons(ic, Collections.singletonList(centeredIcon)); + } catch (InflationException e) { centeredIcon = null; - throw new InflationException("Couldn't update centered icon: " + ic); + 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<StatusBarIconView> 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<ShortcutInfo> 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<Message> 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); } } } @@ -544,30 +670,32 @@ public final class NotificationEntry extends ListEntry { throws InflationException { if (icon != null) { // Update the icon - Notification n = sbn.getNotification(); - final StatusBarIcon ic = new StatusBarIcon( - mSbn.getUser(), - mSbn.getPackageName(), - n.getSmallIcon(), - n.iconLevel, - n.number, - StatusBarIconView.contentDescForNotification(context, n)); + mSmallIcon = null; + mPeopleAvatar = null; + + StatusBarIcon ic = getIcon(context, sbn, false /* redact */); + icon.setNotification(sbn); expandedIcon.setNotification(sbn); aodIcon.setNotification(sbn); - if (!icon.set(ic) || !expandedIcon.set(ic) || !aodIcon.set(ic)) { - throw new InflationException("Couldn't update icon: " + ic); + 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); - if (!centeredIcon.set(ic)) { - throw new InflationException("Couldn't update centered icon: " + ic); - } + 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 : @@ -996,6 +1124,7 @@ public final class NotificationEntry extends ListEntry { getRow().setSensitive(sensitive, deviceSensitive); if (sensitive != mSensitive) { mSensitive = sensitive; + updateSensitiveIconState(); if (mOnSensitiveChangedListener != null) { mOnSensitiveChangedListener.run(); } |