ChannelImpressions.java revision 3d5b3c7eadccca697d54dbb182ce510790e37c4c
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
17package android.ext.services.notification;
18
19import android.os.Parcel;
20import android.os.Parcelable;
21import android.text.TextUtils;
22import android.util.Log;
23
24import org.xmlpull.v1.XmlPullParser;
25import org.xmlpull.v1.XmlSerializer;
26
27import java.io.IOException;
28
29public final class ChannelImpressions implements Parcelable {
30    private static final String TAG = "ExtAssistant.CI";
31    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
32
33    static final double DISMISS_TO_VIEW_RATIO_LIMIT = .8;
34    static final int STREAK_LIMIT = 2;
35    static final String ATT_DISMISSALS = "dismisses";
36    static final String ATT_VIEWS = "views";
37    static final String ATT_STREAK = "streak";
38
39    private int mDismissals = 0;
40    private int mViews = 0;
41    private int mStreak = 0;
42
43    public ChannelImpressions() {
44    }
45
46    public ChannelImpressions(int dismissals, int views) {
47        mDismissals = dismissals;
48        mViews = views;
49    }
50
51    protected ChannelImpressions(Parcel in) {
52        mDismissals = in.readInt();
53        mViews = in.readInt();
54        mStreak = in.readInt();
55    }
56
57    public int getStreak() {
58        return mStreak;
59    }
60
61    public int getDismissals() {
62        return mDismissals;
63    }
64
65    public int getViews() {
66        return mViews;
67    }
68
69    public void incrementDismissals() {
70        mDismissals++;
71        mStreak++;
72    }
73
74    public void append(ChannelImpressions additionalImpressions) {
75        if (additionalImpressions != null) {
76            mViews += additionalImpressions.getViews();
77            mStreak += additionalImpressions.getStreak();
78            mDismissals += additionalImpressions.getDismissals();
79        }
80    }
81
82    public void incrementViews() {
83        mViews++;
84    }
85
86    public void resetStreak() {
87        mStreak = 0;
88    }
89
90    public boolean shouldTriggerBlock() {
91        if (getViews() == 0) {
92            return false;
93        }
94        if (DEBUG) {
95            Log.d(TAG, "should trigger? " + getDismissals() + " " + getViews() + " " + getStreak());
96        }
97        return ((double) getDismissals() / getViews()) > DISMISS_TO_VIEW_RATIO_LIMIT
98                && getStreak() > STREAK_LIMIT;
99    }
100
101    @Override
102    public void writeToParcel(Parcel dest, int flags) {
103        dest.writeInt(mDismissals);
104        dest.writeInt(mViews);
105        dest.writeInt(mStreak);
106    }
107
108    @Override
109    public int describeContents() {
110        return 0;
111    }
112
113    public static final Creator<ChannelImpressions> CREATOR = new Creator<ChannelImpressions>() {
114        @Override
115        public ChannelImpressions createFromParcel(Parcel in) {
116            return new ChannelImpressions(in);
117        }
118
119        @Override
120        public ChannelImpressions[] newArray(int size) {
121            return new ChannelImpressions[size];
122        }
123    };
124
125    @Override
126    public boolean equals(Object o) {
127        if (this == o) return true;
128        if (o == null || getClass() != o.getClass()) return false;
129
130        ChannelImpressions that = (ChannelImpressions) o;
131
132        if (mDismissals != that.mDismissals) return false;
133        if (mViews != that.mViews) return false;
134        return mStreak == that.mStreak;
135    }
136
137    @Override
138    public int hashCode() {
139        int result = mDismissals;
140        result = 31 * result + mViews;
141        result = 31 * result + mStreak;
142        return result;
143    }
144
145    @Override
146    public String toString() {
147        final StringBuilder sb = new StringBuilder("ChannelImpressions{");
148        sb.append("mDismissals=").append(mDismissals);
149        sb.append(", mViews=").append(mViews);
150        sb.append(", mStreak=").append(mStreak);
151        sb.append('}');
152        return sb.toString();
153    }
154
155    protected void populateFromXml(XmlPullParser parser) {
156        mDismissals = safeInt(parser, ATT_DISMISSALS, 0);
157        mStreak = safeInt(parser, ATT_STREAK, 0);
158        mViews = safeInt(parser, ATT_VIEWS, 0);
159    }
160
161    protected void writeXml(XmlSerializer out) throws IOException {
162        if (mDismissals != 0) {
163            out.attribute(null, ATT_DISMISSALS, String.valueOf(mDismissals));
164        }
165        if (mStreak != 0) {
166            out.attribute(null, ATT_STREAK, String.valueOf(mStreak));
167        }
168        if (mViews != 0) {
169            out.attribute(null, ATT_VIEWS, String.valueOf(mViews));
170        }
171    }
172
173    private static int safeInt(XmlPullParser parser, String att, int defValue) {
174        final String val = parser.getAttributeValue(null, att);
175        return tryParseInt(val, defValue);
176    }
177
178    private static int tryParseInt(String value, int defValue) {
179        if (TextUtils.isEmpty(value)) return defValue;
180        try {
181            return Integer.parseInt(value);
182        } catch (NumberFormatException e) {
183            return defValue;
184        }
185    }
186}
187