Allow users to set app-wide Importance default
And the associated ui changes to the notification guts.
Bug: 22451710
Change-Id: I4e0b11e7b24d70b039a432c5e6cd76c9c7cc547c
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 136b810..bce5bf3 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -54,6 +54,7 @@
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 c9dbc79..f15c97e 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" >
<!-- header -->
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingStart="@*android:dimen/notification_content_margin_start"
- android:paddingTop="8dp"
- android:paddingBottom="16dp" >
+ android:paddingBottom="8dp" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/notification_guts_header"
- android:orientation="vertical"
+ android:orientation="horizontal"
android:layout_gravity="center_vertical|start"
android:layout_marginEnd="52dp">
-
- <LinearLayout
- android:id="@+id/notification_guts_app_details"
- android:orientation="horizontal"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:clipChildren="false"
- android:layout_gravity="start|top"
- android:gravity="center_vertical"
- >
-
<ImageView
android:id="@android:id/icon"
android:layout_width="18dp"
@@ -76,22 +64,12 @@
android:layout_gravity="bottom|start"
android:visibility="gone"
android:textColor="#ffffff" />
- </LinearLayout>
-
- <TextView
- android:id="@+id/topic_details"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textAppearance="@android:style/TextAppearance.Material.Notification.Title"
- android:textColor="@color/notification_guts_text_color"
- android:layout_alignParentBottom="true"
- android:layout_alignParentStart="true" />
- </LinearLayout>
+ </LinearLayout>
<ImageButton style="@android:style/Widget.Material.Light.Button.Borderless.Small"
android:id="@+id/notification_inspect_item"
android:layout_width="52dp"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
android:layout_weight="0"
android:gravity="center"
android:layout_gravity="center_vertical|end"
@@ -103,7 +81,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
- android:paddingStart="@*android:dimen/notification_content_margin_start"
android:orientation="vertical"
android:clickable="false"
android:focusable="false"
@@ -116,8 +93,7 @@
android:textAppearance="@android:style/TextAppearance.Material.Subhead"
android:textColor="@color/notification_guts_text_color"
android:ellipsize="marquee"
- android:fadingEdge="horizontal"
- android:text="@*android:string/notification_importance_title"/>
+ android:fadingEdge="horizontal"/>
<TextView
android:id="@+id/summary"
@@ -133,7 +109,7 @@
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingTop="6dp" >
+ android:paddingTop="8dp" >
<ImageView
android:id="@+id/low_importance"
@@ -162,5 +138,21 @@
android:layout_height="24dp"/>
</FrameLayout>
+
+ <RadioGroup android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="8dp">
+ <RadioButton android:id="@+id/apply_to_topic"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@color/notification_guts_text_color"
+ android:visibility="gone"/>
+ <RadioButton android:id="@+id/apply_to_app"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/apply_to_app"
+ android:textColor="@color/notification_guts_text_color"
+ android:visibility="gone"/>
+ </RadioGroup>
</LinearLayout>
</com.android.systemui.statusbar.NotificationGuts>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index f71a71a..50e0661 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1201,4 +1201,34 @@
<!-- Bluetooth enablement ok text [CHAR LIMIT=40] -->
<string name="enable_bluetooth_confirmation_ok">Turn on</string>
+ <!-- Apply notification importance setting to a topic [CHAR LIMIT=NONE] -->
+ <string name="apply_to_topic">Apply to <xliff:g id="topic_name" example="Friend Request">%1$s</xliff:g> notifications</string>
+ <!-- Apply notification importance setting to an app [CHAR LIMIT=NONE] -->
+ <string name="apply_to_app">Apply to all notifications from this app</string>
+ <!-- Notification importance title, blocked status-->
+ <string name="blocked_importance">Blocked</string>
+ <!-- Notification importance title, low status-->
+ <string name="low_importance">Low importance</string>
+ <!-- Notification importance title, normal status-->
+ <string name="default_importance">Normal importance</string>
+ <!-- Notification importance title, high status-->
+ <string name="high_importance">High importance</string>
+ <!-- Notification importance title, max status-->
+ <string name="max_importance">Urgent importance</string>
+
+ <!-- [CHAR LIMIT=100] Notification Importance slider: blocked importance level description -->
+ <string name="notification_importance_blocked">Never show these notifications</string>
+
+ <!-- [CHAR LIMIT=100] Notification Importance slider: low importance level description -->
+ <string name="notification_importance_low">Silently show at the bottom of the notification list</string>
+
+ <!-- [CHAR LIMIT=100] Notification Importance slider: normal importance level description -->
+ <string name="notification_importance_default">Silently show these notifications</string>
+
+ <!-- [CHAR LIMIT=100] Notification Importance slider: high importance level description -->
+ <string name="notification_importance_high">Show at the top of the notifications list and make sound</string>
+
+ <!-- [CHAR LIMIT=100] Notification Importance slider: max importance level description -->
+ <string name="notification_importance_max">Peek onto the screen and make sound</string>
+
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 6d4dc872..b891c21 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 @@
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 @@
((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 @@
} 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 0081496..57db80a 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 @@
}
}
+ 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 bb07e9d..0bfbd7f 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 @@
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 acdd90a..a6c9b0d 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 @@
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 5a31c6a..32c0ce2 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 @@
}
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 @@
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 @@
return t;
} else {
t = new Topic(topic);
+ t.importance = r.importance;
r.topics.put(topic.getId(), t);
return t;
}
@@ -477,6 +493,8 @@
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 @@
String pkg;
int uid = UNKNOWN_UID;
+ int importance = DEFAULT_IMPORTANCE;
Map<String, Topic> topics = new ArrayMap<>();
}
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
index cf1a4aa..fecfdf9 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.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 @@
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 @@
.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()