Merge "add rank to notification visibility log" into mnc-dev

This commit is contained in:
Chris Wren
2015-06-23 12:43:08 +00:00
committed by Android (Google) Code Review
9 changed files with 259 additions and 37 deletions

View File

@@ -19,6 +19,7 @@ package com.android.internal.statusbar;
import com.android.internal.statusbar.IStatusBar; import com.android.internal.statusbar.IStatusBar;
import com.android.internal.statusbar.StatusBarIcon; import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.statusbar.StatusBarIconList; import com.android.internal.statusbar.StatusBarIconList;
import com.android.internal.statusbar.NotificationVisibility;
import android.service.notification.StatusBarNotification; import android.service.notification.StatusBarNotification;
/** @hide */ /** @hide */
@@ -53,8 +54,8 @@ interface IStatusBarService
int uid, int initialPid, String message, int userId); int uid, int initialPid, String message, int userId);
void onClearAllNotifications(int userId); void onClearAllNotifications(int userId);
void onNotificationClear(String pkg, String tag, int id, int userId); void onNotificationClear(String pkg, String tag, int id, int userId);
void onNotificationVisibilityChanged( void onNotificationVisibilityChanged( in NotificationVisibility[] newlyVisibleKeys,
in String[] newlyVisibleKeys, in String[] noLongerVisibleKeys); in NotificationVisibility[] noLongerVisibleKeys);
void onNotificationExpansionChanged(in String key, in boolean userAction, in boolean expanded); void onNotificationExpansionChanged(in String key, in boolean userAction, in boolean expanded);
void setSystemUiVisibility(int vis, int mask, String cause); void setSystemUiVisibility(int vis, int mask, String cause);
void setWindowState(int window, int state); void setWindowState(int window, int state);

View File

@@ -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;

View File

@@ -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];
}
};
}

View File

