Merge "Stop populating RemoteViews in Notifications."
diff --git a/api/current.txt b/api/current.txt
index 5cee2a3..15cc347 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4830,17 +4830,17 @@
field public android.app.Notification.Action[] actions;
field public android.media.AudioAttributes audioAttributes;
field public deprecated int audioStreamType;
- field public android.widget.RemoteViews bigContentView;
+ field public deprecated android.widget.RemoteViews bigContentView;
field public java.lang.String category;
field public int color;
field public android.app.PendingIntent contentIntent;
- field public android.widget.RemoteViews contentView;
+ field public deprecated android.widget.RemoteViews contentView;
field public int defaults;
field public android.app.PendingIntent deleteIntent;
field public android.os.Bundle extras;
field public int flags;
field public android.app.PendingIntent fullScreenIntent;
- field public android.widget.RemoteViews headsUpContentView;
+ field public deprecated android.widget.RemoteViews headsUpContentView;
field public deprecated int icon;
field public int iconLevel;
field public deprecated android.graphics.Bitmap largeIcon;
@@ -4931,14 +4931,22 @@
method public android.app.Notification.Builder extend(android.app.Notification.Extender);
method public android.os.Bundle getExtras();
method public deprecated android.app.Notification getNotification();
+ method public android.widget.RemoteViews makeBigContentView();
+ method public android.widget.RemoteViews makeContentView();
+ method public android.widget.RemoteViews makeHeadsUpContentView();
+ method public static android.app.Notification.Builder recoverBuilder(android.content.Context, android.app.Notification);
+ method public android.app.Notification.Builder setActions(android.app.Notification.Action...);
method public android.app.Notification.Builder setAutoCancel(boolean);
method public android.app.Notification.Builder setCategory(java.lang.String);
method public android.app.Notification.Builder setColor(int);
- method public android.app.Notification.Builder setContent(android.widget.RemoteViews);
+ method public deprecated android.app.Notification.Builder setContent(android.widget.RemoteViews);
method public android.app.Notification.Builder setContentInfo(java.lang.CharSequence);
method public android.app.Notification.Builder setContentIntent(android.app.PendingIntent);
method public android.app.Notification.Builder setContentText(java.lang.CharSequence);
method public android.app.Notification.Builder setContentTitle(java.lang.CharSequence);
+ method public android.app.Notification.Builder setCustomBigContentView(android.widget.RemoteViews);
+ method public android.app.Notification.Builder setCustomContentView(android.widget.RemoteViews);
+ method public android.app.Notification.Builder setCustomHeadsUpContentView(android.widget.RemoteViews);
method public android.app.Notification.Builder setDefaults(int);
method public android.app.Notification.Builder setDeleteIntent(android.app.PendingIntent);
method public android.app.Notification.Builder setExtras(android.os.Bundle);
diff --git a/api/system-current.txt b/api/system-current.txt
index bdba865..a9a8753 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4947,17 +4947,17 @@
field public android.app.Notification.Action[] actions;
field public android.media.AudioAttributes audioAttributes;
field public deprecated int audioStreamType;
- field public android.widget.RemoteViews bigContentView;
+ field public deprecated android.widget.RemoteViews bigContentView;
field public java.lang.String category;
field public int color;
field public android.app.PendingIntent contentIntent;
- field public android.widget.RemoteViews contentView;
+ field public deprecated android.widget.RemoteViews contentView;
field public int defaults;
field public android.app.PendingIntent deleteIntent;
field public android.os.Bundle extras;
field public int flags;
field public android.app.PendingIntent fullScreenIntent;
- field public android.widget.RemoteViews headsUpContentView;
+ field public deprecated android.widget.RemoteViews headsUpContentView;
field public deprecated int icon;
field public int iconLevel;
field public deprecated android.graphics.Bitmap largeIcon;
@@ -5048,14 +5048,22 @@
method public android.app.Notification.Builder extend(android.app.Notification.Extender);
method public android.os.Bundle getExtras();
method public deprecated android.app.Notification getNotification();
+ method public android.widget.RemoteViews makeBigContentView();
+ method public android.widget.RemoteViews makeContentView();
+ method public android.widget.RemoteViews makeHeadsUpContentView();
+ method public static android.app.Notification.Builder recoverBuilder(android.content.Context, android.app.Notification);
+ method public android.app.Notification.Builder setActions(android.app.Notification.Action...);
method public android.app.Notification.Builder setAutoCancel(boolean);
method public android.app.Notification.Builder setCategory(java.lang.String);
method public android.app.Notification.Builder setColor(int);
- method public android.app.Notification.Builder setContent(android.widget.RemoteViews);
+ method public deprecated android.app.Notification.Builder setContent(android.widget.RemoteViews);
method public android.app.Notification.Builder setContentInfo(java.lang.CharSequence);
method public android.app.Notification.Builder setContentIntent(android.app.PendingIntent);
method public android.app.Notification.Builder setContentText(java.lang.CharSequence);
method public android.app.Notification.Builder setContentTitle(java.lang.CharSequence);
+ method public android.app.Notification.Builder setCustomBigContentView(android.widget.RemoteViews);
+ method public android.app.Notification.Builder setCustomContentView(android.widget.RemoteViews);
+ method public android.app.Notification.Builder setCustomHeadsUpContentView(android.widget.RemoteViews);
method public android.app.Notification.Builder setDefaults(int);
method public android.app.Notification.Builder setDeleteIntent(android.app.PendingIntent);
method public android.app.Notification.Builder setExtras(android.os.Bundle);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index db18722..49edff4 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -251,15 +251,26 @@
public RemoteViews tickerView;
/**
- * The view that will represent this notification in the expanded status bar.
+ * The view that will represent this notification in the notification list (which is pulled
+ * down from the status bar).
+ *
+ * As of N, this field is not used. The notification view is determined by the inputs to
+ * {@link Notification.Builder}; a custom RemoteViews can optionally be
+ * supplied with {@link Notification.Builder#setCustomContentView(RemoteViews)}.
*/
+ @Deprecated
public RemoteViews contentView;
/**
* A large-format version of {@link #contentView}, giving the Notification an
* opportunity to show more detail. The system UI may choose to show this
* instead of the normal content view at its discretion.
+ *
+ * As of N, this field is not used. The expanded notification view is determined by the
+ * inputs to {@link Notification.Builder}; a custom RemoteViews can optionally be
+ * supplied with {@link Notification.Builder#setCustomBigContentView(RemoteViews)}.
*/
+ @Deprecated
public RemoteViews bigContentView;
@@ -268,7 +279,12 @@
* opportunity to add action buttons to contentView. At its discretion, the system UI may
* choose to show this as a heads-up notification, which will pop up so the user can see
* it without leaving their current activity.
+ *
+ * As of N, this field is not used. The heads-up notification view is determined by the
+ * inputs to {@link Notification.Builder}; a custom RemoteViews can optionally be
+ * supplied with {@link Notification.Builder#setCustomHeadsUpContentView(RemoteViews)}.
*/
+ @Deprecated
public RemoteViews headsUpContentView;
/**
@@ -867,6 +883,11 @@
public static final String EXTRA_ORIGINATING_USERID = "android.originatingUserId";
/**
+ * @hide
+ */
+ public static final String EXTRA_BUILDER_APPLICATION_INFO = "android.appInfo";
+
+ /**
* Value for {@link #EXTRA_AS_HEADS_UP} that indicates this notification should not be
* displayed in the heads up space.
*
@@ -1707,8 +1728,6 @@
extras.remove(Notification.EXTRA_LARGE_ICON_BIG);
extras.remove(Notification.EXTRA_PICTURE);
extras.remove(Notification.EXTRA_BIG_TEXT);
- // Prevent light notifications from being rebuilt.
- extras.remove(Builder.EXTRA_NEEDS_REBUILD);
}
}
@@ -1901,21 +1920,13 @@
@Deprecated
public void setLatestEventInfo(Context context,
CharSequence contentTitle, CharSequence contentText, PendingIntent contentIntent) {
- Notification.Builder builder = new Notification.Builder(context);
+ if (context.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1){
+ Log.e(TAG, "setLatestEventInfo() is deprecated and you should feel deprecated.",
+ new Throwable());
+ }
- // First, ensure that key pieces of information that may have been set directly
- // are preserved
- builder.setWhen(this.when);
- builder.setSmallIcon(this.icon);
- builder.setPriority(this.priority);
- builder.setTicker(this.tickerText);
- builder.setNumber(this.number);
- builder.setColor(this.color);
- builder.mFlags = this.flags;
- builder.setSound(this.sound, this.audioStreamType);
- builder.setDefaults(this.defaults);
- builder.setVibrate(this.vibrate);
- builder.setDeleteIntent(this.deleteIntent);
+ // ensure that any information already set directly is preserved
+ final Notification.Builder builder = new Notification.Builder(context, this);
// now apply the latestEventInfo fields
if (contentTitle != null) {
@@ -1925,7 +1936,8 @@
builder.setContentText(contentText);
}
builder.setContentIntent(contentIntent);
- builder.buildInto(this);
+
+ builder.build(); // callers expect this notification to be ready to use
}
@Override
@@ -2080,15 +2092,6 @@
/**
* @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);
- }
-
- /**
- * @hide
- */
public boolean isGroupSummary() {
return mGroupKey != null && (flags & FLAG_GROUP_SUMMARY) != 0;
}
@@ -2125,99 +2128,14 @@
private static final int MAX_ACTION_BUTTONS = 3;
private static final float LARGE_TEXT_SCALE = 1.3f;
- /**
- * @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 ApplicationInfo of the package that created the notification, used to create
- * a context to rebuild the notification via a Builder.
- * @hide
- */
- private static final String EXTRA_REBUILD_CONTEXT_APPLICATION_INFO =
- "android.rebuild.applicationInfo";
-
- // 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;
- private Icon mSmallIcon, mLargeIcon;
- private int mSmallIconLevel;
- private int mNumber;
- private CharSequence mContentTitle;
- private CharSequence mContentText;
- private CharSequence mContentInfo;
- private CharSequence mSubText;
- private PendingIntent mContentIntent;
- private RemoteViews mContentView;
- private PendingIntent mDeleteIntent;
- private PendingIntent mFullScreenIntent;
- private CharSequence mTickerText;
- private RemoteViews mTickerView;
- private Uri mSound;
- private int mAudioStreamType;
- private AudioAttributes mAudioAttributes;
- private long[] mVibrate;
- private int mLedArgb;
- private int mLedOnMs;
- private int mLedOffMs;
- private int mDefaults;
- private int mFlags;
- private int mProgressMax;
- private int mProgress;
- private boolean mProgressIndeterminate;
- private String mCategory;
- private String mGroupKey;
- private String mSortKey;
- private Bundle mExtras;
- private int mPriority;
- private ArrayList<Action> mActions = new ArrayList<Action>(MAX_ACTION_BUTTONS);
- private boolean mUseChronometer;
+ private Notification mN;
+ private Bundle mUserExtras = new Bundle();
private Style mStyle;
- private boolean mShowWhen = true;
- private int mVisibility = VISIBILITY_PRIVATE;
- private Notification mPublicVersion = null;
- private final NotificationColorUtil mColorUtil;
- private ArrayList<String> mPeople;
- private int mColor = COLOR_DEFAULT;
+ private ArrayList<Action> mActions = new ArrayList<Action>(MAX_ACTION_BUTTONS);
+ private ArrayList<String> mPersonList = new ArrayList<String>();
+ private NotificationColorUtil mColorUtil;
+ private boolean mColorUtilInited = false;
private List<Topic> mTopics = new ArrayList<>();
/**
@@ -2226,25 +2144,6 @@
private int mOriginatingUserId;
/**
- * 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;
-
- /**
- * Whether the build notification has three lines. This is used to make the top padding for
- * both the contracted and expanded layout consistent.
- *
- * <p>
- * This field is only valid during the build phase.
- */
- private boolean mHasThreeLines;
-
- /**
* Constructs a new Builder with the defaults:
*
@@ -2264,61 +2163,67 @@
* object.
*/
public Builder(Context context) {
- /*
- * Important compatibility note!
- * Some apps out in the wild create a Notification.Builder in their Activity subclass
- * constructor for later use. At this point Activities - themselves subclasses of
- * ContextWrapper - do not have their inner Context populated yet. This means that
- * any calls to Context methods from within this constructor can cause NPEs in existing
- * apps. Any data populated from mContext should therefore be populated lazily to
- * preserve compatibility.
- */
- mContext = context;
-
- // Set defaults to match the defaults of a Notification
- mWhen = System.currentTimeMillis();
- mAudioStreamType = STREAM_DEFAULT;
- mAudioAttributes = AUDIO_ATTRIBUTES_DEFAULT;
- mPriority = PRIORITY_DEFAULT;
- mPeople = new ArrayList<String>();
-
- mColorUtil = context.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.LOLLIPOP ?
- NotificationColorUtil.getInstance(mContext) : null;
+ this(context, null);
}
/**
- * Creates a Builder for rebuilding the given Notification.
- * <p>
- * Call {@link #rebuild()} to retrieve the rebuilt version of 'n'.
+ * @hide
*/
- private Builder(Context context, Notification n) {
- this(context);
- mRebuildNotification = n;
- restoreFromNotification(n);
+ public Builder(Context context, Notification toAdopt) {
+ mContext = context;
- 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;
+ if (toAdopt == null) {
+ mN = new Notification();
+ mN.extras.putBoolean(EXTRA_SHOW_WHEN, true);
+ mN.priority = PRIORITY_DEFAULT;
+ mN.visibility = VISIBILITY_PRIVATE;
+ } else {
+ mN = toAdopt;
+ if (mN.actions != null) {
+ Collections.addAll(mActions, mN.actions);
}
- try {
- Constructor<? extends Style> constructor = styleClass.getConstructor();
- constructor.setAccessible(true);
- style = constructor.newInstance();
- style.restoreFromExtras(extras);
- } catch (Throwable t) {
- Log.e(TAG, "Could not create Style", t);
- return;
+ if (mN.extras.containsKey(EXTRA_PEOPLE)) {
+ Collections.addAll(mPersonList, mN.extras.getStringArray(EXTRA_PEOPLE));
+ }
+
+ if (mN.getTopics() != null) {
+ Collections.addAll(mTopics, mN.getTopics());
+ }
+
+ String templateClass = mN.extras.getString(EXTRA_TEMPLATE);
+ if (!TextUtils.isEmpty(templateClass)) {
+ final Class<? extends Style> styleClass
+ = getNotificationStyleClass(templateClass);
+ if (styleClass == null) {
+ Log.d(TAG, "Unknown style class: " + templateClass);
+ } else {
+ try {
+ final Constructor<? extends Style> ctor = styleClass.getConstructor();
+ ctor.setAccessible(true);
+ final Style style = ctor.newInstance();
+ style.restoreFromExtras(mN.extras);
+
+ if (style != null) {
+ setStyle(style);
+ }
+ } catch (Throwable t) {
+ Log.e(TAG, "Could not create Style", t);
+ }
+ }
+ }
+
+ }
+ }
+
+ private NotificationColorUtil getColorUtil() {
+ if (!mColorUtilInited) {
+ mColorUtilInited = true;
+ if (mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.LOLLIPOP) {
+ mColorUtil = NotificationColorUtil.getInstance(mContext);
}
}
- if (style != null) {
- setStyle(style);
- }
+ return mColorUtil;
}
/**
@@ -2329,7 +2234,7 @@
* @see Notification#when
*/
public Builder setWhen(long when) {
- mWhen = when;
+ mN.when = when;
return this;
}
@@ -2338,7 +2243,7 @@
* in the content view.
*/
public Builder setShowWhen(boolean show) {
- mShowWhen = show;
+ mN.extras.putBoolean(EXTRA_SHOW_WHEN, show);
return this;
}
@@ -2354,7 +2259,7 @@
* @see Notification#when
*/
public Builder setUsesChronometer(boolean b) {
- mUseChronometer = b;
+ mN.extras.putBoolean(EXTRA_SHOW_CHRONOMETER, b);
return this;
}
@@ -2390,7 +2295,7 @@
* @see Notification#iconLevel
*/
public Builder setSmallIcon(@DrawableRes int icon, int level) {
- mSmallIconLevel = level;
+ mN.iconLevel = level;
return setSmallIcon(icon);
}
@@ -2403,7 +2308,10 @@
* @see Notification#icon
*/
public Builder setSmallIcon(Icon icon) {
- mSmallIcon = icon;
+ mN.setSmallIcon(icon);
+ if (icon != null && icon.getType() == Icon.TYPE_RESOURCE) {
+ mN.icon = icon.getResId();
+ }
return this;
}
@@ -2411,7 +2319,7 @@
* Set the first line of text in the platform notification template.
*/
public Builder setContentTitle(CharSequence title) {
- mContentTitle = safeCharSequence(title);
+ mN.extras.putCharSequence(EXTRA_TITLE, safeCharSequence(title));
return this;
}
@@ -2419,7 +2327,7 @@
* Set the second line of text in the platform notification template.
*/
public Builder setContentText(CharSequence text) {
- mContentText = safeCharSequence(text);
+ mN.extras.putCharSequence(EXTRA_TEXT, safeCharSequence(text));
return this;
}
@@ -2429,7 +2337,7 @@
* same location in the standard template.
*/
public Builder setSubText(CharSequence text) {
- mSubText = safeCharSequence(text);
+ mN.extras.putCharSequence(EXTRA_SUB_TEXT, safeCharSequence(text));
return this;
}
@@ -2439,7 +2347,7 @@
* font size for readability.
*/
public Builder setNumber(int number) {
- mNumber = number;
+ mN.number = number;
return this;
}
@@ -2450,7 +2358,7 @@
* right (to the right of a smallIcon if it has been placed there).
*/
public Builder setContentInfo(CharSequence info) {
- mContentInfo = safeCharSequence(info);
+ mN.extras.putCharSequence(EXTRA_INFO_TEXT, safeCharSequence(info));
return this;
}
@@ -2460,19 +2368,52 @@
* The platform template will represent this using a {@link ProgressBar}.
*/
public Builder setProgress(int max, int progress, boolean indeterminate) {
- mProgressMax = max;
- mProgress = progress;
- mProgressIndeterminate = indeterminate;
+ mN.extras.putInt(EXTRA_PROGRESS, progress);
+ mN.extras.putInt(EXTRA_PROGRESS_MAX, max);
+ mN.extras.putBoolean(EXTRA_PROGRESS_INDETERMINATE, indeterminate);
return this;
}
/**
* Supply a custom RemoteViews to use instead of the platform template.
*
- * @see Notification#contentView
+ * Use {@link #setCustomContentView(RemoteViews)} instead.
*/
+ @Deprecated
public Builder setContent(RemoteViews views) {
- mContentView = views;
+ return setCustomContentView(views);
+ }
+
+ /**
+ * Supply custom RemoteViews to use instead of the platform template.
+ *
+ * This will override the layout that would otherwise be constructed by this Builder
+ * object.
+ */
+ public Builder setCustomContentView(RemoteViews contentView) {
+ mN.contentView = contentView;
+ return this;
+ }
+
+ /**
+ * Supply custom RemoteViews to use instead of the platform template in the expanded form.
+ *
+ * This will override the expanded layout that would otherwise be constructed by this
+ * Builder object.
+ */
+ public Builder setCustomBigContentView(RemoteViews contentView) {
+ mN.bigContentView = contentView;
+ return this;
+ }
+
+ /**
+ * Supply custom RemoteViews to use instead of the platform template in the heads up dialog.
+ *
+ * This will override the heads-up layout that would otherwise be constructed by this
+ * Builder object.
+ */
+ public Builder setCustomHeadsUpContentView(RemoteViews contentView) {
+ mN.headsUpContentView = contentView;
return this;
}
@@ -2488,7 +2429,7 @@
* @see Notification#contentIntent Notification.contentIntent
*/
public Builder setContentIntent(PendingIntent intent) {
- mContentIntent = intent;
+ mN.contentIntent = intent;
return this;
}
@@ -2498,7 +2439,7 @@
* @see Notification#deleteIntent
*/
public Builder setDeleteIntent(PendingIntent intent) {
- mDeleteIntent = intent;
+ mN.deleteIntent = intent;
return this;
}
@@ -2523,7 +2464,7 @@
* @see Notification#fullScreenIntent
*/
public Builder setFullScreenIntent(PendingIntent intent, boolean highPriority) {
- mFullScreenIntent = intent;
+ mN.fullScreenIntent = intent;
setFlag(FLAG_HIGH_PRIORITY, highPriority);
return this;
}
@@ -2534,7 +2475,7 @@
* @see Notification#tickerText
*/
public Builder setTicker(CharSequence tickerText) {
- mTickerText = safeCharSequence(tickerText);
+ mN.tickerText = safeCharSequence(tickerText);
return this;
}
@@ -2544,8 +2485,8 @@
*/
@Deprecated
public Builder setTicker(CharSequence tickerText, RemoteViews views) {
- mTickerText = safeCharSequence(tickerText);
- mTickerView = views; // we'll save it for you anyway
+ setTicker(tickerText);
+ // views is ignored
return this;
}
@@ -2568,7 +2509,8 @@
* badge atop the large icon).
*/
public Builder setLargeIcon(Icon icon) {
- mLargeIcon = icon;
+ mN.mLargeIcon = icon;
+ mN.extras.putParcelable(EXTRA_LARGE_ICON, icon);
return this;
}
@@ -2585,8 +2527,8 @@
* @see Notification#sound
*/
public Builder setSound(Uri sound) {
- mSound = sound;
- mAudioAttributes = AUDIO_ATTRIBUTES_DEFAULT;
+ mN.sound = sound;
+ mN.audioAttributes = AUDIO_ATTRIBUTES_DEFAULT;
return this;
}
@@ -2603,8 +2545,8 @@
*/
@Deprecated
public Builder setSound(Uri sound, int streamType) {
- mSound = sound;
- mAudioStreamType = streamType;
+ mN.sound = sound;
+ mN.audioStreamType = streamType;
return this;
}
@@ -2619,8 +2561,8 @@
* @see Notification#sound
*/
public Builder setSound(Uri sound, AudioAttributes audioAttributes) {
- mSound = sound;
- mAudioAttributes = audioAttributes;
+ mN.sound = sound;
+ mN.audioAttributes = audioAttributes;
return this;
}
@@ -2637,7 +2579,7 @@
* @see Notification#vibrate
*/
public Builder setVibrate(long[] pattern) {
- mVibrate = pattern;
+ mN.vibrate = pattern;
return this;
}
@@ -2654,9 +2596,9 @@
* @see Notification#ledOffMS
*/
public Builder setLights(@ColorInt int argb, int onMs, int offMs) {
- mLedArgb = argb;
- mLedOnMs = onMs;
- mLedOffMs = offMs;
+ mN.ledARGB = argb;
+ mN.ledOnMS = onMs;
+ mN.ledOffMS = offMs;
return this;
}
@@ -2724,7 +2666,7 @@
* For all default values, use {@link #DEFAULT_ALL}.
*/
public Builder setDefaults(int defaults) {
- mDefaults = defaults;
+ mN.defaults = defaults;
return this;
}
@@ -2734,7 +2676,7 @@
* @see Notification#priority
*/
public Builder setPriority(@Priority int pri) {
- mPriority = pri;
+ mN.priority = pri;
return this;
}
@@ -2744,7 +2686,7 @@
* @see Notification#category
*/
public Builder setCategory(String category) {
- mCategory = category;
+ mN.category = category;
return this;
}
@@ -2771,7 +2713,7 @@
* @see Notification#EXTRA_PEOPLE
*/
public Builder addPerson(String uri) {
- mPeople.add(uri);
+ mPersonList.add(uri);
return this;
}
@@ -2787,7 +2729,7 @@
* @return this object for method chaining
*/
public Builder setGroup(String groupKey) {
- mGroupKey = groupKey;
+ mN.mGroupKey = groupKey;
return this;
}
@@ -2816,7 +2758,7 @@
* @see String#compareTo(String)
*/
public Builder setSortKey(String sortKey) {
- mSortKey = sortKey;
+ mN.mSortKey = sortKey;
return this;
}
@@ -2829,11 +2771,7 @@
*/
public Builder addExtras(Bundle extras) {
if (extras != null) {
- if (mExtras == null) {
- mExtras = new Bundle(extras);
- } else {
- mExtras.putAll(extras);
- }
+ mUserExtras.putAll(extras);
}
return this;
}
@@ -2851,7 +2789,9 @@
* @see Notification#extras
*/
public Builder setExtras(Bundle extras) {
- mExtras = extras;
+ if (extras != null) {
+ mUserExtras = extras;
+ }
return this;
}
@@ -2866,10 +2806,13 @@
* @see Notification#extras
*/
public Bundle getExtras() {
- if (mExtras == null) {
- mExtras = new Bundle();
- }
- return mExtras;
+ return mUserExtras;
+ }
+
+ private Bundle getAllExtras() {
+ final Bundle saveExtras = (Bundle) mUserExtras.clone();
+ saveExtras.putAll(mN.extras);
+ return saveExtras;
}
/**
@@ -2918,6 +2861,21 @@
}
/**
+ * Alter the complete list of actions attached to this notification.
+ * @see #addAction(Action).
+ *
+ * @param actions
+ * @return
+ */
+ public Builder setActions(Action... actions) {
+ mActions.clear();
+ for (int i = 0; i < actions.length; i++) {
+ mActions.add(actions[i]);
+ }
+ return this;
+ }
+
+ /**
* Add a rich notification style to be applied at build time.
*
* @param style Object responsible for modifying the notification style.
@@ -2927,6 +2885,9 @@
mStyle = style;
if (mStyle != null) {
mStyle.setBuilder(this);
+ mN.extras.putString(EXTRA_TEMPLATE, style.getClass().getName());
+ } else {
+ mN.extras.remove(EXTRA_TEMPLATE);
}
}
return this;
@@ -2941,7 +2902,7 @@
* @return The same Builder.
*/
public Builder setVisibility(int visibility) {
- mVisibility = visibility;
+ mN.visibility = visibility;
return this;
}
@@ -2952,7 +2913,12 @@
* @return The same Builder.
*/
public Builder setPublicVersion(Notification n) {
- mPublicVersion = n;
+ if (n != null) {
+ mN.publicVersion = new Notification();
+ n.cloneInto(mN.publicVersion, /*heavy=*/ true);
+ } else {
+ mN.publicVersion = null;
+ }
return this;
}
@@ -2970,9 +2936,9 @@
*/
public void setFlag(int mask, boolean value) {
if (value) {
- mFlags |= mask;
+ mN.flags |= mask;
} else {
- mFlags &= ~mask;
+ mN.flags &= ~mask;
}
}
@@ -2984,7 +2950,7 @@
* @return The same Builder.
*/
public Builder setColor(@ColorInt int argb) {
- mColor = argb;
+ mN.color = argb;
return this;
}
@@ -3075,7 +3041,6 @@
contentView.setViewVisibility(R.id.overflow_divider, View.GONE);
contentView.setViewVisibility(R.id.progress, View.GONE);
contentView.setViewVisibility(R.id.chronometer, View.GONE);
- contentView.setViewVisibility(R.id.time, View.GONE);
}
private RemoteViews applyStandardTemplate(int resId) {
@@ -3093,39 +3058,43 @@
boolean showLine3 = false;
boolean showLine2 = false;
boolean contentTextInLine2 = false;
+ final Bundle ex = mN.extras;
- if (mLargeIcon != null) {
- contentView.setImageViewIcon(R.id.icon, mLargeIcon);
- processLargeLegacyIcon(mLargeIcon, contentView);
- contentView.setImageViewIcon(R.id.right_icon, mSmallIcon);
+ if (mN.mLargeIcon != null) {
+ contentView.setImageViewIcon(R.id.icon, mN.mLargeIcon);
+ processLargeLegacyIcon(mN.mLargeIcon, contentView);
+ contentView.setImageViewIcon(R.id.right_icon, mN.mSmallIcon);
contentView.setViewVisibility(R.id.right_icon, View.VISIBLE);
- processSmallRightIcon(mSmallIcon, contentView);
+ processSmallRightIcon(mN.mSmallIcon, contentView);
} else { // small icon at left
- contentView.setImageViewIcon(R.id.icon, mSmallIcon);
+ contentView.setImageViewIcon(R.id.icon, mN.mSmallIcon);
contentView.setViewVisibility(R.id.icon, View.VISIBLE);
- processSmallIconAsLarge(mSmallIcon, contentView);
+ processSmallIconAsLarge(mN.mSmallIcon, contentView);
}
- if (mContentTitle != null) {
- contentView.setTextViewText(R.id.title, processLegacyText(mContentTitle));
+ if (ex.getCharSequence(EXTRA_TITLE) != null) {
+ contentView.setTextViewText(R.id.title,
+ processLegacyText(ex.getCharSequence(EXTRA_TITLE)));
}
- if (mContentText != null) {
- contentView.setTextViewText(R.id.text, processLegacyText(mContentText));
+ if (ex.getCharSequence(EXTRA_TEXT) != null) {
+ contentView.setTextViewText(R.id.text,
+ processLegacyText(ex.getCharSequence(EXTRA_TEXT)));
showLine3 = true;
}
- if (mContentInfo != null) {
- contentView.setTextViewText(R.id.info, processLegacyText(mContentInfo));
+ if (ex.getCharSequence(EXTRA_INFO_TEXT) != null) {
+ contentView.setTextViewText(R.id.info,
+ processLegacyText(ex.getCharSequence(EXTRA_INFO_TEXT)));
contentView.setViewVisibility(R.id.info, View.VISIBLE);
showLine3 = true;
- } else if (mNumber > 0) {
+ } else if (mN.number > 0) {
final int tooBig = mContext.getResources().getInteger(
R.integer.status_bar_notification_info_maxnum);
- if (mNumber > tooBig) {
+ if (mN.number > tooBig) {
contentView.setTextViewText(R.id.info, processLegacyText(
mContext.getResources().getString(
R.string.status_bar_notification_info_overflow)));
} else {
NumberFormat f = NumberFormat.getIntegerInstance();
- contentView.setTextViewText(R.id.info, processLegacyText(f.format(mNumber)));
+ contentView.setTextViewText(R.id.info, processLegacyText(f.format(mN.number)));
}
contentView.setViewVisibility(R.id.info, View.VISIBLE);
showLine3 = true;
@@ -3134,10 +3103,12 @@
}
// Need to show three lines?
- if (mSubText != null) {
- contentView.setTextViewText(R.id.text, processLegacyText(mSubText));
- if (mContentText != null) {
- contentView.setTextViewText(R.id.text2, processLegacyText(mContentText));
+ if (ex.getCharSequence(EXTRA_SUB_TEXT) != null) {
+ contentView.setTextViewText(R.id.text,
+ processLegacyText(ex.getCharSequence(EXTRA_SUB_TEXT)));
+ if (ex.getCharSequence(EXTRA_TEXT) != null) {
+ contentView.setTextViewText(R.id.text2,
+ processLegacyText(ex.getCharSequence(EXTRA_TEXT)));
contentView.setViewVisibility(R.id.text2, View.VISIBLE);
showLine2 = true;
contentTextInLine2 = true;
@@ -3146,15 +3117,18 @@
}
} else {
contentView.setViewVisibility(R.id.text2, View.GONE);
- if (hasProgress && (mProgressMax != 0 || mProgressIndeterminate)) {
+ final int max = ex.getInt(EXTRA_PROGRESS_MAX, 0);
+ final int progress = ex.getInt(EXTRA_PROGRESS, 0);
+ final boolean ind = ex.getBoolean(EXTRA_PROGRESS_INDETERMINATE);
+ if (hasProgress && (max != 0 || ind)) {
contentView.setViewVisibility(R.id.progress, View.VISIBLE);
contentView.setProgressBar(
- R.id.progress, mProgressMax, mProgress, mProgressIndeterminate);
+ R.id.progress, max, progress, ind);
contentView.setProgressBackgroundTintList(
R.id.progress, ColorStateList.valueOf(mContext.getColor(
R.color.notification_progress_background_color)));
- if (mColor != COLOR_DEFAULT) {
- ColorStateList colorStateList = ColorStateList.valueOf(mColor);
+ if (mN.color != COLOR_DEFAULT) {
+ ColorStateList colorStateList = ColorStateList.valueOf(mN.color);
contentView.setProgressTintList(R.id.progress, colorStateList);
contentView.setProgressIndeterminateTintList(R.id.progress, colorStateList);
}
@@ -3170,20 +3144,21 @@
}
if (showsTimeOrChronometer()) {
- if (mUseChronometer) {
+ if (ex.getBoolean(EXTRA_SHOW_CHRONOMETER)) {
contentView.setViewVisibility(R.id.chronometer, View.VISIBLE);
contentView.setLong(R.id.chronometer, "setBase",
- mWhen + (SystemClock.elapsedRealtime() - System.currentTimeMillis()));
+ mN.when + (SystemClock.elapsedRealtime() - System.currentTimeMillis()));
contentView.setBoolean(R.id.chronometer, "setStarted", true);
} else {
contentView.setViewVisibility(R.id.time, View.VISIBLE);
- contentView.setLong(R.id.time, "setTime", mWhen);
+ contentView.setLong(R.id.time, "setTime", mN.when);
}
}
// Adjust padding depending on line count and font size.
- contentView.setViewPadding(R.id.line1, 0, calculateTopPadding(mContext,
- mHasThreeLines, mContext.getResources().getConfiguration().fontScale),
+ contentView.setViewPadding(R.id.line1, 0,
+ calculateTopPadding(mContext, hasThreeLines(),
+ mContext.getResources().getConfiguration().fontScale),
0, 0);
// We want to add badge to first line of text.
@@ -3196,7 +3171,8 @@
// Note getStandardView may hide line 3 again.
contentView.setViewVisibility(R.id.line3, showLine3 ? View.VISIBLE : View.GONE);
- contentView.setViewVisibility(R.id.overflow_divider, showLine3 ? View.VISIBLE : View.GONE);
+ contentView.setViewVisibility(R.id.overflow_divider,
+ showLine3 ? View.VISIBLE : View.GONE);
return contentView;
}
@@ -3205,7 +3181,7 @@
* otherwise
*/
private boolean showsTimeOrChronometer() {
- return mWhen != 0 && mShowWhen;
+ return mN.when != 0 && mN.extras.getBoolean(EXTRA_SHOW_WHEN);
}
/**
@@ -3216,15 +3192,19 @@
* is going to have one or two lines
*/
private boolean hasThreeLines() {
- boolean contentTextInLine2 = mSubText != null && mContentText != null;
+ final CharSequence subText = mN.extras.getCharSequence(EXTRA_SUB_TEXT);
+ final CharSequence text = mN.extras.getCharSequence(EXTRA_TEXT);
+ boolean contentTextInLine2 = subText != null && text != null;
boolean hasProgress = mStyle == null || mStyle.hasProgress();
// If we have content text in line 2, badge goes into line 2, or line 3 otherwise
boolean badgeInLine3 = getProfileBadgeDrawable() != null && !contentTextInLine2;
- boolean hasLine3 = mContentText != null || mContentInfo != null || mNumber > 0
- || badgeInLine3;
- boolean hasLine2 = (mSubText != null && mContentText != null) ||
- (hasProgress && mSubText == null
- && (mProgressMax != 0 || mProgressIndeterminate));
+ boolean hasLine3 = text != null || mN.extras.getCharSequence(EXTRA_INFO_TEXT) != null
+ || mN.number > 0 || badgeInLine3;
+ final Bundle ex = mN.extras;
+ final int max = ex.getInt(EXTRA_PROGRESS_MAX, 0);
+ final boolean ind = ex.getBoolean(EXTRA_PROGRESS_INDETERMINATE);
+ boolean hasLine2 = (subText != null && text != null) ||
+ (hasProgress && subText == null && (max != 0 || ind));
return hasLine2 && hasLine3;
}
@@ -3271,29 +3251,48 @@
return big;
}
- private RemoteViews makeContentView() {
- if (mContentView != null) {
- return mContentView;
- } else {
- return applyStandardTemplate(getBaseLayoutResource());
+ /**
+ * Construct a RemoteViews for the final 1U notification layout. In order:
+ * 1. Custom contentView from the caller
+ * 2. Style's proposed content view
+ * 3. Standard template view
+ */
+ public RemoteViews makeContentView() {
+ if (mN.contentView != null) {
+ return mN.contentView;
+ } else if (mStyle != null) {
+ final RemoteViews styleView = mStyle.makeContentView();
+ if (styleView != null) {
+ return styleView;
+ }
}
+ return applyStandardTemplate(getBaseLayoutResource());
}
- private RemoteViews makeTickerView() {
- if (mTickerView != null) {
- return mTickerView;
- }
- return null; // tickers are not created by default anymore
- }
-
- private RemoteViews makeBigContentView() {
- if (mActions.size() == 0) return null;
+ /**
+ * Construct a RemoteViews for the final big notification layout.
+ */
+ public RemoteViews makeBigContentView() {
+ if (mStyle != null) {
+ final RemoteViews styleView = mStyle.makeBigContentView();
+ if (styleView != null) {
+ return styleView;
+ }
+ } else if (mActions.size() == 0) return null;
return applyStandardTemplateWithActions(getBigBaseLayoutResource());
}
- private RemoteViews makeHeadsUpContentView() {
- if (mActions.size() == 0) return null;
+ /**
+ * Construct a RemoteViews for the final heads-up notification layout.
+ */
+ public RemoteViews makeHeadsUpContentView() {
+ if (mStyle != null) {
+ final RemoteViews styleView = mStyle.makeHeadsUpContentView();
+ if (styleView != null) {
+ return styleView;
+ }
+ } else if (mActions.size() == 0) return null;
return applyStandardTemplateWithActions(getBigBaseLayoutResource());
}
@@ -3320,11 +3319,11 @@
* doesn't create material notifications by itself) app.
*/
private boolean isLegacy() {
- return mColorUtil != null;
+ return getColorUtil() != null;
}
private void processLegacyAction(Action action, RemoteViews button) {
- if (!isLegacy() || mColorUtil.isGrayscaleIcon(mContext, action.getIcon())) {
+ if (!isLegacy() || getColorUtil().isGrayscaleIcon(mContext, action.getIcon())) {
button.setTextViewCompoundDrawablesRelativeColorFilter(R.id.action0, 0,
mContext.getColor(R.color.notification_action_color_filter),
PorterDuff.Mode.MULTIPLY);
@@ -3333,7 +3332,7 @@
private CharSequence processLegacyText(CharSequence charSequence) {
if (isLegacy()) {
- return mColorUtil.invertCharSequenceColors(charSequence);
+ return getColorUtil().invertCharSequenceColors(charSequence);
} else {
return charSequence;
}
@@ -3349,7 +3348,7 @@
PorterDuff.Mode.SRC_ATOP, -1);
applyLargeIconBackground(contentView);
} else {
- if (mColorUtil.isGrayscaleIcon(mContext, largeIcon)) {
+ if (getColorUtil().isGrayscaleIcon(mContext, largeIcon)) {
applyLargeIconBackground(contentView);
}
}
@@ -3362,7 +3361,7 @@
// TODO: also check bounds, transparency, that sort of thing.
private void processLargeLegacyIcon(Icon largeIcon, RemoteViews contentView) {
if (largeIcon != null && isLegacy()
- && mColorUtil.isGrayscaleIcon(mContext, largeIcon)) {
+ && getColorUtil().isGrayscaleIcon(mContext, largeIcon)) {
applyLargeIconBackground(contentView);
} else {
removeLargeIconBackground(contentView);
@@ -3404,7 +3403,7 @@
}
final boolean gray = isLegacy()
&& smallIcon.getType() == Icon.TYPE_RESOURCE
- && mColorUtil.isGrayscaleIcon(mContext, smallIcon.getResId());
+ && getColorUtil().isGrayscaleIcon(mContext, smallIcon.getResId());
if (!isLegacy() || gray) {
contentView.setInt(R.id.right_icon,
"setBackgroundResource",
@@ -3421,17 +3420,17 @@
}
private int sanitizeColor() {
- if (mColor != COLOR_DEFAULT) {
- mColor |= 0xFF000000; // no alpha for custom colors
+ if (mN.color != COLOR_DEFAULT) {
+ mN.color |= 0xFF000000; // no alpha for custom colors
}
- return mColor;
+ return mN.color;
}
private int resolveColor() {
- if (mColor == COLOR_DEFAULT) {
+ if (mN.color == COLOR_DEFAULT) {
return mContext.getColor(R.color.notification_icon_bg_color);
}
- return mColor;
+ return mN.color;
}
/**
@@ -3439,165 +3438,25 @@
* @hide
*/
public Notification buildUnstyled() {
- Notification n = new Notification();
- n.when = mWhen;
- n.mSmallIcon = mSmallIcon;
- if (mSmallIcon != null && mSmallIcon.getType() == Icon.TYPE_RESOURCE) {
- n.icon = mSmallIcon.getResId();
- }
- n.iconLevel = mSmallIconLevel;
- n.number = mNumber;
-
- n.color = sanitizeColor();
-
- setBuilderContentView(n, makeContentView());
- n.contentIntent = mContentIntent;
- n.deleteIntent = mDeleteIntent;
- n.fullScreenIntent = mFullScreenIntent;
- n.tickerText = mTickerText;
- n.tickerView = makeTickerView();
- n.mLargeIcon = mLargeIcon;
- if (mLargeIcon != null && mLargeIcon.getType() == Icon.TYPE_BITMAP) {
- n.largeIcon = mLargeIcon.getBitmap();
- }
- n.sound = mSound;
- n.audioStreamType = mAudioStreamType;
- n.audioAttributes = mAudioAttributes;
- n.vibrate = mVibrate;
- n.ledARGB = mLedArgb;
- n.ledOnMS = mLedOnMs;
- n.ledOffMS = mLedOffMs;
- n.defaults = mDefaults;
- n.flags = mFlags;
- setBuilderBigContentView(n, makeBigContentView());
- setBuilderHeadsUpContentView(n, makeHeadsUpContentView());
- if (mLedOnMs != 0 || mLedOffMs != 0) {
- n.flags |= FLAG_SHOW_LIGHTS;
- }
- if ((mDefaults & DEFAULT_LIGHTS) != 0) {
- n.flags |= FLAG_SHOW_LIGHTS;
- }
- n.category = mCategory;
- n.mGroupKey = mGroupKey;
- n.mSortKey = mSortKey;
- n.priority = mPriority;
if (mActions.size() > 0) {
- n.actions = new Action[mActions.size()];
- mActions.toArray(n.actions);
+ mN.actions = new Action[mActions.size()];
+ mActions.toArray(mN.actions);
}
- n.visibility = mVisibility;
-
- if (mPublicVersion != null) {
- n.publicVersion = new Notification();
- mPublicVersion.cloneInto(n.publicVersion, true);
+ if (!mPersonList.isEmpty()) {
+ mN.extras.putStringArray(EXTRA_PEOPLE,
+ mPersonList.toArray(new String[mPersonList.size()]));
}
if (mTopics.size() > 0) {
- n.topics = new Topic[mTopics.size()];
- mTopics.toArray(n.topics);
+ mN.topics = new Topic[mTopics.size()];
+ mTopics.toArray(mN.topics);
}
- // Note: If you're adding new fields, also update restoreFromNotitification().
- return n;
+ return mN;
}
- /**
- * Capture, in the provided bundle, semantic information used in the construction of
- * this Notification object.
- * @hide
- */
- public void populateExtras(Bundle extras) {
- // Store original information used in the construction of this object
- extras.putInt(EXTRA_ORIGINATING_USERID, mOriginatingUserId);
- extras.putParcelable(EXTRA_REBUILD_CONTEXT_APPLICATION_INFO,
- mContext.getApplicationInfo());
- extras.putCharSequence(EXTRA_TITLE, mContentTitle);
- extras.putCharSequence(EXTRA_TEXT, mContentText);
- extras.putCharSequence(EXTRA_SUB_TEXT, mSubText);
- extras.putCharSequence(EXTRA_INFO_TEXT, mContentInfo);
- extras.putParcelable(EXTRA_SMALL_ICON, mSmallIcon);
- extras.putInt(EXTRA_PROGRESS, mProgress);
- extras.putInt(EXTRA_PROGRESS_MAX, mProgressMax);
- extras.putBoolean(EXTRA_PROGRESS_INDETERMINATE, mProgressIndeterminate);
- extras.putBoolean(EXTRA_SHOW_CHRONOMETER, mUseChronometer);
- extras.putBoolean(EXTRA_SHOW_WHEN, mShowWhen);
- if (mLargeIcon != null) {
- extras.putParcelable(EXTRA_LARGE_ICON, mLargeIcon);
- }
- 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);
-
+ public static Notification.Builder recoverBuilder(Context context, Notification n) {
// Re-create notification context so we can access app resources.
- ApplicationInfo applicationInfo = extras.getParcelable(
- EXTRA_REBUILD_CONTEXT_APPLICATION_INFO);
+ ApplicationInfo applicationInfo = n.extras.getParcelable(
+ EXTRA_BUILDER_APPLICATION_INFO);
Context builderContext;
try {
builderContext = context.createApplicationContext(applicationInfo,
@@ -3607,58 +3466,7 @@
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.");
- }
- mHasThreeLines = hasThreeLines();
-
- 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);
-
- mHasThreeLines = false;
- return mRebuildNotification;
+ return new Builder(builderContext, n);
}
private static Class<? extends Style> getNotificationStyleClass(String templateClass) {
@@ -3674,91 +3482,15 @@
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.mSmallIcon;
- 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.mLargeIcon;
- 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;
-
- if (n.topics != null) {
- Collections.addAll(mTopics, n.topics);
- }
-
- // Extras.
- Bundle extras = n.extras;
- mOriginatingUserId = extras.getInt(EXTRA_ORIGINATING_USERID);
- mContentTitle = extras.getCharSequence(EXTRA_TITLE);
- mContentText = extras.getCharSequence(EXTRA_TEXT);
- mSubText = extras.getCharSequence(EXTRA_SUB_TEXT);
- mContentInfo = extras.getCharSequence(EXTRA_INFO_TEXT);
- 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));
- }
}
/**
@@ -3774,38 +3506,23 @@
* object.
*/
public Notification build() {
- if (mSmallIcon != null) {
- mSmallIcon.convertToAshmem();
+ // first, add any extras from the calling code
+ if (mUserExtras != null) {
+ mN.extras = getAllExtras();
}
- if (mLargeIcon != null) {
- mLargeIcon.convertToAshmem();
- }
+
+ // lazy stuff from mContext; see comment in Builder(Context, Notification)
+ mN.extras.putParcelable(EXTRA_BUILDER_APPLICATION_INFO, mContext.getApplicationInfo());
mOriginatingUserId = mContext.getUserId();
- mHasThreeLines = hasThreeLines();
+ mN.extras.putInt(EXTRA_ORIGINATING_USERID, mOriginatingUserId);
- Notification n = buildUnstyled();
+ buildUnstyled();
if (mStyle != null) {
- mStyle.purgeResources();
- n = mStyle.buildStyled(n);
+ mStyle.buildStyled(mN);
}
- if (mExtras != null) {
- n.extras.putAll(mExtras);
- }
-
- if (mRebuildBundle.size() > 0) {
- n.extras.putAll(mRebuildBundle);
- mRebuildBundle.clear();
- }
-
- populateExtras(n.extras);
- if (mStyle != null) {
- mStyle.addExtras(n.extras);
- }
-
- mHasThreeLines = false;
- return n;
+ return mN;
}
/**
@@ -3901,14 +3618,15 @@
checkBuilder();
// Nasty.
- CharSequence oldBuilderContentTitle = mBuilder.mContentTitle;
+ CharSequence oldBuilderContentTitle =
+ mBuilder.getAllExtras().getCharSequence(EXTRA_TITLE);
if (mBigContentTitle != null) {
mBuilder.setContentTitle(mBigContentTitle);
}
RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(layoutId);
- mBuilder.mContentTitle = oldBuilderContentTitle;
+ mBuilder.getAllExtras().putCharSequence(EXTRA_TITLE, oldBuilderContentTitle);
if (mBigContentTitle != null && mBigContentTitle.equals("")) {
contentView.setViewVisibility(R.id.line1, View.GONE);
@@ -3919,7 +3637,7 @@
// The last line defaults to the subtext, but can be replaced by mSummaryText
final CharSequence overflowText =
mSummaryTextSet ? mSummaryText
- : mBuilder.mSubText;
+ : mBuilder.getAllExtras().getCharSequence(EXTRA_SUB_TEXT);
if (overflowText != null) {
contentView.setTextViewText(R.id.text, mBuilder.processLegacyText(overflowText));
contentView.setViewVisibility(R.id.overflow_divider, View.VISIBLE);
@@ -3935,6 +3653,31 @@
}
/**
+ * Construct a Style-specific RemoteViews for the final 1U notification layout.
+ * The default implementation has nothing additional to add.
+ * @hide
+ */
+ public RemoteViews makeContentView() {
+ return null;
+ }
+
+ /**
+ * Construct a Style-specific RemoteViews for the final big notification layout.
+ * @hide
+ */
+ public RemoteViews makeBigContentView() {
+ return null;
+ }
+
+ /**
+ * Construct a Style-specific RemoteViews for the final HUN layout.
+ * @hide
+ */
+ public RemoteViews makeHeadsUpContentView() {
+ return null;
+ }
+
+ /**
* Changes the padding of the first line such that the big and small content view have the
* same top padding.
*
@@ -3942,12 +3685,13 @@
*/
protected void applyTopPadding(RemoteViews contentView) {
int topPadding = Builder.calculateTopPadding(mBuilder.mContext,
- mBuilder.mHasThreeLines,
+ mBuilder.hasThreeLines(),
mBuilder.mContext.getResources().getConfiguration().fontScale);
contentView.setViewPadding(R.id.line1, 0, topPadding, 0, 0);
}
/**
+ * Apply any style-specific extras to this notification before shipping it out.
* @hide
*/
public void addExtras(Bundle extras) {
@@ -3961,6 +3705,7 @@
}
/**
+ * Reconstruct the internal state of this Style object from extras.
* @hide
*/
protected void restoreFromExtras(Bundle extras) {
@@ -3978,10 +3723,7 @@
* @hide
*/
public Notification buildStyled(Notification wip) {
- populateTickerView(wip);
- populateContentView(wip);
- populateBigContentView(wip);
- populateHeadsUpContentView(wip);
+ addExtras(wip.extras);
return wip;
}
@@ -3990,26 +3732,6 @@
*/
public void purgeResources() {}
- // 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
* attached to.
@@ -4115,29 +3837,33 @@
}
}
- private RemoteViews makeBigContentView() {
- // Replace mLargeIcon with mBigLargeIcon if mBigLargeIconSet
+ /**
+ * @hide
+ */
+ public RemoteViews makeBigContentView() {
+ // Replace mN.mLargeIcon with mBigLargeIcon if mBigLargeIconSet
// This covers the following cases:
// 1. mBigLargeIconSet -> mBigLargeIcon (null or non-null) applies, overrides
- // mLargeIcon
- // 2. !mBigLargeIconSet -> mLargeIcon applies
+ // mN.mLargeIcon
+ // 2. !mBigLargeIconSet -> mN.mLargeIcon applies
Icon oldLargeIcon = null;
if (mBigLargeIconSet) {
- oldLargeIcon = mBuilder.mLargeIcon;
- mBuilder.mLargeIcon = mBigLargeIcon;
+ oldLargeIcon = mBuilder.mN.mLargeIcon;
+ mBuilder.mN.mLargeIcon = mBigLargeIcon;
}
RemoteViews contentView = getStandardView(mBuilder.getBigPictureLayoutResource());
if (mBigLargeIconSet) {
- mBuilder.mLargeIcon = oldLargeIcon;
+ mBuilder.mN.mLargeIcon = oldLargeIcon;
}
contentView.setImageViewBitmap(R.id.big_picture, mPicture);
applyTopPadding(contentView);
- boolean twoTextLines = mBuilder.mSubText != null && mBuilder.mContentText != null;
+ boolean twoTextLines = mBuilder.getAllExtras().getCharSequence(EXTRA_SUB_TEXT) != null
+ && mBuilder.getAllExtras().getCharSequence(EXTRA_TEXT) != null;
mBuilder.addProfileBadge(contentView,
twoTextLines ? R.id.profile_badge_line2 : R.id.profile_badge_line3);
return contentView;
@@ -4168,14 +3894,6 @@
}
mPicture = extras.getParcelable(EXTRA_PICTURE);
}
-
- /**
- * @hide
- */
- @Override
- public void populateBigContentView(Notification wip) {
- mBuilder.setBuilderBigContentView(wip, makeBigContentView());
- }
}
/**
@@ -4255,15 +3973,19 @@
mBigText = extras.getCharSequence(EXTRA_BIG_TEXT);
}
- private RemoteViews makeBigContentView() {
+ /**
+ * @hide
+ */
+ public RemoteViews makeBigContentView() {
// Nasty
- CharSequence oldBuilderContentText = mBuilder.mContentText;
- mBuilder.mContentText = null;
+ CharSequence oldBuilderContentText =
+ mBuilder.getAllExtras().getCharSequence(EXTRA_TEXT);
+ mBuilder.getAllExtras().putCharSequence(EXTRA_TEXT, null);
RemoteViews contentView = getStandardView(mBuilder.getBigTextLayoutResource());
- mBuilder.mContentText = oldBuilderContentText;
+ mBuilder.getAllExtras().putCharSequence(EXTRA_TEXT, oldBuilderContentText);
contentView.setTextViewText(R.id.big_text, mBuilder.processLegacyText(mBigText));
contentView.setViewVisibility(R.id.big_text, View.VISIBLE);
@@ -4282,7 +4004,8 @@
private int calculateMaxLines() {
int lineCount = MAX_LINES;
boolean hasActions = mBuilder.mActions.size() > 0;
- boolean hasSummary = (mSummaryTextSet ? mSummaryText : mBuilder.mSubText) != null;
+ boolean hasSummary = (mSummaryTextSet ? mSummaryText
+ : mBuilder.getAllExtras().getCharSequence(EXTRA_SUB_TEXT)) != null;
if (hasActions) {
lineCount -= LINES_CONSUMED_BY_ACTIONS;
}
@@ -4291,19 +4014,11 @@
}
// If we have less top padding at the top, we can fit less lines.
- if (!mBuilder.mHasThreeLines) {
+ if (!mBuilder.hasThreeLines()) {
lineCount--;
}
return lineCount;
}
-
- /**
- * @hide
- */
- @Override
- public void populateBigContentView(Notification wip) {
- mBuilder.setBuilderBigContentView(wip, makeBigContentView());
- }
}
/**
@@ -4384,16 +4099,18 @@
}
}
- private RemoteViews makeBigContentView() {
+ /**
+ * @hide
+ */
+ public RemoteViews makeBigContentView() {
// Remove the content text so line3 disappears unless you have a summary
-
// Nasty
- CharSequence oldBuilderContentText = mBuilder.mContentText;
- mBuilder.mContentText = null;
+ CharSequence oldBuilderContentText = mBuilder.mN.extras.getCharSequence(EXTRA_TEXT);
+ mBuilder.getAllExtras().putCharSequence(EXTRA_TEXT, null);
RemoteViews contentView = getStandardView(mBuilder.getInboxLayoutResource());
- mBuilder.mContentText = oldBuilderContentText;
+ mBuilder.getAllExtras().putCharSequence(EXTRA_TEXT, oldBuilderContentText);
contentView.setViewVisibility(R.id.text2, View.GONE);
@@ -4437,14 +4154,6 @@
return contentView;
}
-
- /**
- * @hide
- */
- @Override
- public void populateBigContentView(Notification wip) {
- mBuilder.setBuilderBigContentView(wip, makeBigContentView());
- }
}
/**
@@ -4536,16 +4245,16 @@
* @hide
*/
@Override
- public void populateContentView(Notification wip) {
- mBuilder.setBuilderContentView(wip, makeMediaContentView());
+ public RemoteViews makeContentView() {
+ return makeMediaContentView();
}
/**
* @hide
*/
@Override
- public void populateBigContentView(Notification wip) {
- mBuilder.setBuilderBigContentView(wip, makeMediaBigContentView());
+ public RemoteViews makeBigContentView() {
+ return makeMediaBigContentView();
}
/** @hide */
@@ -4659,7 +4368,7 @@
R.color.notification_media_secondary_color);
contentView.setTextColor(R.id.title, primaryColor);
if (mBuilder.showsTimeOrChronometer()) {
- if (mBuilder.mUseChronometer) {
+ if (mBuilder.getAllExtras().getBoolean(EXTRA_SHOW_CHRONOMETER)) {
contentView.setTextColor(R.id.chronometer, secondaryColor);
} else {
contentView.setTextColor(R.id.time, secondaryColor);
@@ -5503,7 +5212,7 @@
/**
* Gets the accent color.
*
- * @see setColor
+ * @see #setColor
*/
@ColorInt
public int getColor() {
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index cb0ff33..f75b22a 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -207,33 +207,7 @@
*/
public void notify(String tag, int id, Notification notification)
{
- int[] idOut = new int[1];
- INotificationManager service = getService();
- String pkg = mContext.getPackageName();
- if (notification.sound != null) {
- notification.sound = notification.sound.getCanonicalUri();
- if (StrictMode.vmFileUriExposureEnabled()) {
- notification.sound.checkFileUriExposed("Notification.sound");
- }
- }
- fixLegacySmallIcon(notification, pkg);
- if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) {
- if (notification.getSmallIcon() == null) {
- throw new IllegalArgumentException("Invalid notification (no valid small icon): "
- + notification);
- }
- }
- if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
- Notification stripped = notification.clone();
- Builder.stripForDelivery(stripped);
- try {
- service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
- stripped, idOut, UserHandle.myUserId());
- if (id != idOut[0]) {
- Log.w(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]);
- }
- } catch (RemoteException e) {
- }
+ notifyAsUser(tag, id, notification, new UserHandle(UserHandle.myUserId()));
}
/**
@@ -251,12 +225,17 @@
}
}
fixLegacySmallIcon(notification, pkg);
+ if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) {
+ if (notification.getSmallIcon() == null) {
+ throw new IllegalArgumentException("Invalid notification (no valid small icon): "
+ + notification);
+ }
+ }
if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
- Notification stripped = notification.clone();
- Builder.stripForDelivery(stripped);
+ final Notification copy = notification.clone();
try {
service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
- stripped, idOut, user.getIdentifier());
+ copy, idOut, user.getIdentifier());
if (id != idOut[0]) {
Log.w(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]);
}
@@ -287,13 +266,7 @@
*/
public void cancel(String tag, int id)
{
- INotificationManager service = getService();
- String pkg = mContext.getPackageName();
- if (localLOGV) Log.v(TAG, pkg + ": cancel(" + id + ")");
- try {
- service.cancelNotificationWithTag(pkg, tag, id, UserHandle.myUserId());
- } catch (RemoteException e) {
- }
+ cancelAsUser(tag, id, new UserHandle(UserHandle.myUserId()));
}
/**
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index d424546..7e7b5fc 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -31,6 +31,7 @@
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.graphics.Bitmap;
+import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
@@ -472,9 +473,10 @@
StatusBarNotification sbn = list.get(i);
Notification notification = sbn.getNotification();
try {
- Builder.rebuild(getContext(), notification);
// convert icon metadata to legacy format for older clients
createLegacyIconExtras(notification);
+ // populate remote views for older clients.
+ maybePopulateRemoteViews(notification);
} catch (IllegalArgumentException e) {
if (corruptNotifications == null) {
corruptNotifications = new ArrayList<>(N);
@@ -676,6 +678,18 @@
}
}
+ /**
+ * Populates remote views for pre-N targeting apps.
+ */
+ private void maybePopulateRemoteViews(Notification notification) {
+ if (getContext().getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N) {
+ Builder builder = Builder.recoverBuilder(getContext(), notification);
+ notification.contentView = builder.makeContentView();
+ notification.bigContentView = builder.makeBigContentView();
+ notification.headsUpContentView = builder.makeHeadsUpContentView();
+ }
+ }
+
private class INotificationListenerWrapper extends INotificationListener.Stub {
@Override
public void onNotificationPosted(IStatusBarNotificationHolder sbnHolder,
@@ -689,9 +703,10 @@
}
try {
- Notification.Builder.rebuild(getContext(), sbn.getNotification());
+ Notification notification = sbn.getNotification();
// convert icon metadata to legacy format for older clients
createLegacyIconExtras(sbn.getNotification());
+ maybePopulateRemoteViews(sbn.getNotification());
} catch (IllegalArgumentException e) {
// drop corrupt notification
sbn = null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 0def599..2c16f81 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -1275,20 +1275,22 @@
int maxHeight = mRowMaxHeight;
final StatusBarNotification sbn = entry.notification;
- RemoteViews contentView = sbn.getNotification().contentView;
- RemoteViews bigContentView = sbn.getNotification().bigContentView;
- RemoteViews headsUpContentView = sbn.getNotification().headsUpContentView;
+ entry.cacheContentViews(mContext, null);
+
+ final RemoteViews contentView = entry.cachedContentView;
+ final RemoteViews bigContentView = entry.cachedBigContentView;
+ final RemoteViews headsUpContentView = entry.cachedHeadsUpContentView;
+ final RemoteViews publicContentView = entry.cachedPublicContentView;
if (contentView == null) {
+ Log.v(TAG, "no contentView for: " + sbn.getNotification());
return false;
}
if (DEBUG) {
- Log.v(TAG, "publicNotification: " + sbn.getNotification().publicVersion);
+ Log.v(TAG, "publicContentView: " + publicContentView);
}
- Notification publicNotification = sbn.getNotification().publicVersion;
-
ExpandableNotificationRow row;
// Stash away previous user expansion state so we can restore it at
@@ -1377,9 +1379,9 @@
// now the public version
View publicViewLocal = null;
- if (publicNotification != null) {
+ if (publicContentView != null) {
try {
- publicViewLocal = publicNotification.contentView.apply(
+ publicViewLocal = publicContentView.apply(
sbn.getPackageContext(mContext),
contentContainerPublic, mOnClickHandler);
@@ -1537,30 +1539,9 @@
}
if (viableAction != null) {
- Notification stripped = n.clone();
- Notification.Builder.stripForDelivery(stripped);
- stripped.extras.putBoolean("android.rebuild", true);
- stripped.actions = new Notification.Action[] { viableAction };
- stripped.extras.putBoolean("android.rebuild.contentView", true);
- stripped.contentView = null;
- stripped.extras.putBoolean("android.rebuild.bigView", true);
- stripped.bigContentView = null;
- stripped.extras.putBoolean("android.rebuild.hudView", true);
- stripped.headsUpContentView = null;
-
- stripped.extras.putParcelable(Notification.EXTRA_LARGE_ICON,
- stripped.getLargeIcon());
- if (SystemProperties.getBoolean("debug.strip_third_line", false)) {
- stripped.extras.putCharSequence(Notification.EXTRA_INFO_TEXT, null);
- stripped.extras.putCharSequence(Notification.EXTRA_SUMMARY_TEXT, null);
- }
-
- Notification rebuilt = Notification.Builder.rebuild(mContext, stripped);
-
- n.actions = rebuilt.actions;
- n.bigContentView = rebuilt.bigContentView;
- n.headsUpContentView = rebuilt.headsUpContentView;
- n.publicVersion = rebuilt.publicVersion;
+ Notification.Builder rebuilder = Notification.Builder.recoverBuilder(mContext, n);
+ rebuilder.setActions(viableAction);
+ rebuilder.build(); // will rewrite n
}
}
}
@@ -2034,12 +2015,15 @@
}
Notification n = notification.getNotification();
- if (DEBUG) {
- logUpdate(entry, n);
- }
- boolean applyInPlace = shouldApplyInPlace(entry, n);
+
+ boolean applyInPlace = !entry.cacheContentViews(mContext, notification.getNotification());
boolean shouldInterrupt = shouldInterrupt(entry, notification);
boolean alertAgain = alertAgain(entry, n);
+ if (DEBUG) {
+ Log.d(TAG, "applyInPlace=" + applyInPlace
+ + " shouldInterrupt=" + shouldInterrupt
+ + " alertAgain=" + alertAgain);
+ }
entry.notification = notification;
mGroupManager.onEntryUpdated(entry, entry.notification);
@@ -2104,101 +2088,32 @@
protected abstract void updateHeadsUp(String key, Entry entry, boolean shouldInterrupt,
boolean alertAgain);
- private void logUpdate(Entry oldEntry, Notification n) {
- StatusBarNotification oldNotification = oldEntry.notification;
- Log.d(TAG, "old notification: when=" + oldNotification.getNotification().when
- + " ongoing=" + oldNotification.isOngoing()
- + " expanded=" + oldEntry.getContentView()
- + " contentView=" + oldNotification.getNotification().contentView
- + " bigContentView=" + oldNotification.getNotification().bigContentView
- + " publicView=" + oldNotification.getNotification().publicVersion
- + " rowParent=" + oldEntry.row.getParent());
- Log.d(TAG, "new notification: when=" + n.when
- + " ongoing=" + oldNotification.isOngoing()
- + " contentView=" + n.contentView
- + " bigContentView=" + n.bigContentView
- + " publicView=" + n.publicVersion);
- }
-
- /**
- * @return whether we can just reapply the RemoteViews from a notification in-place when it is
- * updated
- */
- private boolean shouldApplyInPlace(Entry entry, Notification n) {
- StatusBarNotification oldNotification = entry.notification;
- // XXX: modify when we do something more intelligent with the two content views
- final RemoteViews oldContentView = oldNotification.getNotification().contentView;
- final RemoteViews contentView = n.contentView;
- final RemoteViews oldBigContentView = oldNotification.getNotification().bigContentView;
- final RemoteViews bigContentView = n.bigContentView;
- final RemoteViews oldHeadsUpContentView
- = oldNotification.getNotification().headsUpContentView;
- final RemoteViews headsUpContentView = n.headsUpContentView;
- final Notification oldPublicNotification = oldNotification.getNotification().publicVersion;
- final RemoteViews oldPublicContentView = oldPublicNotification != null
- ? oldPublicNotification.contentView : null;
- final Notification publicNotification = n.publicVersion;
- final RemoteViews publicContentView = publicNotification != null
- ? publicNotification.contentView : null;
- boolean contentsUnchanged = entry.getContentView() != null
- && contentView.getPackage() != null
- && oldContentView.getPackage() != null
- && oldContentView.getPackage().equals(contentView.getPackage())
- && oldContentView.getLayoutId() == contentView.getLayoutId();
- // large view may be null
- boolean bigContentsUnchanged =
- (entry.getExpandedContentView() == null && bigContentView == null)
- || ((entry.getExpandedContentView() != null && bigContentView != null)
- && bigContentView.getPackage() != null
- && oldBigContentView.getPackage() != null
- && oldBigContentView.getPackage().equals(bigContentView.getPackage())
- && oldBigContentView.getLayoutId() == bigContentView.getLayoutId());
- boolean headsUpContentsUnchanged =
- (oldHeadsUpContentView == null && headsUpContentView == null)
- || ((oldHeadsUpContentView != null && headsUpContentView != null)
- && headsUpContentView.getPackage() != null
- && oldHeadsUpContentView.getPackage() != null
- && oldHeadsUpContentView.getPackage().equals(headsUpContentView.getPackage())
- && oldHeadsUpContentView.getLayoutId() == headsUpContentView.getLayoutId());
- boolean publicUnchanged =
- (oldPublicContentView == null && publicContentView == null)
- || ((oldPublicContentView != null && publicContentView != null)
- && publicContentView.getPackage() != null
- && oldPublicContentView.getPackage() != null
- && oldPublicContentView.getPackage().equals(publicContentView.getPackage())
- && oldPublicContentView.getLayoutId() == publicContentView.getLayoutId());
- return contentsUnchanged && bigContentsUnchanged && headsUpContentsUnchanged
- && publicUnchanged;
- }
-
- private void updateNotificationViews(Entry entry, StatusBarNotification notification) {
- final RemoteViews contentView = notification.getNotification().contentView;
- final RemoteViews bigContentView = notification.getNotification().bigContentView;
- final RemoteViews headsUpContentView = notification.getNotification().headsUpContentView;
- final Notification publicVersion = notification.getNotification().publicVersion;
- final RemoteViews publicContentView = publicVersion != null ? publicVersion.contentView
- : null;
+ private void updateNotificationViews(Entry entry, StatusBarNotification sbn) {
+ final RemoteViews contentView = entry.cachedContentView;
+ final RemoteViews bigContentView = entry.cachedBigContentView;
+ final RemoteViews headsUpContentView = entry.cachedHeadsUpContentView;
+ final RemoteViews publicContentView = entry.cachedPublicContentView;
// Reapply the RemoteViews
contentView.reapply(mContext, entry.getContentView(), mOnClickHandler);
if (bigContentView != null && entry.getExpandedContentView() != null) {
- bigContentView.reapply(notification.getPackageContext(mContext),
+ bigContentView.reapply(sbn.getPackageContext(mContext),
entry.getExpandedContentView(),
mOnClickHandler);
}
View headsUpChild = entry.getHeadsUpContentView();
if (headsUpContentView != null && headsUpChild != null) {
- headsUpContentView.reapply(notification.getPackageContext(mContext),
+ headsUpContentView.reapply(sbn.getPackageContext(mContext),
headsUpChild, mOnClickHandler);
}
if (publicContentView != null && entry.getPublicContentView() != null) {
- publicContentView.reapply(notification.getPackageContext(mContext),
+ publicContentView.reapply(sbn.getPackageContext(mContext),
entry.getPublicContentView(), mOnClickHandler);
}
// update the contentIntent
- mNotificationClicker.register(entry.row, notification);
+ mNotificationClicker.register(entry.row, sbn);
- entry.row.setStatusBarNotification(notification);
+ entry.row.setStatusBarNotification(sbn);
entry.row.notifyContentUpdated();
entry.row.resetHeight();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index aedae52..6a90d8e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar;
import android.app.Notification;
+import android.content.Context;
import android.os.SystemClock;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationListenerService.Ranking;
@@ -24,6 +25,7 @@
import android.service.notification.StatusBarNotification;
import android.util.ArrayMap;
import android.view.View;
+import android.widget.RemoteViews;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -53,6 +55,10 @@
public boolean legacy; // whether the notification has a legacy, dark background
public int targetSdk;
private long lastFullScreenIntentLaunchTime = NOT_LAUNCHED_YET;
+ public RemoteViews cachedContentView;
+ public RemoteViews cachedBigContentView;
+ public RemoteViews cachedHeadsUpContentView;
+ public RemoteViews cachedPublicContentView;
public Entry(StatusBarNotification n, StatusBarIconView ic) {
this.key = n.getKey();
@@ -98,6 +104,67 @@
return row.getPublicLayout().getContractedChild();
}
+ public boolean cacheContentViews(Context ctx, Notification updatedNotification) {
+ boolean cached = false;
+ if (updatedNotification != null) {
+ final Notification.Builder updatedNotificationBuilder
+ = Notification.Builder.recoverBuilder(ctx, updatedNotification);
+ final RemoteViews newContentView = updatedNotificationBuilder.makeContentView();
+ if (!compareRemoteViews(cachedContentView, newContentView)) {
+ cachedContentView = newContentView;
+ cached |= true;
+ }
+ final RemoteViews newBigContentView =
+ updatedNotificationBuilder.makeBigContentView();
+ if (!compareRemoteViews(cachedBigContentView, newBigContentView)) {
+ cachedBigContentView = newBigContentView;
+ cached |= true;
+ }
+ final RemoteViews newHeadsUpContentView =
+ updatedNotificationBuilder.makeHeadsUpContentView();
+ if (!compareRemoteViews(cachedHeadsUpContentView, newBigContentView)) {
+ cachedHeadsUpContentView = newHeadsUpContentView;
+ cached |= true;
+ }
+ final Notification updatedPublicNotification = updatedNotification.publicVersion;
+ final RemoteViews newPubContentView = (updatedPublicNotification != null)
+ ? Notification.Builder.recoverBuilder(
+ ctx, updatedPublicNotification).makeContentView()
+ : null;
+ if (!compareRemoteViews(cachedPublicContentView, newPubContentView)) {
+ cachedPublicContentView = newPubContentView;
+ cached |= true;
+ }
+ } else {
+ final Notification.Builder builder
+ = Notification.Builder.recoverBuilder(ctx, notification.getNotification());
+
+ cachedContentView = builder.makeContentView();
+ cachedBigContentView = builder.makeBigContentView();
+ cachedHeadsUpContentView = builder.makeHeadsUpContentView();
+
+ final Notification publicNotification =
+ notification.getNotification().publicVersion;
+ if (publicNotification != null) {
+ final Notification.Builder publicBuilder
+ = Notification.Builder.recoverBuilder(ctx, publicNotification);
+ cachedPublicContentView = publicBuilder.makeContentView();
+ }
+ cached = true;
+ }
+ return cached;
+ }
+
+ // Returns true if the RemoteViews are the same.
+ private boolean compareRemoteViews(final RemoteViews a, final RemoteViews b) {
+ return (a == null && b == null) ||
+ (a != null && b != null
+ && b.getPackage() != null
+ && a.getPackage() != null
+ && a.getPackage().equals(b.getPackage())
+ && a.getLayoutId() == b.getLayoutId());
+ }
+
public void notifyFullScreenIntentLaunched() {
lastFullScreenIntentLaunchTime = SystemClock.elapsedRealtime();
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index e8e46ef..361bbf9 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2146,13 +2146,6 @@
+ " id=" + id + " notification=" + notification);
}
- if (notification.getSmallIcon() != null) {
- if (!notification.isValid()) {
- throw new IllegalArgumentException("Invalid notification (): pkg=" + pkg
- + " id=" + id + " notification=" + notification);
- }
- }
-
mHandler.post(new Runnable() {
@Override
public void run() {