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 * @hide 30 */ 31 @TestApi 32 @SystemApi 33 public final class NotificationStats implements Parcelable { 34 35 private boolean mSeen; 36 private boolean mExpanded; 37 private boolean mDirectReplied; 38 private boolean mSnoozed; 39 private boolean mViewedSettings; 40 private boolean mInteracted; 41 42 /** @hide */ 43 @IntDef(prefix = { "DISMISSAL_SURFACE_" }, value = { 44 DISMISSAL_NOT_DISMISSED, DISMISSAL_OTHER, DISMISSAL_PEEK, DISMISSAL_AOD, DISMISSAL_SHADE 45 }) 46 @Retention(RetentionPolicy.SOURCE) 47 public @interface DismissalSurface {} 48 49 50 private @DismissalSurface int mDismissalSurface = DISMISSAL_NOT_DISMISSED; 51 52 /** 53 * Notification has not been dismissed yet. 54 */ 55 public static final int DISMISSAL_NOT_DISMISSED = -1; 56 /** 57 * Notification has been dismissed from a {@link NotificationListenerService} or the app 58 * itself. 59 */ 60 public static final int DISMISSAL_OTHER = 0; 61 /** 62 * Notification has been dismissed while peeking. 63 */ 64 public static final int DISMISSAL_PEEK = 1; 65 /** 66 * Notification has been dismissed from always on display. 67 */ 68 public static final int DISMISSAL_AOD = 2; 69 /** 70 * Notification has been dismissed from the notification shade. 71 */ 72 public static final int DISMISSAL_SHADE = 3; 73 NotificationStats()74 public NotificationStats() { 75 } 76 NotificationStats(Parcel in)77 protected NotificationStats(Parcel in) { 78 mSeen = in.readByte() != 0; 79 mExpanded = in.readByte() != 0; 80 mDirectReplied = in.readByte() != 0; 81 mSnoozed = in.readByte() != 0; 82 mViewedSettings = in.readByte() != 0; 83 mInteracted = in.readByte() != 0; 84 mDismissalSurface = in.readInt(); 85 } 86 87 @Override writeToParcel(Parcel dest, int flags)88 public void writeToParcel(Parcel dest, int flags) { 89 dest.writeByte((byte) (mSeen ? 1 : 0)); 90 dest.writeByte((byte) (mExpanded ? 1 : 0)); 91 dest.writeByte((byte) (mDirectReplied ? 1 : 0)); 92 dest.writeByte((byte) (mSnoozed ? 1 : 0)); 93 dest.writeByte((byte) (mViewedSettings ? 1 : 0)); 94 dest.writeByte((byte) (mInteracted ? 1 : 0)); 95 dest.writeInt(mDismissalSurface); 96 } 97 98 @Override describeContents()99 public int describeContents() { 100 return 0; 101 } 102 103 public static final Creator<NotificationStats> CREATOR = new Creator<NotificationStats>() { 104 @Override 105 public NotificationStats createFromParcel(Parcel in) { 106 return new NotificationStats(in); 107 } 108 109 @Override 110 public NotificationStats[] newArray(int size) { 111 return new NotificationStats[size]; 112 } 113 }; 114 115 /** 116 * Returns whether the user has seen this notification at least once. 117 */ hasSeen()118 public boolean hasSeen() { 119 return mSeen; 120 } 121 122 /** 123 * Records that the user as seen this notification at least once. 124 */ setSeen()125 public void setSeen() { 126 mSeen = true; 127 } 128 129 /** 130 * Returns whether the user has expanded this notification at least once. 131 */ hasExpanded()132 public boolean hasExpanded() { 133 return mExpanded; 134 } 135 136 /** 137 * Records that the user has expanded this notification at least once. 138 */ setExpanded()139 public void setExpanded() { 140 mExpanded = true; 141 mInteracted = true; 142 } 143 144 /** 145 * Returns whether the user has replied to a notification that has a 146 * {@link android.app.Notification.Action.Builder#addRemoteInput(RemoteInput) direct reply} at 147 * least once. 148 */ hasDirectReplied()149 public boolean hasDirectReplied() { 150 return mDirectReplied; 151 } 152 153 /** 154 * Records that the user has replied to a notification that has a 155 * {@link android.app.Notification.Action.Builder#addRemoteInput(RemoteInput) direct reply} 156 * at least once. 157 */ setDirectReplied()158 public void setDirectReplied() { 159 mDirectReplied = true; 160 mInteracted = true; 161 } 162 163 /** 164 * Returns whether the user has snoozed this notification at least once. 165 */ hasSnoozed()166 public boolean hasSnoozed() { 167 return mSnoozed; 168 } 169 170 /** 171 * Records that the user has snoozed this notification at least once. 172 */ setSnoozed()173 public void setSnoozed() { 174 mSnoozed = true; 175 mInteracted = true; 176 } 177 178 /** 179 * Returns whether the user has viewed the in-shade settings for this notification at least 180 * once. 181 */ hasViewedSettings()182 public boolean hasViewedSettings() { 183 return mViewedSettings; 184 } 185 186 /** 187 * Records that the user has viewed the in-shade settings for this notification at least once. 188 */ setViewedSettings()189 public void setViewedSettings() { 190 mViewedSettings = true; 191 mInteracted = true; 192 } 193 194 /** 195 * Returns whether the user has interacted with this notification beyond having viewed it. 196 */ hasInteracted()197 public boolean hasInteracted() { 198 return mInteracted; 199 } 200 201 /** 202 * Returns from which surface the notification was dismissed. 203 */ getDismissalSurface()204 public @DismissalSurface int getDismissalSurface() { 205 return mDismissalSurface; 206 } 207 208 /** 209 * Returns from which surface the notification was dismissed. 210 */ setDismissalSurface(@ismissalSurface int dismissalSurface)211 public void setDismissalSurface(@DismissalSurface int dismissalSurface) { 212 mDismissalSurface = dismissalSurface; 213 } 214 215 @Override equals(Object o)216 public boolean equals(Object o) { 217 if (this == o) return true; 218 if (o == null || getClass() != o.getClass()) return false; 219 220 NotificationStats that = (NotificationStats) o; 221 222 if (mSeen != that.mSeen) return false; 223 if (mExpanded != that.mExpanded) return false; 224 if (mDirectReplied != that.mDirectReplied) return false; 225 if (mSnoozed != that.mSnoozed) return false; 226 if (mViewedSettings != that.mViewedSettings) return false; 227 if (mInteracted != that.mInteracted) return false; 228 return mDismissalSurface == that.mDismissalSurface; 229 } 230 231 @Override hashCode()232 public int hashCode() { 233 int result = (mSeen ? 1 : 0); 234 result = 31 * result + (mExpanded ? 1 : 0); 235 result = 31 * result + (mDirectReplied ? 1 : 0); 236 result = 31 * result + (mSnoozed ? 1 : 0); 237 result = 31 * result + (mViewedSettings ? 1 : 0); 238 result = 31 * result + (mInteracted ? 1 : 0); 239 result = 31 * result + mDismissalSurface; 240 return result; 241 } 242 243 @Override toString()244 public String toString() { 245 final StringBuilder sb = new StringBuilder("NotificationStats{"); 246 sb.append("mSeen=").append(mSeen); 247 sb.append(", mExpanded=").append(mExpanded); 248 sb.append(", mDirectReplied=").append(mDirectReplied); 249 sb.append(", mSnoozed=").append(mSnoozed); 250 sb.append(", mViewedSettings=").append(mViewedSettings); 251 sb.append(", mInteracted=").append(mInteracted); 252 sb.append(", mDismissalSurface=").append(mDismissalSurface); 253 sb.append('}'); 254 return sb.toString(); 255 } 256 } 257