Allow users to set app-wide Importance default

And the associated ui changes to the notification guts.

Bug: 22451710
Change-Id: I4e0b11e7b24d70b039a432c5e6cd76c9c7cc547c
This commit is contained in:
Julia Reynolds
2015-12-17 08:32:48 -05:00
parent 6e690ac8dc
commit a07af88b95
9 changed files with 199 additions and 97 deletions

View File

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

View File

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

View File

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

View File

@@ -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() {

View File

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

View File

@@ -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.
*

View File

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

View File

@@ -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<String, Topic> topics = new ArrayMap<>();
}

View File

@@ -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()