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