Merge "Allow the ranker to autobundle notifications." into nyc-dev

am: 3898db9

* commit '3898db9e152ff8e2b34ae97f4a2ed37b9cb667db':
  Allow the ranker to autobundle notifications.

Change-Id: I652a43365b8eee51e91ed1c5d22aacb1b488e373
This commit is contained in:
Julia Reynolds
2016-04-09 00:41:35 +00:00
committed by android-build-merger
18 changed files with 889 additions and 118 deletions

View File

@@ -25,6 +25,7 @@ import android.content.Intent;
import android.content.pm.ParceledListSlice;
import android.net.Uri;
import android.os.Bundle;
import android.service.notification.Adjustment;
import android.service.notification.Condition;
import android.service.notification.IConditionListener;
import android.service.notification.IConditionProvider;
@@ -80,7 +81,8 @@ interface INotificationManager
void setOnNotificationPostedTrimFromListener(in INotificationListener token, int trim);
void setInterruptionFilter(String pkg, int interruptionFilter);
void setImportanceFromRankerService(in INotificationListener token, String key, int importance, CharSequence explanation);
void applyAdjustmentFromRankerService(in INotificationListener token, in Adjustment adjustment);
void applyAdjustmentsFromRankerService(in INotificationListener token, in List<Adjustment> adjustments);
ComponentName getEffectsSuppressor();
boolean matchesCallFilter(in Bundle extras);

View File

