Add importance to notification guts.

Note: the guts are still trucated to the height of the notification.
The slider initially shows the importance of the individual notification,
but changing the slider changes the importance for the whole group
of notifications.

Bug: 22451710

Change-Id: Id6de3aaace2bdb88a8cc5db517002dc7f0e349ae
This commit is contained in:
Julia Reynolds
2015-12-07 08:23:48 -05:00
parent 752b070e32
commit ead00aac15
14 changed files with 250 additions and 134 deletions

View File

@@ -33264,11 +33264,11 @@ package android.service.notification {
method public int getSuppressedVisualEffects();
method public boolean isAmbient();
method public boolean matchesInterruptionFilter();
field public static final int IMPORTANCE_DEFAULT = 0; // 0x0
field public static final int IMPORTANCE_HIGH = 1; // 0x1
field public static final int IMPORTANCE_LOW = -1; // 0xffffffff
field public static final int IMPORTANCE_MAX = 2; // 0x2
field public static final int IMPORTANCE_NONE = -2; // 0xfffffffe
field public static final int IMPORTANCE_DEFAULT = 2; // 0x2
field public static final int IMPORTANCE_HIGH = 3; // 0x3
field public static final int IMPORTANCE_LOW = 1; // 0x1
field public static final int IMPORTANCE_MAX = 4; // 0x4
field public static final int IMPORTANCE_NONE = 0; // 0x0
field public static final int IMPORTANCE_UNSPECIFIED = -1000; // 0xfffffc18
}

View File

@@ -35398,11 +35398,11 @@ package android.service.notification {
method public int getSuppressedVisualEffects();
method public boolean isAmbient();
method public boolean matchesInterruptionFilter();
field public static final int IMPORTANCE_DEFAULT = 0; // 0x0
field public static final int IMPORTANCE_HIGH = 1; // 0x1
field public static final int IMPORTANCE_LOW = -1; // 0xffffffff
field public static final int IMPORTANCE_MAX = 2; // 0x2
field public static final int IMPORTANCE_NONE = -2; // 0xfffffffe
field public static final int IMPORTANCE_DEFAULT = 2; // 0x2
field public static final int IMPORTANCE_HIGH = 3; // 0x3
field public static final int IMPORTANCE_LOW = 1; // 0x1
field public static final int IMPORTANCE_MAX = 4; // 0x4
field public static final int IMPORTANCE_NONE = 0; // 0x0
field public static final int IMPORTANCE_UNSPECIFIED = -1000; // 0xfffffc18
}

View File

@@ -33266,11 +33266,11 @@ package android.service.notification {
method public int getSuppressedVisualEffects();
method public boolean isAmbient();
method public boolean matchesInterruptionFilter();
field public static final int IMPORTANCE_DEFAULT = 0; // 0x0
field public static final int IMPORTANCE_HIGH = 1; // 0x1
field public static final int IMPORTANCE_LOW = -1; // 0xffffffff
field public static final int IMPORTANCE_MAX = 2; // 0x2
field public static final int IMPORTANCE_NONE = -2; // 0xfffffffe
field public static final int IMPORTANCE_DEFAULT = 2; // 0x2
field public static final int IMPORTANCE_HIGH = 3; // 0x3
field public static final int IMPORTANCE_LOW = 1; // 0x1
field public static final int IMPORTANCE_MAX = 4; // 0x4
field public static final int IMPORTANCE_NONE = 0; // 0x0
field public static final int IMPORTANCE_UNSPECIFIED = -1000; // 0xfffffc18
}

View File

