am 572532d0: Merge "Strip RemoteViews from Notifications, re-create them in SysUI" into lmp-dev
* commit '572532d089d15057c5e00a1d7fcf926d7555299f': Strip RemoteViews from Notifications, re-create them in SysUI
This commit is contained in:
@@ -4637,6 +4637,7 @@ package android.app {
|
||||
field public static final int DEFAULT_SOUND = 1; // 0x1
|
||||
field public static final int DEFAULT_VIBRATE = 2; // 0x2
|
||||
field public static final java.lang.String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
|
||||
field public static final java.lang.String EXTRA_BIG_TEXT = "android.bigText";
|
||||
field public static final java.lang.String EXTRA_COMPACT_ACTIONS = "android.compactActions";
|
||||
field public static final java.lang.String EXTRA_INFO_TEXT = "android.infoText";
|
||||
field public static final java.lang.String EXTRA_LARGE_ICON = "android.largeIcon";
|
||||
@@ -4825,7 +4826,6 @@ package android.app {
|
||||
public static class Notification.MediaStyle extends android.app.Notification.Style {
|
||||
ctor public Notification.MediaStyle();
|
||||
ctor public Notification.MediaStyle(android.app.Notification.Builder);
|
||||
method public android.app.Notification buildStyled(android.app.Notification);
|
||||
method public android.app.Notification.MediaStyle setMediaSession(android.media.session.MediaSession.Token);
|
||||
method public android.app.Notification.MediaStyle setShowActionsInCompactView(int...);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import android.annotation.SdkConstant;
|
||||
import android.annotation.SdkConstant.SdkConstantType;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
@@ -50,6 +51,7 @@ import com.android.internal.util.NotificationColorUtil;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -690,6 +692,13 @@ public class Notification implements Parcelable
|
||||
*/
|
||||
public static final String EXTRA_SUMMARY_TEXT = "android.summaryText";
|
||||
|
||||
/**
|
||||
* {@link #extras} key: this is the longer text shown in the big form of a
|
||||
* {@link BigTextStyle} notification, as supplied to
|
||||
* {@link BigTextStyle#bigText(CharSequence)}.
|
||||
*/
|
||||
public static final String EXTRA_BIG_TEXT = "android.bigText";
|
||||
|
||||
/**
|
||||
* {@link #extras} key: this is the resource ID of the notification's main small icon, as
|
||||
* supplied to {@link Builder#setSmallIcon(int)}.
|
||||
@@ -1713,6 +1722,15 @@ public class Notification implements Parcelable
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public boolean isValid() {
|
||||
// Would like to check for icon!=0 here, too, but NotificationManagerService accepts that
|
||||
// for legacy reasons.
|
||||
return contentView != null || extras.getBoolean(Builder.EXTRA_REBUILD_CONTENT_VIEW);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder class for {@link Notification} objects.
|
||||
*
|
||||
@@ -1737,6 +1755,55 @@ public class Notification implements Parcelable
|
||||
public static class Builder {
|
||||
private static final int MAX_ACTION_BUTTONS = 3;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static final String EXTRA_NEEDS_REBUILD = "android.rebuild";
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static final String EXTRA_REBUILD_LARGE_ICON = "android.rebuild.largeIcon";
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static final String EXTRA_REBUILD_CONTENT_VIEW = "android.rebuild.contentView";
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static final String EXTRA_REBUILD_CONTENT_VIEW_ACTION_COUNT =
|
||||
"android.rebuild.contentViewActionCount";
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static final String EXTRA_REBUILD_BIG_CONTENT_VIEW
|
||||
= "android.rebuild.bigView";
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static final String EXTRA_REBUILD_BIG_CONTENT_VIEW_ACTION_COUNT
|
||||
= "android.rebuild.bigViewActionCount";
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static final String EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW
|
||||
= "android.rebuild.hudView";
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static final String EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW_ACTION_COUNT
|
||||
= "android.rebuild.hudViewActionCount";
|
||||
|
||||
/**
|
||||
* The package name of the context used to create the notification via a Builder.
|
||||
*/
|
||||
private static final String EXTRA_REBUILD_CONTEXT_PACKAGE =
|
||||
"android.rebuild.contextPackage";
|
||||
|
||||
// Whether to enable stripping (at post time) & rebuilding (at listener receive time) of
|
||||
// memory intensive resources.
|
||||
private static final boolean STRIP_AND_REBUILD = true;
|
||||
|
||||
private Context mContext;
|
||||
|
||||
private long mWhen;
|
||||
@@ -1781,6 +1848,17 @@ public class Notification implements Parcelable
|
||||
private ArrayList<String> mPeople;
|
||||
private int mColor = COLOR_DEFAULT;
|
||||
|
||||
|
||||
/**
|
||||
* Contains extras related to rebuilding during the build phase.
|
||||
*/
|
||||
private Bundle mRebuildBundle = new Bundle();
|
||||
/**
|
||||
* Contains the notification to rebuild when this Builder is in "rebuild" mode.
|
||||
* Null otherwise.
|
||||
*/
|
||||
private Notification mRebuildNotification = null;
|
||||
|
||||
/**
|
||||
* Constructs a new Builder with the defaults:
|
||||
*
|
||||
@@ -1822,6 +1900,40 @@ public class Notification implements Parcelable
|
||||
mColorUtil = NotificationColorUtil.getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Builder for rebuilding the given Notification.
|
||||
* <p>
|
||||
* Call {@link #rebuild()} to retrieve the rebuilt version of 'n'.
|
||||
*/
|
||||
private Builder(Context context, Notification n) {
|
||||
this(context);
|
||||
mRebuildNotification = n;
|
||||
restoreFromNotification(n);
|
||||
|
||||
Style style = null;
|
||||
Bundle extras = n.extras;
|
||||
String templateClass = extras.getString(EXTRA_TEMPLATE);
|
||||
if (!TextUtils.isEmpty(templateClass)) {
|
||||
Class<? extends Style> styleClass = getNotificationStyleClass(templateClass);
|
||||
if (styleClass == null) {
|
||||
Log.d(TAG, "Unknown style class: " + styleClass);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Constructor<? extends Style> constructor = styleClass.getConstructor();
|
||||
style = constructor.newInstance();
|
||||
style.restoreFromExtras(extras);
|
||||
} catch (Throwable t) {
|
||||
Log.e(TAG, "Could not create Style", t);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (style != null) {
|
||||
setStyle(style);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a timestamp pertaining to the notification (usually the time the event occurred).
|
||||
* It will be shown in the notification content view by default; use
|
||||
@@ -2459,7 +2571,7 @@ public class Notification implements Parcelable
|
||||
|
||||
private RemoteViews applyStandardTemplate(int resId, boolean fitIn1U) {
|
||||
Bitmap profileIcon = getProfileBadge();
|
||||
RemoteViews contentView = new RemoteViews(mContext.getPackageName(), resId);
|
||||
RemoteViews contentView = new BuilderRemoteViews(mContext.getPackageName(), resId);
|
||||
boolean showLine3 = false;
|
||||
boolean showLine2 = false;
|
||||
|
||||
@@ -2743,7 +2855,7 @@ public class Notification implements Parcelable
|
||||
|
||||
n.color = sanitizeColor();
|
||||
|
||||
n.contentView = makeContentView();
|
||||
setBuilderContentView(n, makeContentView());
|
||||
n.contentIntent = mContentIntent;
|
||||
n.deleteIntent = mDeleteIntent;
|
||||
n.fullScreenIntent = mFullScreenIntent;
|
||||
@@ -2759,8 +2871,8 @@ public class Notification implements Parcelable
|
||||
n.ledOffMS = mLedOffMs;
|
||||
n.defaults = mDefaults;
|
||||
n.flags = mFlags;
|
||||
n.bigContentView = makeBigContentView();
|
||||
n.headsUpContentView = makeHeadsUpContentView();
|
||||
setBuilderBigContentView(n, makeBigContentView());
|
||||
setBuilderHeadsUpContentView(n, makeHeadsUpContentView());
|
||||
if (mLedOnMs != 0 || mLedOffMs != 0) {
|
||||
n.flags |= FLAG_SHOW_LIGHTS;
|
||||
}
|
||||
@@ -2781,7 +2893,7 @@ public class Notification implements Parcelable
|
||||
n.publicVersion = new Notification();
|
||||
mPublicVersion.cloneInto(n.publicVersion, true);
|
||||
}
|
||||
|
||||
// Note: If you're adding new fields, also update restoreFromNotitification().
|
||||
return n;
|
||||
}
|
||||
|
||||
@@ -2792,6 +2904,7 @@ public class Notification implements Parcelable
|
||||
*/
|
||||
public void populateExtras(Bundle extras) {
|
||||
// Store original information used in the construction of this object
|
||||
extras.putString(EXTRA_REBUILD_CONTEXT_PACKAGE, mContext.getPackageName());
|
||||
extras.putCharSequence(EXTRA_TITLE, mContentTitle);
|
||||
extras.putCharSequence(EXTRA_TEXT, mContentText);
|
||||
extras.putCharSequence(EXTRA_SUB_TEXT, mSubText);
|
||||
@@ -2808,6 +2921,233 @@ public class Notification implements Parcelable
|
||||
if (!mPeople.isEmpty()) {
|
||||
extras.putStringArray(EXTRA_PEOPLE, mPeople.toArray(new String[mPeople.size()]));
|
||||
}
|
||||
// NOTE: If you're adding new extras also update restoreFromNotification().
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static void stripForDelivery(Notification n) {
|
||||
if (!STRIP_AND_REBUILD) {
|
||||
return;
|
||||
}
|
||||
|
||||
String templateClass = n.extras.getString(EXTRA_TEMPLATE);
|
||||
// Only strip views for known Styles because we won't know how to
|
||||
// re-create them otherwise.
|
||||
boolean stripViews = TextUtils.isEmpty(templateClass) ||
|
||||
getNotificationStyleClass(templateClass) != null;
|
||||
|
||||
boolean isStripped = false;
|
||||
|
||||
if (n.largeIcon != null && n.extras.containsKey(EXTRA_LARGE_ICON)) {
|
||||
// TODO: Would like to check for equality here, but if the notification
|
||||
// has been cloned, we can't.
|
||||
n.largeIcon = null;
|
||||
n.extras.putBoolean(EXTRA_REBUILD_LARGE_ICON, true);
|
||||
isStripped = true;
|
||||
}
|
||||
// Get rid of unmodified BuilderRemoteViews.
|
||||
|
||||
if (stripViews &&
|
||||
n.contentView instanceof BuilderRemoteViews &&
|
||||
n.extras.getInt(EXTRA_REBUILD_CONTENT_VIEW_ACTION_COUNT, -1) ==
|
||||
n.contentView.getSequenceNumber()) {
|
||||
n.contentView = null;
|
||||
n.extras.putBoolean(EXTRA_REBUILD_CONTENT_VIEW, true);
|
||||
n.extras.remove(EXTRA_REBUILD_CONTENT_VIEW_ACTION_COUNT);
|
||||
isStripped = true;
|
||||
}
|
||||
if (stripViews &&
|
||||
n.bigContentView instanceof BuilderRemoteViews &&
|
||||
n.extras.getInt(EXTRA_REBUILD_BIG_CONTENT_VIEW_ACTION_COUNT, -1) ==
|
||||
n.bigContentView.getSequenceNumber()) {
|
||||
n.bigContentView = null;
|
||||
n.extras.putBoolean(EXTRA_REBUILD_BIG_CONTENT_VIEW, true);
|
||||
n.extras.remove(EXTRA_REBUILD_BIG_CONTENT_VIEW_ACTION_COUNT);
|
||||
isStripped = true;
|
||||
}
|
||||
if (stripViews &&
|
||||
n.headsUpContentView instanceof BuilderRemoteViews &&
|
||||
n.extras.getInt(EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW_ACTION_COUNT, -1) ==
|
||||
n.headsUpContentView.getSequenceNumber()) {
|
||||
n.headsUpContentView = null;
|
||||
n.extras.putBoolean(EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW, true);
|
||||
n.extras.remove(EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW_ACTION_COUNT);
|
||||
isStripped = true;
|
||||
}
|
||||
|
||||
if (isStripped) {
|
||||
n.extras.putBoolean(EXTRA_NEEDS_REBUILD, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static Notification rebuild(Context context, Notification n) {
|
||||
Bundle extras = n.extras;
|
||||
if (!extras.getBoolean(EXTRA_NEEDS_REBUILD)) return n;
|
||||
extras.remove(EXTRA_NEEDS_REBUILD);
|
||||
|
||||
// Re-create notification context so we can access app resources.
|
||||
String packageName = extras.getString(EXTRA_REBUILD_CONTEXT_PACKAGE);
|
||||
Context builderContext;
|
||||
try {
|
||||
builderContext = context.createPackageContext(packageName,
|
||||
Context.CONTEXT_RESTRICTED);
|
||||
} catch (NameNotFoundException e) {
|
||||
Log.e(TAG, "Package name " + packageName + " not found");
|
||||
builderContext = context; // try with our context
|
||||
}
|
||||
|
||||
Builder b = new Builder(builderContext, n);
|
||||
return b.rebuild();
|
||||
}
|
||||
|
||||
/**
|
||||
* Rebuilds the notification passed in to the rebuild-constructor
|
||||
* {@link #Builder(Context, Notification)}.
|
||||
*
|
||||
* <p>
|
||||
* Throws IllegalStateException when invoked on a Builder that isn't in rebuild mode.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
private Notification rebuild() {
|
||||
if (mRebuildNotification == null) {
|
||||
throw new IllegalStateException("rebuild() only valid when in 'rebuild' mode.");
|
||||
}
|
||||
|
||||
Bundle extras = mRebuildNotification.extras;
|
||||
|
||||
if (extras.getBoolean(EXTRA_REBUILD_LARGE_ICON)) {
|
||||
mRebuildNotification.largeIcon = extras.getParcelable(EXTRA_LARGE_ICON);
|
||||
}
|
||||
extras.remove(EXTRA_REBUILD_LARGE_ICON);
|
||||
|
||||
if (extras.getBoolean(EXTRA_REBUILD_CONTENT_VIEW)) {
|
||||
setBuilderContentView(mRebuildNotification, makeContentView());
|
||||
if (mStyle != null) {
|
||||
mStyle.populateContentView(mRebuildNotification);
|
||||
}
|
||||
}
|
||||
extras.remove(EXTRA_REBUILD_CONTENT_VIEW);
|
||||
|
||||
if (extras.getBoolean(EXTRA_REBUILD_BIG_CONTENT_VIEW)) {
|
||||
setBuilderBigContentView(mRebuildNotification, makeBigContentView());
|
||||
if (mStyle != null) {
|
||||
mStyle.populateBigContentView(mRebuildNotification);
|
||||
}
|
||||
}
|
||||
extras.remove(EXTRA_REBUILD_BIG_CONTENT_VIEW);
|
||||
|
||||
if (extras.getBoolean(EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW)) {
|
||||
setBuilderHeadsUpContentView(mRebuildNotification, makeHeadsUpContentView());
|
||||
if (mStyle != null) {
|
||||
mStyle.populateHeadsUpContentView(mRebuildNotification);
|
||||
}
|
||||
}
|
||||
extras.remove(EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW);
|
||||
|
||||
return mRebuildNotification;
|
||||
}
|
||||
|
||||
private static Class<? extends Style> getNotificationStyleClass(String templateClass) {
|
||||
Class<? extends Style>[] classes = new Class[]{
|
||||
BigTextStyle.class, BigPictureStyle.class, InboxStyle.class, MediaStyle.class};
|
||||
for (Class<? extends Style> innerClass : classes) {
|
||||
if (templateClass.equals(innerClass.getName())) {
|
||||
return innerClass;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void setBuilderContentView(Notification n, RemoteViews contentView) {
|
||||
n.contentView = contentView;
|
||||
if (contentView instanceof BuilderRemoteViews) {
|
||||
mRebuildBundle.putInt(Builder.EXTRA_REBUILD_CONTENT_VIEW_ACTION_COUNT,
|
||||
contentView.getSequenceNumber());
|
||||
}
|
||||
}
|
||||
|
||||
private void setBuilderBigContentView(Notification n, RemoteViews bigContentView) {
|
||||
n.bigContentView = bigContentView;
|
||||
if (bigContentView instanceof BuilderRemoteViews) {
|
||||
mRebuildBundle.putInt(Builder.EXTRA_REBUILD_BIG_CONTENT_VIEW_ACTION_COUNT,
|
||||
bigContentView.getSequenceNumber());
|
||||
}
|
||||
}
|
||||
|
||||
private void setBuilderHeadsUpContentView(Notification n,
|
||||
RemoteViews headsUpContentView) {
|
||||
n.headsUpContentView = headsUpContentView;
|
||||
if (headsUpContentView instanceof BuilderRemoteViews) {
|
||||
mRebuildBundle.putInt(Builder.EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW_ACTION_COUNT,
|
||||
headsUpContentView.getSequenceNumber());
|
||||
}
|
||||
}
|
||||
|
||||
private void restoreFromNotification(Notification n) {
|
||||
|
||||
// Notification fields.
|
||||
mWhen = n.when;
|
||||
mSmallIcon = n.icon;
|
||||
mSmallIconLevel = n.iconLevel;
|
||||
mNumber = n.number;
|
||||
|
||||
mColor = n.color;
|
||||
|
||||
mContentView = n.contentView;
|
||||
mDeleteIntent = n.deleteIntent;
|
||||
mFullScreenIntent = n.fullScreenIntent;
|
||||
mTickerText = n.tickerText;
|
||||
mTickerView = n.tickerView;
|
||||
mLargeIcon = n.largeIcon;
|
||||
mSound = n.sound;
|
||||
mAudioStreamType = n.audioStreamType;
|
||||
mAudioAttributes = n.audioAttributes;
|
||||
|
||||
mVibrate = n.vibrate;
|
||||
mLedArgb = n.ledARGB;
|
||||
mLedOnMs = n.ledOnMS;
|
||||
mLedOffMs = n.ledOffMS;
|
||||
mDefaults = n.defaults;
|
||||
mFlags = n.flags;
|
||||
|
||||
mCategory = n.category;
|
||||
mGroupKey = n.mGroupKey;
|
||||
mSortKey = n.mSortKey;
|
||||
mPriority = n.priority;
|
||||
mActions.clear();
|
||||
if (n.actions != null) {
|
||||
Collections.addAll(mActions, n.actions);
|
||||
}
|
||||
mVisibility = n.visibility;
|
||||
|
||||
mPublicVersion = n.publicVersion;
|
||||
|
||||
// Extras.
|
||||
Bundle extras = n.extras;
|
||||
mContentTitle = extras.getCharSequence(EXTRA_TITLE);
|
||||
mContentText = extras.getCharSequence(EXTRA_TEXT);
|
||||
mSubText = extras.getCharSequence(EXTRA_SUB_TEXT);
|
||||
mContentInfo = extras.getCharSequence(EXTRA_INFO_TEXT);
|
||||
mSmallIcon = extras.getInt(EXTRA_SMALL_ICON);
|
||||
mProgress = extras.getInt(EXTRA_PROGRESS);
|
||||
mProgressMax = extras.getInt(EXTRA_PROGRESS_MAX);
|
||||
mProgressIndeterminate = extras.getBoolean(EXTRA_PROGRESS_INDETERMINATE);
|
||||
mUseChronometer = extras.getBoolean(EXTRA_SHOW_CHRONOMETER);
|
||||
mShowWhen = extras.getBoolean(EXTRA_SHOW_WHEN);
|
||||
if (extras.containsKey(EXTRA_LARGE_ICON)) {
|
||||
mLargeIcon = extras.getParcelable(EXTRA_LARGE_ICON);
|
||||
}
|
||||
if (extras.containsKey(EXTRA_PEOPLE)) {
|
||||
mPeople.clear();
|
||||
Collections.addAll(mPeople, extras.getStringArray(EXTRA_PEOPLE));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2829,7 +3169,14 @@ public class Notification implements Parcelable
|
||||
n = mStyle.buildStyled(n);
|
||||
}
|
||||
|
||||
n.extras = mExtras != null ? new Bundle(mExtras) : new Bundle();
|
||||
if (mExtras != null) {
|
||||
n.extras.putAll(mExtras);
|
||||
}
|
||||
|
||||
if (mRebuildBundle.size() > 0) {
|
||||
n.extras.putAll(mRebuildBundle);
|
||||
mRebuildBundle.clear();
|
||||
}
|
||||
|
||||
populateExtras(n.extras);
|
||||
if (mStyle != null) {
|
||||
@@ -2849,7 +3196,6 @@ public class Notification implements Parcelable
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
private int getBaseLayoutResource() {
|
||||
return R.layout.notification_template_material_base;
|
||||
}
|
||||
@@ -2924,12 +3270,16 @@ public class Notification implements Parcelable
|
||||
protected RemoteViews getStandardView(int layoutId) {
|
||||
checkBuilder();
|
||||
|
||||
// Nasty.
|
||||
CharSequence oldBuilderContentTitle = mBuilder.mContentTitle;
|
||||
if (mBigContentTitle != null) {
|
||||
mBuilder.setContentTitle(mBigContentTitle);
|
||||
}
|
||||
|
||||
RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(layoutId);
|
||||
|
||||
mBuilder.mContentTitle = oldBuilderContentTitle;
|
||||
|
||||
if (mBigContentTitle != null && mBigContentTitle.equals("")) {
|
||||
contentView.setViewVisibility(R.id.line1, View.GONE);
|
||||
} else {
|
||||
@@ -2968,7 +3318,47 @@ public class Notification implements Parcelable
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public abstract Notification buildStyled(Notification wip);
|
||||
protected void restoreFromExtras(Bundle extras) {
|
||||
if (extras.containsKey(EXTRA_SUMMARY_TEXT)) {
|
||||
mSummaryText = extras.getCharSequence(EXTRA_SUMMARY_TEXT);
|
||||
mSummaryTextSet = true;
|
||||
}
|
||||
if (extras.containsKey(EXTRA_TITLE_BIG)) {
|
||||
mBigContentTitle = extras.getCharSequence(EXTRA_TITLE_BIG);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public Notification buildStyled(Notification wip) {
|
||||
populateTickerView(wip);
|
||||
populateContentView(wip);
|
||||
populateBigContentView(wip);
|
||||
populateHeadsUpContentView(wip);
|
||||
return wip;
|
||||
}
|
||||
|
||||
// The following methods are split out so we can re-create notification partially.
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
protected void populateTickerView(Notification wip) {}
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
protected void populateContentView(Notification wip) {}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
protected void populateBigContentView(Notification wip) {}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
protected void populateHeadsUpContentView(Notification wip) {}
|
||||
|
||||
/**
|
||||
* Calls {@link android.app.Notification.Builder#build()} on the Builder this Style is
|
||||
@@ -3069,12 +3459,21 @@ public class Notification implements Parcelable
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public Notification buildStyled(Notification wip) {
|
||||
if (mBigLargeIconSet ) {
|
||||
mBuilder.mLargeIcon = mBigLargeIcon;
|
||||
protected void restoreFromExtras(Bundle extras) {
|
||||
super.restoreFromExtras(extras);
|
||||
|
||||
if (extras.containsKey(EXTRA_LARGE_ICON_BIG)) {
|
||||
mBigLargeIcon = extras.getParcelable(EXTRA_LARGE_ICON_BIG);
|
||||
}
|
||||
wip.bigContentView = makeBigContentView();
|
||||
return wip;
|
||||
mPicture = extras.getParcelable(EXTRA_PICTURE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public void populateBigContentView(Notification wip) {
|
||||
mBuilder.setBuilderBigContentView(wip, makeBigContentView());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3137,16 +3536,31 @@ public class Notification implements Parcelable
|
||||
public void addExtras(Bundle extras) {
|
||||
super.addExtras(extras);
|
||||
|
||||
extras.putCharSequence(EXTRA_TEXT, mBigText);
|
||||
extras.putCharSequence(EXTRA_BIG_TEXT, mBigText);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
protected void restoreFromExtras(Bundle extras) {
|
||||
super.restoreFromExtras(extras);
|
||||
|
||||
mBigText = extras.getCharSequence(EXTRA_BIG_TEXT);
|
||||
}
|
||||
|
||||
private RemoteViews makeBigContentView() {
|
||||
// Remove the content text so line3 only shows if you have a summary
|
||||
final boolean hadThreeLines = (mBuilder.mContentText != null && mBuilder.mSubText != null);
|
||||
|
||||
// Nasty
|
||||
CharSequence oldBuilderContentText = mBuilder.mContentText;
|
||||
mBuilder.mContentText = null;
|
||||
|
||||
RemoteViews contentView = getStandardView(mBuilder.getBigTextLayoutResource());
|
||||
|
||||
mBuilder.mContentText = oldBuilderContentText;
|
||||
|
||||
if (hadThreeLines) {
|
||||
// vertical centering
|
||||
contentView.setViewPadding(R.id.line1, 0, 0, 0, 0);
|
||||
@@ -3163,12 +3577,8 @@ public class Notification implements Parcelable
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public Notification buildStyled(Notification wip) {
|
||||
wip.bigContentView = makeBigContentView();
|
||||
|
||||
wip.extras.putCharSequence(EXTRA_TEXT, mBigText);
|
||||
|
||||
return wip;
|
||||
public void populateBigContentView(Notification wip) {
|
||||
mBuilder.setBuilderBigContentView(wip, makeBigContentView());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3232,15 +3642,35 @@ public class Notification implements Parcelable
|
||||
*/
|
||||
public void addExtras(Bundle extras) {
|
||||
super.addExtras(extras);
|
||||
|
||||
CharSequence[] a = new CharSequence[mTexts.size()];
|
||||
extras.putCharSequenceArray(EXTRA_TEXT_LINES, mTexts.toArray(a));
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
protected void restoreFromExtras(Bundle extras) {
|
||||
super.restoreFromExtras(extras);
|
||||
|
||||
mTexts.clear();
|
||||
if (extras.containsKey(EXTRA_TEXT_LINES)) {
|
||||
Collections.addAll(mTexts, extras.getCharSequenceArray(EXTRA_TEXT_LINES));
|
||||
}
|
||||
}
|
||||
|
||||
private RemoteViews makeBigContentView() {
|
||||
// Remove the content text so line3 disappears unless you have a summary
|
||||
|
||||
// Nasty
|
||||
CharSequence oldBuilderContentText = mBuilder.mContentText;
|
||||
mBuilder.mContentText = null;
|
||||
|
||||
RemoteViews contentView = getStandardView(mBuilder.getInboxLayoutResource());
|
||||
|
||||
mBuilder.mContentText = oldBuilderContentText;
|
||||
|
||||
contentView.setViewVisibility(R.id.text2, View.GONE);
|
||||
|
||||
int[] rowIds = {R.id.inbox_text0, R.id.inbox_text1, R.id.inbox_text2, R.id.inbox_text3,
|
||||
@@ -3275,10 +3705,8 @@ public class Notification implements Parcelable
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public Notification buildStyled(Notification wip) {
|
||||
wip.bigContentView = makeBigContentView();
|
||||
|
||||
return wip;
|
||||
public void populateBigContentView(Notification wip) {
|
||||
mBuilder.setBuilderBigContentView(wip, makeBigContentView());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3353,16 +3781,34 @@ public class Notification implements Parcelable
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public Notification buildStyled(Notification wip) {
|
||||
wip.contentView = makeMediaContentView();
|
||||
wip.bigContentView = makeMediaBigContentView();
|
||||
super.buildStyled(wip);
|
||||
if (wip.category == null) {
|
||||
wip.category = Notification.CATEGORY_TRANSPORT;
|
||||
}
|
||||
return wip;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public void populateContentView(Notification wip) {
|
||||
mBuilder.setBuilderContentView(wip, makeMediaContentView());
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public void populateBigContentView(Notification wip) {
|
||||
mBuilder.setBuilderBigContentView(wip, makeMediaBigContentView());
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@Override
|
||||
public void addExtras(Bundle extras) {
|
||||
@@ -3376,6 +3822,21 @@ public class Notification implements Parcelable
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
protected void restoreFromExtras(Bundle extras) {
|
||||
super.restoreFromExtras(extras);
|
||||
|
||||
if (extras.containsKey(EXTRA_MEDIA_SESSION)) {
|
||||
mToken = extras.getParcelable(EXTRA_MEDIA_SESSION);
|
||||
}
|
||||
if (extras.containsKey(EXTRA_COMPACT_ACTIONS)) {
|
||||
mActionsToShowInCompact = extras.getIntArray(EXTRA_COMPACT_ACTIONS);
|
||||
}
|
||||
}
|
||||
|
||||
private RemoteViews generateMediaActionButton(Action action) {
|
||||
final boolean tombstone = (action.actionIntent == null);
|
||||
RemoteViews button = new RemoteViews(mBuilder.mContext.getPackageName(),
|
||||
@@ -3429,6 +3890,9 @@ public class Notification implements Parcelable
|
||||
}
|
||||
}
|
||||
|
||||
// When adding a new Style subclass here, don't forget to update
|
||||
// Builder.getNotificationStyleClass.
|
||||
|
||||
/**
|
||||
* Extender interface for use with {@link Builder#extend}. Extenders may be used to add
|
||||
* metadata or change options on a notification builder.
|
||||
@@ -4096,4 +4560,24 @@ public class Notification implements Parcelable
|
||||
bundle.putParcelableArray(key, typedArray);
|
||||
return typedArray;
|
||||
}
|
||||
|
||||
private static class BuilderRemoteViews extends RemoteViews {
|
||||
public BuilderRemoteViews(Parcel parcel) {
|
||||
super(parcel);
|
||||
}
|
||||
|
||||
public BuilderRemoteViews(String packageName, int layoutId) {
|
||||
super(packageName, layoutId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderRemoteViews clone() {
|
||||
Parcel p = Parcel.obtain();
|
||||
writeToParcel(p, 0);
|
||||
p.setDataPosition(0);
|
||||
BuilderRemoteViews brv = new BuilderRemoteViews(p);
|
||||
p.recycle();
|
||||
return brv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package android.app;
|
||||
|
||||
import android.app.Notification.Builder;
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
@@ -132,9 +133,11 @@ public class NotificationManager
|
||||
}
|
||||
}
|
||||
if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
|
||||
Notification stripped = notification.clone();
|
||||
Builder.stripForDelivery(stripped);
|
||||
try {
|
||||
service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
|
||||
notification, idOut, UserHandle.myUserId());
|
||||
stripped, idOut, UserHandle.myUserId());
|
||||
if (id != idOut[0]) {
|
||||
Log.w(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]);
|
||||
}
|
||||
@@ -157,9 +160,11 @@ public class NotificationManager
|
||||
}
|
||||
}
|
||||
if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
|
||||
Notification stripped = notification.clone();
|
||||
Builder.stripForDelivery(stripped);
|
||||
try {
|
||||
service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
|
||||
notification, idOut, user.getIdentifier());
|
||||
stripped, idOut, user.getIdentifier());
|
||||
if (id != idOut[0]) {
|
||||
Log.w(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ package android.service.notification;
|
||||
import android.annotation.SystemApi;
|
||||
import android.annotation.SdkConstant;
|
||||
import android.app.INotificationManager;
|
||||
import android.app.Notification;
|
||||
import android.app.Notification.Builder;
|
||||
import android.app.Service;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
@@ -70,6 +72,11 @@ public abstract class NotificationListenerService extends Service {
|
||||
/** Only valid after a successful call to (@link registerAsService}. */
|
||||
private int mCurrentUser;
|
||||
|
||||
|
||||
// This context is required for system services since NotificationListenerService isn't
|
||||
// started as a real Service and hence no context is available.
|
||||
private Context mSystemContext;
|
||||
|
||||
/**
|
||||
* The {@link Intent} that must be declared as handled by the service.
|
||||
*/
|
||||
@@ -290,7 +297,13 @@ public abstract class NotificationListenerService extends Service {
|
||||
ParceledListSlice<StatusBarNotification> parceledList =
|
||||
getNotificationInterface().getActiveNotificationsFromListener(mWrapper);
|
||||
List<StatusBarNotification> list = parceledList.getList();
|
||||
return list.toArray(new StatusBarNotification[list.size()]);
|
||||
|
||||
int N = list.size();
|
||||
for (int i = 0; i < N; i++) {
|
||||
Notification notification = list.get(i).getNotification();
|
||||
Builder.rebuild(getContext(), notification);
|
||||
}
|
||||
return list.toArray(new StatusBarNotification[N]);
|
||||
} catch (android.os.RemoteException ex) {
|
||||
Log.v(TAG, "Unable to contact notification manager", ex);
|
||||
}
|
||||
@@ -379,13 +392,16 @@ public abstract class NotificationListenerService extends Service {
|
||||
* <p>Only system services may use this call. It will fail for non-system callers.
|
||||
* Apps should ask the user to add their listener in Settings.
|
||||
*
|
||||
* @param context Context required for accessing resources. Since this service isn't
|
||||
* launched as a real Service when using this method, a context has to be passed in.
|
||||
* @param componentName the component that will consume the notification information
|
||||
* @param currentUser the user to use as the stream filter
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public void registerAsSystemService(ComponentName componentName, int currentUser)
|
||||
throws RemoteException {
|
||||
public void registerAsSystemService(Context context, ComponentName componentName,
|
||||
int currentUser) throws RemoteException {
|
||||
mSystemContext = context;
|
||||
if (mWrapper == null) {
|
||||
mWrapper = new INotificationListenerWrapper();
|
||||
}
|
||||
@@ -413,6 +429,8 @@ public abstract class NotificationListenerService extends Service {
|
||||
@Override
|
||||
public void onNotificationPosted(StatusBarNotification sbn,
|
||||
NotificationRankingUpdate update) {
|
||||
Notification.Builder.rebuild(getContext(), sbn.getNotification());
|
||||
|
||||
// protect subclass from concurrent modifications of (@link mNotificationKeys}.
|
||||
synchronized (mWrapper) {
|
||||
applyUpdate(update);
|
||||
@@ -475,6 +493,13 @@ public abstract class NotificationListenerService extends Service {
|
||||
mRankingMap = new RankingMap(update);
|
||||
}
|
||||
|
||||
private Context getContext() {
|
||||
if (mSystemContext != null) {
|
||||
return mSystemContext;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores ranking related information on a currently active notification.
|
||||
*
|
||||
|
||||
@@ -2575,6 +2575,15 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of actions in this RemoteViews. Can be used as a sequence number.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public int getSequenceNumber() {
|
||||
return (mActions == null) ? 0 : mActions.size();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* Used to restrict the views which can be inflated
|
||||
*
|
||||
|
||||
@@ -462,7 +462,7 @@ public abstract class BaseStatusBar extends SystemUI implements
|
||||
|
||||
// Set up the initial notification state.
|
||||
try {
|
||||
mNotificationListener.registerAsSystemService(
|
||||
mNotificationListener.registerAsSystemService(mContext,
|
||||
new ComponentName(mContext.getPackageName(), getClass().getCanonicalName()),
|
||||
UserHandle.USER_ALL);
|
||||
} catch (RemoteException e) {
|
||||
|
||||
@@ -29,6 +29,7 @@ import android.app.IActivityManager;
|
||||
import android.app.INotificationManager;
|
||||
import android.app.ITransientNotification;
|
||||
import android.app.Notification;
|
||||
import android.app.Notification.Builder;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.StatusBarManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
@@ -1554,8 +1555,8 @@ public class NotificationManagerService extends SystemService {
|
||||
+ " id=" + id + " notification=" + notification);
|
||||
}
|
||||
if (notification.icon != 0) {
|
||||
if (notification.contentView == null) {
|
||||
throw new IllegalArgumentException("contentView required: pkg=" + pkg
|
||||
if (!notification.isValid()) {
|
||||
throw new IllegalArgumentException("Invalid notification (): pkg=" + pkg
|
||||
+ " id=" + id + " notification=" + notification);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user