@@ -21,6 +21,7 @@ import android.annotation.DrawableRes;
import android.annotation.IntDef;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
@@ -496,6 +497,15 @@ public class Notification implements Parcelable
*/
public static final int FLAG_GROUP_SUMMARY = 0x00000200;
/**
* Bit to be bitswise-ored into the {@link #flags} field that should be
* set if this notification is the group summary for an auto-group of notifications.
*
* @hide
*/
@SystemApi
public static final int FLAG_AUTOGROUP_SUMMARY = 0x00000400;
public int flags;
/** @hide */
@@ -1945,13 +1955,9 @@ public class Notification implements Parcelable
* @hide
*/
public static void addFieldsFromContext(Context context, Notification notification) {
if (notification.extras.getParcelable(EXTRA_BUILDER_APPLICATION_INFO) == null) {
notification.extras.putParcelable(EXTRA_BUILDER_APPLICATION_INFO,
context.getApplicationInfo());
}
if (!notification.extras.containsKey(EXTRA_ORIGINATING_USERID)) {
notification.extras.putInt(EXTRA_ORIGINATING_USERID, context.getUserId());
}
notification.extras.putParcelable(EXTRA_BUILDER_APPLICATION_INFO,
context.getApplicationInfo());
notification.extras.putInt(EXTRA_ORIGINATING_USERID, context.getUserId());
}
@Override
@@ -3020,12 +3026,13 @@ public class Notification implements Parcelable
/**
* @hide
*/
public void setFlag(int mask, boolean value) {
public Builder setFlag(int mask, boolean value) {
if (value) {
mN.flags |= mask;
} else {
mN.flags &= ~mask;
}
return this;
}
/**

View File

@@ -0,0 +1,19 @@
/*
* Copyright (c) 2016, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.service.notification;
parcelable Adjustment;

View File

@@ -0,0 +1,150 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.service.notification;
import android.annotation.SystemApi;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Ranking updates from the Ranker.
*
* @hide
*/
@SystemApi
public final class Adjustment implements Parcelable {
private final String mPackage;
private final String mKey;
private final int mImportance;
private final CharSequence mExplanation;
private final Uri mReference;
private final Bundle mSignals;
public static final String GROUP_KEY_OVERRIDE_KEY = "group_key_override";
public static final String NEEDS_AUTOGROUPING_KEY = "autogroup_needed";
/**
* Create a notification adjustment.
*
* @param pkg The package of the notification.
* @param key The notification key.
* @param importance The recommended importance of the notification.
* @param signals A bundle of signals that should inform notification grouping and ordering.
* @param explanation A human-readable justification for the adjustment.
* @param reference A reference to an external object that augments the
* explanation, such as a
* {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI},
* or null.
*/
public Adjustment(String pkg, String key, int importance, Bundle signals,
CharSequence explanation, Uri reference) {
mPackage = pkg;
mKey = key;
mImportance = importance;
mSignals = signals;
mExplanation = explanation;
mReference = reference;
}
protected Adjustment(Parcel in) {
if (in.readInt() == 1) {
mPackage = in.readString();
} else {
mPackage = null;
}
if (in.readInt() == 1) {
mKey = in.readString();
} else {
mKey = null;
}
mImportance = in.readInt();
if (in.readInt() == 1) {
mExplanation = in.readCharSequence();
} else {
mExplanation = null;
}
mReference = in.readParcelable(Uri.class.getClassLoader());
mSignals = in.readBundle();
}
public static final Creator<Adjustment> CREATOR = new Creator<Adjustment>() {
@Override
public Adjustment createFromParcel(Parcel in) {
return new Adjustment(in);
}
@Override
public Adjustment[] newArray(int size) {
return new Adjustment[size];
}
};
public String getPackage() {
return mPackage;
}
public String getKey() {
return mKey;
}
public int getImportance() {
return mImportance;
}
public CharSequence getExplanation() {
return mExplanation;
}
public Uri getReference() {
return mReference;
}
public Bundle getSignals() {
return mSignals;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
if (mPackage != null) {
dest.writeInt(1);
dest.writeString(mPackage);
} else {
dest.writeInt(0);
}
if (mKey != null) {
dest.writeInt(1);
dest.writeString(mKey);
} else {
dest.writeInt(0);
}
dest.writeInt(mImportance);
if (mExplanation != null) {
dest.writeInt(1);
dest.writeCharSequence(mExplanation);
} else {
dest.writeInt(0);
}
dest.writeParcelable(mReference, flags);
dest.writeBundle(mSignals);
}
}

View File

@@ -1052,6 +1052,8 @@ public abstract class NotificationListenerService extends Service {
private int mSuppressedVisualEffects;
private @Importance int mImportance;
private CharSequence mImportanceExplanation;
// System specified group key.
private String mOverrideGroupKey;
public Ranking() {}
@@ -1130,9 +1132,17 @@ public abstract class NotificationListenerService extends Service {
return mImportanceExplanation;
}
/**
* If the system has overriden the group key, then this will be non-null, and this
* key should be used to bundle notifications.
*/
public String getOverrideGroupKey() {
return mOverrideGroupKey;
}
private void populate(String key, int rank, boolean matchesInterruptionFilter,
int visibilityOverride, int suppressedVisualEffects, int importance,
CharSequence explanation) {
CharSequence explanation, String overrideGroupKey) {
mKey = key;
mRank = rank;
mIsAmbient = importance < IMPORTANCE_LOW;
@@ -1141,6 +1151,7 @@ public abstract class NotificationListenerService extends Service {
mSuppressedVisualEffects = suppressedVisualEffects;
mImportance = importance;
mImportanceExplanation = explanation;
mOverrideGroupKey = overrideGroupKey;
}
/**
@@ -1184,6 +1195,7 @@ public abstract class NotificationListenerService extends Service {
private ArrayMap<String, Integer> mSuppressedVisualEffects;
private ArrayMap<String, Integer> mImportance;
private ArrayMap<String, String> mImportanceExplanation;
private ArrayMap<String, String> mOverrideGroupKeys;
private RankingMap(NotificationRankingUpdate rankingUpdate) {
mRankingUpdate = rankingUpdate;
@@ -1210,7 +1222,7 @@ public abstract class NotificationListenerService extends Service {
int rank = getRank(key);
outRanking.populate(key, rank, !isIntercepted(key),
getVisibilityOverride(key), getSuppressedVisualEffects(key),
getImportance(key), getImportanceExplanation(key));
getImportance(key), getImportanceExplanation(key), getOverrideGroupKey(key));
return rank >= 0;
}
@@ -1281,6 +1293,15 @@ public abstract class NotificationListenerService extends Service {
return mImportanceExplanation.get(key);
}
private String getOverrideGroupKey(String key) {
synchronized (this) {
if (mOverrideGroupKeys == null) {
buildOverrideGroupKeys();
}
}
return mOverrideGroupKeys.get(key);
}
// Locked by 'this'
private void buildRanksLocked() {
String[] orderedKeys = mRankingUpdate.getOrderedKeys();
@@ -1335,6 +1356,15 @@ public abstract class NotificationListenerService extends Service {
}
}
// Locked by 'this'
private void buildOverrideGroupKeys() {
Bundle overrideGroupKeys = mRankingUpdate.getOverrideGroupKeys();
mOverrideGroupKeys = new ArrayMap<>(overrideGroupKeys.size());
for (String key: overrideGroupKeys.keySet()) {
mOverrideGroupKeys.put(key, overrideGroupKeys.getString(key));
}
}
// ----------- Parcelable
@Override

View File

@@ -22,14 +22,19 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
import android.util.Log;
import com.android.internal.os.SomeArgs;
import java.util.List;
/**
* A service that helps the user manage notifications. This class is only used to
* extend the framework service and may not be implemented by non-framework components.
@@ -91,27 +96,8 @@ public abstract class NotificationRankerService extends NotificationListenerServ
/** Notification was canceled by the owning managed profile being turned off. */
public static final int REASON_PROFILE_TURNED_OFF = 15;
public class Adjustment {
int mImportance;
CharSequence mExplanation;
Uri mReference;
/**
* Create a notification importance adjustment.
*
* @param importance The final importance of the notification.
* @param explanation A human-readable justification for the adjustment.
* @param reference A reference to an external object that augments the
* explanation, such as a
* {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI},
* or null.
*/
public Adjustment(int importance, CharSequence explanation, Uri reference) {
mImportance = importance;
mExplanation = explanation;
mReference = reference;
}
}
/** Autobundled summary notification was canceled because its group was unbundled */
public static final int REASON_UNAUTOBUNDLED = 16;
private Handler mHandler;
@@ -200,18 +186,32 @@ public abstract class NotificationRankerService extends NotificationListenerServ
}
/**
* Change the importance of an existing notification. N.B. this wont cause
* Updates a notification. N.B. this wont cause
* an existing notification to alert, but might allow a future update to
* this notification to alert.
*
* @param key the notification key
* @param adjustment the new importance with an explanation
* @param adjustment the adjustment with an explanation
*/
public final void adjustImportance(String key, Adjustment adjustment) {
public final void adjustNotification(Adjustment adjustment) {
if (!isBound()) return;
try {
getNotificationInterface().setImportanceFromRankerService(mWrapper, key,
adjustment.mImportance, adjustment.mExplanation);
getNotificationInterface().applyAdjustmentFromRankerService(mWrapper, adjustment);
} catch (android.os.RemoteException ex) {
Log.v(TAG, "Unable to contact notification manager", ex);
}
}
/**
* Updates existing notifications. Re-ranking won't occur until all adjustments are applied.
* N.B. this wont cause an existing notification to alert, but might allow a future update to
* these notifications to alert.
*
* @param adjustments a list of adjustments with explanations
*/
public final void adjustNotifications(List<Adjustment> adjustments) {
if (!isBound()) return;
try {
getNotificationInterface().applyAdjustmentsFromRankerService(mWrapper, adjustments);
} catch (android.os.RemoteException ex) {
Log.v(TAG, "Unable to contact notification manager", ex);
}
@@ -299,7 +299,7 @@ public abstract class NotificationRankerService extends NotificationListenerServ
args.recycle();
Adjustment adjustment = onNotificationEnqueued(sbn, importance, user);
if (adjustment != null) {
adjustImportance(sbn.getKey(), adjustment);
adjustNotification(adjustment);
}
} break;

View File

@@ -30,16 +30,18 @@ public class NotificationRankingUpdate implements Parcelable {
private final Bundle mSuppressedVisualEffects;
private final int[] mImportance;
private final Bundle mImportanceExplanation;
private final Bundle mOverrideGroupKeys;
public NotificationRankingUpdate(String[] keys, String[] interceptedKeys,
Bundle visibilityOverrides, Bundle suppressedVisualEffects,
int[] importance, Bundle explanation) {
int[] importance, Bundle explanation, Bundle overrideGroupKeys) {
mKeys = keys;
mInterceptedKeys = interceptedKeys;
mVisibilityOverrides = visibilityOverrides;
mSuppressedVisualEffects = suppressedVisualEffects;
mImportance = importance;
mImportanceExplanation = explanation;
mOverrideGroupKeys = overrideGroupKeys;
}
public NotificationRankingUpdate(Parcel in) {
@@ -50,6 +52,7 @@ public class NotificationRankingUpdate implements Parcelable {
mImportance = new int[mKeys.length];
in.readIntArray(mImportance);
mImportanceExplanation = in.readBundle();
mOverrideGroupKeys = in.readBundle();
}
@Override
@@ -65,6 +68,7 @@ public class NotificationRankingUpdate implements Parcelable {
out.writeBundle(mSuppressedVisualEffects);
out.writeIntArray(mImportance);
out.writeBundle(mImportanceExplanation);
out.writeBundle(mOverrideGroupKeys);
}
public static final Parcelable.Creator<NotificationRankingUpdate> CREATOR
@@ -101,4 +105,8 @@ public class NotificationRankingUpdate implements Parcelable {
public Bundle getImportanceExplanation() {
return mImportanceExplanation;
}
public Bundle getOverrideGroupKeys() {
return mOverrideGroupKeys;
}
}

View File

@@ -33,7 +33,8 @@ public class StatusBarNotification implements Parcelable {
private final int id;
private final String tag;
private final String key;
private final String groupKey;
private String groupKey;
private String overrideGroupKey;
private final int uid;
private final String opPkg;
@@ -51,6 +52,27 @@ public class StatusBarNotification implements Parcelable {
System.currentTimeMillis());
}
/** @hide */
public StatusBarNotification(String pkg, String opPkg, int id, String tag, int uid,
int initialPid, Notification notification, UserHandle user, String overrideGroupKey,
long postTime) {
if (pkg == null) throw new NullPointerException();
if (notification == null) throw new NullPointerException();
this.pkg = pkg;
this.opPkg = opPkg;
this.id = id;
this.tag = tag;
this.uid = uid;
this.initialPid = initialPid;
this.notification = notification;
this.user = user;
this.postTime = postTime;
this.overrideGroupKey = overrideGroupKey;
this.key = key();
this.groupKey = groupKey();
}
public StatusBarNotification(String pkg, String opPkg, int id, String tag, int uid,
int initialPid, int score, Notification notification, UserHandle user,
long postTime) {
@@ -84,15 +106,27 @@ public class StatusBarNotification implements Parcelable {
this.notification = new Notification(in);
this.user = UserHandle.readFromParcel(in);
this.postTime = in.readLong();
if (in.readInt() != 0) {
this.overrideGroupKey = in.readString();
} else {
this.overrideGroupKey = null;
}
this.key = key();
this.groupKey = groupKey();
}
private String key() {
return user.getIdentifier() + "|" + pkg + "|" + id + "|" + tag + "|" + uid;
String sbnKey = user.getIdentifier() + "|" + pkg + "|" + id + "|" + tag + "|" + uid;
if (overrideGroupKey != null && getNotification().isGroupSummary()) {
sbnKey = sbnKey + "|" + overrideGroupKey;
}
return sbnKey;
}
private String groupKey() {
if (overrideGroupKey != null) {
return user.getIdentifier() + "|" + pkg + "|" + "g:" + overrideGroupKey;
}
final String group = getNotification().getGroup();
final String sortKey = getNotification().getSortKey();
if (group == null && sortKey == null) {
@@ -105,6 +139,17 @@ public class StatusBarNotification implements Parcelable {
: "g:" + group);
}
/**
* Returns true if this notification is part of a group.
*/
public boolean isGroup() {
if (overrideGroupKey != null || getNotification().getGroup() != null
|| getNotification().getSortKey() != null) {
return true;
}
return false;
}
public void writeToParcel(Parcel out, int flags) {
out.writeString(this.pkg);
out.writeString(this.opPkg);
@@ -121,6 +166,12 @@ public class StatusBarNotification implements Parcelable {
user.writeToParcel(out, flags);
out.writeLong(this.postTime);
if (this.overrideGroupKey != null) {
out.writeInt(1);
out.writeString(this.overrideGroupKey);
} else {
out.writeInt(0);
}
}
public int describeContents() {
@@ -149,22 +200,22 @@ public class StatusBarNotification implements Parcelable {
this.notification.cloneInto(no, false); // light copy
return new StatusBarNotification(this.pkg, this.opPkg,
this.id, this.tag, this.uid, this.initialPid,
0, no, this.user, this.postTime);
no, this.user, this.overrideGroupKey, this.postTime);
}
@Override
public StatusBarNotification clone() {
return new StatusBarNotification(this.pkg, this.opPkg,
this.id, this.tag, this.uid, this.initialPid,
0, this.notification.clone(), this.user, this.postTime);
this.notification.clone(), this.user, this.overrideGroupKey, this.postTime);
}
@Override
public String toString() {
return String.format(
"StatusBarNotification(pkg=%s user=%s id=%d tag=%s score=%d key=%s: %s)",
"StatusBarNotification(pkg=%s user=%s id=%d tag=%s key=%s: %s)",
this.pkg, this.user, this.id, this.tag,
0, this.key, this.notification);
this.key, this.notification);
}
/** Convenience method to check the notification's flags for
@@ -257,6 +308,21 @@ public class StatusBarNotification implements Parcelable {
return groupKey;
}
/**
* Sets the override group key.
*/
public void setOverrideGroupKey(String overrideGroupKey) {
this.overrideGroupKey = overrideGroupKey;
groupKey = groupKey();
}
/**
* Returns the override group key.
*/
public String getOverrideGroupKey() {
return overrideGroupKey;
}
/**
* @hide
*/