summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/com/android/internal/statusbar/IStatusBarService.aidl5
-rw-r--r--core/java/com/android/internal/statusbar/NotificationVisibility.aidl20
-rw-r--r--core/java/com/android/internal/statusbar/NotificationVisibility.java161
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java74
-rw-r--r--services/core/java/com/android/server/EventLogTags.logtags2
-rw-r--r--services/core/java/com/android/server/notification/NotificationDelegate.java5
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java19
-rw-r--r--services/core/java/com/android/server/notification/NotificationRecord.java6
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerService.java4
9 files changed, 259 insertions, 37 deletions
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 663c838..aea1585 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -19,6 +19,7 @@ package com.android.internal.statusbar;
import com.android.internal.statusbar.IStatusBar;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.statusbar.StatusBarIconList;
+import com.android.internal.statusbar.NotificationVisibility;
import android.service.notification.StatusBarNotification;
/** @hide */
@@ -53,8 +54,8 @@ interface IStatusBarService
int uid, int initialPid, String message, int userId);
void onClearAllNotifications(int userId);
void onNotificationClear(String pkg, String tag, int id, int userId);
- void onNotificationVisibilityChanged(
- in String[] newlyVisibleKeys, in String[] noLongerVisibleKeys);
+ void onNotificationVisibilityChanged( in NotificationVisibility[] newlyVisibleKeys,
+ in NotificationVisibility[] noLongerVisibleKeys);
void onNotificationExpansionChanged(in String key, in boolean userAction, in boolean expanded);
void setSystemUiVisibility(int vis, int mask, String cause);
void setWindowState(int window, int state);
diff --git a/core/java/com/android/internal/statusbar/NotificationVisibility.aidl b/core/java/com/android/internal/statusbar/NotificationVisibility.aidl
new file mode 100644
index 0000000..c067551
--- /dev/null
+++ b/core/java/com/android/internal/statusbar/NotificationVisibility.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.statusbar;
+
+parcelable NotificationVisibility;
+
diff --git a/core/java/com/android/internal/statusbar/NotificationVisibility.java b/core/java/com/android/internal/statusbar/NotificationVisibility.java
new file mode 100644
index 0000000..2139ad0
--- /dev/null
+++ b/core/java/com/android/internal/statusbar/NotificationVisibility.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.statusbar;
+
+import android.os.Message;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import java.util.ArrayDeque;
+import java.util.Collection;
+
+public class NotificationVisibility implements Parcelable {
+ private static final String TAG = "NoViz";
+ private static final int MAX_POOL_SIZE = 25;
+ private static ArrayDeque<NotificationVisibility> sPool = new ArrayDeque<>(MAX_POOL_SIZE);
+ private static int sNexrId = 0;
+
+ public String key;
+ public int rank;
+ public boolean visible = true;
+ /*package*/ int id;
+
+ private NotificationVisibility() {
+ id = sNexrId++;
+ }
+
+ private NotificationVisibility(String key, int rank, boolean visibile) {
+ this();
+ this.key = key;
+ this.rank = rank;
+ this.visible = visibile;
+ }
+
+ @Override
+ public String toString() {
+ return "NotificationVisibility(id=" + id
+ + "key=" + key
+ + " rank=" + rank
+ + (visible?" visible":"")
+ + " )";
+ }
+
+ @Override
+ public NotificationVisibility clone() {
+ return obtain(this.key, this.rank, this.visible);
+ }
+
+ @Override
+ public int hashCode() {
+ // allow lookups by key, which _should_ never be null.
+ return key == null ? 0 : key.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object that) {
+ // allow lookups by key, which _should_ never be null.
+ if (that instanceof NotificationVisibility) {
+ NotificationVisibility thatViz = (NotificationVisibility) that;
+ return (key == null && thatViz.key == null) || key.equals(thatViz.key);
+ }
+ return false;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(this.key);
+ out.writeInt(this.rank);
+ out.writeInt(this.visible ? 1 : 0);
+ }
+
+ private void readFromParcel(Parcel in) {
+ this.key = in.readString();
+ this.rank = in.readInt();
+ this.visible = in.readInt() != 0;
+ }
+
+ /**
+ * Return a new NotificationVisibility instance from the global pool. Allows us to
+ * avoid allocating new objects in many cases.
+ */
+ public static NotificationVisibility obtain(String key, int rank, boolean visible) {
+ NotificationVisibility vo = obtain();
+ vo.key = key;
+ vo.rank = rank;
+ vo.visible = visible;
+ return vo;
+ }
+
+ private static NotificationVisibility obtain(Parcel in) {
+ NotificationVisibility vo = obtain();
+ vo.readFromParcel(in);
+ return vo;
+ }
+
+ private static NotificationVisibility obtain() {
+ synchronized (sPool) {
+ if (!sPool.isEmpty()) {
+ return sPool.poll();
+ }
+ }
+ return new NotificationVisibility();
+ }
+
+ /**
+ * Return a NotificationVisibility instance to the global pool.
+ * <p>
+ * You MUST NOT touch the NotificationVisibility after calling this function because it has
+ * effectively been freed.
+ * </p>
+ */
+ public void recycle() {
+ if (key == null) {
+ // do nothing on multiple recycles
+ return;
+ }
+ key = null;
+ if (sPool.size() < MAX_POOL_SIZE) {
+ synchronized (sPool) {
+ sPool.offer(this);
+ }
+ }
+ }
+
+ /**
+ * Parcelable.Creator that instantiates NotificationVisibility objects
+ */
+ public static final Parcelable.Creator<NotificationVisibility> CREATOR
+ = new Parcelable.Creator<NotificationVisibility>()
+ {
+ public NotificationVisibility createFromParcel(Parcel parcel)
+ {
+ return obtain(parcel);
+ }
+
+ public NotificationVisibility[] newArray(int size)
+ {
+ return new NotificationVisibility[size];
+ }
+ };
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 16df64c..5d98fe9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -96,6 +96,7 @@ import android.widget.ImageView;
import android.widget.TextView;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.statusbar.NotificationVisibility;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.keyguard.KeyguardHostView.OnDismissAction;
import com.android.keyguard.ViewMediatorCallback;
@@ -457,7 +458,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
private int mDisabledUnmodified2;
/** Keys of notifications currently visible to the user. */
- private final ArraySet<String> mCurrentlyVisibleNotifications = new ArraySet<String>();
+ private final ArraySet<NotificationVisibility> mCurrentlyVisibleNotifications =
+ new ArraySet<>();
private long mLastVisibilityReportUptimeMs;
private final ShadeUpdates mShadeUpdates = new ShadeUpdates();
@@ -498,12 +500,17 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
// Tracks notifications currently visible in mNotificationStackScroller and
// emits visibility events via NoMan on changes.
private final Runnable mVisibilityReporter = new Runnable() {
- private final ArrayList<String> mTmpNewlyVisibleNotifications = new ArrayList<String>();
- private final ArrayList<String> mTmpCurrentlyVisibleNotifications = new ArrayList<String>();
+ private final ArraySet<NotificationVisibility> mTmpNewlyVisibleNotifications =
+ new ArraySet<>();
+ private final ArraySet<NotificationVisibility> mTmpCurrentlyVisibleNotifications =
+ new ArraySet<>();
+ private final ArraySet<NotificationVisibility> mTmpNoLongerVisibleNotifications =
+ new ArraySet<>();
@Override
public void run() {
mLastVisibilityReportUptimeMs = SystemClock.uptimeMillis();
+ final String mediaKey = getCurrentMediaNotificationKey();
// 1. Loop over mNotificationData entries:
// A. Keep list of visible notifications.
@@ -518,31 +525,45 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
for (int i = 0; i < N; i++) {
Entry entry = activeNotifications.get(i);
String key = entry.notification.getKey();
- boolean previouslyVisible = mCurrentlyVisibleNotifications.contains(key);
- boolean currentlyVisible =
+ boolean isVisible =
(mStackScroller.getChildLocation(entry.row) & VISIBLE_LOCATIONS) != 0;
- if (currentlyVisible) {
+ NotificationVisibility visObj = NotificationVisibility.obtain(key, i, isVisible);
+ boolean previouslyVisible = mCurrentlyVisibleNotifications.contains(visObj);
+ if (isVisible) {
// Build new set of visible notifications.
- mTmpCurrentlyVisibleNotifications.add(key);
- }
- if (!previouslyVisible && currentlyVisible) {
- mTmpNewlyVisibleNotifications.add(key);
+ mTmpCurrentlyVisibleNotifications.add(visObj);
+ if (!previouslyVisible) {
+ mTmpNewlyVisibleNotifications.add(visObj);
+ }
+ } else {
+ // release object
+ visObj.recycle();
}
}
- ArraySet<String> noLongerVisibleNotifications = mCurrentlyVisibleNotifications;
- noLongerVisibleNotifications.removeAll(mTmpCurrentlyVisibleNotifications);
+ mTmpNoLongerVisibleNotifications.addAll(mCurrentlyVisibleNotifications);
+ mTmpNoLongerVisibleNotifications.removeAll(mTmpCurrentlyVisibleNotifications);
logNotificationVisibilityChanges(
- mTmpNewlyVisibleNotifications, noLongerVisibleNotifications);
+ mTmpNewlyVisibleNotifications, mTmpNoLongerVisibleNotifications);
- mCurrentlyVisibleNotifications.clear();
+ recycleAllVisibilityObjects(mCurrentlyVisibleNotifications);
mCurrentlyVisibleNotifications.addAll(mTmpCurrentlyVisibleNotifications);
- mTmpNewlyVisibleNotifications.clear();
+ recycleAllVisibilityObjects(mTmpNoLongerVisibleNotifications);
mTmpCurrentlyVisibleNotifications.clear();
+ mTmpNewlyVisibleNotifications.clear();
+ mTmpNoLongerVisibleNotifications.clear();
}
};
+ private void recycleAllVisibilityObjects(ArraySet<NotificationVisibility> array) {
+ final int N = array.size();
+ for (int i = 0 ; i < N; i++) {
+ array.valueAt(i).recycle();
+ }
+ array.clear();
+ }
+
private final View.OnClickListener mOverflowClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -2987,9 +3008,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
// Report all notifications as invisible and turn down the
// reporter.
if (!mCurrentlyVisibleNotifications.isEmpty()) {
- logNotificationVisibilityChanges(
- Collections.<String>emptyList(), mCurrentlyVisibleNotifications);
- mCurrentlyVisibleNotifications.clear();
+ logNotificationVisibilityChanges(Collections.<NotificationVisibility>emptyList(),
+ mCurrentlyVisibleNotifications);
+ recycleAllVisibilityObjects(mCurrentlyVisibleNotifications);
}
mHandler.removeCallbacks(mVisibilityReporter);
mStackScroller.setChildLocationsChangedListener(null);
@@ -3007,18 +3028,27 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
private void logNotificationVisibilityChanges(
- Collection<String> newlyVisible, Collection<String> noLongerVisible) {
+ Collection<NotificationVisibility> newlyVisible,
+ Collection<NotificationVisibility> noLongerVisible) {
if (newlyVisible.isEmpty() && noLongerVisible.isEmpty()) {
return;
}
- String[] newlyVisibleAr = newlyVisible.toArray(new String[newlyVisible.size()]);
- String[] noLongerVisibleAr = noLongerVisible.toArray(new String[noLongerVisible.size()]);
+ NotificationVisibility[] newlyVisibleAr =
+ newlyVisible.toArray(new NotificationVisibility[newlyVisible.size()]);
+ NotificationVisibility[] noLongerVisibleAr =
+ noLongerVisible.toArray(new NotificationVisibility[noLongerVisible.size()]);
try {
mBarService.onNotificationVisibilityChanged(newlyVisibleAr, noLongerVisibleAr);
} catch (RemoteException e) {
// Ignore.
}
- setNotificationsShown(newlyVisibleAr);
+
+ final int N = newlyVisible.size();
+ String[] newlyVisibleKeyAr = new String[N];
+ for (int i = 0; i < N; i++) {
+ newlyVisibleKeyAr[i] = newlyVisibleAr[i].key;
+ }
+ setNotificationsShown(newlyVisibleKeyAr);
}
// State logging
diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index 49d4c22..43b640b 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -74,7 +74,7 @@ option java_package com.android.server
# when a notification has been canceled
27530 notification_canceled (key|3),(reason|1),(lifespan|1),(freshness|1),(exposure|1)
# replaces 27510 with a row per notification
-27531 notification_visibility (key|3),(visibile|1),(lifespan|1),(freshness|1)
+27531 notification_visibility (key|3),(visibile|1),(lifespan|1),(freshness|1),(exposure|1),(rank|1)
# a notification emited noise, vibration, or light
27532 notification_alert (key|3),(buzz|1),(beep|1),(blink|1)
diff --git a/services/core/java/com/android/server/notification/NotificationDelegate.java b/services/core/java/com/android/server/notification/NotificationDelegate.java
index fdb443e..87b4f8c 100644
--- a/services/core/java/com/android/server/notification/NotificationDelegate.java
+++ b/services/core/java/com/android/server/notification/NotificationDelegate.java
@@ -16,6 +16,8 @@
package com.android.server.notification;
+import com.android.internal.statusbar.NotificationVisibility;
+
public interface NotificationDelegate {
void onSetDisabled(int status);
void onClearAll(int callingUid, int callingPid, int userId);
@@ -30,6 +32,7 @@ public interface NotificationDelegate {
void onPanelHidden();
void clearEffects();
void onNotificationVisibilityChanged(
- String[] newlyVisibleKeys, String[] noLongerVisibleKeys);
+ NotificationVisibility[] newlyVisibleKeys,
+ NotificationVisibility[] noLongerVisibleKeys);
void onNotificationExpansionChanged(String key, boolean userAction, boolean expanded);
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 0dcad82..4524ff8 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -97,6 +97,7 @@ import android.view.accessibility.AccessibilityManager;
import android.widget.Toast;
import com.android.internal.R;
+import com.android.internal.statusbar.NotificationVisibility;
import com.android.internal.util.FastXmlSerializer;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
@@ -622,22 +623,24 @@ public class NotificationManagerService extends SystemService {
}
@Override
- public void onNotificationVisibilityChanged(
- String[] newlyVisibleKeys, String[] noLongerVisibleKeys) {
+ public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
+ NotificationVisibility[] noLongerVisibleKeys) {
synchronized (mNotificationList) {
- for (String key : newlyVisibleKeys) {
- NotificationRecord r = mNotificationsByKey.get(key);
+ for (NotificationVisibility nv : newlyVisibleKeys) {
+ NotificationRecord r = mNotificationsByKey.get(nv.key);
if (r == null) continue;
- r.setVisibility(true);
+ r.setVisibility(true, nv.rank);
+ nv.recycle();
}
// Note that we might receive this event after notifications
// have already left the system, e.g. after dismissing from the
// shade. Hence not finding notifications in
// mNotificationsByKey is not an exceptional condition.
- for (String key : noLongerVisibleKeys) {
- NotificationRecord r = mNotificationsByKey.get(key);
+ for (NotificationVisibility nv : noLongerVisibleKeys) {
+ NotificationRecord r = mNotificationsByKey.get(nv.key);
if (r == null) continue;
- r.setVisibility(false);
+ r.setVisibility(false, nv.rank);
+ nv.recycle();
}
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index c4773ca..b7aea9d 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -314,13 +314,15 @@ public final class NotificationRecord {
/**
* Set the visibility of the notification.
*/
- public void setVisibility(boolean visible) {
+ public void setVisibility(boolean visible, int rank) {
final long now = System.currentTimeMillis();
mVisibleSinceMs = visible ? now : mVisibleSinceMs;
stats.onVisibilityChanged(visible);
EventLogTags.writeNotificationVisibility(getKey(), visible ? 1 : 0,
(int) (now - mCreationTimeMs),
- (int) (now - mUpdateTimeMs));
+ (int) (now - mUpdateTimeMs),
+ 0, // exposure time
+ rank);
}
/**
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index a754379..7640837 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -29,6 +29,7 @@ import android.util.Slog;
import com.android.internal.statusbar.IStatusBar;
import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.statusbar.NotificationVisibility;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.statusbar.StatusBarIconList;
import com.android.server.LocalServices;
@@ -660,7 +661,8 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
@Override
public void onNotificationVisibilityChanged(
- String[] newlyVisibleKeys, String[] noLongerVisibleKeys) throws RemoteException {
+ NotificationVisibility[] newlyVisibleKeys, NotificationVisibility[] noLongerVisibleKeys)
+ throws RemoteException {
enforceStatusBarService();
long identity = Binder.clearCallingIdentity();
try {