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 * Create a notification adjustment. 128 * 129 * @param pkg The package of the notification. 130 * @param key The notification key. 131 * @param signals A bundle of signals that should inform notification display, ordering, and 132 * interruptiveness. 133 * @param explanation A human-readable justification for the adjustment. 134 * @hide 135 */ 136 @SystemApi 137 @TestApi Adjustment(String pkg, String key, Bundle signals, CharSequence explanation, int user)138 public Adjustment(String pkg, String key, Bundle signals, CharSequence explanation, int user) { 139 mPackage = pkg; 140 mKey = key; 141 mSignals = signals; 142 mExplanation = explanation; 143 mUser = user; 144 } 145 146 /** 147 * Create a notification adjustment. 148 * 149 * @param pkg The package of the notification. 150 * @param key The notification key. 151 * @param signals A bundle of signals that should inform notification display, ordering, and 152 * interruptiveness. 153 * @param explanation A human-readable justification for the adjustment. 154 * @param userHandle User handle for for whose the adjustments will be applied. 155 */ Adjustment(@onNull String pkg, @NonNull String key, @NonNull Bundle signals, @NonNull CharSequence explanation, @NonNull UserHandle userHandle)156 public Adjustment(@NonNull String pkg, @NonNull String key, @NonNull Bundle signals, 157 @NonNull CharSequence explanation, 158 @NonNull UserHandle userHandle) { 159 mPackage = pkg; 160 mKey = key; 161 mSignals = signals; 162 mExplanation = explanation; 163 mUser = userHandle.getIdentifier(); 164 } 165 166 /** 167 * @hide 168 */ 169 @SystemApi Adjustment(Parcel in)170 protected Adjustment(Parcel in) { 171 if (in.readInt() == 1) { 172 mPackage = in.readString(); 173 } else { 174 mPackage = null; 175 } 176 if (in.readInt() == 1) { 177 mKey = in.readString(); 178 } else { 179 mKey = null; 180 } 181 if (in.readInt() == 1) { 182 mExplanation = in.readCharSequence(); 183 } else { 184 mExplanation = null; 185 } 186 mSignals = in.readBundle(); 187 mUser = in.readInt(); 188 mIssuer = in.readString(); 189 } 190 191 public static final @android.annotation.NonNull Creator<Adjustment> CREATOR = new Creator<Adjustment>() { 192 @Override 193 public Adjustment createFromParcel(Parcel in) { 194 return new Adjustment(in); 195 } 196 197 @Override 198 public Adjustment[] newArray(int size) { 199 return new Adjustment[size]; 200 } 201 }; 202 getPackage()203 public @NonNull String getPackage() { 204 return mPackage; 205 } 206 getKey()207 public @NonNull String getKey() { 208 return mKey; 209 } 210 getExplanation()211 public @NonNull CharSequence getExplanation() { 212 return mExplanation; 213 } 214 getSignals()215 public @NonNull Bundle getSignals() { 216 return mSignals; 217 } 218 219 /** @hide */ 220 @SystemApi 221 @TestApi getUser()222 public int getUser() { 223 return mUser; 224 } 225 getUserHandle()226 public @NonNull UserHandle getUserHandle() { 227 return UserHandle.of(mUser); 228 } 229 230 @Override describeContents()231 public int describeContents() { 232 return 0; 233 } 234 235 @Override writeToParcel(Parcel dest, int flags)236 public void writeToParcel(Parcel dest, int flags) { 237 if (mPackage != null) { 238 dest.writeInt(1); 239 dest.writeString(mPackage); 240 } else { 241 dest.writeInt(0); 242 } 243 if (mKey != null) { 244 dest.writeInt(1); 245 dest.writeString(mKey); 246 } else { 247 dest.writeInt(0); 248 } 249 if (mExplanation != null) { 250 dest.writeInt(1); 251 dest.writeCharSequence(mExplanation); 252 } else { 253 dest.writeInt(0); 254 } 255 dest.writeBundle(mSignals); 256 dest.writeInt(mUser); 257 dest.writeString(mIssuer); 258 } 259 260 @NonNull 261 @Override toString()262 public String toString() { 263 return "Adjustment{" 264 + "mSignals=" + mSignals 265 + '}'; 266 } 267 268 /** @hide */ setIssuer(@ullable String issuer)269 public void setIssuer(@Nullable String issuer) { 270 mIssuer = issuer; 271 } 272 273 /** @hide */ getIssuer()274 public @Nullable String getIssuer() { 275 return mIssuer; 276 } 277 } 278