blob: 2b4c24cbb0699dac1942456397d32bddc3c4fe08 [file] [log] [blame]
Julia Reynolds503ed942017-10-04 16:04:56 -04001/**
2 * Copyright (C) 2017 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 */
16package android.service.notification;
17
18import android.annotation.IntDef;
Julia Reynolds79f02772019-02-15 11:38:48 -050019import android.annotation.SystemApi;
Julia Reynoldsd0ceefa2019-03-03 16:10:52 -050020import android.annotation.TestApi;
Julia Reynolds503ed942017-10-04 16:04:56 -040021import android.app.RemoteInput;
22import android.os.Parcel;
23import android.os.Parcelable;
24
25import java.lang.annotation.Retention;
26import java.lang.annotation.RetentionPolicy;
27
Julia Reynoldsd0ceefa2019-03-03 16:10:52 -050028/**
29 * Information about how the user has interacted with a given notification.
30 * @hide
31 */
32@TestApi
33@SystemApi
Julia Reynolds503ed942017-10-04 16:04:56 -040034public final class NotificationStats implements Parcelable {
35
36 private boolean mSeen;
37 private boolean mExpanded;
38 private boolean mDirectReplied;
39 private boolean mSnoozed;
40 private boolean mViewedSettings;
41 private boolean mInteracted;
42
43 /** @hide */
44 @IntDef(prefix = { "DISMISSAL_SURFACE_" }, value = {
45 DISMISSAL_NOT_DISMISSED, DISMISSAL_OTHER, DISMISSAL_PEEK, DISMISSAL_AOD, DISMISSAL_SHADE
46 })
47 @Retention(RetentionPolicy.SOURCE)
48 public @interface DismissalSurface {}
49
50
51 private @DismissalSurface int mDismissalSurface = DISMISSAL_NOT_DISMISSED;
52
53 /**
54 * Notification has not been dismissed yet.
55 */
Michael Wright3f4d5462018-08-22 23:34:45 +010056 public static final int DISMISSAL_NOT_DISMISSED = -1;
Julia Reynolds503ed942017-10-04 16:04:56 -040057 /**
58 * Notification has been dismissed from a {@link NotificationListenerService} or the app
59 * itself.
60 */
61 public static final int DISMISSAL_OTHER = 0;
62 /**
63 * Notification has been dismissed while peeking.
64 */
65 public static final int DISMISSAL_PEEK = 1;
66 /**
67 * Notification has been dismissed from always on display.
68 */
69 public static final int DISMISSAL_AOD = 2;
70 /**
71 * Notification has been dismissed from the notification shade.
72 */
73 public static final int DISMISSAL_SHADE = 3;
74
Julia Reynoldsfd4099d2018-08-21 11:06:06 -040075 /** @hide */
76 @IntDef(prefix = { "DISMISS_SENTIMENT_" }, value = {
77 DISMISS_SENTIMENT_UNKNOWN, DISMISS_SENTIMENT_NEGATIVE, DISMISS_SENTIMENT_NEUTRAL,
78 DISMISS_SENTIMENT_POSITIVE
79 })
80 @Retention(RetentionPolicy.SOURCE)
81 public @interface DismissalSentiment {}
82
83 /**
84 * No information is available about why this notification was dismissed, or the notification
85 * isn't dismissed yet.
86 */
87 public static final int DISMISS_SENTIMENT_UNKNOWN = -1000;
88 /**
89 * The user indicated while dismissing that they did not like the notification.
90 */
91 public static final int DISMISS_SENTIMENT_NEGATIVE = 0;
92 /**
93 * The user didn't indicate one way or another how they felt about the notification while
94 * dismissing it.
95 */
96 public static final int DISMISS_SENTIMENT_NEUTRAL = 1;
97 /**
98 * The user indicated while dismissing that they did like the notification.
99 */
100 public static final int DISMISS_SENTIMENT_POSITIVE = 2;
101
102
103 private @DismissalSentiment
104 int mDismissalSentiment = DISMISS_SENTIMENT_UNKNOWN;
105
Julia Reynolds503ed942017-10-04 16:04:56 -0400106 public NotificationStats() {
107 }
108
Julia Reynolds79f02772019-02-15 11:38:48 -0500109 /**
110 * @hide
111 */
112 @SystemApi
113 protected NotificationStats(Parcel in) {
Julia Reynolds503ed942017-10-04 16:04:56 -0400114 mSeen = in.readByte() != 0;
115 mExpanded = in.readByte() != 0;
116 mDirectReplied = in.readByte() != 0;
117 mSnoozed = in.readByte() != 0;
118 mViewedSettings = in.readByte() != 0;
119 mInteracted = in.readByte() != 0;
120 mDismissalSurface = in.readInt();
Julia Reynoldsfd4099d2018-08-21 11:06:06 -0400121 mDismissalSentiment = in.readInt();
Julia Reynolds503ed942017-10-04 16:04:56 -0400122 }
123
124 @Override
125 public void writeToParcel(Parcel dest, int flags) {
126 dest.writeByte((byte) (mSeen ? 1 : 0));
127 dest.writeByte((byte) (mExpanded ? 1 : 0));
128 dest.writeByte((byte) (mDirectReplied ? 1 : 0));
129 dest.writeByte((byte) (mSnoozed ? 1 : 0));
130 dest.writeByte((byte) (mViewedSettings ? 1 : 0));
131 dest.writeByte((byte) (mInteracted ? 1 : 0));
132 dest.writeInt(mDismissalSurface);
Julia Reynoldsfd4099d2018-08-21 11:06:06 -0400133 dest.writeInt(mDismissalSentiment);
Julia Reynolds503ed942017-10-04 16:04:56 -0400134 }
135
136 @Override
137 public int describeContents() {
138 return 0;
139 }
140
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700141 public static final @android.annotation.NonNull Creator<NotificationStats> CREATOR = new Creator<NotificationStats>() {
Julia Reynolds503ed942017-10-04 16:04:56 -0400142 @Override
143 public NotificationStats createFromParcel(Parcel in) {
144 return new NotificationStats(in);
145 }
146
147 @Override
148 public NotificationStats[] newArray(int size) {
149 return new NotificationStats[size];
150 }
151 };
152
153 /**
154 * Returns whether the user has seen this notification at least once.
155 */
156 public boolean hasSeen() {
157 return mSeen;
158 }
159
160 /**
161 * Records that the user as seen this notification at least once.
162 */
163 public void setSeen() {
164 mSeen = true;
165 }
166
167 /**
168 * Returns whether the user has expanded this notification at least once.
169 */
170 public boolean hasExpanded() {
171 return mExpanded;
172 }
173
174 /**
175 * Records that the user has expanded this notification at least once.
176 */
177 public void setExpanded() {
178 mExpanded = true;
179 mInteracted = true;
180 }
181
182 /**
183 * Returns whether the user has replied to a notification that has a
184 * {@link android.app.Notification.Action.Builder#addRemoteInput(RemoteInput) direct reply} at
185 * least once.
186 */
187 public boolean hasDirectReplied() {
188 return mDirectReplied;
189 }
190
191 /**
192 * Records that the user has replied to a notification that has a
193 * {@link android.app.Notification.Action.Builder#addRemoteInput(RemoteInput) direct reply}
194 * at least once.
195 */
196 public void setDirectReplied() {
197 mDirectReplied = true;
198 mInteracted = true;
199 }
200
201 /**
202 * Returns whether the user has snoozed this notification at least once.
203 */
204 public boolean hasSnoozed() {
205 return mSnoozed;
206 }
207
208 /**
209 * Records that the user has snoozed this notification at least once.
210 */
211 public void setSnoozed() {
212 mSnoozed = true;
213 mInteracted = true;
214 }
215
216 /**
217 * Returns whether the user has viewed the in-shade settings for this notification at least
218 * once.
219 */
220 public boolean hasViewedSettings() {
221 return mViewedSettings;
222 }
223
224 /**
225 * Records that the user has viewed the in-shade settings for this notification at least once.
226 */
227 public void setViewedSettings() {
228 mViewedSettings = true;
229 mInteracted = true;
230 }
231
232 /**
233 * Returns whether the user has interacted with this notification beyond having viewed it.
234 */
235 public boolean hasInteracted() {
236 return mInteracted;
237 }
238
239 /**
240 * Returns from which surface the notification was dismissed.
241 */
242 public @DismissalSurface int getDismissalSurface() {
243 return mDismissalSurface;
244 }
245
246 /**
247 * Returns from which surface the notification was dismissed.
248 */
249 public void setDismissalSurface(@DismissalSurface int dismissalSurface) {
250 mDismissalSurface = dismissalSurface;
251 }
252
Julia Reynoldsfd4099d2018-08-21 11:06:06 -0400253 /**
254 * Records whether the user indicated how they felt about a notification before or
255 * during dismissal.
256 */
257 public void setDismissalSentiment(@DismissalSentiment int dismissalSentiment) {
258 mDismissalSentiment = dismissalSentiment;
259 }
260
261 /**
262 * Returns how the user indicated they felt about a notification before or during dismissal.
263 */
264 public @DismissalSentiment int getDismissalSentiment() {
265 return mDismissalSentiment;
266 }
267
Julia Reynolds503ed942017-10-04 16:04:56 -0400268 @Override
269 public boolean equals(Object o) {
270 if (this == o) return true;
271 if (o == null || getClass() != o.getClass()) return false;
272
273 NotificationStats that = (NotificationStats) o;
274
275 if (mSeen != that.mSeen) return false;
276 if (mExpanded != that.mExpanded) return false;
277 if (mDirectReplied != that.mDirectReplied) return false;
278 if (mSnoozed != that.mSnoozed) return false;
279 if (mViewedSettings != that.mViewedSettings) return false;
280 if (mInteracted != that.mInteracted) return false;
281 return mDismissalSurface == that.mDismissalSurface;
282 }
283
284 @Override
285 public int hashCode() {
286 int result = (mSeen ? 1 : 0);
287 result = 31 * result + (mExpanded ? 1 : 0);
288 result = 31 * result + (mDirectReplied ? 1 : 0);
289 result = 31 * result + (mSnoozed ? 1 : 0);
290 result = 31 * result + (mViewedSettings ? 1 : 0);
291 result = 31 * result + (mInteracted ? 1 : 0);
292 result = 31 * result + mDismissalSurface;
293 return result;
294 }
295
296 @Override
297 public String toString() {
298 final StringBuilder sb = new StringBuilder("NotificationStats{");
299 sb.append("mSeen=").append(mSeen);
300 sb.append(", mExpanded=").append(mExpanded);
301 sb.append(", mDirectReplied=").append(mDirectReplied);
302 sb.append(", mSnoozed=").append(mSnoozed);
303 sb.append(", mViewedSettings=").append(mViewedSettings);
304 sb.append(", mInteracted=").append(mInteracted);
305 sb.append(", mDismissalSurface=").append(mDismissalSurface);
306 sb.append('}');
307 return sb.toString();
308 }
309}