NotificationRecord.java revision 333a61c3a5a83fe9c50ebeb5c947317f61385b7b
1/*
2 * Copyright (C) 2014 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 com.android.server.notification;
17
18import android.app.Notification;
19import android.content.Context;
20import android.content.pm.PackageManager.NameNotFoundException;
21import android.content.res.Resources;
22import android.graphics.Bitmap;
23import android.service.notification.StatusBarNotification;
24
25import java.io.PrintWriter;
26import java.lang.reflect.Array;
27import java.util.Arrays;
28
29/**
30 * Holds data about notifications that should not be shared with the
31 * {@link android.service.notification.NotificationListenerService}s.
32 *
33 * <p>These objects should not be mutated unless the code is synchronized
34 * on {@link NotificationManagerService#mNotificationList}, and any
35 * modification should be followed by a sorting of that list.</p>
36 *
37 * <p>Is sortable by {@link NotificationComparator}.</p>
38 *
39 * {@hide}
40 */
41public final class NotificationRecord {
42    final StatusBarNotification sbn;
43    NotificationUsageStats.SingleNotificationStats stats;
44    boolean isCanceled;
45
46    // These members are used by NotificationSignalExtractors
47    // to communicate with the ranking module.
48    private float mContactAffinity;
49    private boolean mRecentlyIntrusive;
50
51    // is this notification currently being intercepted by Zen Mode?
52    private boolean mIntercept;
53    // InterceptedNotifications needs to know if this has been previously evaluated.
54    private boolean mTouchedByZen;
55
56    NotificationRecord(StatusBarNotification sbn)
57    {
58        this.sbn = sbn;
59    }
60
61    // copy any notes that the ranking system may have made before the update
62    public void copyRankingInformation(NotificationRecord previous) {
63        mContactAffinity = previous.mContactAffinity;
64        mRecentlyIntrusive = previous.mRecentlyIntrusive;
65        mTouchedByZen = previous.mTouchedByZen;
66        mIntercept = previous.mIntercept;
67    }
68
69    public Notification getNotification() { return sbn.getNotification(); }
70    public int getFlags() { return sbn.getNotification().flags; }
71    public int getUserId() { return sbn.getUserId(); }
72    public String getKey() { return sbn.getKey(); }
73
74    void dump(PrintWriter pw, String prefix, Context baseContext) {
75        final Notification notification = sbn.getNotification();
76        pw.println(prefix + this);
77        pw.println(prefix + "  uid=" + sbn.getUid() + " userId=" + sbn.getUserId());
78        pw.println(prefix + "  icon=0x" + Integer.toHexString(notification.icon)
79                + " / " + idDebugString(baseContext, sbn.getPackageName(), notification.icon));
80        pw.println(prefix + "  pri=" + notification.priority + " score=" + sbn.getScore());
81        pw.println(prefix + "  key=" + sbn.getKey());
82        pw.println(prefix + "  contentIntent=" + notification.contentIntent);
83        pw.println(prefix + "  deleteIntent=" + notification.deleteIntent);
84        pw.println(prefix + "  tickerText=" + notification.tickerText);
85        pw.println(prefix + "  contentView=" + notification.contentView);
86        pw.println(prefix + String.format("  defaults=0x%08x flags=0x%08x",
87                notification.defaults, notification.flags));
88        pw.println(prefix + "  sound=" + notification.sound);
89        pw.println(prefix + String.format("  color=0x%08x", notification.color));
90        pw.println(prefix + "  vibrate=" + Arrays.toString(notification.vibrate));
91        pw.println(prefix + String.format("  led=0x%08x onMs=%d offMs=%d",
92                notification.ledARGB, notification.ledOnMS, notification.ledOffMS));
93        if (notification.actions != null && notification.actions.length > 0) {
94            pw.println(prefix + "  actions={");
95            final int N = notification.actions.length;
96            for (int i=0; i<N; i++) {
97                final Notification.Action action = notification.actions[i];
98                pw.println(String.format("%s    [%d] \"%s\" -> %s",
99                        prefix,
100                        i,
101                        action.title,
102                        action.actionIntent.toString()
103                        ));
104            }
105            pw.println(prefix + "  }");
106        }
107        if (notification.extras != null && notification.extras.size() > 0) {
108            pw.println(prefix + "  extras={");
109            for (String key : notification.extras.keySet()) {
110                pw.print(prefix + "    " + key + "=");
111                Object val = notification.extras.get(key);
112                if (val == null) {
113                    pw.println("null");
114                } else {
115                    pw.print(val.getClass().getSimpleName());
116                    if (val instanceof CharSequence || val instanceof String) {
117                        // redact contents from bugreports
118                    } else if (val instanceof Bitmap) {
119                        pw.print(String.format(" (%dx%d)",
120                                ((Bitmap) val).getWidth(),
121                                ((Bitmap) val).getHeight()));
122                    } else if (val.getClass().isArray()) {
123                        final int N = Array.getLength(val);
124                        pw.println(" (" + N + ")");
125                    } else {
126                        pw.print(" (" + String.valueOf(val) + ")");
127                    }
128                    pw.println();
129                }
130            }
131            pw.println(prefix + "  }");
132        }
133        pw.println(prefix + "  stats=" + stats.toString());
134        pw.println(prefix + "  mContactAffinity=" + mContactAffinity);
135        pw.println(prefix + "  mRecentlyIntrusive=" + mRecentlyIntrusive);
136        pw.println(prefix + "  mIntercept=" + mIntercept);
137    }
138
139
140    static String idDebugString(Context baseContext, String packageName, int id) {
141        Context c;
142
143        if (packageName != null) {
144            try {
145                c = baseContext.createPackageContext(packageName, 0);
146            } catch (NameNotFoundException e) {
147                c = baseContext;
148            }
149        } else {
150            c = baseContext;
151        }
152
153        Resources r = c.getResources();
154        try {
155            return r.getResourceName(id);
156        } catch (Resources.NotFoundException e) {
157            return "<name unknown>";
158        }
159    }
160
161    @Override
162    public final String toString() {
163        return String.format(
164                "NotificationRecord(0x%08x: pkg=%s user=%s id=%d tag=%s score=%d key=%s: %s)",
165                System.identityHashCode(this),
166                this.sbn.getPackageName(), this.sbn.getUser(), this.sbn.getId(),
167                this.sbn.getTag(), this.sbn.getScore(), this.sbn.getKey(),
168                this.sbn.getNotification());
169    }
170
171    public void setContactAffinity(float contactAffinity) {
172        mContactAffinity = contactAffinity;
173    }
174
175    public float getContactAffinity() {
176        return mContactAffinity;
177    }
178
179    public void setRecentlyIntusive(boolean recentlyIntrusive) {
180        mRecentlyIntrusive = recentlyIntrusive;
181    }
182
183    public boolean isRecentlyIntrusive() {
184        return mRecentlyIntrusive;
185    }
186
187    public boolean setIntercepted(boolean intercept) {
188        mIntercept = intercept;
189        return mIntercept;
190    }
191
192    public boolean isIntercepted() {
193        return mIntercept;
194    }
195
196    public boolean wasTouchedByZen() {
197        return mTouchedByZen;
198    }
199
200    public void setTouchedByZen() {
201        mTouchedByZen = true;
202    }
203
204}
205