Mady Mellor | 7f23490 | 2019-10-20 12:06:29 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2019 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.systemui.bubbles; |
| 18 | |
Mady Mellor | 89eb348 | 2019-11-13 17:32:01 -0800 | [diff] [blame] | 19 | import static android.app.Notification.EXTRA_MESSAGES; |
Mady Mellor | b547e5e | 2019-12-02 10:15:56 -0800 | [diff] [blame] | 20 | import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC; |
| 21 | import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_MANIFEST; |
| 22 | import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED; |
| 23 | |
Mady Mellor | ff076eb | 2019-11-13 10:12:06 -0800 | [diff] [blame] | 24 | import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_EXPERIMENTS; |
| 25 | import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES; |
| 26 | import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME; |
Mady Mellor | b547e5e | 2019-12-02 10:15:56 -0800 | [diff] [blame] | 27 | |
Mady Mellor | 7f23490 | 2019-10-20 12:06:29 -0700 | [diff] [blame] | 28 | import android.app.Notification; |
| 29 | import android.app.PendingIntent; |
Mady Mellor | 89eb348 | 2019-11-13 17:32:01 -0800 | [diff] [blame] | 30 | import android.app.Person; |
Mady Mellor | 7f23490 | 2019-10-20 12:06:29 -0700 | [diff] [blame] | 31 | import android.content.Context; |
Mady Mellor | b547e5e | 2019-12-02 10:15:56 -0800 | [diff] [blame] | 32 | import android.content.pm.LauncherApps; |
| 33 | import android.content.pm.ShortcutInfo; |
Mady Mellor | 58dc519 | 2019-12-16 13:49:56 -0800 | [diff] [blame] | 34 | import android.graphics.Color; |
| 35 | import android.graphics.drawable.BitmapDrawable; |
| 36 | import android.graphics.drawable.Drawable; |
Mady Mellor | 7f23490 | 2019-10-20 12:06:29 -0700 | [diff] [blame] | 37 | import android.graphics.drawable.Icon; |
Mady Mellor | 89eb348 | 2019-11-13 17:32:01 -0800 | [diff] [blame] | 38 | import android.os.Bundle; |
| 39 | import android.os.Parcelable; |
Mady Mellor | b547e5e | 2019-12-02 10:15:56 -0800 | [diff] [blame] | 40 | import android.os.UserHandle; |
Mady Mellor | 7f23490 | 2019-10-20 12:06:29 -0700 | [diff] [blame] | 41 | import android.provider.Settings; |
Mady Mellor | ff076eb | 2019-11-13 10:12:06 -0800 | [diff] [blame] | 42 | import android.util.Log; |
Mady Mellor | 7f23490 | 2019-10-20 12:06:29 -0700 | [diff] [blame] | 43 | |
Mady Mellor | 58dc519 | 2019-12-16 13:49:56 -0800 | [diff] [blame] | 44 | import com.android.internal.graphics.ColorUtils; |
Mady Mellor | 89eb348 | 2019-11-13 17:32:01 -0800 | [diff] [blame] | 45 | import com.android.internal.util.ArrayUtils; |
Mady Mellor | 58dc519 | 2019-12-16 13:49:56 -0800 | [diff] [blame] | 46 | import com.android.internal.util.ContrastColorUtil; |
Mady Mellor | 7f23490 | 2019-10-20 12:06:29 -0700 | [diff] [blame] | 47 | import com.android.systemui.statusbar.notification.collection.NotificationEntry; |
Mady Mellor | 58dc519 | 2019-12-16 13:49:56 -0800 | [diff] [blame] | 48 | import com.android.systemui.statusbar.notification.people.PeopleHubNotificationListenerKt; |
Mady Mellor | 7f23490 | 2019-10-20 12:06:29 -0700 | [diff] [blame] | 49 | |
Mady Mellor | 89eb348 | 2019-11-13 17:32:01 -0800 | [diff] [blame] | 50 | import java.util.ArrayList; |
Mady Mellor | b547e5e | 2019-12-02 10:15:56 -0800 | [diff] [blame] | 51 | import java.util.Arrays; |
| 52 | import java.util.List; |
| 53 | |
Mady Mellor | 7f23490 | 2019-10-20 12:06:29 -0700 | [diff] [blame] | 54 | /** |
| 55 | * Common class for experiments controlled via secure settings. |
| 56 | */ |
| 57 | public class BubbleExperimentConfig { |
Mady Mellor | ff076eb | 2019-11-13 10:12:06 -0800 | [diff] [blame] | 58 | private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleController" : TAG_BUBBLES; |
Mady Mellor | 7f23490 | 2019-10-20 12:06:29 -0700 | [diff] [blame] | 59 | |
Mady Mellor | b547e5e | 2019-12-02 10:15:56 -0800 | [diff] [blame] | 60 | private static final int BUBBLE_HEIGHT = 10000; |
| 61 | |
Mady Mellor | 7f23490 | 2019-10-20 12:06:29 -0700 | [diff] [blame] | 62 | private static final String ALLOW_ANY_NOTIF_TO_BUBBLE = "allow_any_notif_to_bubble"; |
| 63 | private static final boolean ALLOW_ANY_NOTIF_TO_BUBBLE_DEFAULT = false; |
| 64 | |
| 65 | private static final String ALLOW_MESSAGE_NOTIFS_TO_BUBBLE = "allow_message_notifs_to_bubble"; |
Mady Mellor | dd6fe61 | 2020-04-15 11:47:55 -0700 | [diff] [blame] | 66 | private static final boolean ALLOW_MESSAGE_NOTIFS_TO_BUBBLE_DEFAULT = false; |
Mady Mellor | 7f23490 | 2019-10-20 12:06:29 -0700 | [diff] [blame] | 67 | |
Mady Mellor | b547e5e | 2019-12-02 10:15:56 -0800 | [diff] [blame] | 68 | private static final String ALLOW_SHORTCUTS_TO_BUBBLE = "allow_shortcuts_to_bubble"; |
| 69 | private static final boolean ALLOW_SHORTCUT_TO_BUBBLE_DEFAULT = false; |
| 70 | |
Mady Mellor | ea13b23 | 2019-12-05 15:55:46 -0800 | [diff] [blame] | 71 | private static final String WHITELISTED_AUTO_BUBBLE_APPS = "whitelisted_auto_bubble_apps"; |
| 72 | |
Lyn Han | 8cc4bf8 | 2020-03-05 16:34:37 -0800 | [diff] [blame] | 73 | private static final String ALLOW_BUBBLE_OVERFLOW = "allow_bubble_overflow"; |
Lyn Han | 2f6e89d | 2020-04-15 10:01:01 -0700 | [diff] [blame] | 74 | private static final boolean ALLOW_BUBBLE_OVERFLOW_DEFAULT = true; |
Lyn Han | 8cc4bf8 | 2020-03-05 16:34:37 -0800 | [diff] [blame] | 75 | |
Mady Mellor | 7f23490 | 2019-10-20 12:06:29 -0700 | [diff] [blame] | 76 | /** |
| 77 | * When true, if a notification has the information necessary to bubble (i.e. valid |
| 78 | * contentIntent and an icon or image), then a {@link android.app.Notification.BubbleMetadata} |
| 79 | * object will be created by the system and added to the notification. |
Mady Mellor | b547e5e | 2019-12-02 10:15:56 -0800 | [diff] [blame] | 80 | * <p> |
| 81 | * This does not produce a bubble, only adds the metadata based on the notification info. |
Mady Mellor | 7f23490 | 2019-10-20 12:06:29 -0700 | [diff] [blame] | 82 | */ |
| 83 | static boolean allowAnyNotifToBubble(Context context) { |
| 84 | return Settings.Secure.getInt(context.getContentResolver(), |
| 85 | ALLOW_ANY_NOTIF_TO_BUBBLE, |
| 86 | ALLOW_ANY_NOTIF_TO_BUBBLE_DEFAULT ? 1 : 0) != 0; |
| 87 | } |
| 88 | |
| 89 | /** |
Lyn Han | 8cc4bf8 | 2020-03-05 16:34:37 -0800 | [diff] [blame] | 90 | * When true, show a menu with dismissed and aged-out bubbles. |
| 91 | */ |
| 92 | static boolean allowBubbleOverflow(Context context) { |
| 93 | return Settings.Secure.getInt(context.getContentResolver(), |
| 94 | ALLOW_BUBBLE_OVERFLOW, |
| 95 | ALLOW_BUBBLE_OVERFLOW_DEFAULT ? 1 : 0) != 0; |
| 96 | } |
| 97 | |
| 98 | /** |
Mady Mellor | 7f23490 | 2019-10-20 12:06:29 -0700 | [diff] [blame] | 99 | * Same as {@link #allowAnyNotifToBubble(Context)} except it filters for notifications that |
| 100 | * are using {@link Notification.MessagingStyle} and have remote input. |
| 101 | */ |
| 102 | static boolean allowMessageNotifsToBubble(Context context) { |
| 103 | return Settings.Secure.getInt(context.getContentResolver(), |
| 104 | ALLOW_MESSAGE_NOTIFS_TO_BUBBLE, |
| 105 | ALLOW_MESSAGE_NOTIFS_TO_BUBBLE_DEFAULT ? 1 : 0) != 0; |
| 106 | } |
| 107 | |
| 108 | /** |
Mady Mellor | b547e5e | 2019-12-02 10:15:56 -0800 | [diff] [blame] | 109 | * When true, if the notification is able to bubble via {@link #allowAnyNotifToBubble(Context)} |
| 110 | * or {@link #allowMessageNotifsToBubble(Context)} or via normal BubbleMetadata, then a new |
| 111 | * BubbleMetadata object is constructed based on the shortcut info. |
| 112 | * <p> |
| 113 | * This does not produce a bubble, only adds the metadata based on shortcut info. |
| 114 | */ |
| 115 | static boolean useShortcutInfoToBubble(Context context) { |
| 116 | return Settings.Secure.getInt(context.getContentResolver(), |
| 117 | ALLOW_SHORTCUTS_TO_BUBBLE, |
| 118 | ALLOW_SHORTCUT_TO_BUBBLE_DEFAULT ? 1 : 0) != 0; |
| 119 | } |
| 120 | |
| 121 | /** |
Mady Mellor | ea13b23 | 2019-12-05 15:55:46 -0800 | [diff] [blame] | 122 | * Returns whether the provided package is whitelisted to bubble. |
| 123 | */ |
| 124 | static boolean isPackageWhitelistedToAutoBubble(Context context, String packageName) { |
| 125 | String unsplitList = Settings.Secure.getString(context.getContentResolver(), |
| 126 | WHITELISTED_AUTO_BUBBLE_APPS); |
| 127 | if (unsplitList != null) { |
| 128 | // We expect the list to be separated by commas and no white space (but we trim in case) |
| 129 | String[] packageList = unsplitList.split(","); |
| 130 | for (int i = 0; i < packageList.length; i++) { |
| 131 | if (packageList[i].trim().equals(packageName)) { |
| 132 | return true; |
| 133 | } |
| 134 | } |
| 135 | } |
| 136 | return false; |
| 137 | } |
| 138 | |
| 139 | /** |
Mady Mellor | 7f23490 | 2019-10-20 12:06:29 -0700 | [diff] [blame] | 140 | * If {@link #allowAnyNotifToBubble(Context)} is true, this method creates and adds |
| 141 | * {@link android.app.Notification.BubbleMetadata} to the notification entry as long as |
| 142 | * the notification has necessary info for BubbleMetadata. |
Mady Mellor | 3067294 | 2019-12-04 15:43:19 -0800 | [diff] [blame] | 143 | * |
| 144 | * @return whether an adjustment was made. |
Mady Mellor | 7f23490 | 2019-10-20 12:06:29 -0700 | [diff] [blame] | 145 | */ |
Mady Mellor | 3067294 | 2019-12-04 15:43:19 -0800 | [diff] [blame] | 146 | static boolean adjustForExperiments(Context context, NotificationEntry entry, |
Mady Mellor | 3b86a4f | 2019-12-11 13:15:41 -0800 | [diff] [blame] | 147 | boolean previouslyUserCreated, boolean userBlocked) { |
Mady Mellor | b547e5e | 2019-12-02 10:15:56 -0800 | [diff] [blame] | 148 | Notification.BubbleMetadata metadata = null; |
| 149 | boolean addedMetadata = false; |
Mady Mellor | ea13b23 | 2019-12-05 15:55:46 -0800 | [diff] [blame] | 150 | boolean whiteListedToAutoBubble = |
| 151 | isPackageWhitelistedToAutoBubble(context, entry.getSbn().getPackageName()); |
Mady Mellor | 7f23490 | 2019-10-20 12:06:29 -0700 | [diff] [blame] | 152 | |
| 153 | Notification notification = entry.getSbn().getNotification(); |
| 154 | boolean isMessage = Notification.MessagingStyle.class.equals( |
| 155 | notification.getNotificationStyle()); |
| 156 | boolean bubbleNotifForExperiment = (isMessage && allowMessageNotifsToBubble(context)) |
| 157 | || allowAnyNotifToBubble(context); |
| 158 | |
Mady Mellor | b547e5e | 2019-12-02 10:15:56 -0800 | [diff] [blame] | 159 | boolean useShortcutInfo = useShortcutInfoToBubble(context); |
| 160 | String shortcutId = entry.getSbn().getNotification().getShortcutId(); |
| 161 | |
Mady Mellor | ff076eb | 2019-11-13 10:12:06 -0800 | [diff] [blame] | 162 | boolean hasMetadata = entry.getBubbleMetadata() != null; |
| 163 | if ((!hasMetadata && (previouslyUserCreated || bubbleNotifForExperiment)) |
| 164 | || useShortcutInfo) { |
| 165 | if (DEBUG_EXPERIMENTS) { |
| 166 | Log.d(TAG, "Adjusting " + entry.getKey() + " for bubble experiment." |
| 167 | + " allowMessages=" + allowMessageNotifsToBubble(context) |
| 168 | + " isMessage=" + isMessage |
| 169 | + " allowNotifs=" + allowAnyNotifToBubble(context) |
| 170 | + " useShortcutInfo=" + useShortcutInfo |
| 171 | + " previouslyUserCreated=" + previouslyUserCreated); |
| 172 | } |
| 173 | } |
| 174 | |
Mady Mellor | b547e5e | 2019-12-02 10:15:56 -0800 | [diff] [blame] | 175 | if (useShortcutInfo && shortcutId != null) { |
| 176 | // We don't actually get anything useful from ShortcutInfo so just check existence |
| 177 | ShortcutInfo info = getShortcutInfo(context, entry.getSbn().getPackageName(), |
| 178 | entry.getSbn().getUser(), shortcutId); |
| 179 | if (info != null) { |
Mady Mellor | 2ac2d3a | 2020-01-08 17:18:54 -0800 | [diff] [blame] | 180 | metadata = createForShortcut(shortcutId); |
Mady Mellor | b547e5e | 2019-12-02 10:15:56 -0800 | [diff] [blame] | 181 | } |
| 182 | |
| 183 | // Replace existing metadata with shortcut, or we're bubbling for experiment |
Mady Mellor | ff076eb | 2019-11-13 10:12:06 -0800 | [diff] [blame] | 184 | boolean shouldBubble = entry.getBubbleMetadata() != null |
| 185 | || bubbleNotifForExperiment |
| 186 | || previouslyUserCreated; |
Mady Mellor | b547e5e | 2019-12-02 10:15:56 -0800 | [diff] [blame] | 187 | if (shouldBubble && metadata != null) { |
Mady Mellor | ff076eb | 2019-11-13 10:12:06 -0800 | [diff] [blame] | 188 | if (DEBUG_EXPERIMENTS) { |
| 189 | Log.d(TAG, "Adding experimental shortcut bubble for: " + entry.getKey()); |
| 190 | } |
Mady Mellor | b547e5e | 2019-12-02 10:15:56 -0800 | [diff] [blame] | 191 | entry.setBubbleMetadata(metadata); |
| 192 | addedMetadata = true; |
| 193 | } |
Mady Mellor | 7f23490 | 2019-10-20 12:06:29 -0700 | [diff] [blame] | 194 | } |
| 195 | |
Mady Mellor | b547e5e | 2019-12-02 10:15:56 -0800 | [diff] [blame] | 196 | // Didn't get metadata from a shortcut & we're bubbling for experiment |
Mady Mellor | ff076eb | 2019-11-13 10:12:06 -0800 | [diff] [blame] | 197 | if (entry.getBubbleMetadata() == null |
| 198 | && (bubbleNotifForExperiment || previouslyUserCreated)) { |
Mady Mellor | b547e5e | 2019-12-02 10:15:56 -0800 | [diff] [blame] | 199 | metadata = createFromNotif(context, entry); |
| 200 | if (metadata != null) { |
Mady Mellor | ff076eb | 2019-11-13 10:12:06 -0800 | [diff] [blame] | 201 | if (DEBUG_EXPERIMENTS) { |
| 202 | Log.d(TAG, "Adding experimental notification bubble for: " + entry.getKey()); |
| 203 | } |
Mady Mellor | b547e5e | 2019-12-02 10:15:56 -0800 | [diff] [blame] | 204 | entry.setBubbleMetadata(metadata); |
| 205 | addedMetadata = true; |
| 206 | } |
| 207 | } |
| 208 | |
Mady Mellor | 3b86a4f | 2019-12-11 13:15:41 -0800 | [diff] [blame] | 209 | boolean bubbleForWhitelist = !userBlocked |
| 210 | && whiteListedToAutoBubble |
| 211 | && (addedMetadata || hasMetadata); |
Mady Mellor | ea13b23 | 2019-12-05 15:55:46 -0800 | [diff] [blame] | 212 | if ((previouslyUserCreated && addedMetadata) || bubbleForWhitelist) { |
| 213 | // Update to a previous bubble (or new autobubble), set its flag now. |
Mady Mellor | ff076eb | 2019-11-13 10:12:06 -0800 | [diff] [blame] | 214 | if (DEBUG_EXPERIMENTS) { |
| 215 | Log.d(TAG, "Setting FLAG_BUBBLE for: " + entry.getKey()); |
| 216 | } |
Mady Mellor | 7f23490 | 2019-10-20 12:06:29 -0700 | [diff] [blame] | 217 | entry.setFlagBubble(true); |
Mady Mellor | 3067294 | 2019-12-04 15:43:19 -0800 | [diff] [blame] | 218 | return true; |
Mady Mellor | 7f23490 | 2019-10-20 12:06:29 -0700 | [diff] [blame] | 219 | } |
Mady Mellor | 3067294 | 2019-12-04 15:43:19 -0800 | [diff] [blame] | 220 | return addedMetadata; |
Mady Mellor | 7f23490 | 2019-10-20 12:06:29 -0700 | [diff] [blame] | 221 | } |
Mady Mellor | b547e5e | 2019-12-02 10:15:56 -0800 | [diff] [blame] | 222 | |
| 223 | static Notification.BubbleMetadata createFromNotif(Context context, NotificationEntry entry) { |
| 224 | Notification notification = entry.getSbn().getNotification(); |
| 225 | final PendingIntent intent = notification.contentIntent; |
Mady Mellor | 89eb348 | 2019-11-13 17:32:01 -0800 | [diff] [blame] | 226 | Icon icon = null; |
| 227 | // Use the icon of the person if available |
| 228 | List<Person> personList = getPeopleFromNotification(entry); |
| 229 | if (personList.size() > 0) { |
Joshua Tsuji | 22f90a0 | 2019-12-11 14:41:10 -0500 | [diff] [blame] | 230 | final Person person = personList.get(0); |
Joshua Tsuji | 22f90a0 | 2019-12-11 14:41:10 -0500 | [diff] [blame] | 231 | if (person != null) { |
| 232 | icon = person.getIcon(); |
Mady Mellor | 58dc519 | 2019-12-16 13:49:56 -0800 | [diff] [blame] | 233 | if (icon == null) { |
| 234 | // Lets try and grab the icon constructed by the layout |
| 235 | Drawable d = PeopleHubNotificationListenerKt.extractAvatarFromRow(entry); |
| 236 | if (d instanceof BitmapDrawable) { |
| 237 | icon = Icon.createWithBitmap(((BitmapDrawable) d).getBitmap()); |
| 238 | } |
| 239 | } |
Joshua Tsuji | 22f90a0 | 2019-12-11 14:41:10 -0500 | [diff] [blame] | 240 | } |
Mady Mellor | 89eb348 | 2019-11-13 17:32:01 -0800 | [diff] [blame] | 241 | } |
| 242 | if (icon == null) { |
Mady Mellor | 58dc519 | 2019-12-16 13:49:56 -0800 | [diff] [blame] | 243 | boolean shouldTint = notification.getLargeIcon() == null; |
| 244 | icon = shouldTint |
| 245 | ? notification.getSmallIcon() |
| 246 | : notification.getLargeIcon(); |
| 247 | if (shouldTint) { |
| 248 | int notifColor = entry.getSbn().getNotification().color; |
| 249 | notifColor = ColorUtils.setAlphaComponent(notifColor, 255); |
| 250 | notifColor = ContrastColorUtil.findContrastColor(notifColor, Color.WHITE, |
| 251 | true /* findFg */, 3f); |
| 252 | icon.setTint(notifColor); |
| 253 | } |
Mady Mellor | 89eb348 | 2019-11-13 17:32:01 -0800 | [diff] [blame] | 254 | } |
Mady Mellor | 3067294 | 2019-12-04 15:43:19 -0800 | [diff] [blame] | 255 | if (intent != null) { |
Mady Mellor | aa9ce17 | 2020-03-17 10:34:20 -0700 | [diff] [blame] | 256 | return new Notification.BubbleMetadata.Builder(intent, icon) |
Mady Mellor | b547e5e | 2019-12-02 10:15:56 -0800 | [diff] [blame] | 257 | .setDesiredHeight(BUBBLE_HEIGHT) |
Mady Mellor | b547e5e | 2019-12-02 10:15:56 -0800 | [diff] [blame] | 258 | .build(); |
| 259 | } |
| 260 | return null; |
| 261 | } |
| 262 | |
Mady Mellor | 2ac2d3a | 2020-01-08 17:18:54 -0800 | [diff] [blame] | 263 | static Notification.BubbleMetadata createForShortcut(String shortcutId) { |
Mady Mellor | aa9ce17 | 2020-03-17 10:34:20 -0700 | [diff] [blame] | 264 | return new Notification.BubbleMetadata.Builder(shortcutId) |
Mady Mellor | b547e5e | 2019-12-02 10:15:56 -0800 | [diff] [blame] | 265 | .setDesiredHeight(BUBBLE_HEIGHT) |
Mady Mellor | b547e5e | 2019-12-02 10:15:56 -0800 | [diff] [blame] | 266 | .build(); |
| 267 | } |
| 268 | |
| 269 | static ShortcutInfo getShortcutInfo(Context context, String packageName, UserHandle user, |
| 270 | String shortcutId) { |
| 271 | LauncherApps launcherAppService = |
| 272 | (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE); |
| 273 | LauncherApps.ShortcutQuery query = new LauncherApps.ShortcutQuery(); |
| 274 | if (packageName != null) { |
| 275 | query.setPackage(packageName); |
| 276 | } |
| 277 | if (shortcutId != null) { |
| 278 | query.setShortcutIds(Arrays.asList(shortcutId)); |
| 279 | } |
| 280 | query.setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_MANIFEST); |
| 281 | List<ShortcutInfo> shortcuts = launcherAppService.getShortcuts(query, user); |
| 282 | return shortcuts != null && shortcuts.size() > 0 |
| 283 | ? shortcuts.get(0) |
| 284 | : null; |
| 285 | } |
| 286 | |
Mady Mellor | 89eb348 | 2019-11-13 17:32:01 -0800 | [diff] [blame] | 287 | static List<Person> getPeopleFromNotification(NotificationEntry entry) { |
| 288 | Bundle extras = entry.getSbn().getNotification().extras; |
| 289 | ArrayList<Person> personList = new ArrayList<>(); |
| 290 | if (extras == null) { |
| 291 | return personList; |
| 292 | } |
| 293 | |
| 294 | List<Person> p = extras.getParcelableArrayList(Notification.EXTRA_PEOPLE_LIST); |
| 295 | |
| 296 | if (p != null) { |
| 297 | personList.addAll(p); |
| 298 | } |
| 299 | |
| 300 | if (Notification.MessagingStyle.class.equals( |
| 301 | entry.getSbn().getNotification().getNotificationStyle())) { |
| 302 | final Parcelable[] messages = extras.getParcelableArray(EXTRA_MESSAGES); |
| 303 | if (!ArrayUtils.isEmpty(messages)) { |
| 304 | for (Notification.MessagingStyle.Message message : |
| 305 | Notification.MessagingStyle.Message |
| 306 | .getMessagesFromBundleArray(messages)) { |
| 307 | personList.add(message.getSenderPerson()); |
| 308 | } |
| 309 | } |
| 310 | } |
| 311 | return personList; |
| 312 | } |
Mady Mellor | 7f23490 | 2019-10-20 12:06:29 -0700 | [diff] [blame] | 313 | } |