1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.launcher3.notification; 18 19 import static com.android.launcher3.AbstractFloatingView.TYPE_ACTION_POPUP; 20 import static com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_ALL_APPS; 21 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_NOTIFICATION_LAUNCH_TAP; 22 23 import android.app.ActivityOptions; 24 import android.app.Notification; 25 import android.app.PendingIntent; 26 import android.content.Context; 27 import android.graphics.drawable.Drawable; 28 import android.graphics.drawable.Icon; 29 import android.os.Bundle; 30 import android.service.notification.StatusBarNotification; 31 import android.view.View; 32 33 import com.android.launcher3.AbstractFloatingView; 34 import com.android.launcher3.LauncherAppState; 35 import com.android.launcher3.dot.DotInfo; 36 import com.android.launcher3.graphics.IconPalette; 37 import com.android.launcher3.model.data.ItemInfo; 38 import com.android.launcher3.popup.PopupDataProvider; 39 import com.android.launcher3.util.PackageUserKey; 40 import com.android.launcher3.views.ActivityContext; 41 42 /** 43 * An object that contains relevant information from a {@link StatusBarNotification}. This should 44 * only be created when we need to show the notification contents on the UI; until then, a 45 * {@link DotInfo} with only the notification key should 46 * be passed around, and then this can be constructed using the StatusBarNotification from 47 * {@link NotificationListener#getNotificationsForKeys(java.util.List)}. 48 */ 49 public class NotificationInfo implements View.OnClickListener { 50 51 public final PackageUserKey packageUserKey; 52 public final String notificationKey; 53 public final CharSequence title; 54 public final CharSequence text; 55 public final PendingIntent intent; 56 public final boolean autoCancel; 57 public final boolean dismissable; 58 59 private final ItemInfo mItemInfo; 60 private Drawable mIconDrawable; 61 private int mIconColor; 62 private boolean mIsIconLarge; 63 64 /** 65 * Extracts the data that we need from the StatusBarNotification. 66 */ NotificationInfo(Context context, StatusBarNotification statusBarNotification, ItemInfo itemInfo)67 public NotificationInfo(Context context, StatusBarNotification statusBarNotification, 68 ItemInfo itemInfo) { 69 packageUserKey = PackageUserKey.fromNotification(statusBarNotification); 70 notificationKey = statusBarNotification.getKey(); 71 Notification notification = statusBarNotification.getNotification(); 72 title = notification.extras.getCharSequence(Notification.EXTRA_TITLE); 73 text = notification.extras.getCharSequence(Notification.EXTRA_TEXT); 74 75 int iconType = notification.getBadgeIconType(); 76 // Load the icon. Since it is backed by ashmem, we won't copy the entire bitmap 77 // into our process as long as we don't touch it and it exists in systemui. 78 Icon icon = iconType == Notification.BADGE_ICON_SMALL ? null : notification.getLargeIcon(); 79 if (icon == null) { 80 // Use the small icon. 81 icon = notification.getSmallIcon(); 82 mIconDrawable = icon == null ? null : icon.loadDrawable(context); 83 mIconColor = statusBarNotification.getNotification().color; 84 mIsIconLarge = false; 85 } else { 86 // Use the large icon. 87 mIconDrawable = icon.loadDrawable(context); 88 mIsIconLarge = true; 89 } 90 if (mIconDrawable == null) { 91 mIconDrawable = LauncherAppState.getInstance(context).getIconCache() 92 .getDefaultIcon(statusBarNotification.getUser()).newIcon(context); 93 } 94 intent = notification.contentIntent; 95 autoCancel = (notification.flags & Notification.FLAG_AUTO_CANCEL) != 0; 96 dismissable = (notification.flags & Notification.FLAG_ONGOING_EVENT) == 0; 97 this.mItemInfo = itemInfo; 98 } 99 100 @Override onClick(View view)101 public void onClick(View view) { 102 if (intent == null) { 103 return; 104 } 105 final ActivityContext context = ActivityContext.lookupContext(view.getContext()); 106 Bundle activityOptions = ActivityOptions.makeClipRevealAnimation( 107 view, 0, 0, view.getWidth(), view.getHeight()).toBundle(); 108 try { 109 intent.send(null, 0, null, null, null, null, activityOptions); 110 context.getStatsLogManager().logger().withItemInfo(mItemInfo) 111 .log(LAUNCHER_NOTIFICATION_LAUNCH_TAP); 112 } catch (PendingIntent.CanceledException e) { 113 e.printStackTrace(); 114 } 115 if (autoCancel) { 116 PopupDataProvider popupDataProvider = context.getPopupDataProvider(); 117 if (popupDataProvider != null) { 118 popupDataProvider.cancelNotification(notificationKey); 119 } 120 } 121 AbstractFloatingView.closeOpenViews( 122 context, true, TYPE_ACTION_POPUP | TYPE_TASKBAR_ALL_APPS); 123 } 124 getIconForBackground(Context context, int background)125 public Drawable getIconForBackground(Context context, int background) { 126 if (mIsIconLarge) { 127 // Only small icons should be tinted. 128 return mIconDrawable; 129 } 130 mIconColor = IconPalette.resolveContrastColor(context, mIconColor, background); 131 Drawable icon = mIconDrawable.mutate(); 132 // DrawableContainer ignores the color filter if it's already set, so clear it first to 133 // get it set and invalidated properly. 134 icon.setTintList(null); 135 icon.setTint(mIconColor); 136 return icon; 137 } 138 } 139