• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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 package android.service.notification;
17 
18 import android.annotation.NonNull;
19 import android.annotation.Nullable;
20 import android.annotation.StringDef;
21 import android.annotation.SystemApi;
22 import android.app.Notification;
23 import android.os.Bundle;
24 import android.os.Parcel;
25 import android.os.Parcelable;
26 import android.os.UserHandle;
27 
28 import java.lang.annotation.Retention;
29 import java.lang.annotation.RetentionPolicy;
30 
31 /**
32  * Ranking updates from the Assistant.
33  *
34  * The updates are provides as a {@link Bundle} of signals, using the keys provided in this
35  * class.
36  * Each {@code KEY} specifies what type of data it supports and what kind of Adjustment it
37  * realizes on the notification rankings.
38  *
39  * Notifications affected by the Adjustment will be re-ranked if necessary.
40  *
41  * @hide
42  */
43 @SystemApi
44 public final class Adjustment implements Parcelable {
45     private final String mPackage;
46     private final String mKey;
47     private final CharSequence mExplanation;
48     private final Bundle mSignals;
49     private final int mUser;
50     @Nullable private String mIssuer;
51 
52     /** @hide */
53     @StringDef (prefix = { "KEY_" }, value = {
54             KEY_CONTEXTUAL_ACTIONS, KEY_GROUP_KEY, KEY_IMPORTANCE, KEY_PEOPLE, KEY_SNOOZE_CRITERIA,
55             KEY_TEXT_REPLIES, KEY_USER_SENTIMENT, KEY_IMPORTANCE_PROPOSAL
56     })
57     @Retention(RetentionPolicy.SOURCE)
58     public @interface Keys {}
59 
60     /**
61      * Data type: ArrayList of {@code String}, where each is a representation of a
62      * {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI}.
63      * See {@link android.app.Notification.Builder#addPerson(String)}.
64      * @hide
65      */
66     @SystemApi
67     public static final String KEY_PEOPLE = "key_people";
68     /**
69      * Parcelable {@code ArrayList} of {@link SnoozeCriterion}. These criteria may be visible to
70      * users. If a user chooses to snooze a notification until one of these criterion, the
71      * assistant will be notified via
72      * {@link NotificationAssistantService#onNotificationSnoozedUntilContext}.
73      */
74     public static final String KEY_SNOOZE_CRITERIA = "key_snooze_criteria";
75     /**
76      * Data type: String. Used to change what {@link Notification#getGroup() group} a notification
77      * belongs to.
78      * @hide
79      */
80     public static final String KEY_GROUP_KEY = "key_group_key";
81 
82     /**
83      * Data type: int, one of {@link NotificationListenerService.Ranking#USER_SENTIMENT_POSITIVE},
84      * {@link NotificationListenerService.Ranking#USER_SENTIMENT_NEUTRAL},
85      * {@link NotificationListenerService.Ranking#USER_SENTIMENT_NEGATIVE}. Used to express how
86      * a user feels about notifications in the same {@link android.app.NotificationChannel} as
87      * the notification represented by {@link #getKey()}.
88      */
89     public static final String KEY_USER_SENTIMENT = "key_user_sentiment";
90 
91     /**
92      * Data type: ArrayList of {@link android.app.Notification.Action}.
93      * Used to suggest contextual actions for a notification.
94      *
95      * @see Notification.Action.Builder#setContextual(boolean)
96      */
97     public static final String KEY_CONTEXTUAL_ACTIONS = "key_contextual_actions";
98 
99     /**
100      * Data type: ArrayList of {@link CharSequence}.
101      * Used to suggest smart replies for a notification.
102      */
103     public static final String KEY_TEXT_REPLIES = "key_text_replies";
104 
105     /**
106      * Data type: int, one of importance values e.g.
107      * {@link android.app.NotificationManager#IMPORTANCE_MIN}.
108      *
109      * <p> If used from
110      * {@link NotificationAssistantService#onNotificationEnqueued(StatusBarNotification)}, and
111      * received before the notification is posted, it can block a notification from appearing or
112      * silence it. Importance adjustments received too late from
113      * {@link NotificationAssistantService#onNotificationEnqueued(StatusBarNotification)} will be
114      * ignored.
115      * </p>
116      * <p>If used from
117      * {@link NotificationAssistantService#adjustNotification(Adjustment)}, it can
118      * visually demote or cancel a notification, but use this with care if they notification was
119      * recently posted because the notification may already have made noise.
120      * </p>
121      */
122     public static final String KEY_IMPORTANCE = "key_importance";
123 
124     /**
125      * Weaker than {@link #KEY_IMPORTANCE}, this adjustment suggests an importance rather than
126      * mandates an importance change.
127      *
128      * A notification listener can interpet this suggestion to show the user a prompt to change
129      * notification importance for the notification (or type, or app) moving forward.
130      *
131      * Data type: int, one of importance values e.g.
132      * {@link android.app.NotificationManager#IMPORTANCE_MIN}.
133      * @hide
134      */
135     public static final String KEY_IMPORTANCE_PROPOSAL = "key_importance_proposal";
136 
137     /**
138      * Data type: float, a ranking score from 0 (lowest) to 1 (highest).
139      * Used to rank notifications inside that fall under the same classification (i.e. alerting,
140      * silenced).
141      */
142     public static final String KEY_RANKING_SCORE = "key_ranking_score";
143 
144     /**
145      * Data type: boolean, when true it suggests this is NOT a conversation notification.
146      * @hide
147      */
148     @SystemApi
149     public static final String KEY_NOT_CONVERSATION = "key_not_conversation";
150 
151     /**
152      * Create a notification adjustment.
153      *
154      * @param pkg The package of the notification.
155      * @param key The notification key.
156      * @param signals A bundle of signals that should inform notification display, ordering, and
157      *                interruptiveness.
158      * @param explanation A human-readable justification for the adjustment.
159      * @hide
160      */
161     @SystemApi
Adjustment(String pkg, String key, Bundle signals, CharSequence explanation, int user)162     public Adjustment(String pkg, String key, Bundle signals, CharSequence explanation, int user) {
163         mPackage = pkg;
164         mKey = key;
165         mSignals = signals;
166         mExplanation = explanation;
167         mUser = user;
168     }
169 
170     /**
171      * Create a notification adjustment.
172      *
173      * @param pkg The package of the notification.
174      * @param key The notification key.
175      * @param signals A bundle of signals that should inform notification display, ordering, and
176      *                interruptiveness.
177      * @param explanation A human-readable justification for the adjustment.
178      * @param userHandle User handle for for whose the adjustments will be applied.
179      */
Adjustment(@onNull String pkg, @NonNull String key, @NonNull Bundle signals, @NonNull CharSequence explanation, @NonNull UserHandle userHandle)180     public Adjustment(@NonNull String pkg, @NonNull String key, @NonNull Bundle signals,
181             @NonNull CharSequence explanation,
182             @NonNull UserHandle userHandle) {
183         mPackage = pkg;
184         mKey = key;
185         mSignals = signals;
186         mExplanation = explanation;
187         mUser = userHandle.getIdentifier();
188     }
189 
190     /**
191      * @hide
192      */
193     @SystemApi
Adjustment(Parcel in)194     protected Adjustment(Parcel in) {
195         if (in.readInt() == 1) {
196             mPackage = in.readString();
197         } else {
198             mPackage = null;
199         }
200         if (in.readInt() == 1) {
201             mKey = in.readString();
202         } else {
203             mKey = null;
204         }
205         if (in.readInt() == 1) {
206             mExplanation = in.readCharSequence();
207         } else {
208             mExplanation = null;
209         }
210         mSignals = in.readBundle();
211         mUser = in.readInt();
212         mIssuer = in.readString();
213     }
214 
215     public static final @android.annotation.NonNull Creator<Adjustment> CREATOR = new Creator<Adjustment>() {
216         @Override
217         public Adjustment createFromParcel(Parcel in) {
218             return new Adjustment(in);
219         }
220 
221         @Override
222         public Adjustment[] newArray(int size) {
223             return new Adjustment[size];
224         }
225     };
226 
getPackage()227     public @NonNull String getPackage() {
228         return mPackage;
229     }
230 
getKey()231     public @NonNull String getKey() {
232         return mKey;
233     }
234 
getExplanation()235     public @NonNull CharSequence getExplanation() {
236         return mExplanation;
237     }
238 
getSignals()239     public @NonNull Bundle getSignals() {
240         return mSignals;
241     }
242 
243     /** @hide */
244     @SystemApi
getUser()245     public int getUser() {
246         return mUser;
247     }
248 
getUserHandle()249     public @NonNull UserHandle getUserHandle() {
250         return UserHandle.of(mUser);
251     }
252 
253     @Override
describeContents()254     public int describeContents() {
255         return 0;
256     }
257 
258     @Override
writeToParcel(Parcel dest, int flags)259     public void writeToParcel(Parcel dest, int flags) {
260         if (mPackage != null) {
261             dest.writeInt(1);
262             dest.writeString(mPackage);
263         } else {
264             dest.writeInt(0);
265         }
266         if (mKey != null) {
267             dest.writeInt(1);
268             dest.writeString(mKey);
269         } else {
270             dest.writeInt(0);
271         }
272         if (mExplanation != null) {
273             dest.writeInt(1);
274             dest.writeCharSequence(mExplanation);
275         } else {
276             dest.writeInt(0);
277         }
278         dest.writeBundle(mSignals);
279         dest.writeInt(mUser);
280         dest.writeString(mIssuer);
281     }
282 
283     @NonNull
284     @Override
toString()285     public String toString() {
286         return "Adjustment{"
287                 + "mSignals=" + mSignals
288                 + '}';
289     }
290 
291     /** @hide */
setIssuer(@ullable String issuer)292     public void setIssuer(@Nullable String issuer) {
293         mIssuer = issuer;
294     }
295 
296     /** @hide */
getIssuer()297     public @Nullable String getIssuer() {
298         return mIssuer;
299     }
300 }
301