@@ -96,6 +96,7 @@ import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.MetricsLogger;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.internal.statusbar.StatusBarIcon; import com.android.internal.statusbar.StatusBarIcon;
import com.android.keyguard.KeyguardHostView.OnDismissAction; import com.android.keyguard.KeyguardHostView.OnDismissAction;
import com.android.keyguard.ViewMediatorCallback; import com.android.keyguard.ViewMediatorCallback;
@@ -457,7 +458,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
private int mDisabledUnmodified2; private int mDisabledUnmodified2;
/** Keys of notifications currently visible to the user. */ /** 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 long mLastVisibilityReportUptimeMs;
private final ShadeUpdates mShadeUpdates = new ShadeUpdates(); private final ShadeUpdates mShadeUpdates = new ShadeUpdates();
@@ -498,12 +500,17 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
// Tracks notifications currently visible in mNotificationStackScroller and // Tracks notifications currently visible in mNotificationStackScroller and
// emits visibility events via NoMan on changes. // emits visibility events via NoMan on changes.
private final Runnable mVisibilityReporter = new Runnable() { private final Runnable mVisibilityReporter = new Runnable() {
private final ArrayList<String> mTmpNewlyVisibleNotifications = new ArrayList<String>(); private final ArraySet<NotificationVisibility> mTmpNewlyVisibleNotifications =
private final ArrayList<String> mTmpCurrentlyVisibleNotifications = new ArrayList<String>(); new ArraySet<>();
private final ArraySet<NotificationVisibility> mTmpCurrentlyVisibleNotifications =
new ArraySet<>();
private final ArraySet<NotificationVisibility> mTmpNoLongerVisibleNotifications =
new ArraySet<>();
@Override @Override
public void run() { public void run() {
mLastVisibilityReportUptimeMs = SystemClock.uptimeMillis(); mLastVisibilityReportUptimeMs = SystemClock.uptimeMillis();
final String mediaKey = getCurrentMediaNotificationKey();
// 1. Loop over mNotificationData entries: // 1. Loop over mNotificationData entries:
// A. Keep list of visible notifications. // A. Keep list of visible notifications.
@@ -518,31 +525,45 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
Entry entry = activeNotifications.get(i); Entry entry = activeNotifications.get(i);
String key = entry.notification.getKey(); String key = entry.notification.getKey();
boolean previouslyVisible = mCurrentlyVisibleNotifications.contains(key); boolean isVisible =
boolean currentlyVisible =
(mStackScroller.getChildLocation(entry.row) & VISIBLE_LOCATIONS) != 0; (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. // Build new set of visible notifications.
mTmpCurrentlyVisibleNotifications.add(key); mTmpCurrentlyVisibleNotifications.add(visObj);
} if (!previouslyVisible) {
if (!previouslyVisible && currentlyVisible) { mTmpNewlyVisibleNotifications.add(visObj);
mTmpNewlyVisibleNotifications.add(key); }
} else {
// release object
visObj.recycle();
} }
} }
ArraySet<String> noLongerVisibleNotifications = mCurrentlyVisibleNotifications; mTmpNoLongerVisibleNotifications.addAll(mCurrentlyVisibleNotifications);
noLongerVisibleNotifications.removeAll(mTmpCurrentlyVisibleNotifications); mTmpNoLongerVisibleNotifications.removeAll(mTmpCurrentlyVisibleNotifications);
logNotificationVisibilityChanges( logNotificationVisibilityChanges(
mTmpNewlyVisibleNotifications, noLongerVisibleNotifications); mTmpNewlyVisibleNotifications, mTmpNoLongerVisibleNotifications);
mCurrentlyVisibleNotifications.clear(); recycleAllVisibilityObjects(mCurrentlyVisibleNotifications);
mCurrentlyVisibleNotifications.addAll(mTmpCurrentlyVisibleNotifications); mCurrentlyVisibleNotifications.addAll(mTmpCurrentlyVisibleNotifications);
mTmpNewlyVisibleNotifications.clear(); recycleAllVisibilityObjects(mTmpNoLongerVisibleNotifications);
mTmpCurrentlyVisibleNotifications.clear(); 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() { private final View.OnClickListener mOverflowClickListener = new View.OnClickListener() {
@Override @Override
public void onClick(View v) { 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 // Report all notifications as invisible and turn down the
// reporter. // reporter.
if (!mCurrentlyVisibleNotifications.isEmpty()) { if (!mCurrentlyVisibleNotifications.isEmpty()) {
logNotificationVisibilityChanges( logNotificationVisibilityChanges(Collections.<NotificationVisibility>emptyList(),
Collections.<String>emptyList(), mCurrentlyVisibleNotifications); mCurrentlyVisibleNotifications);
mCurrentlyVisibleNotifications.clear(); recycleAllVisibilityObjects(mCurrentlyVisibleNotifications);
} }
mHandler.removeCallbacks(mVisibilityReporter); mHandler.removeCallbacks(mVisibilityReporter);
mStackScroller.setChildLocationsChangedListener(null); mStackScroller.setChildLocationsChangedListener(null);
@@ -3007,18 +3028,27 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
} }
private void logNotificationVisibilityChanges( private void logNotificationVisibilityChanges(
Collection<String> newlyVisible, Collection<String> noLongerVisible) { Collection<NotificationVisibility> newlyVisible,
Collection<NotificationVisibility> noLongerVisible) {
if (newlyVisible.isEmpty() && noLongerVisible.isEmpty()) { if (newlyVisible.isEmpty() && noLongerVisible.isEmpty()) {
return; return;
} }
String[] newlyVisibleAr = newlyVisible.toArray(new String[newlyVisible.size()]); NotificationVisibility[] newlyVisibleAr =
String[] noLongerVisibleAr = noLongerVisible.toArray(new String[noLongerVisible.size()]); newlyVisible.toArray(new NotificationVisibility[newlyVisible.size()]);
NotificationVisibility[] noLongerVisibleAr =
noLongerVisible.toArray(new NotificationVisibility[noLongerVisible.size()]);
try { try {
mBarService.onNotificationVisibilityChanged(newlyVisibleAr, noLongerVisibleAr); mBarService.onNotificationVisibilityChanged(newlyVisibleAr, noLongerVisibleAr);
} catch (RemoteException e) { } catch (RemoteException e) {
// Ignore. // 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 // State logging

View File

@@ -74,7 +74,7 @@ option java_package com.android.server
# when a notification has been canceled # when a notification has been canceled
27530 notification_canceled (key|3),(reason|1),(lifespan|1),(freshness|1),(exposure|1) 27530 notification_canceled (key|3),(reason|1),(lifespan|1),(freshness|1),(exposure|1)
# replaces 27510 with a row per notification # 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 # a notification emited noise, vibration, or light
27532 notification_alert (key|3),(buzz|1),(beep|1),(blink|1) 27532 notification_alert (key|3),(buzz|1),(beep|1),(blink|1)

View File

@@ -16,6 +16,8 @@
package com.android.server.notification; package com.android.server.notification;
import com.android.internal.statusbar.NotificationVisibility;
public interface NotificationDelegate { public interface NotificationDelegate {
void onSetDisabled(int status); void onSetDisabled(int status);
void onClearAll(int callingUid, int callingPid, int userId); void onClearAll(int callingUid, int callingPid, int userId);
@@ -30,6 +32,7 @@ public interface NotificationDelegate {
void onPanelHidden(); void onPanelHidden();
void clearEffects(); void clearEffects();
void onNotificationVisibilityChanged( void onNotificationVisibilityChanged(
String[] newlyVisibleKeys, String[] noLongerVisibleKeys); NotificationVisibility[] newlyVisibleKeys,
NotificationVisibility[] noLongerVisibleKeys);
void onNotificationExpansionChanged(String key, boolean userAction, boolean expanded); void onNotificationExpansionChanged(String key, boolean userAction, boolean expanded);
} }

View File

@@ -97,6 +97,7 @@ import android.view.accessibility.AccessibilityManager;
import android.widget.Toast; import android.widget.Toast;
import com.android.internal.R; import com.android.internal.R;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.FastXmlSerializer;
import com.android.server.EventLogTags; import com.android.server.EventLogTags;
import com.android.server.LocalServices; import com.android.server.LocalServices;
@@ -622,22 +623,24 @@ public class NotificationManagerService extends SystemService {
} }
@Override @Override
public void onNotificationVisibilityChanged( public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
String[] newlyVisibleKeys, String[] noLongerVisibleKeys) { NotificationVisibility[] noLongerVisibleKeys) {
synchronized (mNotificationList) { synchronized (mNotificationList) {
for (String key : newlyVisibleKeys) { for (NotificationVisibility nv : newlyVisibleKeys) {
NotificationRecord r = mNotificationsByKey.get(key); NotificationRecord r = mNotificationsByKey.get(nv.key);
if (r == null) continue; if (r == null) continue;
r.setVisibility(true); r.setVisibility(true, nv.rank);
nv.recycle();
} }
// Note that we might receive this event after notifications // Note that we might receive this event after notifications
// have already left the system, e.g. after dismissing from the // have already left the system, e.g. after dismissing from the
// shade. Hence not finding notifications in // shade. Hence not finding notifications in
// mNotificationsByKey is not an exceptional condition. // mNotificationsByKey is not an exceptional condition.
for (String key : noLongerVisibleKeys) { for (NotificationVisibility nv : noLongerVisibleKeys) {
NotificationRecord r = mNotificationsByKey.get(key); NotificationRecord r = mNotificationsByKey.get(nv.key);
if (r == null) continue; if (r == null) continue;
r.setVisibility(false); r.setVisibility(false, nv.rank);
nv.recycle();
} }
} }
} }

View File

@@ -314,13 +314,15 @@ public final class NotificationRecord {
/** /**
* Set the visibility of the notification. * Set the visibility of the notification.
*/ */
public void setVisibility(boolean visible) { public void setVisibility(boolean visible, int rank) {
final long now = System.currentTimeMillis(); final long now = System.currentTimeMillis();
mVisibleSinceMs = visible ? now : mVisibleSinceMs; mVisibleSinceMs = visible ? now : mVisibleSinceMs;
stats.onVisibilityChanged(visible); stats.onVisibilityChanged(visible);
EventLogTags.writeNotificationVisibility(getKey(), visible ? 1 : 0, EventLogTags.writeNotificationVisibility(getKey(), visible ? 1 : 0,
(int) (now - mCreationTimeMs), (int) (now - mCreationTimeMs),
(int) (now - mUpdateTimeMs)); (int) (now - mUpdateTimeMs),
0, // exposure time
rank);
} }
/** /**

View File

@@ -29,6 +29,7 @@ import android.util.Slog;
import com.android.internal.statusbar.IStatusBar; import com.android.internal.statusbar.IStatusBar;
import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.internal.statusbar.StatusBarIcon; import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.statusbar.StatusBarIconList; import com.android.internal.statusbar.StatusBarIconList;
import com.android.server.LocalServices; import com.android.server.LocalServices;
@@ -660,7 +661,8 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
@Override @Override
public void onNotificationVisibilityChanged( public void onNotificationVisibilityChanged(
String[] newlyVisibleKeys, String[] noLongerVisibleKeys) throws RemoteException { NotificationVisibility[] newlyVisibleKeys, NotificationVisibility[] noLongerVisibleKeys)
throws RemoteException {
enforceStatusBarService(); enforceStatusBarService();
long identity = Binder.clearCallingIdentity(); long identity = Binder.clearCallingIdentity();
try { try {