diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index 136b810d5ee7d..bce5bf37f0eb5 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -54,6 +54,7 @@ interface INotificationManager int getTopicPriority(String pkg, int uid, in Notification.Topic topic); void setTopicImportance(String pkg, int uid, in Notification.Topic topic, int importance); int getTopicImportance(String pkg, int uid, in Notification.Topic topic); + void setAppImportance(String pkg, int uid, int importance); // TODO: Remove this when callers have been migrated to the equivalent // INotificationListener method. diff --git a/packages/SystemUI/res/layout/notification_guts.xml b/packages/SystemUI/res/layout/notification_guts.xml index c9dbc79f56263..f15c97ef66948 100644 --- a/packages/SystemUI/res/layout/notification_guts.xml +++ b/packages/SystemUI/res/layout/notification_guts.xml @@ -24,35 +24,23 @@ android:clickable="true" android:gravity="top|start" android:orientation="vertical" - android:paddingEnd="8dp" + android:paddingStart="@*android:dimen/notification_content_margin_start" + android:paddingEnd="@*android:dimen/notification_content_margin_end" android:background="@color/notification_guts_text_color" > + android:paddingBottom="8dp" > - - - - - - - + + android:fadingEdge="horizontal"/> + android:paddingTop="8dp" > + + + + + diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index f71a71ae378b7..50e0661c55883 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1201,4 +1201,34 @@ Turn on + + Apply to %1$s notifications + + Apply to all notifications from this app + + Blocked + + Low importance + + Normal importance + + High importance + + Urgent importance + + + Never show these notifications + + + Silently show at the bottom of the notification list + + + Silently show these notifications + + + Show at the top of the notifications list and make sound + + + Peek onto the screen and make sound + diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index 6d4dc87283a3b..b891c21420860 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -947,7 +947,7 @@ public abstract class BaseStatusBar extends SystemUI implements final StatusBarNotification sbn = row.getStatusBarNotification(); PackageManager pmUser = getPackageManagerForUser(mContext, sbn.getUser().getIdentifier()); row.setTag(sbn.getPackageName()); - final View guts = row.getGuts(); + final NotificationGuts guts = row.getGuts(); final String pkg = sbn.getPackageName(); String appname = pkg; Drawable pkgicon = null; @@ -969,8 +969,6 @@ public abstract class BaseStatusBar extends SystemUI implements ((ImageView) row.findViewById(android.R.id.icon)).setImageDrawable(pkgicon); ((TextView) row.findViewById(R.id.pkgname)).setText(appname); - bindTopicImportance(sbn, row); - final View settingsButton = guts.findViewById(R.id.notification_inspect_item); if (appUid >= 0) { final int appUidF = appUid; @@ -983,69 +981,8 @@ public abstract class BaseStatusBar extends SystemUI implements } else { settingsButton.setVisibility(View.GONE); } - } - private void bindTopicImportance(final StatusBarNotification sbn, - ExpandableNotificationRow row) { - final INotificationManager sINM = INotificationManager.Stub.asInterface( - ServiceManager.getService(Context.NOTIFICATION_SERVICE)); - final Notification.Topic topic = sbn.getNotification().getTopic() == null - ? new Notification.Topic(Notification.TOPIC_DEFAULT, mContext.getString( - com.android.internal.R.string.default_notification_topic_label)) - : sbn.getNotification().getTopic(); - - ((TextView) row.findViewById(R.id.topic_details)).setText(topic.getLabel()); - final TextView topicSummary = ((TextView) row.findViewById(R.id.summary)); - int importance = mNotificationData.getImportance(sbn.getKey()); - SeekBar seekBar = (SeekBar) row.findViewById(R.id.seekbar); - seekBar.setMax(4); - seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { - @Override - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - topicSummary.setText(getProgressSummary(progress)); - if (fromUser) { - try { - sINM.setTopicImportance(sbn.getPackageName(), sbn.getUid(), topic, - progress); - } catch (RemoteException e) { - // :( - } - } - } - - @Override - public void onStartTrackingTouch(SeekBar seekBar) { - // no-op - } - - @Override - public void onStopTrackingTouch(SeekBar seekBar) { - // no-op - } - - private String getProgressSummary(int progress) { - switch (progress) { - case NotificationListenerService.Ranking.IMPORTANCE_NONE: - return mContext.getString( - com.android.internal.R.string.notification_importance_blocked); - case NotificationListenerService.Ranking.IMPORTANCE_LOW: - return mContext.getString( - com.android.internal.R.string.notification_importance_low); - case NotificationListenerService.Ranking.IMPORTANCE_DEFAULT: - return mContext.getString( - com.android.internal.R.string.notification_importance_default); - case NotificationListenerService.Ranking.IMPORTANCE_HIGH: - return mContext.getString( - com.android.internal.R.string.notification_importance_high); - case NotificationListenerService.Ranking.IMPORTANCE_MAX: - return mContext.getString( - com.android.internal.R.string.notification_importance_max); - default: - return ""; - } - } - }); - seekBar.setProgress(importance); + guts.bindImportance(sbn, row, mNotificationData.getImportance(sbn.getKey())); } protected SwipeHelper.LongPressListener getNotificationLongClicker() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java index 0081496d23512..57db80a0744b6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java @@ -16,12 +16,22 @@ package com.android.systemui.statusbar; +import android.app.INotificationManager; +import android.app.Notification; import android.content.Context; import android.graphics.Canvas; import android.graphics.drawable.Drawable; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.service.notification.NotificationListenerService; +import android.service.notification.StatusBarNotification; import android.util.AttributeSet; +import android.view.View; import android.widget.FrameLayout; import android.widget.LinearLayout; +import android.widget.RadioButton; +import android.widget.SeekBar; +import android.widget.TextView; import com.android.systemui.R; @@ -83,6 +93,88 @@ public class NotificationGuts extends LinearLayout { } } + void bindImportance(final StatusBarNotification sbn, final ExpandableNotificationRow row, + final int importance) { + final INotificationManager sINM = INotificationManager.Stub.asInterface( + ServiceManager.getService(Context.NOTIFICATION_SERVICE)); + final Notification.Topic topic = sbn.getNotification().getTopic() == null + ? new Notification.Topic(Notification.TOPIC_DEFAULT, mContext.getString( + com.android.internal.R.string.default_notification_topic_label)) + : sbn.getNotification().getTopic(); + + final RadioButton applyToTopic = (RadioButton) row.findViewById(R.id.apply_to_topic); + if (sbn.getNotification().getTopic() != null) { + applyToTopic.setVisibility(View.VISIBLE); + applyToTopic.setChecked(true); + applyToTopic.setText(mContext.getString(R.string.apply_to_topic, topic.getLabel())); + row.findViewById(R.id.apply_to_app).setVisibility(View.VISIBLE); + } + + final TextView topicSummary = ((TextView) row.findViewById(R.id.summary)); + final TextView topicTitle = ((TextView) row.findViewById(R.id.title)); + SeekBar seekBar = (SeekBar) row.findViewById(R.id.seekbar); + seekBar.setMax(4); + seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + updateTitleAndSummary(progress); + if (fromUser) { + try { + if (applyToTopic.isChecked()) { + sINM.setTopicImportance(sbn.getPackageName(), sbn.getUid(), topic, + progress); + } else { + sINM.setAppImportance(sbn.getPackageName(), sbn.getUid(), progress); + } + } catch (RemoteException e) { + // :( + } + } + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + // no-op + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + // no-op + } + + private void updateTitleAndSummary(int progress) { + switch (progress) { + case NotificationListenerService.Ranking.IMPORTANCE_NONE: + topicSummary.setText(mContext.getString( + R.string.notification_importance_blocked)); + topicTitle.setText(mContext.getString(R.string.blocked_importance)); + break; + case NotificationListenerService.Ranking.IMPORTANCE_LOW: + topicSummary.setText(mContext.getString( + R.string.notification_importance_low)); + topicTitle.setText(mContext.getString(R.string.low_importance)); + break; + case NotificationListenerService.Ranking.IMPORTANCE_DEFAULT: + topicSummary.setText(mContext.getString( + R.string.notification_importance_default)); + topicTitle.setText(mContext.getString(R.string.default_importance)); + break; + case NotificationListenerService.Ranking.IMPORTANCE_HIGH: + topicSummary.setText(mContext.getString( + R.string.notification_importance_high)); + topicTitle.setText(mContext.getString(R.string.high_importance)); + break; + case NotificationListenerService.Ranking.IMPORTANCE_MAX: + topicSummary.setText(mContext.getString( + R.string.notification_importance_max)); + topicTitle.setText(mContext.getString(R.string.max_importance)); + break; + } + } + }); + seekBar.setProgress(importance); + } + public void setActualHeight(int actualHeight) { mActualHeight = actualHeight; invalidate(); diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index bb07e9d7e881c..0bfbd7f5cd9f3 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -1248,6 +1248,13 @@ public class NotificationManagerService extends SystemService { return mRankingHelper.getTopicImportance(pkg, uid, topic); } + @Override + public void setAppImportance(String pkg, int uid, int importance) { + enforceSystemOrSystemUI("Caller not system or systemui"); + mRankingHelper.setAppImportance(pkg, uid, importance); + savePolicyFile(); + } + /** * System-only API for getting a list of current (i.e. not cleared) notifications. * diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java index acdd90ae95777..a6c9b0d946e2d 100644 --- a/services/core/java/com/android/server/notification/RankingConfig.java +++ b/services/core/java/com/android/server/notification/RankingConfig.java @@ -35,4 +35,6 @@ public interface RankingConfig { void setTopicImportance(String packageName, int uid, Notification.Topic topic, int importance); int getTopicImportance(String packageName, int uid, Notification.Topic topic); + + void setAppImportance(String packageName, int uid, int importance); } diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java index 5a31c6a27a4fc..32c0ce24dc205 100644 --- a/services/core/java/com/android/server/notification/RankingHelper.java +++ b/services/core/java/com/android/server/notification/RankingHelper.java @@ -251,6 +251,7 @@ public class RankingHelper implements RankingConfig { } out.startTag(null, TAG_PACKAGE); out.attribute(null, ATT_NAME, r.pkg); + out.attribute(null, ATT_IMPORTANCE, Integer.toString(r.importance)); if (!forBackup) { out.attribute(null, ATT_UID, Integer.toString(r.uid)); @@ -426,6 +427,20 @@ public class RankingHelper implements RankingConfig { updateConfig(); } + /** + * Sets the default importance for all new topics that appear in the future, and resets + * the importance of all current topics. + */ + @Override + public void setAppImportance(String pkgName, int uid, int importance) { + final Record r = getOrCreateRecord(pkgName, uid); + r.importance = importance; + for (Topic t : r.topics.values()) { + t.importance = importance; + } + updateConfig(); + } + private Topic getOrCreateTopic(Record r, Notification.Topic topic) { if (topic == null) { topic = createDefaultTopic(); @@ -435,6 +450,7 @@ public class RankingHelper implements RankingConfig { return t; } else { t = new Topic(topic); + t.importance = r.importance; r.topics.put(topic.getId(), t); return t; } @@ -477,6 +493,8 @@ public class RankingHelper implements RankingConfig { pw.print(" ("); pw.print(r.uid == Record.UNKNOWN_UID ? "UNKNOWN_UID" : Integer.toString(r.uid)); pw.print(')'); + pw.print(" importance="); + pw.print(Ranking.importanceToString(r.importance)); pw.println(); for (Topic t : r.topics.values()) { pw.print(prefix); @@ -532,6 +550,7 @@ public class RankingHelper implements RankingConfig { String pkg; int uid = UNKNOWN_UID; + int importance = DEFAULT_IMPORTANCE; Map topics = new ArrayMap<>(); } diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java index cf1a4aa97c6da..fecfdf98d0e72 100644 --- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java +++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java @@ -23,6 +23,7 @@ import android.content.Context; import android.content.ContentResolver; import android.content.Intent; import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.graphics.drawable.BitmapDrawable; import android.os.Bundle; import android.os.Vibrator; @@ -180,6 +181,9 @@ public class NotificationTestList extends TestActivity new Test("with topic GoodBye") { public void run() { + Notification.BigPictureStyle picture = new Notification.BigPictureStyle(); + picture.bigPicture(BitmapFactory.decodeResource(getResources(), + R.id.large_icon_pineapple2)); Notification n = new Notification.Builder(NotificationTestList.this) .setSmallIcon(R.drawable.icon1) .setWhen(mActivityCreateTime) @@ -187,11 +191,29 @@ public class NotificationTestList extends TestActivity .setContentText("This is a notification!!!") .setContentIntent(makeIntent2()) .setTopic(new Notification.Topic("bye", "Goodbye")) + .setStyle(picture) .build(); mNM.notify(9999, n); } }, + new Test("with topic Bananas") { + public void run() { + Notification.BigTextStyle bigText = new Notification.BigTextStyle(); + bigText.bigText("bananas are great\nso tasty\nyum\nyum\nyum\n"); + Notification n = new Notification.Builder(NotificationTestList.this) + .setSmallIcon(R.drawable.icon1) + .setStyle(bigText) + .setWhen(mActivityCreateTime) + .setContentTitle("bananananana") + .setContentText("This is a banana!!!") + .setContentIntent(makeIntent2()) + .setTopic(new Notification.Topic("bananas", "Bananas")) + .build(); + + mNM.notify(999, n); + } + }, new Test("Whens") { public void run()