@@ -833,29 +833,29 @@ public abstract class NotificationListenerService extends Service {
/**
* A notification with no importance: shows nowhere, is blocked.
*/
public static final int IMPORTANCE_NONE = -2;
public static final int IMPORTANCE_NONE = 0;
/**
* Low notification importance: only shows in the shade, below the fold.
*/
public static final int IMPORTANCE_LOW = -1;
public static final int IMPORTANCE_LOW = 1;
/**
* Default notification importance: shows everywhere, but is not intrusive.
*/
public static final int IMPORTANCE_DEFAULT = 0;
public static final int IMPORTANCE_DEFAULT = 2;
/**
* Higher notification importance: shows everywhere, makes noise,
* but does not visually intrude.
*/
public static final int IMPORTANCE_HIGH = 1;
public static final int IMPORTANCE_HIGH = 3;
/**
* Highest notification importance: shows everywhere, makes noise,
* and also visually intrudes.
*/
public static final int IMPORTANCE_MAX = 2;
public static final int IMPORTANCE_MAX = 4;
private String mKey;
private int mRank = -1;

View File

@@ -3955,6 +3955,9 @@
<string name="battery_saver_description">To help improve battery life, battery saver reduces your devices performance and limits vibration, location services, and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery saver turns off automatically when your device is charging.</string>
<!-- [CHAR LIMIT=100] Notification importance slider title -->
<string name="notification_importance_title">Importance</string>
<!-- [CHAR LIMIT=100] Notification Importance slider: blocked importance level description -->
<string name="notification_importance_blocked">Blocked: Never show these notifications</string>

View File

@@ -2088,6 +2088,7 @@
<java-symbol type="string" name="notification_importance_default" />
<java-symbol type="string" name="notification_importance_high" />
<java-symbol type="string" name="notification_importance_max" />
<java-symbol type="string" name="notification_importance_title" />
<java-symbol type="string" name="select_day" />
<java-symbol type="string" name="select_year" />

View File

@@ -16,75 +16,77 @@
-->
<com.android.systemui.statusbar.NotificationGuts
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/notification_guts"
android:visibility="gone"
android:clickable="true"
android:gravity="top|start"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="@android:dimen/notification_large_icon_height"
android:orientation="horizontal"
>
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/notification_guts"
android:visibility="gone"
android:clickable="true"
android:gravity="top|start"
android:orientation="vertical"
android:paddingEnd="8dp"
android:background="@color/notification_guts_text_color" >
<ImageView android:id="@android:id/icon"
android:layout_width="@android:dimen/notification_large_icon_width"
android:layout_height="@android:dimen/notification_large_icon_height"
android:layout_weight="0"
android:padding="8dp"
android:scaleType="centerInside"
/>
<LinearLayout
<!-- header -->
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="start|center_vertical"
android:orientation="vertical"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:layout_weight="1"
>
<TextView
android:id="@+id/pkgname"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|start"
android:layout_weight="1"
android:textAppearance="@*android:style/TextAppearance.Material.Notification.Title"
android:textColor="@color/notification_guts_title_color"
/>
<DateTimeView
android:id="@+id/timestamp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0"
android:layout_gravity="center_vertical|start"
android:textAppearance="@*android:style/TextAppearance.Material.Notification.Time"
android:textColor="@color/notification_guts_text_color"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/debug_info"
android:layout_weight="0"
android:textAppearance="@*android:style/TextAppearance.Material.Notification.Time"
android:layout_gravity="bottom|start"
android:visibility="gone"
android:textColor="@color/notification_guts_text_color"
/>
</LinearLayout>
android:paddingStart="@*android:dimen/notification_content_margin_start"
android:paddingTop="8dp"
android:paddingBottom="16dp" >
<ImageButton style="@android:style/Widget.Material.Light.Button.Borderless.Small"
android:id="@+id/notification_inspect_app_provided_settings"
android:layout_width="52dp"
android:layout_height="match_parent"
android:layout_weight="0"
android:gravity="center"
android:src="@drawable/ic_settings"
android:visibility="gone"
/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/notification_guts_header"
android:orientation="vertical"
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"
android:layout_height="18dp"
android:layout_marginEnd="3dp"
android:src="@android:drawable/arrow_down_float" />
<TextView
android:id="@+id/pkgname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@android:style/TextAppearance.Material.Notification.Info"
android:layout_marginStart="3dp"
android:layout_marginEnd="4dp"
android:textColor="@color/notification_guts_title_color" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/debug_info"
android:layout_weight="0"
android:textAppearance="@android:style/TextAppearance.Material.Notification.Time"
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>
<ImageButton style="@android:style/Widget.Material.Light.Button.Borderless.Small"
android:id="@+id/notification_inspect_item"
@@ -92,8 +94,73 @@
android:layout_height="match_parent"
android:layout_weight="0"
android:gravity="center"
android:layout_gravity="center_vertical|end"
android:contentDescription="@string/status_bar_notification_inspect_item_title"
android:src="@drawable/ic_info"
/>
android:src="@drawable/ic_settings" />
</FrameLayout>
<!-- Importance slider -->
<LinearLayout
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"
android:paddingBottom="8dip">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
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"/>
<TextView
android:id="@+id/summary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignStart="@android:id/title"
android:textAlignment="viewStart"
android:textAppearance="@android:style/TextAppearance.Material.Body1"
android:textColor="@color/notification_guts_title_color"
android:maxLines="3"
android:minLines="2" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="6dp" >
<ImageView
android:id="@+id/low_importance"
android:src="@android:drawable/ic_menu_close_clear_cancel"
android:layout_gravity="center_vertical|start"
android:layout_width="24dp"
android:layout_height="24dp" />
<SeekBar
android:id="@+id/seekbar"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:layout_gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusable="true"
android:background="#00ffffff"
android:thumbTint="@android:color/white"
android:progressTint="@android:color/white" />
<ImageView
android:id="@+id/max_importance"
android:src="@android:drawable/ic_popup_reminder"
android:layout_gravity="center_vertical|end"
android:layout_width="24dp"
android:layout_height="24dp"/>
</FrameLayout>
</LinearLayout>
</com.android.systemui.statusbar.NotificationGuts>

View File

@@ -100,9 +100,9 @@
<color name="current_user_border_color">@color/system_accent_color</color>
<!-- The "inside" of a notification, reached via longpress -->
<color name="notification_guts_bg_color">@color/system_secondary_color</color>
<color name="notification_guts_title_color">#FFFFFFFF</color>
<color name="notification_guts_text_color">#b2FFFFFF</color>
<color name="notification_guts_bg_color">@*android:color/material_deep_teal_500</color>
<color name="notification_guts_title_color">#B2DFDB</color>
<color name="notification_guts_text_color">#FFFFFFFF</color>
<color name="notification_guts_btn_color">#FFFFFFFF</color>
<color name="assist_orb_color">#ffffff</color>

View File

@@ -246,7 +246,10 @@ public class SwipeHelper implements Gefingerpoken {
mWatchLongPress = new Runnable() {
@Override
public void run() {
if (mCurrView != null && !mLongPressSent) {
float pos = getPos(ev);
float delta = pos - mInitialTouchPos;
if (mCurrView != null && !mLongPressSent
&& Math.abs(delta) < mPagingTouchSlop) {
mLongPressSent = true;
mCurrView.sendAccessibilityEvent(
AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);

View File

@@ -21,6 +21,7 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.TimeInterpolator;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.INotificationManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -35,7 +36,6 @@ import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -82,6 +82,7 @@ import android.widget.DateTimeView;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.RemoteViews;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
@@ -902,14 +903,6 @@ public abstract class BaseStatusBar extends SystemUI implements
.findViewById(com.android.internal.R.id.media_actions) != null;
}
// The gear button in the guts that links to the app's own notification settings
private void startAppOwnNotificationSettingsActivity(Intent intent,
final int notificationId, final String notificationTag, final int appUid) {
intent.putExtra("notification_id", notificationId);
intent.putExtra("notification_tag", notificationTag);
startNotificationGutsIntent(intent, appUid);
}
// The (i) button in the guts that links to the system notification settings for that app
private void startAppNotificationSettingsActivity(String packageName, final int appUid) {
final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
@@ -968,12 +961,13 @@ public abstract class BaseStatusBar extends SystemUI implements
// app is gone, just show package name and generic icon
pkgicon = pmUser.getDefaultActivityIcon();
}
((ImageView) row.findViewById(android.R.id.icon)).setImageDrawable(pkgicon);
((DateTimeView) row.findViewById(R.id.timestamp)).setTime(sbn.getPostTime());
((TextView) row.findViewById(R.id.pkgname)).setText(appname);
bindTopicImportance(sbn, row);
final View settingsButton = guts.findViewById(R.id.notification_inspect_item);
final View appSettingsButton
= guts.findViewById(R.id.notification_inspect_app_provided_settings);
if (appUid >= 0) {
final int appUidF = appUid;
settingsButton.setOnClickListener(new View.OnClickListener() {
@@ -982,38 +976,72 @@ public abstract class BaseStatusBar extends SystemUI implements
startAppNotificationSettingsActivity(pkg, appUidF);
}
});
final Intent appSettingsQueryIntent
= new Intent(Intent.ACTION_MAIN)
.addCategory(Notification.INTENT_CATEGORY_NOTIFICATION_PREFERENCES)
.setPackage(pkg);
List<ResolveInfo> infos = pmUser.queryIntentActivities(appSettingsQueryIntent, 0);
if (infos.size() > 0) {
appSettingsButton.setVisibility(View.VISIBLE);
appSettingsButton.setContentDescription(
mContext.getResources().getString(
R.string.status_bar_notification_app_settings_title,
appname
));
final Intent appSettingsLaunchIntent = new Intent(appSettingsQueryIntent)
.setClassName(pkg, infos.get(0).activityInfo.name);
appSettingsButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
MetricsLogger.action(mContext, MetricsLogger.ACTION_APP_NOTE_SETTINGS);
startAppOwnNotificationSettingsActivity(appSettingsLaunchIntent,
sbn.getId(),
sbn.getTag(),
appUidF);
}
});
} else {
appSettingsButton.setVisibility(View.GONE);
}
} else {
settingsButton.setVisibility(View.GONE);
appSettingsButton.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);
}
protected SwipeHelper.LongPressListener getNotificationLongClicker() {
@@ -1048,6 +1076,7 @@ public abstract class BaseStatusBar extends SystemUI implements
MetricsLogger.action(mContext, MetricsLogger.ACTION_NOTE_CONTROLS);
guts.setVisibility(View.VISIBLE);
final double horz = Math.max(guts.getWidth() - x, x);
final double vert = Math.max(guts.getActualHeight() - y, y);
final float r = (float) Math.hypot(horz, vert);

View File

@@ -283,7 +283,7 @@ public class NotificationData {
mRankingMap.getRanking(key, mTmpRanking);
return mTmpRanking.getVisibilityOverride();
}
return NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE;
return Ranking.VISIBILITY_NO_OVERRIDE;
}
public boolean shouldSuppressPeek(String key) {
@@ -295,6 +295,14 @@ public class NotificationData {
return false;
}
public int getImportance(String key) {
if (mRankingMap != null) {
mRankingMap.getRanking(key, mTmpRanking);
return mTmpRanking.getImportance();
}
return Ranking.IMPORTANCE_UNSPECIFIED;
}
private void updateRankingAndSort(RankingMap ranking) {
if (ranking != null) {
mRankingMap = ranking;

View File

@@ -21,12 +21,14 @@ import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import com.android.systemui.R;
/**
* The guts of a notification revealed when performing a long press.
*/
public class NotificationGuts extends FrameLayout {
public class NotificationGuts extends LinearLayout {
private Drawable mBackground;
private int mClipTopAmount;

View File

@@ -1246,7 +1246,7 @@ public class NotificationManagerService extends SystemService {
@Override
public void setTopicImportance(String pkg, int uid, Notification.Topic topic,
int importance) {
checkCallerIsSystem();
enforceSystemOrSystemUI("Caller not system or systemui");
mRankingHelper.setTopicImportance(pkg, uid, topic, importance);
savePolicyFile();
}

View File

@@ -162,8 +162,11 @@ public class NotificationTestList extends TestActivity
new Test("with topic Hello") {
public void run() {
Notification.BigTextStyle bigText = new Notification.BigTextStyle();
bigText.bigText("FgBHreherhethethethe\ntwetwrterter\netetweterteryetry");
Notification n = new Notification.Builder(NotificationTestList.this)
.setSmallIcon(R.drawable.icon1)
.setStyle(bigText)
.setWhen(mActivityCreateTime)
.setContentTitle("hihi")
.setContentText("This is a notification!!!")