• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
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  */
16 package android.service.notification;
17 
18 import android.annotation.IntDef;
19 import android.annotation.SystemApi;
20 import android.annotation.TestApi;
21 import android.app.RemoteInput;
22 import android.os.Parcel;
23 import android.os.Parcelable;
24 
25 import java.lang.annotation.Retention;
26 import java.lang.annotation.RetentionPolicy;
27 
28 /**
29  * Information about how the user has interacted with a given notification.
30  * @hide
31  */
32 @TestApi
33 @SystemApi
34 public 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      */
56     public static final int DISMISSAL_NOT_DISMISSED = -1;
57     /**
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 
75     /** @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 
NotificationStats()106     public NotificationStats() {
107     }
108 
109     /**
110      * @hide
111      */
112     @SystemApi
NotificationStats(Parcel in)113     protected NotificationStats(Parcel in) {
114         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();
121         mDismissalSentiment = in.readInt();
122     }
123 
124     @Override
writeToParcel(Parcel dest, int flags)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);
133         dest.writeInt(mDismissalSentiment);
134     }
135 
136     @Override
describeContents()137     public int describeContents() {
138         return 0;
139     }
140 
141     public static final @android.annotation.NonNull Creator<NotificationStats> CREATOR = new Creator<NotificationStats>() {
142         @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      */
hasSeen()156     public boolean hasSeen() {
157         return mSeen;
158     }
159 
160     /**
161      * Records that the user as seen this notification at least once.
162      */
setSeen()163     public void setSeen() {
164         mSeen = true;
165     }
166 
167     /**
168      * Returns whether the user has expanded this notification at least once.
169      */
hasExpanded()170     public boolean hasExpanded() {
171         return mExpanded;
172     }
173 
174     /**
175      * Records that the user has expanded this notification at least once.
176      */
setExpanded()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      */
hasDirectReplied()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      */
setDirectReplied()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      */
hasSnoozed()204     public boolean hasSnoozed() {
205         return mSnoozed;
206     }
207 
208     /**
209      * Records that the user has snoozed this notification at least once.
210      */
setSnoozed()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      */
hasViewedSettings()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      */
setViewedSettings()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      */
hasInteracted()235     public boolean hasInteracted() {
236         return mInteracted;
237     }
238 
239     /**
240      * Returns from which surface the notification was dismissed.
241      */
getDismissalSurface()242     public @DismissalSurface int getDismissalSurface() {
243         return mDismissalSurface;
244     }
245 
246     /**
247      * Returns from which surface the notification was dismissed.
248      */
setDismissalSurface(@ismissalSurface int dismissalSurface)249     public void setDismissalSurface(@DismissalSurface int dismissalSurface) {
250         mDismissalSurface = dismissalSurface;
251     }
252 
253     /**
254      * Records whether the user indicated how they felt about a notification before or
255      * during dismissal.
256      */
setDismissalSentiment(@ismissalSentiment int dismissalSentiment)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      */
getDismissalSentiment()264     public @DismissalSentiment int getDismissalSentiment() {
265         return mDismissalSentiment;
266     }
267 
268     @Override
equals(Object o)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
hashCode()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
toString()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 }
310