• 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.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.SystemApi;
22 import android.app.RemoteInput;
23 import android.os.Parcel;
24 import android.os.Parcelable;
25 
26 import java.lang.annotation.Retention;
27 import java.lang.annotation.RetentionPolicy;
28 
29 /**
30  * Information about how the user has interacted with a given notification.
31  * @hide
32  */
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      * Notification has been dismissed as a bubble.
76      * @hide
77      */
78     public static final int DISMISSAL_BUBBLE = 3;
79 
80     /** @hide */
81     @IntDef(prefix = { "DISMISS_SENTIMENT_" }, value = {
82             DISMISS_SENTIMENT_UNKNOWN, DISMISS_SENTIMENT_NEGATIVE, DISMISS_SENTIMENT_NEUTRAL,
83             DISMISS_SENTIMENT_POSITIVE
84     })
85     @Retention(RetentionPolicy.SOURCE)
86     public @interface DismissalSentiment {}
87 
88     /**
89      * No information is available about why this notification was dismissed, or the notification
90      * isn't dismissed yet.
91      */
92     public static final int DISMISS_SENTIMENT_UNKNOWN = -1000;
93     /**
94      * The user indicated while dismissing that they did not like the notification.
95      */
96     public static final int DISMISS_SENTIMENT_NEGATIVE = 0;
97     /**
98      * The user didn't indicate one way or another how they felt about the notification while
99      * dismissing it.
100      */
101     public static final int DISMISS_SENTIMENT_NEUTRAL = 1;
102     /**
103      * The user indicated while dismissing that they did like the notification.
104      */
105     public static final int DISMISS_SENTIMENT_POSITIVE = 2;
106 
107 
108     private @DismissalSentiment
109     int mDismissalSentiment = DISMISS_SENTIMENT_UNKNOWN;
110 
NotificationStats()111     public NotificationStats() {
112     }
113 
114     /**
115      * @hide
116      */
117     @SystemApi
NotificationStats(Parcel in)118     protected NotificationStats(Parcel in) {
119         mSeen = in.readByte() != 0;
120         mExpanded = in.readByte() != 0;
121         mDirectReplied = in.readByte() != 0;
122         mSnoozed = in.readByte() != 0;
123         mViewedSettings = in.readByte() != 0;
124         mInteracted = in.readByte() != 0;
125         mDismissalSurface = in.readInt();
126         mDismissalSentiment = in.readInt();
127     }
128 
129     @Override
writeToParcel(Parcel dest, int flags)130     public void writeToParcel(Parcel dest, int flags) {
131         dest.writeByte((byte) (mSeen ? 1 : 0));
132         dest.writeByte((byte) (mExpanded ? 1 : 0));
133         dest.writeByte((byte) (mDirectReplied ? 1 : 0));
134         dest.writeByte((byte) (mSnoozed ? 1 : 0));
135         dest.writeByte((byte) (mViewedSettings ? 1 : 0));
136         dest.writeByte((byte) (mInteracted ? 1 : 0));
137         dest.writeInt(mDismissalSurface);
138         dest.writeInt(mDismissalSentiment);
139     }
140 
141     @Override
describeContents()142     public int describeContents() {
143         return 0;
144     }
145 
146     public static final @android.annotation.NonNull Creator<NotificationStats> CREATOR = new Creator<NotificationStats>() {
147         @Override
148         public NotificationStats createFromParcel(Parcel in) {
149             return new NotificationStats(in);
150         }
151 
152         @Override
153         public NotificationStats[] newArray(int size) {
154             return new NotificationStats[size];
155         }
156     };
157 
158     /**
159      * Returns whether the user has seen this notification at least once.
160      */
hasSeen()161     public boolean hasSeen() {
162         return mSeen;
163     }
164 
165     /**
166      * Records that the user as seen this notification at least once.
167      */
setSeen()168     public void setSeen() {
169         mSeen = true;
170     }
171 
172     /**
173      * Returns whether the user has expanded this notification at least once.
174      */
hasExpanded()175     public boolean hasExpanded() {
176         return mExpanded;
177     }
178 
179     /**
180      * Records that the user has expanded this notification at least once.
181      */
setExpanded()182     public void setExpanded() {
183         mExpanded = true;
184         mInteracted = true;
185     }
186 
187     /**
188      * Returns whether the user has replied to a notification that has a
189      * {@link android.app.Notification.Action.Builder#addRemoteInput(RemoteInput) direct reply} at
190      * least once.
191      */
hasDirectReplied()192     public boolean hasDirectReplied() {
193         return mDirectReplied;
194     }
195 
196     /**
197      * Records that the user has replied to a notification that has a
198      * {@link android.app.Notification.Action.Builder#addRemoteInput(RemoteInput) direct reply}
199      * at least once.
200      */
setDirectReplied()201     public void setDirectReplied() {
202         mDirectReplied = true;
203         mInteracted = true;
204     }
205 
206     /**
207      * Returns whether the user has snoozed this notification at least once.
208      */
hasSnoozed()209     public boolean hasSnoozed() {
210         return mSnoozed;
211     }
212 
213     /**
214      * Records that the user has snoozed this notification at least once.
215      */
setSnoozed()216     public void setSnoozed() {
217         mSnoozed = true;
218         mInteracted = true;
219     }
220 
221     /**
222      * Returns whether the user has viewed the in-shade settings for this notification at least
223      * once.
224      */
hasViewedSettings()225     public boolean hasViewedSettings() {
226         return mViewedSettings;
227     }
228 
229     /**
230      * Records that the user has viewed the in-shade settings for this notification at least once.
231      */
setViewedSettings()232     public void setViewedSettings() {
233         mViewedSettings = true;
234         mInteracted = true;
235     }
236 
237     /**
238      * Returns whether the user has interacted with this notification beyond having viewed it.
239      */
hasInteracted()240     public boolean hasInteracted() {
241         return mInteracted;
242     }
243 
244     /**
245      * Returns from which surface the notification was dismissed.
246      */
getDismissalSurface()247     public @DismissalSurface int getDismissalSurface() {
248         return mDismissalSurface;
249     }
250 
251     /**
252      * Returns from which surface the notification was dismissed.
253      */
setDismissalSurface(@ismissalSurface int dismissalSurface)254     public void setDismissalSurface(@DismissalSurface int dismissalSurface) {
255         mDismissalSurface = dismissalSurface;
256     }
257 
258     /**
259      * Records whether the user indicated how they felt about a notification before or
260      * during dismissal.
261      */
setDismissalSentiment(@ismissalSentiment int dismissalSentiment)262     public void setDismissalSentiment(@DismissalSentiment int dismissalSentiment) {
263         mDismissalSentiment = dismissalSentiment;
264     }
265 
266     /**
267      * Returns how the user indicated they felt about a notification before or during dismissal.
268      */
getDismissalSentiment()269     public @DismissalSentiment int getDismissalSentiment() {
270         return mDismissalSentiment;
271     }
272 
273     @Override
equals(@ullable Object o)274     public boolean equals(@Nullable Object o) {
275         if (this == o) return true;
276         if (o == null || getClass() != o.getClass()) return false;
277 
278         NotificationStats that = (NotificationStats) o;
279 
280         if (mSeen != that.mSeen) return false;
281         if (mExpanded != that.mExpanded) return false;
282         if (mDirectReplied != that.mDirectReplied) return false;
283         if (mSnoozed != that.mSnoozed) return false;
284         if (mViewedSettings != that.mViewedSettings) return false;
285         if (mInteracted != that.mInteracted) return false;
286         return mDismissalSurface == that.mDismissalSurface;
287     }
288 
289     @Override
hashCode()290     public int hashCode() {
291         int result = (mSeen ? 1 : 0);
292         result = 31 * result + (mExpanded ? 1 : 0);
293         result = 31 * result + (mDirectReplied ? 1 : 0);
294         result = 31 * result + (mSnoozed ? 1 : 0);
295         result = 31 * result + (mViewedSettings ? 1 : 0);
296         result = 31 * result + (mInteracted ? 1 : 0);
297         result = 31 * result + mDismissalSurface;
298         return result;
299     }
300 
301     @NonNull
302     @Override
toString()303     public String toString() {
304         final StringBuilder sb = new StringBuilder("NotificationStats{");
305         sb.append("mSeen=").append(mSeen);
306         sb.append(", mExpanded=").append(mExpanded);
307         sb.append(", mDirectReplied=").append(mDirectReplied);
308         sb.append(", mSnoozed=").append(mSnoozed);
309         sb.append(", mViewedSettings=").append(mViewedSettings);
310         sb.append(", mInteracted=").append(mInteracted);
311         sb.append(", mDismissalSurface=").append(mDismissalSurface);
312         sb.append('}');
313         return sb.toString();
314     }
315 }
316