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