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.statusbar.notification.collection; 18 19 import android.annotation.Nullable; 20 import android.app.Notification; 21 import android.app.NotificationChannel; 22 import android.app.NotificationManager; 23 import android.content.Context; 24 import android.content.pm.ShortcutInfo; 25 import android.os.UserHandle; 26 import android.service.notification.NotificationListenerService.Ranking; 27 import android.service.notification.SnoozeCriterion; 28 import android.service.notification.StatusBarNotification; 29 30 import androidx.annotation.NonNull; 31 32 import com.android.internal.logging.InstanceId; 33 import com.android.systemui.statusbar.RankingBuilder; 34 import com.android.systemui.statusbar.SbnBuilder; 35 import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection; 36 import com.android.systemui.util.time.FakeSystemClock; 37 38 import kotlin.Unit; 39 40 import java.util.ArrayList; 41 import java.util.function.Consumer; 42 43 /** 44 * Combined builder for constructing a NotificationEntry and its associated StatusBarNotification 45 * and Ranking. Is largely a proxy for the SBN and Ranking builders, but does a little extra magic 46 * to make sure the keys match between the two, etc. 47 * 48 * Has the ability to set ListEntry properties as well. 49 * 50 * Only for use in tests. 51 */ 52 public class NotificationEntryBuilder { 53 private final SbnBuilder mSbnBuilder; 54 private final RankingBuilder mRankingBuilder; 55 private final FakeSystemClock mClock = new FakeSystemClock(); 56 private StatusBarNotification mSbn = null; 57 58 /* ListEntry properties */ 59 private GroupEntry mParent; 60 private NotifSection mNotifSection; 61 62 /* If set, use this creation time instead of mClock.uptimeMillis */ 63 private long mCreationTime = -1; 64 private int mStableIndex = -1; 65 NotificationEntryBuilder()66 public NotificationEntryBuilder() { 67 mSbnBuilder = new SbnBuilder(); 68 mRankingBuilder = new RankingBuilder(); 69 } 70 NotificationEntryBuilder(NotificationEntry source)71 public NotificationEntryBuilder(NotificationEntry source) { 72 mSbnBuilder = new SbnBuilder(source.getSbn()); 73 mRankingBuilder = new RankingBuilder(source.getRanking()); 74 75 mParent = source.getParent(); 76 mCreationTime = source.getCreationTime(); 77 } 78 79 /** Allows the caller to sub-build the ranking */ 80 @NonNull updateRanking(@onNull Consumer<RankingBuilder> rankingUpdater)81 public NotificationEntryBuilder updateRanking(@NonNull Consumer<RankingBuilder> rankingUpdater) { 82 rankingUpdater.accept(mRankingBuilder); 83 return this; 84 } 85 86 /** Allows the caller to sub-build the SBN */ 87 @NonNull updateSbn(@onNull Consumer<SbnBuilder> sbnUpdater)88 public NotificationEntryBuilder updateSbn(@NonNull Consumer<SbnBuilder> sbnUpdater) { 89 sbnUpdater.accept(mSbnBuilder); 90 return this; 91 } 92 93 /** Update an the parent on an existing entry */ setNewParent(NotificationEntry entry, GroupEntry parent)94 public static void setNewParent(NotificationEntry entry, GroupEntry parent) { 95 entry.setParent(parent); 96 } 97 98 /** Build a new instance of NotificationEntry */ build()99 public NotificationEntry build() { 100 return buildOrApply(null); 101 } 102 103 /** Modifies [target] to match the contents of this builder */ apply(NotificationEntry target)104 public void apply(NotificationEntry target) { 105 buildOrApply(target); 106 } 107 108 /** Convenience method for Kotlin callbacks that are passed a builder and need to return Unit */ done()109 public Unit done() { 110 return Unit.INSTANCE; 111 } 112 buildOrApply(NotificationEntry target)113 private NotificationEntry buildOrApply(NotificationEntry target) { 114 final StatusBarNotification sbn = mSbn != null ? mSbn : mSbnBuilder.build(); 115 final Ranking ranking = mRankingBuilder.setKey(sbn.getKey()).build(); 116 final long creationTime = mCreationTime != -1 ? mCreationTime : mClock.uptimeMillis(); 117 118 final NotificationEntry entry; 119 if (target == null) { 120 entry = new NotificationEntry(sbn, ranking, creationTime); 121 } else { 122 entry = target; 123 entry.setSbn(sbn); 124 entry.setRanking(ranking); 125 // Note: we can't modify the creation time as it's immutable 126 } 127 128 /* ListEntry properties */ 129 entry.setParent(mParent); 130 entry.getAttachState().setSection(mNotifSection); 131 entry.getAttachState().setStableIndex(mStableIndex); 132 return entry; 133 } 134 135 /** 136 * Sets the parent. 137 */ setParent(@ullable GroupEntry parent)138 public NotificationEntryBuilder setParent(@Nullable GroupEntry parent) { 139 mParent = parent; 140 return this; 141 } 142 143 /** 144 * Sets the parent. 145 */ setSection(@ullable NotifSection section)146 public NotificationEntryBuilder setSection(@Nullable NotifSection section) { 147 mNotifSection = section; 148 return this; 149 } 150 151 /** 152 * Sets the SBN directly. If set, causes all calls to delegated SbnBuilder methods to be 153 * ignored. 154 */ setSbn(@ullable StatusBarNotification sbn)155 public NotificationEntryBuilder setSbn(@Nullable StatusBarNotification sbn) { 156 mSbn = sbn; 157 return this; 158 } 159 setStableIndex(int index)160 public NotificationEntryBuilder setStableIndex(int index) { 161 mStableIndex = index; 162 return this; 163 } 164 165 /** 166 * Set the creation time 167 */ setCreationTime(long creationTime)168 public NotificationEntryBuilder setCreationTime(long creationTime) { 169 mCreationTime = creationTime; 170 return this; 171 } 172 173 /* Delegated to SbnBuilder */ 174 setPkg(String pkg)175 public NotificationEntryBuilder setPkg(String pkg) { 176 mSbnBuilder.setPkg(pkg); 177 return this; 178 } 179 setOpPkg(String opPkg)180 public NotificationEntryBuilder setOpPkg(String opPkg) { 181 mSbnBuilder.setOpPkg(opPkg); 182 return this; 183 } 184 setId(int id)185 public NotificationEntryBuilder setId(int id) { 186 mSbnBuilder.setId(id); 187 return this; 188 } 189 setTag(String tag)190 public NotificationEntryBuilder setTag(String tag) { 191 mSbnBuilder.setTag(tag); 192 return this; 193 } 194 setUid(int uid)195 public NotificationEntryBuilder setUid(int uid) { 196 mSbnBuilder.setUid(uid); 197 return this; 198 } 199 setInitialPid(int initialPid)200 public NotificationEntryBuilder setInitialPid(int initialPid) { 201 mSbnBuilder.setInitialPid(initialPid); 202 return this; 203 } 204 setNotification(Notification notification)205 public NotificationEntryBuilder setNotification(Notification notification) { 206 mSbnBuilder.setNotification(notification); 207 return this; 208 } 209 modifyNotification(Context context)210 public Notification.Builder modifyNotification(Context context) { 211 return mSbnBuilder.modifyNotification(context); 212 } 213 setUser(UserHandle user)214 public NotificationEntryBuilder setUser(UserHandle user) { 215 mSbnBuilder.setUser(user); 216 return this; 217 } 218 setOverrideGroupKey(String overrideGroupKey)219 public NotificationEntryBuilder setOverrideGroupKey(String overrideGroupKey) { 220 mSbnBuilder.setOverrideGroupKey(overrideGroupKey); 221 return this; 222 } 223 setPostTime(long postTime)224 public NotificationEntryBuilder setPostTime(long postTime) { 225 mSbnBuilder.setPostTime(postTime); 226 return this; 227 } 228 setInstanceId(InstanceId instanceId)229 public NotificationEntryBuilder setInstanceId(InstanceId instanceId) { 230 mSbnBuilder.setInstanceId(instanceId); 231 return this; 232 } 233 234 /* Delegated to Notification.Builder (via SbnBuilder) */ 235 setContentTitle(Context context, String contentTitle)236 public NotificationEntryBuilder setContentTitle(Context context, String contentTitle) { 237 mSbnBuilder.setContentTitle(context, contentTitle); 238 return this; 239 } 240 setContentText(Context context, String contentText)241 public NotificationEntryBuilder setContentText(Context context, String contentText) { 242 mSbnBuilder.setContentText(context, contentText); 243 return this; 244 } 245 setGroup(Context context, String groupKey)246 public NotificationEntryBuilder setGroup(Context context, String groupKey) { 247 mSbnBuilder.setGroup(context, groupKey); 248 return this; 249 } 250 setGroupSummary(Context context, boolean isGroupSummary)251 public NotificationEntryBuilder setGroupSummary(Context context, boolean isGroupSummary) { 252 mSbnBuilder.setGroupSummary(context, isGroupSummary); 253 return this; 254 } 255 setFlag(Context context, int mask, boolean value)256 public NotificationEntryBuilder setFlag(Context context, int mask, boolean value) { 257 mSbnBuilder.setFlag(context, mask, value); 258 return this; 259 } 260 261 /* Delegated to RankingBuilder */ 262 setRank(int rank)263 public NotificationEntryBuilder setRank(int rank) { 264 mRankingBuilder.setRank(rank); 265 return this; 266 } 267 setMatchesInterruptionFilter( boolean matchesInterruptionFilter)268 public NotificationEntryBuilder setMatchesInterruptionFilter( 269 boolean matchesInterruptionFilter) { 270 mRankingBuilder.setMatchesInterruptionFilter(matchesInterruptionFilter); 271 return this; 272 } 273 setVisibilityOverride(int visibilityOverride)274 public NotificationEntryBuilder setVisibilityOverride(int visibilityOverride) { 275 mRankingBuilder.setVisibilityOverride(visibilityOverride); 276 return this; 277 } 278 setSuppressedVisualEffects(int suppressedVisualEffects)279 public NotificationEntryBuilder setSuppressedVisualEffects(int suppressedVisualEffects) { 280 mRankingBuilder.setSuppressedVisualEffects(suppressedVisualEffects); 281 return this; 282 } 283 setExplanation(CharSequence explanation)284 public NotificationEntryBuilder setExplanation(CharSequence explanation) { 285 mRankingBuilder.setExplanation(explanation); 286 return this; 287 } 288 setAdditionalPeople(ArrayList<String> additionalPeople)289 public NotificationEntryBuilder setAdditionalPeople(ArrayList<String> additionalPeople) { 290 mRankingBuilder.setAdditionalPeople(additionalPeople); 291 return this; 292 } 293 setSnoozeCriteria( ArrayList<SnoozeCriterion> snoozeCriteria)294 public NotificationEntryBuilder setSnoozeCriteria( 295 ArrayList<SnoozeCriterion> snoozeCriteria) { 296 mRankingBuilder.setSnoozeCriteria(snoozeCriteria); 297 return this; 298 } 299 setCanShowBadge(boolean canShowBadge)300 public NotificationEntryBuilder setCanShowBadge(boolean canShowBadge) { 301 mRankingBuilder.setCanShowBadge(canShowBadge); 302 return this; 303 } 304 setSuspended(boolean suspended)305 public NotificationEntryBuilder setSuspended(boolean suspended) { 306 mRankingBuilder.setSuspended(suspended); 307 return this; 308 } 309 setLastAudiblyAlertedMs(long lastAudiblyAlertedMs)310 public NotificationEntryBuilder setLastAudiblyAlertedMs(long lastAudiblyAlertedMs) { 311 mRankingBuilder.setLastAudiblyAlertedMs(lastAudiblyAlertedMs); 312 return this; 313 } 314 setNoisy(boolean noisy)315 public NotificationEntryBuilder setNoisy(boolean noisy) { 316 mRankingBuilder.setNoisy(noisy); 317 return this; 318 } 319 setCanBubble(boolean canBubble)320 public NotificationEntryBuilder setCanBubble(boolean canBubble) { 321 mRankingBuilder.setCanBubble(canBubble); 322 return this; 323 } 324 setImportance(@otificationManager.Importance int importance)325 public NotificationEntryBuilder setImportance(@NotificationManager.Importance int importance) { 326 mRankingBuilder.setImportance(importance); 327 return this; 328 } 329 setUserSentiment(int userSentiment)330 public NotificationEntryBuilder setUserSentiment(int userSentiment) { 331 mRankingBuilder.setUserSentiment(userSentiment); 332 return this; 333 } 334 setChannel(NotificationChannel channel)335 public NotificationEntryBuilder setChannel(NotificationChannel channel) { 336 mRankingBuilder.setChannel(channel); 337 return this; 338 } 339 setSmartActions( ArrayList<Notification.Action> smartActions)340 public NotificationEntryBuilder setSmartActions( 341 ArrayList<Notification.Action> smartActions) { 342 mRankingBuilder.setSmartActions(smartActions); 343 return this; 344 } 345 setSmartActions(Notification.Action... smartActions)346 public NotificationEntryBuilder setSmartActions(Notification.Action... smartActions) { 347 mRankingBuilder.setSmartActions(smartActions); 348 return this; 349 } 350 setSmartReplies(ArrayList<CharSequence> smartReplies)351 public NotificationEntryBuilder setSmartReplies(ArrayList<CharSequence> smartReplies) { 352 mRankingBuilder.setSmartReplies(smartReplies); 353 return this; 354 } 355 setSmartReplies(CharSequence... smartReplies)356 public NotificationEntryBuilder setSmartReplies(CharSequence... smartReplies) { 357 mRankingBuilder.setSmartReplies(smartReplies); 358 return this; 359 } 360 setShortcutInfo(ShortcutInfo shortcutInfo)361 public NotificationEntryBuilder setShortcutInfo(ShortcutInfo shortcutInfo) { 362 mRankingBuilder.setShortcutInfo(shortcutInfo); 363 return this; 364 } 365 setRankingAdjustment(int rankingAdjustment)366 public NotificationEntryBuilder setRankingAdjustment(int rankingAdjustment) { 367 mRankingBuilder.setRankingAdjustment(rankingAdjustment); 368 return this; 369 } 370 } 371