diff --git a/res/layout/notification_log_row.xml b/res/layout/notification_log_row.xml
index d7f57c60b07..e76835e76d2 100644
--- a/res/layout/notification_log_row.xml
+++ b/res/layout/notification_log_row.xml
@@ -27,11 +27,11 @@
-
-
+
+
+
diff --git a/res/values/strings.xml b/res/values/strings.xml
index fd21db1f297..f0538369b32 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -7183,4 +7183,56 @@
- @*android:string/gigabyteShort
+
+ (none)
+
+ ": "
+
+ pkg
+
+ key
+
+ group
+
+ (summary)
+
+ visibility
+
+ publicVersion
+
+ priority
+
+ importance
+
+ explanation
+
+ intent
+
+ delete intent
+
+ full screen intent
+
+ actions
+
+ title
+
+ remote inputs
+
+ custom view
+
+ extras
+
+ icon
+
+ parcel size
+
+ ashmem
+
+ sound
+
+ vibrate
+
+ default
+
+ none
diff --git a/src/com/android/settings/CopyablePreference.java b/src/com/android/settings/CopyablePreference.java
index b1f101d9bfc..03147c211c0 100644
--- a/src/com/android/settings/CopyablePreference.java
+++ b/src/com/android/settings/CopyablePreference.java
@@ -30,6 +30,10 @@ public class CopyablePreference extends Preference {
super(context, attrs);
}
+ public CopyablePreference(Context context) {
+ this(context, null);
+ }
+
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
@@ -45,10 +49,14 @@ public class CopyablePreference extends Preference {
});
}
- public static void copyPreference(Context context, Preference pref) {
+ public CharSequence getCopyableText() {
+ return getSummary();
+ }
+
+ public static void copyPreference(Context context, CopyablePreference pref) {
ClipboardManager cm =
(ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
- cm.setText(pref.getSummary());
+ cm.setText(pref.getCopyableText());
Toast.makeText(context, com.android.internal.R.string.text_copied, Toast.LENGTH_SHORT)
.show();
}
diff --git a/src/com/android/settings/notification/NotificationStation.java b/src/com/android/settings/notification/NotificationStation.java
index 44f0ffcf8f4..7c79e8b0bab 100644
--- a/src/com/android/settings/notification/NotificationStation.java
+++ b/src/com/android/settings/notification/NotificationStation.java
@@ -16,28 +16,31 @@
package com.android.settings.notification;
-import android.app.Activity;
-import android.app.ActivityManager;
+import android.app.*;
import android.app.INotificationManager;
-import android.app.Notification;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentSender;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
+import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.UserHandle;
+import android.os.*;
import android.service.notification.NotificationListenerService;
+import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.StatusBarNotification;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceViewHolder;
import android.support.v7.widget.RecyclerView;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.SpannableStringBuilder;
+import android.text.TextUtils;
+import android.text.style.StyleSpan;
import android.util.Log;
import android.view.View;
import android.widget.DateTimeView;
@@ -45,19 +48,20 @@ import android.widget.ImageView;
import android.widget.TextView;
import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.settings.CopyablePreference;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.Utils;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
+import java.lang.StringBuilder;
+import java.util.*;
public class NotificationStation extends SettingsPreferenceFragment {
private static final String TAG = NotificationStation.class.getSimpleName();
private static final boolean DEBUG = false;
+ private static final boolean DUMP_EXTRAS = true;
+ private static final boolean DUMP_PARCEL = true;
private static class HistoricalNotificationInfo {
public String pkg;
@@ -69,10 +73,12 @@ public class NotificationStation extends SettingsPreferenceFragment {
public int user;
public long timestamp;
public boolean active;
+ public CharSequence extra;
}
private PackageManager mPm;
private INotificationManager mNoMan;
+ private RankingMap mRanking;
private Runnable mRefreshListRunnable = new Runnable() {
@Override
@@ -83,19 +89,26 @@ public class NotificationStation extends SettingsPreferenceFragment {
private NotificationListenerService mListener = new NotificationListenerService() {
@Override
- public void onNotificationPosted(StatusBarNotification notification) {
- logd("onNotificationPosted: %s", notification);
+ public void onNotificationPosted(StatusBarNotification sbn, RankingMap ranking) {
+ logd("onNotificationPosted: %s", sbn.getNotification());
final Handler h = getListView().getHandler();
+ mRanking = ranking;
h.removeCallbacks(mRefreshListRunnable);
h.postDelayed(mRefreshListRunnable, 100);
}
@Override
- public void onNotificationRemoved(StatusBarNotification notification) {
+ public void onNotificationRemoved(StatusBarNotification notification, RankingMap ranking) {
final Handler h = getListView().getHandler();
+ mRanking = ranking;
h.removeCallbacks(mRefreshListRunnable);
h.postDelayed(mRefreshListRunnable, 100);
}
+
+ @Override
+ public void onNotificationRankingUpdate(RankingMap ranking) {
+ mRanking = ranking;
+ }
};
private Context mContext;
@@ -179,6 +192,40 @@ public class NotificationStation extends SettingsPreferenceFragment {
}
}
+ private static CharSequence bold(CharSequence cs) {
+ if (cs.length() == 0) return cs;
+ SpannableString ss = new SpannableString(cs);
+ ss.setSpan(new StyleSpan(Typeface.BOLD), 0, cs.length(), 0);
+ return ss;
+ }
+
+ private static String getTitleString(Notification n) {
+ String title = null;
+ if (n.extras != null) {
+ title = n.extras.getString(Notification.EXTRA_TITLE);
+ if (TextUtils.isEmpty(title)) {
+ title = n.extras.getString(Notification.EXTRA_TEXT);
+ }
+ }
+ if (TextUtils.isEmpty(title) && !TextUtils.isEmpty(n.tickerText)) {
+ title = n.tickerText.toString();
+ }
+ return title;
+ }
+
+ private static String formatPendingIntent(PendingIntent pi) {
+ final StringBuilder sb = new StringBuilder();
+ final IntentSender is = pi.getIntentSender();
+ sb.append("Intent(pkg=").append(is.getCreatorPackage());
+ try {
+ final boolean isActivity =
+ ActivityManagerNative.getDefault().isIntentSenderAnActivity(is.getTarget());
+ if (isActivity) sb.append(" (activity)");
+ } catch (RemoteException ex) {}
+ sb.append(")");
+ return sb.toString();
+ }
+
private List loadNotifications() {
final int currentUserId = ActivityManager.getCurrentUser();
try {
@@ -190,40 +237,189 @@ public class NotificationStation extends SettingsPreferenceFragment {
List list
= new ArrayList(active.length + dismissed.length);
+ final Ranking rank = new Ranking();
+
for (StatusBarNotification[] resultset
: new StatusBarNotification[][] { active, dismissed }) {
for (StatusBarNotification sbn : resultset) {
+ if (sbn.getUserId() != UserHandle.USER_ALL & sbn.getUserId() != currentUserId) {
+ continue;
+ }
+
+ final Notification n = sbn.getNotification();
final HistoricalNotificationInfo info = new HistoricalNotificationInfo();
info.pkg = sbn.getPackageName();
info.user = sbn.getUserId();
- info.icon = loadIconDrawable(info.pkg, info.user, sbn.getNotification().icon);
+ info.icon = loadIconDrawable(info.pkg, info.user, n.icon);
info.pkgicon = loadPackageIconDrawable(info.pkg, info.user);
info.pkgname = loadPackageName(info.pkg);
- if (sbn.getNotification().extras != null) {
- info.title = sbn.getNotification().extras.getString(
- Notification.EXTRA_TITLE);
- if (info.title == null || "".equals(info.title)) {
- info.title = sbn.getNotification().extras.getString(
- Notification.EXTRA_TEXT);
- }
- }
- if (info.title == null || "".equals(info.title)) {
- info.title = sbn.getNotification().tickerText;
- }
- // still nothing? come on, give us something!
- if (info.title == null || "".equals(info.title)) {
- info.title = info.pkgname;
+ info.title = getTitleString(n);
+ if (TextUtils.isEmpty(info.title)) {
+ info.title = getString(R.string.notification_log_no_title);
}
info.timestamp = sbn.getPostTime();
- info.priority = sbn.getNotification().priority;
- logd(" [%d] %s: %s", info.timestamp, info.pkg, info.title);
+ info.priority = n.priority;
info.active = (resultset == active);
- if (info.user == UserHandle.USER_ALL
- || info.user == currentUserId) {
- list.add(info);
+ final SpannableStringBuilder sb = new SpannableStringBuilder();
+ final String delim = getString(R.string.notification_log_details_delimiter);
+ sb.append(bold(getString(R.string.notification_log_details_package)))
+ .append(delim)
+ .append(info.pkg)
+ .append("\n")
+ .append(bold(getString(R.string.notification_log_details_key)))
+ .append(delim)
+ .append(sbn.getKey());
+ sb.append("\n")
+ .append(bold(getString(R.string.notification_log_details_icon)))
+ .append(delim)
+ .append(n.getSmallIcon().toString());
+ if (!TextUtils.isEmpty(n.getGroup())) {
+ sb.append("\n")
+ .append(bold(getString(R.string.notification_log_details_group)))
+ .append(delim)
+ .append(n.getGroup());
+ if (n.isGroupSummary()) {
+ sb.append(bold(
+ getString(R.string.notification_log_details_group_summary)));
+ }
}
+ sb.append("\n")
+ .append(bold(getString(R.string.notification_log_details_sound)))
+ .append(delim);
+ if (0 != (n.defaults & Notification.DEFAULT_SOUND)) {
+ sb.append(getString(R.string.notification_log_details_default));
+ } else if (n.sound != null) {
+ sb.append(n.sound.toString());
+ } else {
+ sb.append(getString(R.string.notification_log_details_none));
+ }
+ sb.append("\n")
+ .append(bold(getString(R.string.notification_log_details_vibrate)))
+ .append(delim);
+ if (0 != (n.defaults & Notification.DEFAULT_VIBRATE)) {
+ sb.append(getString(R.string.notification_log_details_default));
+ } else if (n.vibrate != null) {
+ for (int vi=0;vi 0) sb.append(',');
+ sb.append(String.valueOf(n.vibrate[vi]));
+ }
+ } else {
+ sb.append(getString(R.string.notification_log_details_none));
+ }
+ sb.append("\n")
+ .append(bold(getString(R.string.notification_log_details_visibility)))
+ .append(delim)
+ .append(Notification.visibilityToString(n.visibility));
+ if (n.publicVersion != null) {
+ sb.append("\n")
+ .append(bold(getString(
+ R.string.notification_log_details_public_version)))
+ .append(delim)
+ .append(getTitleString(n.publicVersion));
+ }
+ sb.append("\n")
+ .append(bold(getString(R.string.notification_log_details_priority)))
+ .append(delim)
+ .append(Notification.priorityToString(n.priority));
+ if (mRanking != null && mRanking.getRanking(sbn.getKey(), rank)) {
+ sb.append("\n")
+ .append(bold(getString(
+ R.string.notification_log_details_importance)))
+ .append(delim)
+ .append(Ranking.importanceToString(rank.getImportance()));
+ if (rank.getImportanceExplanation() != null) {
+ sb.append("\n")
+ .append(bold(getString(
+ R.string.notification_log_details_explanation)))
+ .append(delim)
+ .append(rank.getImportanceExplanation());
+ }
+ }
+ if (n.contentIntent != null) {
+ sb.append("\n")
+ .append(bold(getString(
+ R.string.notification_log_details_content_intent)))
+ .append(delim)
+ .append(formatPendingIntent(n.contentIntent));
+ }
+ if (n.deleteIntent != null) {
+ sb.append("\n")
+ .append(bold(getString(
+ R.string.notification_log_details_delete_intent)))
+ .append(delim)
+ .append(formatPendingIntent(n.deleteIntent));
+ }
+ if (n.fullScreenIntent != null) {
+ sb.append("\n")
+ .append(bold(getString(
+ R.string.notification_log_details_full_screen_intent)))
+ .append(delim)
+ .append(formatPendingIntent(n.fullScreenIntent));
+ }
+ if (n.actions != null && n.actions.length > 0) {
+ sb.append("\n")
+ .append(bold(getString(R.string.notification_log_details_actions)));
+ for (int ai=0; ai 0) {
+ sb.append("\n")
+ .append(bold(getString(
+ R.string.notification_log_details_extras)));
+ for (String extraKey : n.extras.keySet()) {
+ String val = String.valueOf(n.extras.get(extraKey));
+ if (val.length() > 100) val = val.substring(0, 100) + "...";
+ sb.append("\n ").append(extraKey).append(delim).append(val);
+ }
+ }
+ }
+ if (DUMP_PARCEL) {
+ final Parcel p = Parcel.obtain();
+ n.writeToParcel(p, 0);
+ sb.append("\n")
+ .append(bold(getString(R.string.notification_log_details_parcel)))
+ .append(delim)
+ .append(String.valueOf(p.dataPosition()))
+ .append(' ')
+ .append(bold(getString(R.string.notification_log_details_ashmem)))
+ .append(delim)
+ .append(String.valueOf(p.getBlobAshmemSize()))
+ .append("\n");
+ }
+
+ info.extra = sb;
+
+ logd(" [%d] %s: %s", info.timestamp, info.pkg, info.title);
+ list.add(info);
}
}
@@ -293,7 +489,7 @@ public class NotificationStation extends SettingsPreferenceFragment {
return null;
}
- private static class HistoricalNotificationPreference extends Preference {
+ private static class HistoricalNotificationPreference extends CopyablePreference {
private final HistoricalNotificationInfo mInfo;
public HistoricalNotificationPreference(Context context, HistoricalNotificationInfo info) {
@@ -304,27 +500,49 @@ public class NotificationStation extends SettingsPreferenceFragment {
@Override
public void onBindViewHolder(PreferenceViewHolder row) {
+ super.onBindViewHolder(row);
+
if (mInfo.icon != null) {
- ((ImageView) row.findViewById(android.R.id.icon)).setImageDrawable(mInfo.icon);
+ ((ImageView) row.findViewById(R.id.icon)).setImageDrawable(mInfo.icon);
}
if (mInfo.pkgicon != null) {
((ImageView) row.findViewById(R.id.pkgicon)).setImageDrawable(mInfo.pkgicon);
}
((DateTimeView) row.findViewById(R.id.timestamp)).setTime(mInfo.timestamp);
- ((TextView) row.findViewById(android.R.id.title)).setText(mInfo.title);
+ ((TextView) row.findViewById(R.id.title)).setText(mInfo.title);
((TextView) row.findViewById(R.id.pkgname)).setText(mInfo.pkgname);
- row.findViewById(R.id.extra).setVisibility(View.GONE);
+ final TextView extra = (TextView) row.findViewById(R.id.extra);
+ extra.setText(mInfo.extra);
+ extra.setVisibility(View.GONE);
+
+ row.itemView.setOnClickListener(
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ extra.setVisibility(extra.getVisibility() == View.VISIBLE
+ ? View.GONE : View.VISIBLE);
+ }
+ });
+
row.itemView.setAlpha(mInfo.active ? 1.0f : 0.5f);
}
+ @Override
+ public CharSequence getCopyableText() {
+ return new SpannableStringBuilder(mInfo.title)
+ .append(" [").append(new Date(mInfo.timestamp).toString())
+ .append("]\n").append(mInfo.pkgname)
+ .append("\n").append(mInfo.extra);
+ }
+
@Override
public void performClick() {
- Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
- Uri.fromParts("package", mInfo.pkg, null));
- intent.setComponent(intent.resolveActivity(getContext().getPackageManager()));
- getContext().startActivity(intent);
+// Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
+// Uri.fromParts("package", mInfo.pkg, null));
+// intent.setComponent(intent.resolveActivity(getContext().getPackageManager()));
+// getContext().startActivity(intent);
}
}
}