blob: 3ff0896594567343c3a698f8efa0a9d218dcca0e [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.app;
18
Tor Norbye80756e32015-03-02 09:39:27 -080019import android.annotation.ColorInt;
Tor Norbye7b9c9122013-05-30 16:48:33 -070020import android.annotation.DrawableRes;
Tor Norbyed9273d62013-05-30 15:59:53 -070021import android.annotation.IntDef;
Daniel Sandler01df1c62014-06-09 10:54:01 -040022import android.annotation.SdkConstant;
23import android.annotation.SdkConstant.SdkConstantType;
Julia Reynolds233a5f92015-10-19 13:51:23 -040024import android.annotation.SystemApi;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.content.Context;
26import android.content.Intent;
Kenny Guy77320062014-08-27 21:37:15 +010027import android.content.pm.ApplicationInfo;
Selim Cinek65b2e7c2015-10-26 14:11:31 -070028import android.content.pm.PackageManager;
Christoph Studer4600f9b2014-07-22 22:44:43 +020029import android.content.pm.PackageManager.NameNotFoundException;
Jorim Jaggief72a192014-08-26 21:57:46 +020030import android.content.res.ColorStateList;
Joe Onoratoef1e7762010-09-17 18:38:38 -040031import android.graphics.Bitmap;
Kenny Guy8a0101b2014-05-08 23:34:12 +010032import android.graphics.Canvas;
Jorim Jaggi5c2d8462014-03-21 17:37:00 +010033import android.graphics.PorterDuff;
Kenny Guy8a0101b2014-05-08 23:34:12 +010034import android.graphics.drawable.Drawable;
Dan Sandlerd63f9322015-05-06 15:18:49 -040035import android.graphics.drawable.Icon;
John Spurlockc0650f022014-07-19 13:22:39 -040036import android.media.AudioAttributes;
Jeff Sharkey098d5802012-04-26 17:30:34 -070037import android.media.AudioManager;
Jeff Browndba34ba2014-06-24 20:46:03 -070038import android.media.session.MediaSession;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.net.Uri;
Daniel Sandlerdcbaf662013-04-26 16:23:09 -040040import android.os.BadParcelableException;
Christoph Studer239f8352014-08-25 15:13:18 +020041import android.os.Build;
Daniel Sandler2561b0b2012-02-13 21:04:12 -050042import android.os.Bundle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.os.Parcel;
44import android.os.Parcelable;
Daniel Sandlera2985ed2012-04-03 16:42:00 -040045import android.os.SystemClock;
Jeff Sharkey6d515712012-09-20 16:06:08 -070046import android.os.UserHandle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047import android.text.TextUtils;
Daniel Sandlerdcbaf662013-04-26 16:23:09 -040048import android.util.Log;
Dan Sandler50128532015-12-08 15:42:41 -050049import android.util.SparseArray;
Daniel Sandler9f7936a2012-05-21 16:14:28 -040050import android.util.TypedValue;
Griff Hazen61a9e862014-05-22 16:05:19 -070051import android.view.Gravity;
Selim Cinekea4bef72015-12-02 15:51:10 -080052import android.view.NotificationHeaderView;
Joe Onorato8595a3d2010-11-19 18:12:07 -080053import android.view.View;
Jeff Sharkey1c400132011-08-05 14:50:13 -070054import android.widget.ProgressBar;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import android.widget.RemoteViews;
56
Griff Hazen959591e2014-05-15 22:26:18 -070057import com.android.internal.R;
Griff Hazenc091ba82014-05-16 10:13:26 -070058import com.android.internal.util.NotificationColorUtil;
Griff Hazen959591e2014-05-15 22:26:18 -070059
Tor Norbyed9273d62013-05-30 15:59:53 -070060import java.lang.annotation.Retention;
61import java.lang.annotation.RetentionPolicy;
Christoph Studer4600f9b2014-07-22 22:44:43 +020062import java.lang.reflect.Constructor;
Daniel Sandler2561b0b2012-02-13 21:04:12 -050063import java.util.ArrayList;
Griff Hazen61a9e862014-05-22 16:05:19 -070064import java.util.Arrays;
Griff Hazen5cadc3b2014-05-20 09:55:39 -070065import java.util.Collections;
Griff Hazen61a9e862014-05-22 16:05:19 -070066import java.util.List;
Julia Reynolds74303cf2015-10-16 11:37:55 -040067import java.util.Objects;
Dan Sandler50128532015-12-08 15:42:41 -050068import java.util.Set;
Joe Onorato561d3852010-11-20 18:09:34 -080069
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070/**
71 * A class that represents how a persistent notification is to be presented to
72 * the user using the {@link android.app.NotificationManager}.
73 *
Joe Onoratocb109a02011-01-18 17:57:41 -080074 * <p>The {@link Notification.Builder Notification.Builder} has been added to make it
75 * easier to construct Notifications.</p>
76 *
Joe Fernandez558459f2011-10-13 16:47:36 -070077 * <div class="special reference">
78 * <h3>Developer Guides</h3>
79 * <p>For a guide to creating notifications, read the
80 * <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Status Bar Notifications</a>
81 * developer guide.</p>
82 * </div>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083 */
84public class Notification implements Parcelable
85{
Daniel Sandlerdcbaf662013-04-26 16:23:09 -040086 private static final String TAG = "Notification";
87
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088 /**
Daniel Sandler01df1c62014-06-09 10:54:01 -040089 * An activity that provides a user interface for adjusting notification preferences for its
90 * containing application. Optional but recommended for apps that post
91 * {@link android.app.Notification Notifications}.
92 */
93 @SdkConstant(SdkConstantType.INTENT_CATEGORY)
94 public static final String INTENT_CATEGORY_NOTIFICATION_PREFERENCES
95 = "android.intent.category.NOTIFICATION_PREFERENCES";
96
97 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098 * Use all default values (where applicable).
99 */
100 public static final int DEFAULT_ALL = ~0;
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500101
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102 /**
103 * Use the default notification sound. This will ignore any given
104 * {@link #sound}.
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500105 *
Chris Wren47c20a12014-06-18 17:27:29 -0400106 * <p>
107 * A notification that is noisy is more likely to be presented as a heads-up notification.
108 * </p>
109 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110 * @see #defaults
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500111 */
112
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113 public static final int DEFAULT_SOUND = 1;
114
115 /**
116 * Use the default notification vibrate. This will ignore any given
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500117 * {@link #vibrate}. Using phone vibration requires the
Scott Mainb8b36452009-04-26 15:50:49 -0700118 * {@link android.Manifest.permission#VIBRATE VIBRATE} permission.
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500119 *
Chris Wren47c20a12014-06-18 17:27:29 -0400120 * <p>
121 * A notification that vibrates is more likely to be presented as a heads-up notification.
122 * </p>
123 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124 * @see #defaults
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500125 */
126
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127 public static final int DEFAULT_VIBRATE = 2;
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500128
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129 /**
130 * Use the default notification lights. This will ignore the
131 * {@link #FLAG_SHOW_LIGHTS} bit, and {@link #ledARGB}, {@link #ledOffMS}, or
132 * {@link #ledOnMS}.
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500133 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134 * @see #defaults
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500135 */
136
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137 public static final int DEFAULT_LIGHTS = 4;
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500138
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800139 /**
Christoph Studer535ec612014-09-03 15:47:47 +0200140 * Maximum length of CharSequences accepted by Builder and friends.
141 *
142 * <p>
143 * Avoids spamming the system with overly large strings such as full e-mails.
144 */
145 private static final int MAX_CHARSEQUENCE_LENGTH = 5 * 1024;
146
147 /**
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500148 * A timestamp related to this notification, in milliseconds since the epoch.
Joe Malin8d40d042012-11-05 11:36:40 -0800149 *
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500150 * Default value: {@link System#currentTimeMillis() Now}.
151 *
152 * Choose a timestamp that will be most relevant to the user. For most finite events, this
153 * corresponds to the time the event happened (or will happen, in the case of events that have
154 * yet to occur but about which the user is being informed). Indefinite events should be
Joe Malin8d40d042012-11-05 11:36:40 -0800155 * timestamped according to when the activity began.
156 *
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500157 * Some examples:
Joe Malin8d40d042012-11-05 11:36:40 -0800158 *
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500159 * <ul>
160 * <li>Notification of a new chat message should be stamped when the message was received.</li>
161 * <li>Notification of an ongoing file download (with a progress bar, for example) should be stamped when the download started.</li>
162 * <li>Notification of a completed file download should be stamped when the download finished.</li>
163 * <li>Notification of an upcoming meeting should be stamped with the time the meeting will begin (that is, in the future).</li>
164 * <li>Notification of an ongoing stopwatch (increasing timer) should be stamped with the watch's start time.
165 * <li>Notification of an ongoing countdown timer should be stamped with the timer's end time.
Joe Malin8d40d042012-11-05 11:36:40 -0800166 * </ul>
167 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800168 */
169 public long when;
170
171 /**
172 * The resource id of a drawable to use as the icon in the status bar.
Dan Sandler86647982015-05-13 23:41:13 -0400173 *
174 * @deprecated Use {@link Builder#setSmallIcon(Icon)} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800175 */
Dan Sandler86647982015-05-13 23:41:13 -0400176 @Deprecated
Tor Norbye7b9c9122013-05-30 16:48:33 -0700177 @DrawableRes
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178 public int icon;
179
180 /**
Joe Onorato46439ce2010-11-19 13:56:21 -0800181 * If the icon in the status bar is to have more than one level, you can set this. Otherwise,
182 * leave it at its default value of 0.
183 *
184 * @see android.widget.ImageView#setImageLevel
Griff Hazen959591e2014-05-15 22:26:18 -0700185 * @see android.graphics.drawable.Drawable#setLevel
Joe Onorato46439ce2010-11-19 13:56:21 -0800186 */
187 public int iconLevel;
188
189 /**
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500190 * The number of events that this notification represents. For example, in a new mail
191 * notification, this could be the number of unread messages.
Joe Malin8d40d042012-11-05 11:36:40 -0800192 *
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500193 * The system may or may not use this field to modify the appearance of the notification. For
194 * example, before {@link android.os.Build.VERSION_CODES#HONEYCOMB}, this number was
195 * superimposed over the icon in the status bar. Starting with
196 * {@link android.os.Build.VERSION_CODES#HONEYCOMB}, the template used by
197 * {@link Notification.Builder} has displayed the number in the expanded notification view.
Joe Malin8d40d042012-11-05 11:36:40 -0800198 *
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500199 * If the number is 0 or negative, it is never shown.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800200 */
201 public int number;
202
203 /**
204 * The intent to execute when the expanded status entry is clicked. If
205 * this is an activity, it must include the
206 * {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} flag, which requires
Scott Main7aee61f2011-02-08 11:25:01 -0800207 * that you take care of task management as described in the
208 * <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back
Dianne Hackborn6ceca582012-01-10 15:24:26 -0800209 * Stack</a> document. In particular, make sure to read the notification section
210 * <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html#HandlingNotifications">Handling
211 * Notifications</a> for the correct ways to launch an application from a
212 * notification.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800213 */
214 public PendingIntent contentIntent;
215
216 /**
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500217 * The intent to execute when the notification is explicitly dismissed by the user, either with
218 * the "Clear All" button or by swiping it away individually.
219 *
220 * This probably shouldn't be launching an activity since several of those will be sent
221 * at the same time.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800222 */
223 public PendingIntent deleteIntent;
224
225 /**
Dianne Hackborn170bae72010-09-03 15:14:28 -0700226 * An intent to launch instead of posting the notification to the status bar.
Joe Onoratocb109a02011-01-18 17:57:41 -0800227 *
Chris Wren47c20a12014-06-18 17:27:29 -0400228 * <p>
229 * The system UI may choose to display a heads-up notification, instead of
230 * launching this intent, while the user is using the device.
231 * </p>
232 *
Joe Onoratocb109a02011-01-18 17:57:41 -0800233 * @see Notification.Builder#setFullScreenIntent
Daniel Sandlere46cbd32010-06-17 10:35:26 -0400234 */
235 public PendingIntent fullScreenIntent;
236
237 /**
Dan Sandler5fcdf6e2014-07-18 11:31:15 -0400238 * Text that summarizes this notification for accessibility services.
239 *
240 * As of the L release, this text is no longer shown on screen, but it is still useful to
241 * accessibility services (where it serves as an audible announcement of the notification's
242 * appearance).
Joe Onoratoef1e7762010-09-17 18:38:38 -0400243 *
Joe Onorato46439ce2010-11-19 13:56:21 -0800244 * @see #tickerView
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800245 */
246 public CharSequence tickerText;
247
248 /**
Dan Sandler5fcdf6e2014-07-18 11:31:15 -0400249 * Formerly, a view showing the {@link #tickerText}.
250 *
251 * No longer displayed in the status bar as of API 21.
Joe Onoratoef1e7762010-09-17 18:38:38 -0400252 */
Dan Sandler5fcdf6e2014-07-18 11:31:15 -0400253 @Deprecated
Joe Onorato46439ce2010-11-19 13:56:21 -0800254 public RemoteViews tickerView;
Joe Onoratoef1e7762010-09-17 18:38:38 -0400255
256 /**
Julia Reynoldsd9228f12015-10-20 10:37:27 -0400257 * The view that will represent this notification in the notification list (which is pulled
258 * down from the status bar).
259 *
260 * As of N, this field is not used. The notification view is determined by the inputs to
261 * {@link Notification.Builder}; a custom RemoteViews can optionally be
262 * supplied with {@link Notification.Builder#setCustomContentView(RemoteViews)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800263 */
Julia Reynoldsd9228f12015-10-20 10:37:27 -0400264 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800265 public RemoteViews contentView;
266
Daniel Sandlera0a938c2012-03-15 08:42:37 -0400267 /**
Daniel Sandler4dfbe832012-04-11 14:51:46 -0400268 * A large-format version of {@link #contentView}, giving the Notification an
Daniel Sandlerf3b73432012-03-27 15:01:25 -0400269 * opportunity to show more detail. The system UI may choose to show this
270 * instead of the normal content view at its discretion.
Julia Reynoldsd9228f12015-10-20 10:37:27 -0400271 *
272 * As of N, this field is not used. The expanded notification view is determined by the
273 * inputs to {@link Notification.Builder}; a custom RemoteViews can optionally be
274 * supplied with {@link Notification.Builder#setCustomBigContentView(RemoteViews)}.
Daniel Sandlerf3b73432012-03-27 15:01:25 -0400275 */
Julia Reynoldsd9228f12015-10-20 10:37:27 -0400276 @Deprecated
Daniel Sandlerf3b73432012-03-27 15:01:25 -0400277 public RemoteViews bigContentView;
278
Chris Wren8fd39ec2014-02-27 17:43:26 -0500279
280 /**
Chris Wren47c20a12014-06-18 17:27:29 -0400281 * A medium-format version of {@link #contentView}, providing the Notification an
282 * opportunity to add action buttons to contentView. At its discretion, the system UI may
283 * choose to show this as a heads-up notification, which will pop up so the user can see
284 * it without leaving their current activity.
Julia Reynoldsd9228f12015-10-20 10:37:27 -0400285 *
286 * As of N, this field is not used. The heads-up notification view is determined by the
287 * inputs to {@link Notification.Builder}; a custom RemoteViews can optionally be
288 * supplied with {@link Notification.Builder#setCustomHeadsUpContentView(RemoteViews)}.
Chris Wren8fd39ec2014-02-27 17:43:26 -0500289 */
Julia Reynoldsd9228f12015-10-20 10:37:27 -0400290 @Deprecated
Chris Wren8fd39ec2014-02-27 17:43:26 -0500291 public RemoteViews headsUpContentView;
292
Daniel Sandlerf3b73432012-03-27 15:01:25 -0400293 /**
Dan Sandler86647982015-05-13 23:41:13 -0400294 * A large bitmap to be shown in the notification content area.
295 *
296 * @deprecated Use {@link Builder#setLargeIcon(Icon)} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800297 */
Dan Sandler86647982015-05-13 23:41:13 -0400298 @Deprecated
Joe Onorato46439ce2010-11-19 13:56:21 -0800299 public Bitmap largeIcon;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800300
301 /**
302 * The sound to play.
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500303 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800304 * <p>
Chris Wren47c20a12014-06-18 17:27:29 -0400305 * A notification that is noisy is more likely to be presented as a heads-up notification.
306 * </p>
307 *
308 * <p>
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500309 * To play the default notification sound, see {@link #defaults}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800310 * </p>
311 */
312 public Uri sound;
313
314 /**
315 * Use this constant as the value for audioStreamType to request that
316 * the default stream type for notifications be used. Currently the
Jeff Sharkey098d5802012-04-26 17:30:34 -0700317 * default stream type is {@link AudioManager#STREAM_NOTIFICATION}.
John Spurlockc0650f022014-07-19 13:22:39 -0400318 *
319 * @deprecated Use {@link #audioAttributes} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800320 */
Jean-Michel Trivi81f871e2014-08-06 16:32:38 -0700321 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800322 public static final int STREAM_DEFAULT = -1;
323
324 /**
325 * The audio stream type to use when playing the sound.
326 * Should be one of the STREAM_ constants from
327 * {@link android.media.AudioManager}.
John Spurlockc0650f022014-07-19 13:22:39 -0400328 *
329 * @deprecated Use {@link #audioAttributes} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800330 */
Jean-Michel Trivi81f871e2014-08-06 16:32:38 -0700331 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800332 public int audioStreamType = STREAM_DEFAULT;
333
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800334 /**
John Spurlockc0650f022014-07-19 13:22:39 -0400335 * The default value of {@link #audioAttributes}.
336 */
337 public static final AudioAttributes AUDIO_ATTRIBUTES_DEFAULT = new AudioAttributes.Builder()
338 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
339 .setUsage(AudioAttributes.USAGE_NOTIFICATION)
340 .build();
341
342 /**
343 * The {@link AudioAttributes audio attributes} to use when playing the sound.
344 */
345 public AudioAttributes audioAttributes = AUDIO_ATTRIBUTES_DEFAULT;
346
347 /**
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500348 * The pattern with which to vibrate.
349 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800350 * <p>
351 * To vibrate the default pattern, see {@link #defaults}.
352 * </p>
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500353 *
Chris Wren47c20a12014-06-18 17:27:29 -0400354 * <p>
355 * A notification that vibrates is more likely to be presented as a heads-up notification.
356 * </p>
357 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800358 * @see android.os.Vibrator#vibrate(long[],int)
359 */
360 public long[] vibrate;
361
362 /**
363 * The color of the led. The hardware will do its best approximation.
364 *
365 * @see #FLAG_SHOW_LIGHTS
366 * @see #flags
367 */
Tor Norbye80756e32015-03-02 09:39:27 -0800368 @ColorInt
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800369 public int ledARGB;
370
371 /**
372 * The number of milliseconds for the LED to be on while it's flashing.
373 * The hardware will do its best approximation.
374 *
375 * @see #FLAG_SHOW_LIGHTS
376 * @see #flags
377 */
378 public int ledOnMS;
379
380 /**
381 * The number of milliseconds for the LED to be off while it's flashing.
382 * The hardware will do its best approximation.
383 *
384 * @see #FLAG_SHOW_LIGHTS
385 * @see #flags
386 */
387 public int ledOffMS;
388
389 /**
390 * Specifies which values should be taken from the defaults.
391 * <p>
392 * To set, OR the desired from {@link #DEFAULT_SOUND},
393 * {@link #DEFAULT_VIBRATE}, {@link #DEFAULT_LIGHTS}. For all default
394 * values, use {@link #DEFAULT_ALL}.
395 * </p>
396 */
397 public int defaults;
398
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800399 /**
400 * Bit to be bitwise-ored into the {@link #flags} field that should be
401 * set if you want the LED on for this notification.
402 * <ul>
403 * <li>To turn the LED off, pass 0 in the alpha channel for colorARGB
404 * or 0 for both ledOnMS and ledOffMS.</li>
405 * <li>To turn the LED on, pass 1 for ledOnMS and 0 for ledOffMS.</li>
406 * <li>To flash the LED, pass the number of milliseconds that it should
407 * be on and off to ledOnMS and ledOffMS.</li>
408 * </ul>
409 * <p>
410 * Since hardware varies, you are not guaranteed that any of the values
411 * you pass are honored exactly. Use the system defaults (TODO) if possible
412 * because they will be set to values that work on any given hardware.
413 * <p>
414 * The alpha channel must be set for forward compatibility.
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500415 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800416 */
417 public static final int FLAG_SHOW_LIGHTS = 0x00000001;
418
419 /**
420 * Bit to be bitwise-ored into the {@link #flags} field that should be
421 * set if this notification is in reference to something that is ongoing,
422 * like a phone call. It should not be set if this notification is in
423 * reference to something that happened at a particular point in time,
424 * like a missed phone call.
425 */
426 public static final int FLAG_ONGOING_EVENT = 0x00000002;
427
428 /**
429 * Bit to be bitwise-ored into the {@link #flags} field that if set,
Scott Mainb8b36452009-04-26 15:50:49 -0700430 * the audio will be repeated until the notification is
431 * cancelled or the notification window is opened.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800432 */
433 public static final int FLAG_INSISTENT = 0x00000004;
434
435 /**
436 * Bit to be bitwise-ored into the {@link #flags} field that should be
Griff Hazen293977b2014-04-28 08:37:20 -0700437 * set if you would only like the sound, vibrate and ticker to be played
438 * if the notification was not already showing.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800439 */
440 public static final int FLAG_ONLY_ALERT_ONCE = 0x00000008;
441
442 /**
443 * Bit to be bitwise-ored into the {@link #flags} field that should be
444 * set if the notification should be canceled when it is clicked by the
Daniel Sandler8aa9ae62012-12-04 23:31:47 -0500445 * user.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800446 */
447 public static final int FLAG_AUTO_CANCEL = 0x00000010;
448
449 /**
450 * Bit to be bitwise-ored into the {@link #flags} field that should be
451 * set if the notification should not be canceled when the user clicks
452 * the Clear all button.
453 */
454 public static final int FLAG_NO_CLEAR = 0x00000020;
455
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700456 /**
457 * Bit to be bitwise-ored into the {@link #flags} field that should be
458 * set if this notification represents a currently running service. This
459 * will normally be set for you by {@link Service#startForeground}.
460 */
461 public static final int FLAG_FOREGROUND_SERVICE = 0x00000040;
462
Daniel Sandlere46cbd32010-06-17 10:35:26 -0400463 /**
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500464 * Obsolete flag indicating high-priority notifications; use the priority field instead.
Joe Malin8d40d042012-11-05 11:36:40 -0800465 *
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500466 * @deprecated Use {@link #priority} with a positive value.
Daniel Sandlere46cbd32010-06-17 10:35:26 -0400467 */
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500468 public static final int FLAG_HIGH_PRIORITY = 0x00000080;
Daniel Sandlere46cbd32010-06-17 10:35:26 -0400469
Griff Hazendfcb0802014-02-11 12:00:00 -0800470 /**
471 * Bit to be bitswise-ored into the {@link #flags} field that should be
472 * set if this notification is relevant to the current device only
473 * and it is not recommended that it bridge to other devices.
474 */
475 public static final int FLAG_LOCAL_ONLY = 0x00000100;
476
Griff Hazen5cadc3b2014-05-20 09:55:39 -0700477 /**
478 * Bit to be bitswise-ored into the {@link #flags} field that should be
479 * set if this notification is the group summary for a group of notifications.
480 * Grouped notifications may display in a cluster or stack on devices which
481 * support such rendering. Requires a group key also be set using {@link Builder#setGroup}.
482 */
483 public static final int FLAG_GROUP_SUMMARY = 0x00000200;
484
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800485 public int flags;
486
Tor Norbyed9273d62013-05-30 15:59:53 -0700487 /** @hide */
488 @IntDef({PRIORITY_DEFAULT,PRIORITY_LOW,PRIORITY_MIN,PRIORITY_HIGH,PRIORITY_MAX})
489 @Retention(RetentionPolicy.SOURCE)
490 public @interface Priority {}
491
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800492 /**
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500493 * Default notification {@link #priority}. If your application does not prioritize its own
494 * notifications, use this value for all notifications.
495 */
496 public static final int PRIORITY_DEFAULT = 0;
497
498 /**
499 * Lower {@link #priority}, for items that are less important. The UI may choose to show these
500 * items smaller, or at a different position in the list, compared with your app's
501 * {@link #PRIORITY_DEFAULT} items.
502 */
503 public static final int PRIORITY_LOW = -1;
504
505 /**
506 * Lowest {@link #priority}; these items might not be shown to the user except under special
507 * circumstances, such as detailed notification logs.
508 */
509 public static final int PRIORITY_MIN = -2;
510
511 /**
512 * Higher {@link #priority}, for more important notifications or alerts. The UI may choose to
513 * show these items larger, or at a different position in notification lists, compared with
514 * your app's {@link #PRIORITY_DEFAULT} items.
515 */
516 public static final int PRIORITY_HIGH = 1;
517
518 /**
519 * Highest {@link #priority}, for your application's most important items that require the
520 * user's prompt attention or input.
521 */
522 public static final int PRIORITY_MAX = 2;
523
524 /**
525 * Relative priority for this notification.
Joe Malin8d40d042012-11-05 11:36:40 -0800526 *
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500527 * Priority is an indication of how much of the user's valuable attention should be consumed by
528 * this notification. Low-priority notifications may be hidden from the user in certain
529 * situations, while the user might be interrupted for a higher-priority notification. The
Daniel Sandler6738eee2012-11-16 12:03:32 -0500530 * system will make a determination about how to interpret this priority when presenting
531 * the notification.
Chris Wren47c20a12014-06-18 17:27:29 -0400532 *
533 * <p>
534 * A notification that is at least {@link #PRIORITY_HIGH} is more likely to be presented
535 * as a heads-up notification.
536 * </p>
537 *
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500538 */
Tor Norbyed9273d62013-05-30 15:59:53 -0700539 @Priority
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500540 public int priority;
Joe Malin8d40d042012-11-05 11:36:40 -0800541
Dan Sandler26e81cf2014-05-06 10:01:27 -0400542 /**
543 * Accent color (an ARGB integer like the constants in {@link android.graphics.Color})
544 * to be applied by the standard Style templates when presenting this notification.
545 *
546 * The current template design constructs a colorful header image by overlaying the
547 * {@link #icon} image (stenciled in white) atop a field of this color. Alpha components are
548 * ignored.
549 */
Tor Norbye80756e32015-03-02 09:39:27 -0800550 @ColorInt
Dan Sandler26e81cf2014-05-06 10:01:27 -0400551 public int color = COLOR_DEFAULT;
552
553 /**
554 * Special value of {@link #color} telling the system not to decorate this notification with
555 * any special color but instead use default colors when presenting this notification.
556 */
Tor Norbye80756e32015-03-02 09:39:27 -0800557 @ColorInt
Dan Sandler26e81cf2014-05-06 10:01:27 -0400558 public static final int COLOR_DEFAULT = 0; // AKA Color.TRANSPARENT
Dan Sandler0bf2ed82013-12-21 23:33:41 -0600559
560 /**
561 * Sphere of visibility of this notification, which affects how and when the SystemUI reveals
562 * the notification's presence and contents in untrusted situations (namely, on the secure
563 * lockscreen).
564 *
565 * The default level, {@link #VISIBILITY_PRIVATE}, behaves exactly as notifications have always
566 * done on Android: The notification's {@link #icon} and {@link #tickerText} (if available) are
567 * shown in all situations, but the contents are only available if the device is unlocked for
568 * the appropriate user.
569 *
570 * A more permissive policy can be expressed by {@link #VISIBILITY_PUBLIC}; such a notification
571 * can be read even in an "insecure" context (that is, above a secure lockscreen).
572 * To modify the public version of this notification—for example, to redact some portions—see
573 * {@link Builder#setPublicVersion(Notification)}.
574 *
575 * Finally, a notification can be made {@link #VISIBILITY_SECRET}, which will suppress its icon
576 * and ticker until the user has bypassed the lockscreen.
577 */
578 public int visibility;
579
Griff Hazenfc3922d2014-08-20 11:56:44 -0700580 /**
581 * Notification visibility: Show this notification in its entirety on all lockscreens.
582 *
583 * {@see #visibility}
584 */
Dan Sandler0bf2ed82013-12-21 23:33:41 -0600585 public static final int VISIBILITY_PUBLIC = 1;
Griff Hazenfc3922d2014-08-20 11:56:44 -0700586
587 /**
588 * Notification visibility: Show this notification on all lockscreens, but conceal sensitive or
589 * private information on secure lockscreens.
590 *
591 * {@see #visibility}
592 */
Dan Sandler0bf2ed82013-12-21 23:33:41 -0600593 public static final int VISIBILITY_PRIVATE = 0;
Griff Hazenfc3922d2014-08-20 11:56:44 -0700594
595 /**
596 * Notification visibility: Do not reveal any part of this notification on a secure lockscreen.
597 *
598 * {@see #visibility}
599 */
Dan Sandler0bf2ed82013-12-21 23:33:41 -0600600 public static final int VISIBILITY_SECRET = -1;
601
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500602 /**
John Spurlockfd7f1e02014-03-18 16:41:57 -0400603 * Notification category: incoming call (voice or video) or similar synchronous communication request.
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500604 */
John Spurlockfd7f1e02014-03-18 16:41:57 -0400605 public static final String CATEGORY_CALL = "call";
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500606
607 /**
John Spurlockfd7f1e02014-03-18 16:41:57 -0400608 * Notification category: incoming direct message (SMS, instant message, etc.).
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500609 */
John Spurlockfd7f1e02014-03-18 16:41:57 -0400610 public static final String CATEGORY_MESSAGE = "msg";
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500611
612 /**
John Spurlockfd7f1e02014-03-18 16:41:57 -0400613 * Notification category: asynchronous bulk message (email).
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500614 */
John Spurlockfd7f1e02014-03-18 16:41:57 -0400615 public static final String CATEGORY_EMAIL = "email";
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500616
617 /**
John Spurlockfd7f1e02014-03-18 16:41:57 -0400618 * Notification category: calendar event.
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500619 */
John Spurlockfd7f1e02014-03-18 16:41:57 -0400620 public static final String CATEGORY_EVENT = "event";
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500621
622 /**
John Spurlockfd7f1e02014-03-18 16:41:57 -0400623 * Notification category: promotion or advertisement.
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500624 */
John Spurlockfd7f1e02014-03-18 16:41:57 -0400625 public static final String CATEGORY_PROMO = "promo";
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500626
627 /**
John Spurlockfd7f1e02014-03-18 16:41:57 -0400628 * Notification category: alarm or timer.
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500629 */
John Spurlockfd7f1e02014-03-18 16:41:57 -0400630 public static final String CATEGORY_ALARM = "alarm";
631
632 /**
633 * Notification category: progress of a long-running background operation.
634 */
635 public static final String CATEGORY_PROGRESS = "progress";
636
637 /**
638 * Notification category: social network or sharing update.
639 */
640 public static final String CATEGORY_SOCIAL = "social";
641
642 /**
643 * Notification category: error in background operation or authentication status.
644 */
645 public static final String CATEGORY_ERROR = "err";
646
647 /**
648 * Notification category: media transport control for playback.
649 */
650 public static final String CATEGORY_TRANSPORT = "transport";
651
652 /**
653 * Notification category: system or device status update. Reserved for system use.
654 */
655 public static final String CATEGORY_SYSTEM = "sys";
656
657 /**
658 * Notification category: indication of running background service.
659 */
660 public static final String CATEGORY_SERVICE = "service";
661
662 /**
John Spurlock0a69c8c2014-03-21 13:30:57 -0400663 * Notification category: a specific, timely recommendation for a single thing.
664 * For example, a news app might want to recommend a news story it believes the user will
665 * want to read next.
666 */
667 public static final String CATEGORY_RECOMMENDATION = "recommendation";
668
669 /**
John Spurlockfd7f1e02014-03-18 16:41:57 -0400670 * Notification category: ongoing information about device or contextual status.
671 */
672 public static final String CATEGORY_STATUS = "status";
673
674 /**
John Spurlock24d3dad2015-04-02 12:24:02 -0400675 * Notification category: user-scheduled reminder.
676 */
677 public static final String CATEGORY_REMINDER = "reminder";
678
679 /**
John Spurlockfd7f1e02014-03-18 16:41:57 -0400680 * One of the predefined notification categories (see the <code>CATEGORY_*</code> constants)
681 * that best describes this Notification. May be used by the system for ranking and filtering.
682 */
683 public String category;
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500684
Griff Hazen5cadc3b2014-05-20 09:55:39 -0700685 private String mGroupKey;
686
687 /**
688 * Get the key used to group this notification into a cluster or stack
689 * with other notifications on devices which support such rendering.
690 */
691 public String getGroup() {
692 return mGroupKey;
693 }
694
695 private String mSortKey;
696
697 /**
698 * Get a sort key that orders this notification among other notifications from the
699 * same package. This can be useful if an external sort was already applied and an app
700 * would like to preserve this. Notifications will be sorted lexicographically using this
701 * value, although providing different priorities in addition to providing sort key may
702 * cause this value to be ignored.
703 *
704 * <p>This sort key can also be used to order members of a notification group. See
705 * {@link Builder#setGroup}.
706 *
707 * @see String#compareTo(String)
708 */
709 public String getSortKey() {
710 return mSortKey;
711 }
712
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500713 /**
Daniel Sandlerf45564e2013-04-15 15:05:08 -0400714 * Additional semantic data to be carried around with this Notification.
Daniel Sandlercf1d39b2013-09-23 13:35:35 -0400715 * <p>
716 * The extras keys defined here are intended to capture the original inputs to {@link Builder}
717 * APIs, and are intended to be used by
718 * {@link android.service.notification.NotificationListenerService} implementations to extract
719 * detailed information from notification objects.
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500720 */
Daniel Sandlerf45564e2013-04-15 15:05:08 -0400721 public Bundle extras = new Bundle();
722
Daniel Sandlercf1d39b2013-09-23 13:35:35 -0400723 /**
724 * {@link #extras} key: this is the title of the notification,
725 * as supplied to {@link Builder#setContentTitle(CharSequence)}.
726 */
Daniel Sandlerbe6e7e02013-02-01 17:49:11 -0500727 public static final String EXTRA_TITLE = "android.title";
Daniel Sandlercf1d39b2013-09-23 13:35:35 -0400728
729 /**
730 * {@link #extras} key: this is the title of the notification when shown in expanded form,
731 * e.g. as supplied to {@link BigTextStyle#setBigContentTitle(CharSequence)}.
732 */
Daniel Sandlerf45564e2013-04-15 15:05:08 -0400733 public static final String EXTRA_TITLE_BIG = EXTRA_TITLE + ".big";
Daniel Sandlercf1d39b2013-09-23 13:35:35 -0400734
735 /**
736 * {@link #extras} key: this is the main text payload, as supplied to
737 * {@link Builder#setContentText(CharSequence)}.
738 */
Daniel Sandlerbe6e7e02013-02-01 17:49:11 -0500739 public static final String EXTRA_TEXT = "android.text";
Daniel Sandlercf1d39b2013-09-23 13:35:35 -0400740
741 /**
742 * {@link #extras} key: this is a third line of text, as supplied to
743 * {@link Builder#setSubText(CharSequence)}.
744 */
Daniel Sandlerf45564e2013-04-15 15:05:08 -0400745 public static final String EXTRA_SUB_TEXT = "android.subText";
Daniel Sandlercf1d39b2013-09-23 13:35:35 -0400746
747 /**
748 * {@link #extras} key: this is a small piece of additional text as supplied to
749 * {@link Builder#setContentInfo(CharSequence)}.
750 */
Daniel Sandlerf45564e2013-04-15 15:05:08 -0400751 public static final String EXTRA_INFO_TEXT = "android.infoText";
Daniel Sandlercf1d39b2013-09-23 13:35:35 -0400752
753 /**
754 * {@link #extras} key: this is a line of summary information intended to be shown
755 * alongside expanded notifications, as supplied to (e.g.)
756 * {@link BigTextStyle#setSummaryText(CharSequence)}.
757 */
Daniel Sandlerf45564e2013-04-15 15:05:08 -0400758 public static final String EXTRA_SUMMARY_TEXT = "android.summaryText";
Daniel Sandlercf1d39b2013-09-23 13:35:35 -0400759
760 /**
Christoph Studer4600f9b2014-07-22 22:44:43 +0200761 * {@link #extras} key: this is the longer text shown in the big form of a
762 * {@link BigTextStyle} notification, as supplied to
763 * {@link BigTextStyle#bigText(CharSequence)}.
764 */
765 public static final String EXTRA_BIG_TEXT = "android.bigText";
766
767 /**
Daniel Sandlercf1d39b2013-09-23 13:35:35 -0400768 * {@link #extras} key: this is the resource ID of the notification's main small icon, as
769 * supplied to {@link Builder#setSmallIcon(int)}.
770 */
Daniel Sandlerbe6e7e02013-02-01 17:49:11 -0500771 public static final String EXTRA_SMALL_ICON = "android.icon";
Daniel Sandlercf1d39b2013-09-23 13:35:35 -0400772
773 /**
774 * {@link #extras} key: this is a bitmap to be used instead of the small icon when showing the
775 * notification payload, as
776 * supplied to {@link Builder#setLargeIcon(android.graphics.Bitmap)}.
777 */
Daniel Sandlerf45564e2013-04-15 15:05:08 -0400778 public static final String EXTRA_LARGE_ICON = "android.largeIcon";
Daniel Sandlercf1d39b2013-09-23 13:35:35 -0400779
780 /**
781 * {@link #extras} key: this is a bitmap to be used instead of the one from
782 * {@link Builder#setLargeIcon(android.graphics.Bitmap)} when the notification is
783 * shown in its expanded form, as supplied to
784 * {@link BigPictureStyle#bigLargeIcon(android.graphics.Bitmap)}.
785 */
Daniel Sandlerf45564e2013-04-15 15:05:08 -0400786 public static final String EXTRA_LARGE_ICON_BIG = EXTRA_LARGE_ICON + ".big";
Daniel Sandlercf1d39b2013-09-23 13:35:35 -0400787
788 /**
789 * {@link #extras} key: this is the progress value supplied to
790 * {@link Builder#setProgress(int, int, boolean)}.
791 */
Daniel Sandlerf45564e2013-04-15 15:05:08 -0400792 public static final String EXTRA_PROGRESS = "android.progress";
Daniel Sandlercf1d39b2013-09-23 13:35:35 -0400793
794 /**
795 * {@link #extras} key: this is the maximum value supplied to
796 * {@link Builder#setProgress(int, int, boolean)}.
797 */
Daniel Sandlerf45564e2013-04-15 15:05:08 -0400798 public static final String EXTRA_PROGRESS_MAX = "android.progressMax";
Daniel Sandlercf1d39b2013-09-23 13:35:35 -0400799
800 /**
801 * {@link #extras} key: whether the progress bar is indeterminate, supplied to
802 * {@link Builder#setProgress(int, int, boolean)}.
803 */
Daniel Sandlerf45564e2013-04-15 15:05:08 -0400804 public static final String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
Daniel Sandlercf1d39b2013-09-23 13:35:35 -0400805
806 /**
807 * {@link #extras} key: whether {@link #when} should be shown as a count-up timer (specifically
808 * a {@link android.widget.Chronometer}) instead of a timestamp, as supplied to
809 * {@link Builder#setUsesChronometer(boolean)}.
810 */
Daniel Sandlerf45564e2013-04-15 15:05:08 -0400811 public static final String EXTRA_SHOW_CHRONOMETER = "android.showChronometer";
Daniel Sandlercf1d39b2013-09-23 13:35:35 -0400812
813 /**
814 * {@link #extras} key: whether {@link #when} should be shown,
815 * as supplied to {@link Builder#setShowWhen(boolean)}.
816 */
Daniel Sandlerf45564e2013-04-15 15:05:08 -0400817 public static final String EXTRA_SHOW_WHEN = "android.showWhen";
Daniel Sandlercf1d39b2013-09-23 13:35:35 -0400818
819 /**
820 * {@link #extras} key: this is a bitmap to be shown in {@link BigPictureStyle} expanded
821 * notifications, supplied to {@link BigPictureStyle#bigPicture(android.graphics.Bitmap)}.
822 */
Daniel Sandlerf45564e2013-04-15 15:05:08 -0400823 public static final String EXTRA_PICTURE = "android.picture";
Daniel Sandlercf1d39b2013-09-23 13:35:35 -0400824
825 /**
826 * {@link #extras} key: An array of CharSequences to show in {@link InboxStyle} expanded
827 * notifications, each of which was supplied to {@link InboxStyle#addLine(CharSequence)}.
828 */
Daniel Sandlerf45564e2013-04-15 15:05:08 -0400829 public static final String EXTRA_TEXT_LINES = "android.textLines";
Dan Sandler842dd772014-05-15 09:36:47 -0400830
831 /**
832 * {@link #extras} key: A string representing the name of the specific
833 * {@link android.app.Notification.Style} used to create this notification.
834 */
Chris Wren91ad5632013-06-05 15:05:57 -0400835 public static final String EXTRA_TEMPLATE = "android.template";
Daniel Sandlerf45564e2013-04-15 15:05:08 -0400836
Daniel Sandlercf1d39b2013-09-23 13:35:35 -0400837 /**
Chris Wrene6c48932014-09-29 17:19:27 -0400838 * {@link #extras} key: A String array containing the people that this notification relates to,
839 * each of which was supplied to {@link Builder#addPerson(String)}.
Daniel Sandlercf1d39b2013-09-23 13:35:35 -0400840 */
Daniel Sandlerf45564e2013-04-15 15:05:08 -0400841 public static final String EXTRA_PEOPLE = "android.people";
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500842
843 /**
John Spurlockfd7f1e02014-03-18 16:41:57 -0400844 * Allow certain system-generated notifications to appear before the device is provisioned.
845 * Only available to notifications coming from the android package.
846 * @hide
847 */
848 public static final String EXTRA_ALLOW_DURING_SETUP = "android.allowDuringSetup";
849
850 /**
Jose Limae9e3b3b2014-05-18 23:44:50 -0700851 * {@link #extras} key: A
852 * {@link android.content.ContentUris content URI} pointing to an image that can be displayed
853 * in the background when the notification is selected. The URI must point to an image stream
854 * suitable for passing into
855 * {@link android.graphics.BitmapFactory#decodeStream(java.io.InputStream)
856 * BitmapFactory.decodeStream}; all other content types will be ignored. The content provider
857 * URI used for this purpose must require no permissions to read the image data.
858 */
859 public static final String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
860
861 /**
Dan Sandler842dd772014-05-15 09:36:47 -0400862 * {@link #extras} key: A
Jeff Browndba34ba2014-06-24 20:46:03 -0700863 * {@link android.media.session.MediaSession.Token} associated with a
Dan Sandler842dd772014-05-15 09:36:47 -0400864 * {@link android.app.Notification.MediaStyle} notification.
865 */
866 public static final String EXTRA_MEDIA_SESSION = "android.mediaSession";
867
868 /**
Bryan Mawhinneye191f902014-07-22 12:50:09 +0100869 * {@link #extras} key: the indices of actions to be shown in the compact view,
870 * as supplied to (e.g.) {@link MediaStyle#setShowActionsInCompactView(int...)}.
871 */
872 public static final String EXTRA_COMPACT_ACTIONS = "android.compactActions";
873
Christoph Studer943aa672014-08-03 20:31:16 +0200874 /**
Kenny Guy8942bcd2014-09-08 21:09:47 +0100875 * {@link #extras} key: the user that built the notification.
876 *
877 * @hide
878 */
879 public static final String EXTRA_ORIGINATING_USERID = "android.originatingUserId";
880
881 /**
Julia Reynoldsd9228f12015-10-20 10:37:27 -0400882 * @hide
883 */
884 public static final String EXTRA_BUILDER_APPLICATION_INFO = "android.appInfo";
885
Dan Sandlerd63f9322015-05-06 15:18:49 -0400886 private Icon mSmallIcon;
887 private Icon mLargeIcon;
888
Chris Wren51c75102013-07-16 20:49:17 -0400889 /**
Daniel Sandlercf1d39b2013-09-23 13:35:35 -0400890 * Structure to encapsulate a named action that can be shown as part of this notification.
891 * It must include an icon, a label, and a {@link PendingIntent} to be fired when the action is
892 * selected by the user.
893 * <p>
Griff Hazen959591e2014-05-15 22:26:18 -0700894 * Apps should use {@link Notification.Builder#addAction(int, CharSequence, PendingIntent)}
895 * or {@link Notification.Builder#addAction(Notification.Action)}
896 * to attach actions.
Daniel Sandlera0a938c2012-03-15 08:42:37 -0400897 */
Daniel Sandlerea2a3172013-02-20 22:24:20 -0500898 public static class Action implements Parcelable {
Griff Hazen959591e2014-05-15 22:26:18 -0700899 private final Bundle mExtras;
Dan Sandler86647982015-05-13 23:41:13 -0400900 private Icon mIcon;
Griff Hazen61a9e862014-05-22 16:05:19 -0700901 private final RemoteInput[] mRemoteInputs;
Griff Hazen959591e2014-05-15 22:26:18 -0700902
Daniel Sandlercf1d39b2013-09-23 13:35:35 -0400903 /**
904 * Small icon representing the action.
Dan Sandler86647982015-05-13 23:41:13 -0400905 *
906 * @deprecated Use {@link Action#getIcon()} instead.
Daniel Sandlercf1d39b2013-09-23 13:35:35 -0400907 */
Dan Sandler86647982015-05-13 23:41:13 -0400908 @Deprecated
Daniel Sandlera0a938c2012-03-15 08:42:37 -0400909 public int icon;
Griff Hazen5cadc3b2014-05-20 09:55:39 -0700910
Daniel Sandlercf1d39b2013-09-23 13:35:35 -0400911 /**
912 * Title of the action.
913 */
Daniel Sandlera0a938c2012-03-15 08:42:37 -0400914 public CharSequence title;
Griff Hazen5cadc3b2014-05-20 09:55:39 -0700915
Daniel Sandlercf1d39b2013-09-23 13:35:35 -0400916 /**
917 * Intent to send when the user invokes this action. May be null, in which case the action
918 * may be rendered in a disabled presentation by the system UI.
919 */
Daniel Sandlera0a938c2012-03-15 08:42:37 -0400920 public PendingIntent actionIntent;
Griff Hazen959591e2014-05-15 22:26:18 -0700921
Daniel Sandlera0a938c2012-03-15 08:42:37 -0400922 private Action(Parcel in) {
Dan Sandler86647982015-05-13 23:41:13 -0400923 if (in.readInt() != 0) {
924 mIcon = Icon.CREATOR.createFromParcel(in);
Dan Sandler68079d52015-07-22 10:45:30 -0400925 if (mIcon.getType() == Icon.TYPE_RESOURCE) {
926 icon = mIcon.getResId();
927 }
Dan Sandler86647982015-05-13 23:41:13 -0400928 }
Daniel Sandlera0a938c2012-03-15 08:42:37 -0400929 title = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
930 if (in.readInt() == 1) {
931 actionIntent = PendingIntent.CREATOR.createFromParcel(in);
932 }
Griff Hazen959591e2014-05-15 22:26:18 -0700933 mExtras = in.readBundle();
Griff Hazen5cadc3b2014-05-20 09:55:39 -0700934 mRemoteInputs = in.createTypedArray(RemoteInput.CREATOR);
Daniel Sandlera0a938c2012-03-15 08:42:37 -0400935 }
Griff Hazen5cadc3b2014-05-20 09:55:39 -0700936
Daniel Sandlercf1d39b2013-09-23 13:35:35 -0400937 /**
Dan Sandler86647982015-05-13 23:41:13 -0400938 * @deprecated Use {@link android.app.Notification.Action.Builder}.
Daniel Sandlercf1d39b2013-09-23 13:35:35 -0400939 */
Dan Sandler86647982015-05-13 23:41:13 -0400940 @Deprecated
Daniel Sandlercf1d39b2013-09-23 13:35:35 -0400941 public Action(int icon, CharSequence title, PendingIntent intent) {
Dan Sandler86647982015-05-13 23:41:13 -0400942 this(Icon.createWithResource("", icon), title, intent, new Bundle(), null);
Griff Hazen959591e2014-05-15 22:26:18 -0700943 }
944
Dan Sandler86647982015-05-13 23:41:13 -0400945 private Action(Icon icon, CharSequence title, PendingIntent intent, Bundle extras,
Griff Hazen5cadc3b2014-05-20 09:55:39 -0700946 RemoteInput[] remoteInputs) {
Dan Sandler86647982015-05-13 23:41:13 -0400947 this.mIcon = icon;
Gus Prevasf5bff46f2015-08-24 10:34:28 -0400948 if (icon != null && icon.getType() == Icon.TYPE_RESOURCE) {
949 this.icon = icon.getResId();
950 }
Daniel Sandlercf1d39b2013-09-23 13:35:35 -0400951 this.title = title;
952 this.actionIntent = intent;
Griff Hazen959591e2014-05-15 22:26:18 -0700953 this.mExtras = extras != null ? extras : new Bundle();
Griff Hazen5cadc3b2014-05-20 09:55:39 -0700954 this.mRemoteInputs = remoteInputs;
Griff Hazen959591e2014-05-15 22:26:18 -0700955 }
956
957 /**
Dan Sandler86647982015-05-13 23:41:13 -0400958 * Return an icon representing the action.
959 */
960 public Icon getIcon() {
961 if (mIcon == null && icon != 0) {
962 // you snuck an icon in here without using the builder; let's try to keep it
963 mIcon = Icon.createWithResource("", icon);
964 }
965 return mIcon;
966 }
967
968 /**
Griff Hazen959591e2014-05-15 22:26:18 -0700969 * Get additional metadata carried around with this Action.
970 */
971 public Bundle getExtras() {
972 return mExtras;
973 }
974
975 /**
Griff Hazen5cadc3b2014-05-20 09:55:39 -0700976 * Get the list of inputs to be collected from the user when this action is sent.
977 * May return null if no remote inputs were added.
978 */
979 public RemoteInput[] getRemoteInputs() {
980 return mRemoteInputs;
981 }
982
983 /**
Griff Hazen959591e2014-05-15 22:26:18 -0700984 * Builder class for {@link Action} objects.
985 */
Griff Hazen5cadc3b2014-05-20 09:55:39 -0700986 public static final class Builder {
Dan Sandler86647982015-05-13 23:41:13 -0400987 private final Icon mIcon;
Griff Hazen959591e2014-05-15 22:26:18 -0700988 private final CharSequence mTitle;
989 private final PendingIntent mIntent;
990 private final Bundle mExtras;
Griff Hazen5cadc3b2014-05-20 09:55:39 -0700991 private ArrayList<RemoteInput> mRemoteInputs;
Griff Hazen959591e2014-05-15 22:26:18 -0700992
993 /**
994 * Construct a new builder for {@link Action} object.
995 * @param icon icon to show for this action
996 * @param title the title of the action
997 * @param intent the {@link PendingIntent} to fire when users trigger this action
998 */
Dan Sandler86647982015-05-13 23:41:13 -0400999 @Deprecated
Griff Hazen959591e2014-05-15 22:26:18 -07001000 public Builder(int icon, CharSequence title, PendingIntent intent) {
Dan Sandler86647982015-05-13 23:41:13 -04001001 this(Icon.createWithResource("", icon), title, intent, new Bundle(), null);
1002 }
1003
1004 /**
1005 * Construct a new builder for {@link Action} object.
1006 * @param icon icon to show for this action
1007 * @param title the title of the action
1008 * @param intent the {@link PendingIntent} to fire when users trigger this action
1009 */
1010 public Builder(Icon icon, CharSequence title, PendingIntent intent) {
Griff Hazen5cadc3b2014-05-20 09:55:39 -07001011 this(icon, title, intent, new Bundle(), null);
Griff Hazen959591e2014-05-15 22:26:18 -07001012 }
1013
1014 /**
1015 * Construct a new builder for {@link Action} object using the fields from an
1016 * {@link Action}.
1017 * @param action the action to read fields from.
1018 */
1019 public Builder(Action action) {
Dan Sandler86647982015-05-13 23:41:13 -04001020 this(action.getIcon(), action.title, action.actionIntent, new Bundle(action.mExtras),
Griff Hazen5cadc3b2014-05-20 09:55:39 -07001021 action.getRemoteInputs());
Griff Hazen959591e2014-05-15 22:26:18 -07001022 }
1023
Dan Sandler86647982015-05-13 23:41:13 -04001024 private Builder(Icon icon, CharSequence title, PendingIntent intent, Bundle extras,
Griff Hazen5cadc3b2014-05-20 09:55:39 -07001025 RemoteInput[] remoteInputs) {
Griff Hazen959591e2014-05-15 22:26:18 -07001026 mIcon = icon;
1027 mTitle = title;
1028 mIntent = intent;
1029 mExtras = extras;
Griff Hazen5cadc3b2014-05-20 09:55:39 -07001030 if (remoteInputs != null) {
1031 mRemoteInputs = new ArrayList<RemoteInput>(remoteInputs.length);
1032 Collections.addAll(mRemoteInputs, remoteInputs);
1033 }
Griff Hazen959591e2014-05-15 22:26:18 -07001034 }
1035
1036 /**
1037 * Merge additional metadata into this builder.
1038 *
1039 * <p>Values within the Bundle will replace existing extras values in this Builder.
1040 *
1041 * @see Notification.Action#extras
1042 */
1043 public Builder addExtras(Bundle extras) {
1044 if (extras != null) {
1045 mExtras.putAll(extras);
1046 }
1047 return this;
1048 }
1049
1050 /**
1051 * Get the metadata Bundle used by this Builder.
1052 *
1053 * <p>The returned Bundle is shared with this Builder.
1054 */
1055 public Bundle getExtras() {
1056 return mExtras;
1057 }
1058
1059 /**
Griff Hazen5cadc3b2014-05-20 09:55:39 -07001060 * Add an input to be collected from the user when this action is sent.
1061 * Response values can be retrieved from the fired intent by using the
1062 * {@link RemoteInput#getResultsFromIntent} function.
1063 * @param remoteInput a {@link RemoteInput} to add to the action
1064 * @return this object for method chaining
1065 */
1066 public Builder addRemoteInput(RemoteInput remoteInput) {
1067 if (mRemoteInputs == null) {
1068 mRemoteInputs = new ArrayList<RemoteInput>();
1069 }
1070 mRemoteInputs.add(remoteInput);
1071 return this;
1072 }
1073
1074 /**
1075 * Apply an extender to this action builder. Extenders may be used to add
1076 * metadata or change options on this builder.
1077 */
Griff Hazen61a9e862014-05-22 16:05:19 -07001078 public Builder extend(Extender extender) {
1079 extender.extend(this);
Griff Hazen5cadc3b2014-05-20 09:55:39 -07001080 return this;
1081 }
1082
1083 /**
Griff Hazen959591e2014-05-15 22:26:18 -07001084 * Combine all of the options that have been set and return a new {@link Action}
1085 * object.
1086 * @return the built action
1087 */
1088 public Action build() {
Griff Hazen5cadc3b2014-05-20 09:55:39 -07001089 RemoteInput[] remoteInputs = mRemoteInputs != null
1090 ? mRemoteInputs.toArray(new RemoteInput[mRemoteInputs.size()]) : null;
1091 return new Action(mIcon, mTitle, mIntent, mExtras, remoteInputs);
Griff Hazen959591e2014-05-15 22:26:18 -07001092 }
Daniel Sandlera0a938c2012-03-15 08:42:37 -04001093 }
Daniel Sandlercf1d39b2013-09-23 13:35:35 -04001094
Daniel Sandlera0a938c2012-03-15 08:42:37 -04001095 @Override
1096 public Action clone() {
1097 return new Action(
Dan Sandler86647982015-05-13 23:41:13 -04001098 getIcon(),
Griff Hazen5cadc3b2014-05-20 09:55:39 -07001099 title,
1100 actionIntent, // safe to alias
1101 new Bundle(mExtras),
1102 getRemoteInputs());
Daniel Sandlera0a938c2012-03-15 08:42:37 -04001103 }
1104 @Override
1105 public int describeContents() {
1106 return 0;
1107 }
1108 @Override
1109 public void writeToParcel(Parcel out, int flags) {
Dan Sandler86647982015-05-13 23:41:13 -04001110 final Icon ic = getIcon();
1111 if (ic != null) {
1112 out.writeInt(1);
1113 ic.writeToParcel(out, 0);
1114 } else {
1115 out.writeInt(0);
1116 }
Daniel Sandlera0a938c2012-03-15 08:42:37 -04001117 TextUtils.writeToParcel(title, out, flags);
1118 if (actionIntent != null) {
1119 out.writeInt(1);
1120 actionIntent.writeToParcel(out, flags);
1121 } else {
1122 out.writeInt(0);
1123 }
Griff Hazen959591e2014-05-15 22:26:18 -07001124 out.writeBundle(mExtras);
Griff Hazen5cadc3b2014-05-20 09:55:39 -07001125 out.writeTypedArray(mRemoteInputs, flags);
Daniel Sandlera0a938c2012-03-15 08:42:37 -04001126 }
Griff Hazen959591e2014-05-15 22:26:18 -07001127 public static final Parcelable.Creator<Action> CREATOR =
1128 new Parcelable.Creator<Action>() {
Daniel Sandlera0a938c2012-03-15 08:42:37 -04001129 public Action createFromParcel(Parcel in) {
1130 return new Action(in);
1131 }
1132 public Action[] newArray(int size) {
1133 return new Action[size];
1134 }
1135 };
Griff Hazen61a9e862014-05-22 16:05:19 -07001136
1137 /**
1138 * Extender interface for use with {@link Builder#extend}. Extenders may be used to add
1139 * metadata or change options on an action builder.
1140 */
1141 public interface Extender {
1142 /**
1143 * Apply this extender to a notification action builder.
1144 * @param builder the builder to be modified.
1145 * @return the build object for chaining.
1146 */
1147 public Builder extend(Builder builder);
1148 }
1149
1150 /**
1151 * Wearable extender for notification actions. To add extensions to an action,
1152 * create a new {@link android.app.Notification.Action.WearableExtender} object using
1153 * the {@code WearableExtender()} constructor and apply it to a
1154 * {@link android.app.Notification.Action.Builder} using
1155 * {@link android.app.Notification.Action.Builder#extend}.
1156 *
1157 * <pre class="prettyprint">
1158 * Notification.Action action = new Notification.Action.Builder(
1159 * R.drawable.archive_all, "Archive all", actionIntent)
Griff Hazen14f57992014-05-26 09:07:14 -07001160 * .extend(new Notification.Action.WearableExtender()
Griff Hazen61a9e862014-05-22 16:05:19 -07001161 * .setAvailableOffline(false))
Griff Hazen14f57992014-05-26 09:07:14 -07001162 * .build();</pre>
Griff Hazen61a9e862014-05-22 16:05:19 -07001163 */
1164 public static final class WearableExtender implements Extender {
1165 /** Notification action extra which contains wearable extensions */
1166 private static final String EXTRA_WEARABLE_EXTENSIONS = "android.wearable.EXTENSIONS";
1167
Pete Gastaf6781d2014-10-07 15:17:05 -04001168 // Keys within EXTRA_WEARABLE_EXTENSIONS for wearable options.
Griff Hazen61a9e862014-05-22 16:05:19 -07001169 private static final String KEY_FLAGS = "flags";
Pete Gastaf6781d2014-10-07 15:17:05 -04001170 private static final String KEY_IN_PROGRESS_LABEL = "inProgressLabel";
1171 private static final String KEY_CONFIRM_LABEL = "confirmLabel";
1172 private static final String KEY_CANCEL_LABEL = "cancelLabel";
Griff Hazen61a9e862014-05-22 16:05:19 -07001173
1174 // Flags bitwise-ored to mFlags
1175 private static final int FLAG_AVAILABLE_OFFLINE = 0x1;
1176
1177 // Default value for flags integer
1178 private static final int DEFAULT_FLAGS = FLAG_AVAILABLE_OFFLINE;
1179
1180 private int mFlags = DEFAULT_FLAGS;
1181
Pete Gastaf6781d2014-10-07 15:17:05 -04001182 private CharSequence mInProgressLabel;
1183 private CharSequence mConfirmLabel;
1184 private CharSequence mCancelLabel;
1185
Griff Hazen61a9e862014-05-22 16:05:19 -07001186 /**
1187 * Create a {@link android.app.Notification.Action.WearableExtender} with default
1188 * options.
1189 */
1190 public WearableExtender() {
1191 }
1192
1193 /**
1194 * Create a {@link android.app.Notification.Action.WearableExtender} by reading
1195 * wearable options present in an existing notification action.
1196 * @param action the notification action to inspect.
1197 */
1198 public WearableExtender(Action action) {
1199 Bundle wearableBundle = action.getExtras().getBundle(EXTRA_WEARABLE_EXTENSIONS);
1200 if (wearableBundle != null) {
1201 mFlags = wearableBundle.getInt(KEY_FLAGS, DEFAULT_FLAGS);
Pete Gastaf6781d2014-10-07 15:17:05 -04001202 mInProgressLabel = wearableBundle.getCharSequence(KEY_IN_PROGRESS_LABEL);
1203 mConfirmLabel = wearableBundle.getCharSequence(KEY_CONFIRM_LABEL);
1204 mCancelLabel = wearableBundle.getCharSequence(KEY_CANCEL_LABEL);
Griff Hazen61a9e862014-05-22 16:05:19 -07001205 }
1206 }
1207
1208 /**
1209 * Apply wearable extensions to a notification action that is being built. This is
1210 * typically called by the {@link android.app.Notification.Action.Builder#extend}
1211 * method of {@link android.app.Notification.Action.Builder}.
1212 */
1213 @Override
1214 public Action.Builder extend(Action.Builder builder) {
1215 Bundle wearableBundle = new Bundle();
1216
1217 if (mFlags != DEFAULT_FLAGS) {
1218 wearableBundle.putInt(KEY_FLAGS, mFlags);
1219 }
Pete Gastaf6781d2014-10-07 15:17:05 -04001220 if (mInProgressLabel != null) {
1221 wearableBundle.putCharSequence(KEY_IN_PROGRESS_LABEL, mInProgressLabel);
1222 }
1223 if (mConfirmLabel != null) {
1224 wearableBundle.putCharSequence(KEY_CONFIRM_LABEL, mConfirmLabel);
1225 }
1226 if (mCancelLabel != null) {
1227 wearableBundle.putCharSequence(KEY_CANCEL_LABEL, mCancelLabel);
1228 }
Griff Hazen61a9e862014-05-22 16:05:19 -07001229
1230 builder.getExtras().putBundle(EXTRA_WEARABLE_EXTENSIONS, wearableBundle);
1231 return builder;
1232 }
1233
1234 @Override
1235 public WearableExtender clone() {
1236 WearableExtender that = new WearableExtender();
1237 that.mFlags = this.mFlags;
Pete Gastaf6781d2014-10-07 15:17:05 -04001238 that.mInProgressLabel = this.mInProgressLabel;
1239 that.mConfirmLabel = this.mConfirmLabel;
1240 that.mCancelLabel = this.mCancelLabel;
Griff Hazen61a9e862014-05-22 16:05:19 -07001241 return that;
1242 }
1243
1244 /**
1245 * Set whether this action is available when the wearable device is not connected to
1246 * a companion device. The user can still trigger this action when the wearable device is
1247 * offline, but a visual hint will indicate that the action may not be available.
1248 * Defaults to true.
1249 */
1250 public WearableExtender setAvailableOffline(boolean availableOffline) {
1251 setFlag(FLAG_AVAILABLE_OFFLINE, availableOffline);
1252 return this;
1253 }
1254
1255 /**
1256 * Get whether this action is available when the wearable device is not connected to
1257 * a companion device. The user can still trigger this action when the wearable device is
1258 * offline, but a visual hint will indicate that the action may not be available.
1259 * Defaults to true.
1260 */
1261 public boolean isAvailableOffline() {
1262 return (mFlags & FLAG_AVAILABLE_OFFLINE) != 0;
1263 }
1264
1265 private void setFlag(int mask, boolean value) {
1266 if (value) {
1267 mFlags |= mask;
1268 } else {
1269 mFlags &= ~mask;
1270 }
1271 }
Pete Gastaf6781d2014-10-07 15:17:05 -04001272
1273 /**
1274 * Set a label to display while the wearable is preparing to automatically execute the
1275 * action. This is usually a 'ing' verb ending in ellipsis like "Sending..."
1276 *
1277 * @param label the label to display while the action is being prepared to execute
1278 * @return this object for method chaining
1279 */
1280 public WearableExtender setInProgressLabel(CharSequence label) {
1281 mInProgressLabel = label;
1282 return this;
1283 }
1284
1285 /**
1286 * Get the label to display while the wearable is preparing to automatically execute
1287 * the action. This is usually a 'ing' verb ending in ellipsis like "Sending..."
1288 *
1289 * @return the label to display while the action is being prepared to execute
1290 */
1291 public CharSequence getInProgressLabel() {
1292 return mInProgressLabel;
1293 }
1294
1295 /**
1296 * Set a label to display to confirm that the action should be executed.
1297 * This is usually an imperative verb like "Send".
1298 *
1299 * @param label the label to confirm the action should be executed
1300 * @return this object for method chaining
1301 */
1302 public WearableExtender setConfirmLabel(CharSequence label) {
1303 mConfirmLabel = label;
1304 return this;
1305 }
1306
1307 /**
1308 * Get the label to display to confirm that the action should be executed.
1309 * This is usually an imperative verb like "Send".
1310 *
1311 * @return the label to confirm the action should be executed
1312 */
1313 public CharSequence getConfirmLabel() {
1314 return mConfirmLabel;
1315 }
1316
1317 /**
1318 * Set a label to display to cancel the action.
1319 * This is usually an imperative verb, like "Cancel".
1320 *
1321 * @param label the label to display to cancel the action
1322 * @return this object for method chaining
1323 */
1324 public WearableExtender setCancelLabel(CharSequence label) {
1325 mCancelLabel = label;
1326 return this;
1327 }
1328
1329 /**
1330 * Get the label to display to cancel the action.
1331 * This is usually an imperative verb like "Cancel".
1332 *
1333 * @return the label to display to cancel the action
1334 */
1335 public CharSequence getCancelLabel() {
1336 return mCancelLabel;
1337 }
Griff Hazen61a9e862014-05-22 16:05:19 -07001338 }
Daniel Sandlera0a938c2012-03-15 08:42:37 -04001339 }
1340
Daniel Sandlercf1d39b2013-09-23 13:35:35 -04001341 /**
1342 * Array of all {@link Action} structures attached to this notification by
1343 * {@link Builder#addAction(int, CharSequence, PendingIntent)}. Mostly useful for instances of
1344 * {@link android.service.notification.NotificationListenerService} that provide an alternative
1345 * interface for invoking actions.
1346 */
Daniel Sandlerea2a3172013-02-20 22:24:20 -05001347 public Action[] actions;
Daniel Sandlera0a938c2012-03-15 08:42:37 -04001348
1349 /**
Dan Sandler0bf2ed82013-12-21 23:33:41 -06001350 * Replacement version of this notification whose content will be shown
1351 * in an insecure context such as atop a secure keyguard. See {@link #visibility}
1352 * and {@link #VISIBILITY_PUBLIC}.
1353 */
1354 public Notification publicVersion;
1355
1356 /**
Julia Reynolds74303cf2015-10-16 11:37:55 -04001357 * Structure to encapsulate a topic that is shown in Notification settings.
1358 * It must include an id and label.
1359 */
1360 public static class Topic implements Parcelable {
1361 private final String id;
1362 private final CharSequence label;
1363
1364 public Topic(String id, CharSequence label) {
1365 this.id = id;
1366 this.label = safeCharSequence(label);
1367 }
1368
1369 private Topic(Parcel in) {
1370 if (in.readInt() != 0) {
1371 id = in.readString();
1372 } else {
1373 id = null;
1374 }
1375 label = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
1376 }
1377
1378 public String getId() {
1379 return id;
1380 }
1381
1382 public CharSequence getLabel() {
1383 return label;
1384 }
1385
1386 @Override
1387 public String toString() {
1388 return new StringBuilder(Topic.class.getSimpleName()).append('[')
1389 .append("id=").append(id)
1390 .append(",label=").append(label)
1391 .append(']').toString();
1392 }
1393
1394 @Override
1395 public boolean equals(Object o) {
1396 if (!(o instanceof Topic)) return false;
1397 if (o == this) return true;
1398 final Topic other = (Topic) o;
1399 return Objects.equals(other.id, id)
1400 && Objects.equals(other.label, label);
1401 }
1402
1403 @Override
1404 public int hashCode() {
1405 return Objects.hash(id, label);
1406 }
1407
1408 @Override
1409 public Topic clone() {
1410 return new Topic(id, label);
1411 }
1412
1413 @Override
1414 public int describeContents() {
1415 return 0;
1416 }
1417
1418 @Override
1419 public void writeToParcel(Parcel out, int flags) {
1420 if (id != null) {
1421 out.writeInt(1);
1422 out.writeString(id);
1423 } else {
1424 out.writeInt(0);
1425 }
1426 TextUtils.writeToParcel(label, out, flags);
1427 }
1428 public static final Parcelable.Creator<Topic> CREATOR =
1429 new Parcelable.Creator<Topic>() {
1430 public Topic createFromParcel(Parcel in) {
1431 return new Topic(in);
1432 }
1433 public Topic[] newArray(int size) {
1434 return new Topic[size];
1435 }
1436 };
1437 }
1438
Julia Reynolds233a5f92015-10-19 13:51:23 -04001439 @SystemApi
1440 public static final String TOPIC_DEFAULT = "system_default_topic";
1441
Julia Reynolds054c5dc2015-11-17 15:36:30 -05001442 private Topic topic;
Julia Reynolds74303cf2015-10-16 11:37:55 -04001443
Julia Reynolds054c5dc2015-11-17 15:36:30 -05001444 public Topic getTopic() {
1445 return topic;
Julia Reynolds74303cf2015-10-16 11:37:55 -04001446 }
1447
1448 /**
Daniel Sandler2561b0b2012-02-13 21:04:12 -05001449 * Constructs a Notification object with default values.
Joe Onorato46439ce2010-11-19 13:56:21 -08001450 * You might want to consider using {@link Builder} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001451 */
1452 public Notification()
1453 {
1454 this.when = System.currentTimeMillis();
Daniel Sandler2561b0b2012-02-13 21:04:12 -05001455 this.priority = PRIORITY_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001456 }
1457
1458 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001459 * @hide
1460 */
1461 public Notification(Context context, int icon, CharSequence tickerText, long when,
1462 CharSequence contentTitle, CharSequence contentText, Intent contentIntent)
1463 {
Chris Wren1ce4b6d2015-06-11 10:19:43 -04001464 new Builder(context)
1465 .setWhen(when)
1466 .setSmallIcon(icon)
1467 .setTicker(tickerText)
1468 .setContentTitle(contentTitle)
1469 .setContentText(contentText)
1470 .setContentIntent(PendingIntent.getActivity(context, 0, contentIntent, 0))
1471 .buildInto(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001472 }
1473
1474 /**
1475 * Constructs a Notification object with the information needed to
1476 * have a status bar icon without the standard expanded view.
1477 *
1478 * @param icon The resource id of the icon to put in the status bar.
1479 * @param tickerText The text that flows by in the status bar when the notification first
1480 * activates.
1481 * @param when The time to show in the time field. In the System.currentTimeMillis
1482 * timebase.
Joe Onorato46439ce2010-11-19 13:56:21 -08001483 *
1484 * @deprecated Use {@link Builder} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001485 */
Joe Onorato46439ce2010-11-19 13:56:21 -08001486 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001487 public Notification(int icon, CharSequence tickerText, long when)
1488 {
1489 this.icon = icon;
1490 this.tickerText = tickerText;
1491 this.when = when;
1492 }
1493
1494 /**
1495 * Unflatten the notification from a parcel.
1496 */
1497 public Notification(Parcel parcel)
1498 {
1499 int version = parcel.readInt();
1500
1501 when = parcel.readLong();
Dan Sandler3936e7a2015-05-19 20:59:12 -04001502 if (parcel.readInt() != 0) {
1503 mSmallIcon = Icon.CREATOR.createFromParcel(parcel);
Dan Sandler4e787062015-06-17 15:09:48 -04001504 if (mSmallIcon.getType() == Icon.TYPE_RESOURCE) {
1505 icon = mSmallIcon.getResId();
1506 }
Dan Sandler3936e7a2015-05-19 20:59:12 -04001507 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001508 number = parcel.readInt();
1509 if (parcel.readInt() != 0) {
1510 contentIntent = PendingIntent.CREATOR.createFromParcel(parcel);
1511 }
1512 if (parcel.readInt() != 0) {
1513 deleteIntent = PendingIntent.CREATOR.createFromParcel(parcel);
1514 }
1515 if (parcel.readInt() != 0) {
1516 tickerText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
1517 }
1518 if (parcel.readInt() != 0) {
Joe Onorato46439ce2010-11-19 13:56:21 -08001519 tickerView = RemoteViews.CREATOR.createFromParcel(parcel);
Joe Onoratoef1e7762010-09-17 18:38:38 -04001520 }
1521 if (parcel.readInt() != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001522 contentView = RemoteViews.CREATOR.createFromParcel(parcel);
1523 }
Joe Onorato561d3852010-11-20 18:09:34 -08001524 if (parcel.readInt() != 0) {
Dan Sandlerd63f9322015-05-06 15:18:49 -04001525 mLargeIcon = Icon.CREATOR.createFromParcel(parcel);
Joe Onorato561d3852010-11-20 18:09:34 -08001526 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001527 defaults = parcel.readInt();
1528 flags = parcel.readInt();
1529 if (parcel.readInt() != 0) {
1530 sound = Uri.CREATOR.createFromParcel(parcel);
1531 }
1532
1533 audioStreamType = parcel.readInt();
John Spurlockc0650f022014-07-19 13:22:39 -04001534 if (parcel.readInt() != 0) {
1535 audioAttributes = AudioAttributes.CREATOR.createFromParcel(parcel);
1536 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001537 vibrate = parcel.createLongArray();
1538 ledARGB = parcel.readInt();
1539 ledOnMS = parcel.readInt();
1540 ledOffMS = parcel.readInt();
1541 iconLevel = parcel.readInt();
Daniel Sandlere46cbd32010-06-17 10:35:26 -04001542
1543 if (parcel.readInt() != 0) {
1544 fullScreenIntent = PendingIntent.CREATOR.createFromParcel(parcel);
1545 }
Daniel Sandler2561b0b2012-02-13 21:04:12 -05001546
1547 priority = parcel.readInt();
Daniel Sandlera0a938c2012-03-15 08:42:37 -04001548
John Spurlockfd7f1e02014-03-18 16:41:57 -04001549 category = parcel.readString();
Daniel Sandler2561b0b2012-02-13 21:04:12 -05001550
Griff Hazen5cadc3b2014-05-20 09:55:39 -07001551 mGroupKey = parcel.readString();
1552
1553 mSortKey = parcel.readString();
1554
Daniel Sandlerbe6e7e02013-02-01 17:49:11 -05001555 extras = parcel.readBundle(); // may be null
Daniel Sandlera0a938c2012-03-15 08:42:37 -04001556
Daniel Sandlerbe6e7e02013-02-01 17:49:11 -05001557 actions = parcel.createTypedArray(Action.CREATOR); // may be null
1558
Daniel Sandlera0a938c2012-03-15 08:42:37 -04001559 if (parcel.readInt() != 0) {
Daniel Sandlerf3b73432012-03-27 15:01:25 -04001560 bigContentView = RemoteViews.CREATOR.createFromParcel(parcel);
1561 }
Dan Sandler0bf2ed82013-12-21 23:33:41 -06001562
Chris Wren8fd39ec2014-02-27 17:43:26 -05001563 if (parcel.readInt() != 0) {
1564 headsUpContentView = RemoteViews.CREATOR.createFromParcel(parcel);
1565 }
1566
Dan Sandler0bf2ed82013-12-21 23:33:41 -06001567 visibility = parcel.readInt();
1568
1569 if (parcel.readInt() != 0) {
1570 publicVersion = Notification.CREATOR.createFromParcel(parcel);
1571 }
Dan Sandler26e81cf2014-05-06 10:01:27 -04001572
1573 color = parcel.readInt();
Julia Reynolds74303cf2015-10-16 11:37:55 -04001574
Julia Reynolds054c5dc2015-11-17 15:36:30 -05001575 if (parcel.readInt() != 0) {
1576 topic = Topic.CREATOR.createFromParcel(parcel);
1577 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001578 }
1579
Andy Stadler110988c2010-12-03 14:29:16 -08001580 @Override
Joe Onorato18e69df2010-05-17 22:26:12 -07001581 public Notification clone() {
1582 Notification that = new Notification();
Daniel Sandler1a497d32013-04-18 14:52:45 -04001583 cloneInto(that, true);
Daniel Sandlerbe6e7e02013-02-01 17:49:11 -05001584 return that;
1585 }
Joe Onorato18e69df2010-05-17 22:26:12 -07001586
Daniel Sandler1a497d32013-04-18 14:52:45 -04001587 /**
1588 * Copy all (or if heavy is false, all except Bitmaps and RemoteViews) members
1589 * of this into that.
1590 * @hide
1591 */
1592 public void cloneInto(Notification that, boolean heavy) {
Joe Onorato18e69df2010-05-17 22:26:12 -07001593 that.when = this.when;
Dan Sandlerd63f9322015-05-06 15:18:49 -04001594 that.mSmallIcon = this.mSmallIcon;
Joe Onorato18e69df2010-05-17 22:26:12 -07001595 that.number = this.number;
1596
1597 // PendingIntents are global, so there's no reason (or way) to clone them.
1598 that.contentIntent = this.contentIntent;
1599 that.deleteIntent = this.deleteIntent;
Daniel Sandlere46cbd32010-06-17 10:35:26 -04001600 that.fullScreenIntent = this.fullScreenIntent;
Joe Onorato18e69df2010-05-17 22:26:12 -07001601
1602 if (this.tickerText != null) {
1603 that.tickerText = this.tickerText.toString();
1604 }
Daniel Sandler1a497d32013-04-18 14:52:45 -04001605 if (heavy && this.tickerView != null) {
Joe Onorato46439ce2010-11-19 13:56:21 -08001606 that.tickerView = this.tickerView.clone();
Joe Onoratoef1e7762010-09-17 18:38:38 -04001607 }
Daniel Sandler1a497d32013-04-18 14:52:45 -04001608 if (heavy && this.contentView != null) {
Joe Onorato18e69df2010-05-17 22:26:12 -07001609 that.contentView = this.contentView.clone();
1610 }
Dan Sandlerd63f9322015-05-06 15:18:49 -04001611 if (heavy && this.mLargeIcon != null) {
1612 that.mLargeIcon = this.mLargeIcon;
Joe Onorato561d3852010-11-20 18:09:34 -08001613 }
Jozef BABJAKa8b91832011-02-22 08:05:08 +01001614 that.iconLevel = this.iconLevel;
Joe Onorato18e69df2010-05-17 22:26:12 -07001615 that.sound = this.sound; // android.net.Uri is immutable
1616 that.audioStreamType = this.audioStreamType;
John Spurlockc0650f022014-07-19 13:22:39 -04001617 if (this.audioAttributes != null) {
1618 that.audioAttributes = new AudioAttributes.Builder(this.audioAttributes).build();
1619 }
Joe Onorato18e69df2010-05-17 22:26:12 -07001620
1621 final long[] vibrate = this.vibrate;
1622 if (vibrate != null) {
1623 final int N = vibrate.length;
1624 final long[] vib = that.vibrate = new long[N];
1625 System.arraycopy(vibrate, 0, vib, 0, N);
1626 }
1627
1628 that.ledARGB = this.ledARGB;
1629 that.ledOnMS = this.ledOnMS;
1630 that.ledOffMS = this.ledOffMS;
1631 that.defaults = this.defaults;
Daniel Sandler2561b0b2012-02-13 21:04:12 -05001632
Joe Onorato18e69df2010-05-17 22:26:12 -07001633 that.flags = this.flags;
1634
Daniel Sandler2561b0b2012-02-13 21:04:12 -05001635 that.priority = this.priority;
Joe Malin8d40d042012-11-05 11:36:40 -08001636
John Spurlockfd7f1e02014-03-18 16:41:57 -04001637 that.category = this.category;
Daniel Sandler2561b0b2012-02-13 21:04:12 -05001638
Griff Hazen5cadc3b2014-05-20 09:55:39 -07001639 that.mGroupKey = this.mGroupKey;
1640
1641 that.mSortKey = this.mSortKey;
1642
Daniel Sandler2561b0b2012-02-13 21:04:12 -05001643 if (this.extras != null) {
Daniel Sandlerdcbaf662013-04-26 16:23:09 -04001644 try {
1645 that.extras = new Bundle(this.extras);
1646 // will unparcel
1647 that.extras.size();
1648 } catch (BadParcelableException e) {
1649 Log.e(TAG, "could not unparcel extras from notification: " + this, e);
1650 that.extras = null;
1651 }
Daniel Sandler2561b0b2012-02-13 21:04:12 -05001652 }
1653
Daniel Sandlerbe6e7e02013-02-01 17:49:11 -05001654 if (this.actions != null) {
1655 that.actions = new Action[this.actions.length];
1656 for(int i=0; i<this.actions.length; i++) {
1657 that.actions[i] = this.actions[i].clone();
1658 }
Daniel Sandlera0a938c2012-03-15 08:42:37 -04001659 }
Daniel Sandlerbe6e7e02013-02-01 17:49:11 -05001660
Daniel Sandler1a497d32013-04-18 14:52:45 -04001661 if (heavy && this.bigContentView != null) {
Daniel Sandlerf3b73432012-03-27 15:01:25 -04001662 that.bigContentView = this.bigContentView.clone();
1663 }
Daniel Sandler1a497d32013-04-18 14:52:45 -04001664
Chris Wren8fd39ec2014-02-27 17:43:26 -05001665 if (heavy && this.headsUpContentView != null) {
1666 that.headsUpContentView = this.headsUpContentView.clone();
1667 }
1668
Dan Sandler0bf2ed82013-12-21 23:33:41 -06001669 that.visibility = this.visibility;
1670
1671 if (this.publicVersion != null) {
1672 that.publicVersion = new Notification();
1673 this.publicVersion.cloneInto(that.publicVersion, heavy);
1674 }
1675
Dan Sandler26e81cf2014-05-06 10:01:27 -04001676 that.color = this.color;
1677
Julia Reynolds054c5dc2015-11-17 15:36:30 -05001678 if (this.topic != null) {
1679 that.topic = this.topic.clone();
Julia Reynolds74303cf2015-10-16 11:37:55 -04001680 }
1681
Daniel Sandler1a497d32013-04-18 14:52:45 -04001682 if (!heavy) {
1683 that.lightenPayload(); // will clean out extras
1684 }
1685 }
1686
1687 /**
1688 * Removes heavyweight parts of the Notification object for archival or for sending to
1689 * listeners when the full contents are not necessary.
1690 * @hide
1691 */
1692 public final void lightenPayload() {
1693 tickerView = null;
1694 contentView = null;
1695 bigContentView = null;
Chris Wren8fd39ec2014-02-27 17:43:26 -05001696 headsUpContentView = null;
Dan Sandlerd63f9322015-05-06 15:18:49 -04001697 mLargeIcon = null;
Dan Sandler50128532015-12-08 15:42:41 -05001698 if (extras != null && !extras.isEmpty()) {
1699 final Set<String> keyset = extras.keySet();
1700 final int N = keyset.size();
1701 final String[] keys = keyset.toArray(new String[N]);
1702 for (int i=0; i<N; i++) {
1703 final String key = keys[i];
1704 final Object obj = extras.get(key);
1705 if (obj != null &&
1706 ( obj instanceof Parcelable
1707 || obj instanceof Parcelable[]
1708 || obj instanceof SparseArray
1709 || obj instanceof ArrayList)) {
1710 extras.remove(key);
1711 }
1712 }
Daniel Sandler1a497d32013-04-18 14:52:45 -04001713 }
Joe Onorato18e69df2010-05-17 22:26:12 -07001714 }
1715
Daniel Sandlerdcbaf662013-04-26 16:23:09 -04001716 /**
1717 * Make sure this CharSequence is safe to put into a bundle, which basically
1718 * means it had better not be some custom Parcelable implementation.
1719 * @hide
1720 */
1721 public static CharSequence safeCharSequence(CharSequence cs) {
Christoph Studer535ec612014-09-03 15:47:47 +02001722 if (cs == null) return cs;
1723 if (cs.length() > MAX_CHARSEQUENCE_LENGTH) {
1724 cs = cs.subSequence(0, MAX_CHARSEQUENCE_LENGTH);
1725 }
Daniel Sandlerdcbaf662013-04-26 16:23:09 -04001726 if (cs instanceof Parcelable) {
1727 Log.e(TAG, "warning: " + cs.getClass().getCanonicalName()
1728 + " instance is a custom Parcelable and not allowed in Notification");
1729 return cs.toString();
1730 }
1731
1732 return cs;
1733 }
1734
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001735 public int describeContents() {
1736 return 0;
1737 }
1738
1739 /**
Dan Sandler4e787062015-06-17 15:09:48 -04001740 * Flatten this notification into a parcel.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001741 */
1742 public void writeToParcel(Parcel parcel, int flags)
1743 {
1744 parcel.writeInt(1);
1745
1746 parcel.writeLong(when);
Dan Sandler4e787062015-06-17 15:09:48 -04001747 if (mSmallIcon == null && icon != 0) {
1748 // you snuck an icon in here without using the builder; let's try to keep it
1749 mSmallIcon = Icon.createWithResource("", icon);
1750 }
Dan Sandler3936e7a2015-05-19 20:59:12 -04001751 if (mSmallIcon != null) {
1752 parcel.writeInt(1);
1753 mSmallIcon.writeToParcel(parcel, 0);
1754 } else {
1755 parcel.writeInt(0);
1756 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001757 parcel.writeInt(number);
1758 if (contentIntent != null) {
1759 parcel.writeInt(1);
1760 contentIntent.writeToParcel(parcel, 0);
1761 } else {
1762 parcel.writeInt(0);
1763 }
1764 if (deleteIntent != null) {
1765 parcel.writeInt(1);
1766 deleteIntent.writeToParcel(parcel, 0);
1767 } else {
1768 parcel.writeInt(0);
1769 }
1770 if (tickerText != null) {
1771 parcel.writeInt(1);
1772 TextUtils.writeToParcel(tickerText, parcel, flags);
1773 } else {
1774 parcel.writeInt(0);
1775 }
Joe Onorato46439ce2010-11-19 13:56:21 -08001776 if (tickerView != null) {
Joe Onoratoef1e7762010-09-17 18:38:38 -04001777 parcel.writeInt(1);
Joe Onorato46439ce2010-11-19 13:56:21 -08001778 tickerView.writeToParcel(parcel, 0);
Joe Onoratoef1e7762010-09-17 18:38:38 -04001779 } else {
1780 parcel.writeInt(0);
1781 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001782 if (contentView != null) {
1783 parcel.writeInt(1);
1784 contentView.writeToParcel(parcel, 0);
1785 } else {
1786 parcel.writeInt(0);
1787 }
Dan Sandlerd63f9322015-05-06 15:18:49 -04001788 if (mLargeIcon != null) {
Joe Onorato561d3852010-11-20 18:09:34 -08001789 parcel.writeInt(1);
Dan Sandlerd63f9322015-05-06 15:18:49 -04001790 mLargeIcon.writeToParcel(parcel, 0);
Joe Onorato561d3852010-11-20 18:09:34 -08001791 } else {
1792 parcel.writeInt(0);
1793 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001794
1795 parcel.writeInt(defaults);
1796 parcel.writeInt(this.flags);
1797
1798 if (sound != null) {
1799 parcel.writeInt(1);
1800 sound.writeToParcel(parcel, 0);
1801 } else {
1802 parcel.writeInt(0);
1803 }
1804 parcel.writeInt(audioStreamType);
John Spurlockc0650f022014-07-19 13:22:39 -04001805
1806 if (audioAttributes != null) {
1807 parcel.writeInt(1);
1808 audioAttributes.writeToParcel(parcel, 0);
1809 } else {
1810 parcel.writeInt(0);
1811 }
1812
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001813 parcel.writeLongArray(vibrate);
1814 parcel.writeInt(ledARGB);
1815 parcel.writeInt(ledOnMS);
1816 parcel.writeInt(ledOffMS);
1817 parcel.writeInt(iconLevel);
Daniel Sandlere46cbd32010-06-17 10:35:26 -04001818
1819 if (fullScreenIntent != null) {
1820 parcel.writeInt(1);
1821 fullScreenIntent.writeToParcel(parcel, 0);
1822 } else {
1823 parcel.writeInt(0);
1824 }
Daniel Sandler2561b0b2012-02-13 21:04:12 -05001825
1826 parcel.writeInt(priority);
Joe Malin8d40d042012-11-05 11:36:40 -08001827
John Spurlockfd7f1e02014-03-18 16:41:57 -04001828 parcel.writeString(category);
Joe Malin8d40d042012-11-05 11:36:40 -08001829
Griff Hazen5cadc3b2014-05-20 09:55:39 -07001830 parcel.writeString(mGroupKey);
1831
1832 parcel.writeString(mSortKey);
1833
Daniel Sandlerbe6e7e02013-02-01 17:49:11 -05001834 parcel.writeBundle(extras); // null ok
Daniel Sandlera0a938c2012-03-15 08:42:37 -04001835
Daniel Sandlerbe6e7e02013-02-01 17:49:11 -05001836 parcel.writeTypedArray(actions, 0); // null ok
Daniel Sandlera0a938c2012-03-15 08:42:37 -04001837
Daniel Sandlerf3b73432012-03-27 15:01:25 -04001838 if (bigContentView != null) {
1839 parcel.writeInt(1);
1840 bigContentView.writeToParcel(parcel, 0);
1841 } else {
1842 parcel.writeInt(0);
1843 }
Dan Sandler0bf2ed82013-12-21 23:33:41 -06001844
Chris Wren8fd39ec2014-02-27 17:43:26 -05001845 if (headsUpContentView != null) {
1846 parcel.writeInt(1);
1847 headsUpContentView.writeToParcel(parcel, 0);
1848 } else {
1849 parcel.writeInt(0);
1850 }
1851
Dan Sandler0bf2ed82013-12-21 23:33:41 -06001852 parcel.writeInt(visibility);
1853
1854 if (publicVersion != null) {
1855 parcel.writeInt(1);
1856 publicVersion.writeToParcel(parcel, 0);
1857 } else {
1858 parcel.writeInt(0);
1859 }
Dan Sandler26e81cf2014-05-06 10:01:27 -04001860
1861 parcel.writeInt(color);
Julia Reynolds74303cf2015-10-16 11:37:55 -04001862
Julia Reynolds054c5dc2015-11-17 15:36:30 -05001863 if (topic != null) {
1864 parcel.writeInt(1);
1865 topic.writeToParcel(parcel, 0);
1866 } else {
1867 parcel.writeInt(0);
1868 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001869 }
1870
1871 /**
1872 * Parcelable.Creator that instantiates Notification objects
1873 */
1874 public static final Parcelable.Creator<Notification> CREATOR
1875 = new Parcelable.Creator<Notification>()
1876 {
1877 public Notification createFromParcel(Parcel parcel)
1878 {
1879 return new Notification(parcel);
1880 }
1881
1882 public Notification[] newArray(int size)
1883 {
1884 return new Notification[size];
1885 }
1886 };
1887
1888 /**
1889 * Sets the {@link #contentView} field to be a view with the standard "Latest Event"
1890 * layout.
1891 *
1892 * <p>Uses the {@link #icon} and {@link #when} fields to set the icon and time fields
1893 * in the view.</p>
1894 * @param context The context for your application / activity.
1895 * @param contentTitle The title that goes in the expanded entry.
1896 * @param contentText The text that goes in the expanded entry.
1897 * @param contentIntent The intent to launch when the user clicks the expanded notification.
1898 * If this is an activity, it must include the
1899 * {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} flag, which requires
Scott Main7aee61f2011-02-08 11:25:01 -08001900 * that you take care of task management as described in the
1901 * <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back
1902 * Stack</a> document.
Daniel Sandler2561b0b2012-02-13 21:04:12 -05001903 *
Joe Onorato46439ce2010-11-19 13:56:21 -08001904 * @deprecated Use {@link Builder} instead.
Chris Wrena05db382015-06-24 15:18:34 -04001905 * @removed
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001906 */
Joe Onorato46439ce2010-11-19 13:56:21 -08001907 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001908 public void setLatestEventInfo(Context context,
1909 CharSequence contentTitle, CharSequence contentText, PendingIntent contentIntent) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04001910 if (context.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1){
1911 Log.e(TAG, "setLatestEventInfo() is deprecated and you should feel deprecated.",
1912 new Throwable());
1913 }
Daniel Sandlerbe6e7e02013-02-01 17:49:11 -05001914
Julia Reynoldsd9228f12015-10-20 10:37:27 -04001915 // ensure that any information already set directly is preserved
1916 final Notification.Builder builder = new Notification.Builder(context, this);
Daniel Sandlerbe6e7e02013-02-01 17:49:11 -05001917
1918 // now apply the latestEventInfo fields
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001919 if (contentTitle != null) {
Daniel Sandlerbe6e7e02013-02-01 17:49:11 -05001920 builder.setContentTitle(contentTitle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001921 }
1922 if (contentText != null) {
Daniel Sandlerbe6e7e02013-02-01 17:49:11 -05001923 builder.setContentText(contentText);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001924 }
Daniel Sandlerbe6e7e02013-02-01 17:49:11 -05001925 builder.setContentIntent(contentIntent);
Julia Reynoldsd9228f12015-10-20 10:37:27 -04001926
1927 builder.build(); // callers expect this notification to be ready to use
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001928 }
1929
Julia Reynoldsda303542015-11-23 14:00:20 -05001930 /**
1931 * @hide
1932 */
1933 public static void addFieldsFromContext(Context context, Notification notification) {
1934 if (notification.extras.getParcelable(EXTRA_BUILDER_APPLICATION_INFO) == null) {
1935 notification.extras.putParcelable(EXTRA_BUILDER_APPLICATION_INFO,
1936 context.getApplicationInfo());
1937 }
1938 if (!notification.extras.containsKey(EXTRA_ORIGINATING_USERID)) {
1939 notification.extras.putInt(EXTRA_ORIGINATING_USERID, context.getUserId());
1940 }
1941 }
1942
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001943 @Override
1944 public String toString() {
1945 StringBuilder sb = new StringBuilder();
Daniel Sandler2561b0b2012-02-13 21:04:12 -05001946 sb.append("Notification(pri=");
1947 sb.append(priority);
1948 sb.append(" contentView=");
Joe Onoratoc9596d62011-01-12 17:03:11 -08001949 if (contentView != null) {
1950 sb.append(contentView.getPackage());
1951 sb.append("/0x");
1952 sb.append(Integer.toHexString(contentView.getLayoutId()));
1953 } else {
1954 sb.append("null");
1955 }
1956 sb.append(" vibrate=");
Daniel Sandler6738eee2012-11-16 12:03:32 -05001957 if ((this.defaults & DEFAULT_VIBRATE) != 0) {
1958 sb.append("default");
1959 } else if (this.vibrate != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001960 int N = this.vibrate.length-1;
1961 sb.append("[");
1962 for (int i=0; i<N; i++) {
1963 sb.append(this.vibrate[i]);
1964 sb.append(',');
1965 }
Simon Schoar8cf97d92009-06-10 22:08:37 +02001966 if (N != -1) {
1967 sb.append(this.vibrate[N]);
1968 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001969 sb.append("]");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001970 } else {
1971 sb.append("null");
1972 }
Daniel Sandler2561b0b2012-02-13 21:04:12 -05001973 sb.append(" sound=");
Daniel Sandler6738eee2012-11-16 12:03:32 -05001974 if ((this.defaults & DEFAULT_SOUND) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001975 sb.append("default");
Daniel Sandler6738eee2012-11-16 12:03:32 -05001976 } else if (this.sound != null) {
1977 sb.append(this.sound.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001978 } else {
1979 sb.append("null");
1980 }
Chris Wren365b6d32015-07-16 10:39:26 -04001981 if (this.tickerText != null) {
1982 sb.append(" tick");
1983 }
Daniel Sandler2561b0b2012-02-13 21:04:12 -05001984 sb.append(" defaults=0x");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001985 sb.append(Integer.toHexString(this.defaults));
Daniel Sandler2561b0b2012-02-13 21:04:12 -05001986 sb.append(" flags=0x");
Daniel Sandlere46cbd32010-06-17 10:35:26 -04001987 sb.append(Integer.toHexString(this.flags));
Dan Sandler26e81cf2014-05-06 10:01:27 -04001988 sb.append(String.format(" color=0x%08x", this.color));
Griff Hazen5cadc3b2014-05-20 09:55:39 -07001989 if (this.category != null) {
1990 sb.append(" category=");
1991 sb.append(this.category);
1992 }
1993 if (this.mGroupKey != null) {
1994 sb.append(" groupKey=");
1995 sb.append(this.mGroupKey);
1996 }
1997 if (this.mSortKey != null) {
1998 sb.append(" sortKey=");
1999 sb.append(this.mSortKey);
2000 }
Daniel Sandlera0a938c2012-03-15 08:42:37 -04002001 if (actions != null) {
Dan Sandler1b718782014-07-18 12:43:45 -04002002 sb.append(" actions=");
Daniel Sandlera0a938c2012-03-15 08:42:37 -04002003 sb.append(actions.length);
Dan Sandler1b718782014-07-18 12:43:45 -04002004 }
2005 sb.append(" vis=");
2006 sb.append(visibilityToString(this.visibility));
2007 if (this.publicVersion != null) {
2008 sb.append(" publicVersion=");
2009 sb.append(publicVersion.toString());
Daniel Sandlera0a938c2012-03-15 08:42:37 -04002010 }
Julia Reynolds054c5dc2015-11-17 15:36:30 -05002011 if (topic != null) {
2012 sb.append("topic=");
2013 sb.append(topic.toString());
Julia Reynolds74303cf2015-10-16 11:37:55 -04002014 }
Daniel Sandlera0a938c2012-03-15 08:42:37 -04002015 sb.append(")");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002016 return sb.toString();
2017 }
Joe Onorato46439ce2010-11-19 13:56:21 -08002018
Dan Sandler1b718782014-07-18 12:43:45 -04002019 /**
2020 * {@hide}
2021 */
2022 public static String visibilityToString(int vis) {
2023 switch (vis) {
2024 case VISIBILITY_PRIVATE:
2025 return "PRIVATE";
2026 case VISIBILITY_PUBLIC:
2027 return "PUBLIC";
2028 case VISIBILITY_SECRET:
2029 return "SECRET";
2030 default:
2031 return "UNKNOWN(" + String.valueOf(vis) + ")";
2032 }
2033 }
2034
Joe Onoratocb109a02011-01-18 17:57:41 -08002035 /**
John Spurlock1d881a12015-03-18 19:21:54 -04002036 * {@hide}
2037 */
2038 public static String priorityToString(@Priority int pri) {
2039 switch (pri) {
2040 case PRIORITY_MIN:
2041 return "MIN";
2042 case PRIORITY_LOW:
2043 return "LOW";
2044 case PRIORITY_DEFAULT:
2045 return "DEFAULT";
2046 case PRIORITY_HIGH:
2047 return "HIGH";
2048 case PRIORITY_MAX:
2049 return "MAX";
2050 default:
2051 return "UNKNOWN(" + String.valueOf(pri) + ")";
2052 }
2053 }
2054
2055 /**
Dan Sandlerd63f9322015-05-06 15:18:49 -04002056 * The small icon representing this notification in the status bar and content view.
2057 *
2058 * @return the small icon representing this notification.
2059 *
2060 * @see Builder#getSmallIcon()
2061 * @see Builder#setSmallIcon(Icon)
2062 */
2063 public Icon getSmallIcon() {
2064 return mSmallIcon;
2065 }
2066
2067 /**
2068 * Used when notifying to clean up legacy small icons.
2069 * @hide
2070 */
2071 public void setSmallIcon(Icon icon) {
2072 mSmallIcon = icon;
2073 }
2074
2075 /**
2076 * The large icon shown in this notification's content view.
2077 * @see Builder#getLargeIcon()
2078 * @see Builder#setLargeIcon(Icon)
2079 */
2080 public Icon getLargeIcon() {
2081 return mLargeIcon;
2082 }
2083
2084 /**
Christoph Studer4600f9b2014-07-22 22:44:43 +02002085 * @hide
2086 */
Christoph Studerc8db24b2014-07-25 17:50:30 +02002087 public boolean isGroupSummary() {
2088 return mGroupKey != null && (flags & FLAG_GROUP_SUMMARY) != 0;
2089 }
2090
2091 /**
2092 * @hide
2093 */
2094 public boolean isGroupChild() {
2095 return mGroupKey != null && (flags & FLAG_GROUP_SUMMARY) == 0;
2096 }
2097
2098 /**
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002099 * Builder class for {@link Notification} objects.
Joe Malin8d40d042012-11-05 11:36:40 -08002100 *
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002101 * Provides a convenient way to set the various fields of a {@link Notification} and generate
Scott Main183bf112012-08-13 19:12:13 -07002102 * content views using the platform's notification layout template. If your app supports
2103 * versions of Android as old as API level 4, you can instead use
2104 * {@link android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder},
2105 * available in the <a href="{@docRoot}tools/extras/support-library.html">Android Support
2106 * library</a>.
Joe Malin8d40d042012-11-05 11:36:40 -08002107 *
Scott Main183bf112012-08-13 19:12:13 -07002108 * <p>Example:
Joe Malin8d40d042012-11-05 11:36:40 -08002109 *
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002110 * <pre class="prettyprint">
Scott Main183bf112012-08-13 19:12:13 -07002111 * Notification noti = new Notification.Builder(mContext)
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002112 * .setContentTitle(&quot;New mail from &quot; + sender.toString())
2113 * .setContentText(subject)
2114 * .setSmallIcon(R.drawable.new_mail)
2115 * .setLargeIcon(aBitmap)
Chris Wrenfbd96ba2012-05-01 12:03:58 -04002116 * .build();
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002117 * </pre>
Joe Onoratocb109a02011-01-18 17:57:41 -08002118 */
Joe Onorato46439ce2010-11-19 13:56:21 -08002119 public static class Builder {
Daniel Sandler602ad1c2012-06-12 16:06:27 -04002120 private static final int MAX_ACTION_BUTTONS = 3;
Jorim Jaggi445d3c02014-08-19 22:33:42 +02002121 private static final float LARGE_TEXT_SCALE = 1.3f;
Daniel Sandler8680bf82012-05-15 16:52:52 -04002122
Joe Onorato46439ce2010-11-19 13:56:21 -08002123 private Context mContext;
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002124 private Notification mN;
2125 private Bundle mUserExtras = new Bundle();
Chris Wrenfbd96ba2012-05-01 12:03:58 -04002126 private Style mStyle;
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002127 private ArrayList<Action> mActions = new ArrayList<Action>(MAX_ACTION_BUTTONS);
2128 private ArrayList<String> mPersonList = new ArrayList<String>();
2129 private NotificationColorUtil mColorUtil;
2130 private boolean mColorUtilInited = false;
Christoph Studer7ac80e62014-08-04 16:01:57 +02002131
2132 /**
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002133 * Constructs a new Builder with the defaults:
Joe Onoratocb109a02011-01-18 17:57:41 -08002134 *
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002135
2136 * <table>
2137 * <tr><th align=right>priority</th>
2138 * <td>{@link #PRIORITY_DEFAULT}</td></tr>
2139 * <tr><th align=right>when</th>
2140 * <td>now ({@link System#currentTimeMillis()})</td></tr>
2141 * <tr><th align=right>audio stream</th>
2142 * <td>{@link #STREAM_DEFAULT}</td></tr>
2143 * </table>
Joe Onoratocb109a02011-01-18 17:57:41 -08002144 *
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002145
2146 * @param context
2147 * A {@link Context} that will be used by the Builder to construct the
2148 * RemoteViews. The Context will not be held past the lifetime of this Builder
2149 * object.
Joe Onoratocb109a02011-01-18 17:57:41 -08002150 */
Joe Onorato46439ce2010-11-19 13:56:21 -08002151 public Builder(Context context) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002152 this(context, null);
Joe Onorato46439ce2010-11-19 13:56:21 -08002153 }
2154
Joe Onoratocb109a02011-01-18 17:57:41 -08002155 /**
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002156 * @hide
Christoph Studer4600f9b2014-07-22 22:44:43 +02002157 */
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002158 public Builder(Context context, Notification toAdopt) {
2159 mContext = context;
Christoph Studer4600f9b2014-07-22 22:44:43 +02002160
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002161 if (toAdopt == null) {
2162 mN = new Notification();
2163 mN.extras.putBoolean(EXTRA_SHOW_WHEN, true);
2164 mN.priority = PRIORITY_DEFAULT;
2165 mN.visibility = VISIBILITY_PRIVATE;
2166 } else {
2167 mN = toAdopt;
2168 if (mN.actions != null) {
2169 Collections.addAll(mActions, mN.actions);
Christoph Studer4600f9b2014-07-22 22:44:43 +02002170 }
2171
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002172 if (mN.extras.containsKey(EXTRA_PEOPLE)) {
2173 Collections.addAll(mPersonList, mN.extras.getStringArray(EXTRA_PEOPLE));
2174 }
2175
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002176 String templateClass = mN.extras.getString(EXTRA_TEMPLATE);
2177 if (!TextUtils.isEmpty(templateClass)) {
2178 final Class<? extends Style> styleClass
2179 = getNotificationStyleClass(templateClass);
2180 if (styleClass == null) {
2181 Log.d(TAG, "Unknown style class: " + templateClass);
2182 } else {
2183 try {
2184 final Constructor<? extends Style> ctor = styleClass.getConstructor();
2185 ctor.setAccessible(true);
2186 final Style style = ctor.newInstance();
2187 style.restoreFromExtras(mN.extras);
2188
2189 if (style != null) {
2190 setStyle(style);
2191 }
2192 } catch (Throwable t) {
2193 Log.e(TAG, "Could not create Style", t);
2194 }
2195 }
2196 }
2197
2198 }
2199 }
2200
2201 private NotificationColorUtil getColorUtil() {
2202 if (!mColorUtilInited) {
2203 mColorUtilInited = true;
2204 if (mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.LOLLIPOP) {
2205 mColorUtil = NotificationColorUtil.getInstance(mContext);
Christoph Studer4600f9b2014-07-22 22:44:43 +02002206 }
2207 }
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002208 return mColorUtil;
Christoph Studer4600f9b2014-07-22 22:44:43 +02002209 }
2210
2211 /**
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002212 * Add a timestamp pertaining to the notification (usually the time the event occurred).
Daniel Sandler0c890492012-09-12 17:23:10 -07002213 * It will be shown in the notification content view by default; use
Griff Hazen50c11652014-05-16 09:46:31 -07002214 * {@link #setShowWhen(boolean) setShowWhen} to control this.
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002215 *
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002216 * @see Notification#when
Joe Onoratocb109a02011-01-18 17:57:41 -08002217 */
Joe Onorato46439ce2010-11-19 13:56:21 -08002218 public Builder setWhen(long when) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002219 mN.when = when;
Joe Onorato46439ce2010-11-19 13:56:21 -08002220 return this;
2221 }
2222
Joe Onoratocb109a02011-01-18 17:57:41 -08002223 /**
Griff Hazen50c11652014-05-16 09:46:31 -07002224 * Control whether the timestamp set with {@link #setWhen(long) setWhen} is shown
Daniel Sandler0c890492012-09-12 17:23:10 -07002225 * in the content view.
2226 */
2227 public Builder setShowWhen(boolean show) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002228 mN.extras.putBoolean(EXTRA_SHOW_WHEN, show);
Daniel Sandler0c890492012-09-12 17:23:10 -07002229 return this;
2230 }
2231
2232 /**
Daniel Sandlerd33b8032012-05-10 11:41:48 -04002233 * Show the {@link Notification#when} field as a stopwatch.
Joe Malin8d40d042012-11-05 11:36:40 -08002234 *
2235 * Instead of presenting <code>when</code> as a timestamp, the notification will show an
Daniel Sandlerd33b8032012-05-10 11:41:48 -04002236 * automatically updating display of the minutes and seconds since <code>when</code>.
Daniel Sandlera2985ed2012-04-03 16:42:00 -04002237 *
Daniel Sandlerd33b8032012-05-10 11:41:48 -04002238 * Useful when showing an elapsed time (like an ongoing phone call).
2239 *
2240 * @see android.widget.Chronometer
Daniel Sandlera2985ed2012-04-03 16:42:00 -04002241 * @see Notification#when
2242 */
2243 public Builder setUsesChronometer(boolean b) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002244 mN.extras.putBoolean(EXTRA_SHOW_CHRONOMETER, b);
Daniel Sandlera2985ed2012-04-03 16:42:00 -04002245 return this;
2246 }
2247
2248 /**
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002249 * Set the small icon resource, which will be used to represent the notification in the
2250 * status bar.
Joe Onoratocb109a02011-01-18 17:57:41 -08002251 *
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002252
2253 * The platform template for the expanded view will draw this icon in the left, unless a
2254 * {@link #setLargeIcon(Bitmap) large icon} has also been specified, in which case the small
2255 * icon will be moved to the right-hand side.
2256 *
2257
2258 * @param icon
2259 * A resource ID in the application's package of the drawable to use.
2260 * @see Notification#icon
Joe Onoratocb109a02011-01-18 17:57:41 -08002261 */
Tor Norbye7b9c9122013-05-30 16:48:33 -07002262 public Builder setSmallIcon(@DrawableRes int icon) {
Dan Sandlerd63f9322015-05-06 15:18:49 -04002263 return setSmallIcon(icon != 0
2264 ? Icon.createWithResource(mContext, icon)
2265 : null);
Joe Onorato46439ce2010-11-19 13:56:21 -08002266 }
2267
Joe Onoratocb109a02011-01-18 17:57:41 -08002268 /**
2269 * A variant of {@link #setSmallIcon(int) setSmallIcon(int)} that takes an additional
2270 * level parameter for when the icon is a {@link android.graphics.drawable.LevelListDrawable
2271 * LevelListDrawable}.
2272 *
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002273 * @param icon A resource ID in the application's package of the drawable to use.
Joe Onoratocb109a02011-01-18 17:57:41 -08002274 * @param level The level to use for the icon.
2275 *
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002276 * @see Notification#icon
2277 * @see Notification#iconLevel
Joe Onoratocb109a02011-01-18 17:57:41 -08002278 */
Tor Norbye7b9c9122013-05-30 16:48:33 -07002279 public Builder setSmallIcon(@DrawableRes int icon, int level) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002280 mN.iconLevel = level;
Dan Sandlerd63f9322015-05-06 15:18:49 -04002281 return setSmallIcon(icon);
2282 }
2283
2284 /**
2285 * Set the small icon, which will be used to represent the notification in the
2286 * status bar and content view (unless overriden there by a
2287 * {@link #setLargeIcon(Bitmap) large icon}).
2288 *
2289 * @param icon An Icon object to use.
2290 * @see Notification#icon
2291 */
2292 public Builder setSmallIcon(Icon icon) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002293 mN.setSmallIcon(icon);
2294 if (icon != null && icon.getType() == Icon.TYPE_RESOURCE) {
2295 mN.icon = icon.getResId();
2296 }
Joe Onorato46439ce2010-11-19 13:56:21 -08002297 return this;
2298 }
2299
Joe Onoratocb109a02011-01-18 17:57:41 -08002300 /**
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002301 * Set the first line of text in the platform notification template.
Joe Onoratocb109a02011-01-18 17:57:41 -08002302 */
Joe Onorato46439ce2010-11-19 13:56:21 -08002303 public Builder setContentTitle(CharSequence title) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002304 mN.extras.putCharSequence(EXTRA_TITLE, safeCharSequence(title));
Joe Onorato46439ce2010-11-19 13:56:21 -08002305 return this;
2306 }
2307
Joe Onoratocb109a02011-01-18 17:57:41 -08002308 /**
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002309 * Set the second line of text in the platform notification template.
Joe Onoratocb109a02011-01-18 17:57:41 -08002310 */
Joe Onorato46439ce2010-11-19 13:56:21 -08002311 public Builder setContentText(CharSequence text) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002312 mN.extras.putCharSequence(EXTRA_TEXT, safeCharSequence(text));
Joe Onorato46439ce2010-11-19 13:56:21 -08002313 return this;
2314 }
2315
Joe Onoratocb109a02011-01-18 17:57:41 -08002316 /**
Joe Malin8d40d042012-11-05 11:36:40 -08002317 * Set the third line of text in the platform notification template.
Daniel Sandlerdcbaf662013-04-26 16:23:09 -04002318 * Don't use if you're also using {@link #setProgress(int, int, boolean)}; they occupy the
2319 * same location in the standard template.
Daniel Sandlerf3b73432012-03-27 15:01:25 -04002320 */
2321 public Builder setSubText(CharSequence text) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002322 mN.extras.putCharSequence(EXTRA_SUB_TEXT, safeCharSequence(text));
Daniel Sandlerf3b73432012-03-27 15:01:25 -04002323 return this;
2324 }
2325
2326 /**
Joe Onoratocb109a02011-01-18 17:57:41 -08002327 * Set the large number at the right-hand side of the notification. This is
2328 * equivalent to setContentInfo, although it might show the number in a different
2329 * font size for readability.
2330 */
Joe Onorato8595a3d2010-11-19 18:12:07 -08002331 public Builder setNumber(int number) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002332 mN.number = number;
Joe Onorato8595a3d2010-11-19 18:12:07 -08002333 return this;
2334 }
2335
Joe Onoratocb109a02011-01-18 17:57:41 -08002336 /**
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002337 * A small piece of additional information pertaining to this notification.
2338 *
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002339 * The platform template will draw this on the last line of the notification, at the far
2340 * right (to the right of a smallIcon if it has been placed there).
Joe Onoratocb109a02011-01-18 17:57:41 -08002341 */
Joe Onorato46439ce2010-11-19 13:56:21 -08002342 public Builder setContentInfo(CharSequence info) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002343 mN.extras.putCharSequence(EXTRA_INFO_TEXT, safeCharSequence(info));
Joe Onorato46439ce2010-11-19 13:56:21 -08002344 return this;
2345 }
2346
Joe Onoratocb109a02011-01-18 17:57:41 -08002347 /**
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002348 * Set the progress this notification represents.
2349 *
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002350 * The platform template will represent this using a {@link ProgressBar}.
Jeff Sharkey1c400132011-08-05 14:50:13 -07002351 */
2352 public Builder setProgress(int max, int progress, boolean indeterminate) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002353 mN.extras.putInt(EXTRA_PROGRESS, progress);
2354 mN.extras.putInt(EXTRA_PROGRESS_MAX, max);
2355 mN.extras.putBoolean(EXTRA_PROGRESS_INDETERMINATE, indeterminate);
Jeff Sharkey1c400132011-08-05 14:50:13 -07002356 return this;
2357 }
2358
2359 /**
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002360 * Supply a custom RemoteViews to use instead of the platform template.
2361 *
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002362 * Use {@link #setCustomContentView(RemoteViews)} instead.
Joe Onoratocb109a02011-01-18 17:57:41 -08002363 */
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002364 @Deprecated
Joe Onorato46439ce2010-11-19 13:56:21 -08002365 public Builder setContent(RemoteViews views) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002366 return setCustomContentView(views);
2367 }
2368
2369 /**
2370 * Supply custom RemoteViews to use instead of the platform template.
2371 *
2372 * This will override the layout that would otherwise be constructed by this Builder
2373 * object.
2374 */
2375 public Builder setCustomContentView(RemoteViews contentView) {
2376 mN.contentView = contentView;
2377 return this;
2378 }
2379
2380 /**
2381 * Supply custom RemoteViews to use instead of the platform template in the expanded form.
2382 *
2383 * This will override the expanded layout that would otherwise be constructed by this
2384 * Builder object.
2385 */
2386 public Builder setCustomBigContentView(RemoteViews contentView) {
2387 mN.bigContentView = contentView;
2388 return this;
2389 }
2390
2391 /**
2392 * Supply custom RemoteViews to use instead of the platform template in the heads up dialog.
2393 *
2394 * This will override the heads-up layout that would otherwise be constructed by this
2395 * Builder object.
2396 */
2397 public Builder setCustomHeadsUpContentView(RemoteViews contentView) {
2398 mN.headsUpContentView = contentView;
Joe Onorato46439ce2010-11-19 13:56:21 -08002399 return this;
2400 }
2401
Joe Onoratocb109a02011-01-18 17:57:41 -08002402 /**
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002403 * Supply a {@link PendingIntent} to be sent when the notification is clicked.
2404 *
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002405 * As of {@link android.os.Build.VERSION_CODES#HONEYCOMB}, if this field is unset and you
2406 * have specified a custom RemoteViews with {@link #setContent(RemoteViews)}, you can use
2407 * {@link RemoteViews#setOnClickPendingIntent RemoteViews.setOnClickPendingIntent(int,PendingIntent)}
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002408 * to assign PendingIntents to individual views in that custom layout (i.e., to create
Daniel Sandlerf3b73432012-03-27 15:01:25 -04002409 * clickable buttons inside the notification view).
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002410 *
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002411 * @see Notification#contentIntent Notification.contentIntent
Joe Onoratocb109a02011-01-18 17:57:41 -08002412 */
Joe Onorato46439ce2010-11-19 13:56:21 -08002413 public Builder setContentIntent(PendingIntent intent) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002414 mN.contentIntent = intent;
Joe Onorato46439ce2010-11-19 13:56:21 -08002415 return this;
2416 }
2417
Joe Onoratocb109a02011-01-18 17:57:41 -08002418 /**
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002419 * Supply a {@link PendingIntent} to send when the notification is cleared explicitly by the user.
2420 *
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002421 * @see Notification#deleteIntent
Joe Onoratocb109a02011-01-18 17:57:41 -08002422 */
Joe Onorato46439ce2010-11-19 13:56:21 -08002423 public Builder setDeleteIntent(PendingIntent intent) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002424 mN.deleteIntent = intent;
Joe Onorato46439ce2010-11-19 13:56:21 -08002425 return this;
2426 }
2427
Joe Onoratocb109a02011-01-18 17:57:41 -08002428 /**
2429 * An intent to launch instead of posting the notification to the status bar.
2430 * Only for use with extremely high-priority notifications demanding the user's
2431 * <strong>immediate</strong> attention, such as an incoming phone call or
2432 * alarm clock that the user has explicitly set to a particular time.
2433 * If this facility is used for something else, please give the user an option
2434 * to turn it off and use a normal notification, as this can be extremely
2435 * disruptive.
2436 *
Chris Wren47c20a12014-06-18 17:27:29 -04002437 * <p>
2438 * The system UI may choose to display a heads-up notification, instead of
2439 * launching this intent, while the user is using the device.
2440 * </p>
2441 *
Joe Onoratocb109a02011-01-18 17:57:41 -08002442 * @param intent The pending intent to launch.
2443 * @param highPriority Passing true will cause this notification to be sent
2444 * even if other notifications are suppressed.
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002445 *
2446 * @see Notification#fullScreenIntent
Joe Onoratocb109a02011-01-18 17:57:41 -08002447 */
Joe Onorato46439ce2010-11-19 13:56:21 -08002448 public Builder setFullScreenIntent(PendingIntent intent, boolean highPriority) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002449 mN.fullScreenIntent = intent;
Joe Onorato46439ce2010-11-19 13:56:21 -08002450 setFlag(FLAG_HIGH_PRIORITY, highPriority);
2451 return this;
2452 }
2453
Joe Onoratocb109a02011-01-18 17:57:41 -08002454 /**
Dan Sandler5fcdf6e2014-07-18 11:31:15 -04002455 * Set the "ticker" text which is sent to accessibility services.
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002456 *
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002457 * @see Notification#tickerText
Joe Onoratocb109a02011-01-18 17:57:41 -08002458 */
Joe Onorato46439ce2010-11-19 13:56:21 -08002459 public Builder setTicker(CharSequence tickerText) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002460 mN.tickerText = safeCharSequence(tickerText);
Joe Onorato46439ce2010-11-19 13:56:21 -08002461 return this;
2462 }
2463
Joe Onoratocb109a02011-01-18 17:57:41 -08002464 /**
Dan Sandler5fcdf6e2014-07-18 11:31:15 -04002465 * Obsolete version of {@link #setTicker(CharSequence)}.
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002466 *
Joe Onoratocb109a02011-01-18 17:57:41 -08002467 */
Dan Sandler5fcdf6e2014-07-18 11:31:15 -04002468 @Deprecated
Joe Onorato46439ce2010-11-19 13:56:21 -08002469 public Builder setTicker(CharSequence tickerText, RemoteViews views) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002470 setTicker(tickerText);
2471 // views is ignored
Joe Onorato46439ce2010-11-19 13:56:21 -08002472 return this;
2473 }
2474
Joe Onoratocb109a02011-01-18 17:57:41 -08002475 /**
Dan Sandlerd63f9322015-05-06 15:18:49 -04002476 * Add a large icon to the notification content view.
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002477 *
2478 * In the platform template, this image will be shown on the left of the notification view
Dan Sandlerd63f9322015-05-06 15:18:49 -04002479 * in place of the {@link #setSmallIcon(Icon) small icon} (which will be placed in a small
2480 * badge atop the large icon).
Dan Sandler08a04c12015-05-06 15:18:49 -04002481 */
Dan Sandlerd63f9322015-05-06 15:18:49 -04002482 public Builder setLargeIcon(Bitmap b) {
2483 return setLargeIcon(b != null ? Icon.createWithBitmap(b) : null);
2484 }
2485
2486 /**
2487 * Add a large icon to the notification content view.
2488 *
2489 * In the platform template, this image will be shown on the left of the notification view
2490 * in place of the {@link #setSmallIcon(Icon) small icon} (which will be placed in a small
2491 * badge atop the large icon).
2492 */
2493 public Builder setLargeIcon(Icon icon) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002494 mN.mLargeIcon = icon;
2495 mN.extras.putParcelable(EXTRA_LARGE_ICON, icon);
Joe Onorato46439ce2010-11-19 13:56:21 -08002496 return this;
2497 }
2498
Joe Onoratocb109a02011-01-18 17:57:41 -08002499 /**
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002500 * Set the sound to play.
2501 *
John Spurlockc0650f022014-07-19 13:22:39 -04002502 * It will be played using the {@link #AUDIO_ATTRIBUTES_DEFAULT default audio attributes}
2503 * for notifications.
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002504 *
Chris Wren47c20a12014-06-18 17:27:29 -04002505 * <p>
2506 * A notification that is noisy is more likely to be presented as a heads-up notification.
2507 * </p>
2508 *
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002509 * @see Notification#sound
Joe Onoratocb109a02011-01-18 17:57:41 -08002510 */
Joe Onorato52f80cd2010-11-21 15:34:48 -08002511 public Builder setSound(Uri sound) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002512 mN.sound = sound;
2513 mN.audioAttributes = AUDIO_ATTRIBUTES_DEFAULT;
Joe Onorato52f80cd2010-11-21 15:34:48 -08002514 return this;
2515 }
2516
Joe Onoratocb109a02011-01-18 17:57:41 -08002517 /**
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002518 * Set the sound to play, along with a specific stream on which to play it.
Joe Onoratocb109a02011-01-18 17:57:41 -08002519 *
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002520 * See {@link android.media.AudioManager} for the <code>STREAM_</code> constants.
2521 *
Chris Wren47c20a12014-06-18 17:27:29 -04002522 * <p>
2523 * A notification that is noisy is more likely to be presented as a heads-up notification.
2524 * </p>
John Spurlockc0650f022014-07-19 13:22:39 -04002525 * @deprecated use {@link #setSound(Uri, AudioAttributes)} instead.
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002526 * @see Notification#sound
Joe Onoratocb109a02011-01-18 17:57:41 -08002527 */
Jean-Michel Trivi81f871e2014-08-06 16:32:38 -07002528 @Deprecated
Joe Onorato46439ce2010-11-19 13:56:21 -08002529 public Builder setSound(Uri sound, int streamType) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002530 mN.sound = sound;
2531 mN.audioStreamType = streamType;
Joe Onorato46439ce2010-11-19 13:56:21 -08002532 return this;
2533 }
2534
Joe Onoratocb109a02011-01-18 17:57:41 -08002535 /**
John Spurlockc0650f022014-07-19 13:22:39 -04002536 * Set the sound to play, along with specific {@link AudioAttributes audio attributes} to
2537 * use during playback.
2538 *
2539 * <p>
2540 * A notification that is noisy is more likely to be presented as a heads-up notification.
2541 * </p>
2542 *
2543 * @see Notification#sound
2544 */
2545 public Builder setSound(Uri sound, AudioAttributes audioAttributes) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002546 mN.sound = sound;
2547 mN.audioAttributes = audioAttributes;
John Spurlockc0650f022014-07-19 13:22:39 -04002548 return this;
2549 }
2550
2551 /**
Joe Onoratocb109a02011-01-18 17:57:41 -08002552 * Set the vibration pattern to use.
2553 *
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002554 * See {@link android.os.Vibrator#vibrate(long[], int)} for a discussion of the
2555 * <code>pattern</code> parameter.
2556 *
Chris Wren47c20a12014-06-18 17:27:29 -04002557 * <p>
2558 * A notification that vibrates is more likely to be presented as a heads-up notification.
2559 * </p>
2560 *
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002561 * @see Notification#vibrate
Joe Onoratocb109a02011-01-18 17:57:41 -08002562 */
Joe Onorato46439ce2010-11-19 13:56:21 -08002563 public Builder setVibrate(long[] pattern) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002564 mN.vibrate = pattern;
Joe Onorato46439ce2010-11-19 13:56:21 -08002565 return this;
2566 }
2567
Joe Onoratocb109a02011-01-18 17:57:41 -08002568 /**
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002569 * Set the desired color for the indicator LED on the device, as well as the
2570 * blink duty cycle (specified in milliseconds).
2571 *
2572
2573 * Not all devices will honor all (or even any) of these values.
2574 *
2575
2576 * @see Notification#ledARGB
2577 * @see Notification#ledOnMS
2578 * @see Notification#ledOffMS
Joe Onoratocb109a02011-01-18 17:57:41 -08002579 */
Tor Norbye80756e32015-03-02 09:39:27 -08002580 public Builder setLights(@ColorInt int argb, int onMs, int offMs) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002581 mN.ledARGB = argb;
2582 mN.ledOnMS = onMs;
2583 mN.ledOffMS = offMs;
Julia Reynolds10ee1fc2015-11-09 11:04:55 -05002584 if (onMs != 0 || offMs != 0) {
2585 mN.flags |= FLAG_SHOW_LIGHTS;
2586 }
2587 if ((mN.defaults & DEFAULT_LIGHTS) != 0) {
2588 mN.flags |= FLAG_SHOW_LIGHTS;
2589 }
Joe Onorato46439ce2010-11-19 13:56:21 -08002590 return this;
2591 }
2592
Joe Onoratocb109a02011-01-18 17:57:41 -08002593 /**
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002594 * Set whether this is an "ongoing" notification.
Joe Onoratocb109a02011-01-18 17:57:41 -08002595 *
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002596
2597 * Ongoing notifications cannot be dismissed by the user, so your application or service
2598 * must take care of canceling them.
2599 *
2600
2601 * They are typically used to indicate a background task that the user is actively engaged
2602 * with (e.g., playing music) or is pending in some way and therefore occupying the device
2603 * (e.g., a file download, sync operation, active network connection).
2604 *
2605
2606 * @see Notification#FLAG_ONGOING_EVENT
2607 * @see Service#setForeground(boolean)
Joe Onoratocb109a02011-01-18 17:57:41 -08002608 */
Joe Onorato46439ce2010-11-19 13:56:21 -08002609 public Builder setOngoing(boolean ongoing) {
2610 setFlag(FLAG_ONGOING_EVENT, ongoing);
2611 return this;
2612 }
2613
Joe Onoratocb109a02011-01-18 17:57:41 -08002614 /**
2615 * Set this flag if you would only like the sound, vibrate
2616 * and ticker to be played if the notification is not already showing.
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002617 *
2618 * @see Notification#FLAG_ONLY_ALERT_ONCE
Joe Onoratocb109a02011-01-18 17:57:41 -08002619 */
Joe Onorato46439ce2010-11-19 13:56:21 -08002620 public Builder setOnlyAlertOnce(boolean onlyAlertOnce) {
2621 setFlag(FLAG_ONLY_ALERT_ONCE, onlyAlertOnce);
2622 return this;
2623 }
2624
Joe Onoratocb109a02011-01-18 17:57:41 -08002625 /**
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002626 * Make this notification automatically dismissed when the user touches it. The
2627 * PendingIntent set with {@link #setDeleteIntent} will be sent when this happens.
2628 *
2629 * @see Notification#FLAG_AUTO_CANCEL
Joe Onoratocb109a02011-01-18 17:57:41 -08002630 */
Joe Onorato46439ce2010-11-19 13:56:21 -08002631 public Builder setAutoCancel(boolean autoCancel) {
Joe Onorato281d83f2011-01-04 17:13:10 -08002632 setFlag(FLAG_AUTO_CANCEL, autoCancel);
Joe Onorato46439ce2010-11-19 13:56:21 -08002633 return this;
2634 }
2635
Joe Onoratocb109a02011-01-18 17:57:41 -08002636 /**
Griff Hazendfcb0802014-02-11 12:00:00 -08002637 * Set whether or not this notification should not bridge to other devices.
2638 *
2639 * <p>Some notifications can be bridged to other devices for remote display.
2640 * This hint can be set to recommend this notification not be bridged.
2641 */
2642 public Builder setLocalOnly(boolean localOnly) {
2643 setFlag(FLAG_LOCAL_ONLY, localOnly);
2644 return this;
2645 }
2646
2647 /**
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002648 * Set which notification properties will be inherited from system defaults.
Joe Onoratocb109a02011-01-18 17:57:41 -08002649 * <p>
2650 * The value should be one or more of the following fields combined with
2651 * bitwise-or:
2652 * {@link #DEFAULT_SOUND}, {@link #DEFAULT_VIBRATE}, {@link #DEFAULT_LIGHTS}.
2653 * <p>
2654 * For all default values, use {@link #DEFAULT_ALL}.
2655 */
Joe Onorato46439ce2010-11-19 13:56:21 -08002656 public Builder setDefaults(int defaults) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002657 mN.defaults = defaults;
Joe Onorato46439ce2010-11-19 13:56:21 -08002658 return this;
2659 }
2660
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002661 /**
2662 * Set the priority of this notification.
2663 *
2664 * @see Notification#priority
2665 */
Tor Norbyed9273d62013-05-30 15:59:53 -07002666 public Builder setPriority(@Priority int pri) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002667 mN.priority = pri;
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002668 return this;
2669 }
Joe Malin8d40d042012-11-05 11:36:40 -08002670
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002671 /**
John Spurlockfd7f1e02014-03-18 16:41:57 -04002672 * Set the notification category.
Joe Malin8d40d042012-11-05 11:36:40 -08002673 *
John Spurlockfd7f1e02014-03-18 16:41:57 -04002674 * @see Notification#category
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002675 */
John Spurlockfd7f1e02014-03-18 16:41:57 -04002676 public Builder setCategory(String category) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002677 mN.category = category;
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002678 return this;
2679 }
2680
2681 /**
Chris Wrendde75302014-03-26 17:24:15 -04002682 * Add a person that is relevant to this notification.
2683 *
Chris Wrene6c48932014-09-29 17:19:27 -04002684 * <P>
2685 * Depending on user preferences, this annotation may allow the notification to pass
2686 * through interruption filters, and to appear more prominently in the user interface.
2687 * </P>
2688 *
2689 * <P>
2690 * The person should be specified by the {@code String} representation of a
2691 * {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI}.
2692 * </P>
2693 *
2694 * <P>The system will also attempt to resolve {@code mailto:} and {@code tel:} schema
2695 * URIs. The path part of these URIs must exist in the contacts database, in the
2696 * appropriate column, or the reference will be discarded as invalid. Telephone schema
2697 * URIs will be resolved by {@link android.provider.ContactsContract.PhoneLookup}.
2698 * </P>
2699 *
2700 * @param uri A URI for the person.
Chris Wrendde75302014-03-26 17:24:15 -04002701 * @see Notification#EXTRA_PEOPLE
2702 */
Chris Wrene6c48932014-09-29 17:19:27 -04002703 public Builder addPerson(String uri) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002704 mPersonList.add(uri);
Chris Wrendde75302014-03-26 17:24:15 -04002705 return this;
2706 }
2707
2708 /**
Griff Hazen5cadc3b2014-05-20 09:55:39 -07002709 * Set this notification to be part of a group of notifications sharing the same key.
2710 * Grouped notifications may display in a cluster or stack on devices which
2711 * support such rendering.
2712 *
2713 * <p>To make this notification the summary for its group, also call
2714 * {@link #setGroupSummary}. A sort order can be specified for group members by using
2715 * {@link #setSortKey}.
2716 * @param groupKey The group key of the group.
2717 * @return this object for method chaining
2718 */
2719 public Builder setGroup(String groupKey) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002720 mN.mGroupKey = groupKey;
Griff Hazen5cadc3b2014-05-20 09:55:39 -07002721 return this;
2722 }
2723
2724 /**
2725 * Set this notification to be the group summary for a group of notifications.
2726 * Grouped notifications may display in a cluster or stack on devices which
2727 * support such rendering. Requires a group key also be set using {@link #setGroup}.
2728 * @param isGroupSummary Whether this notification should be a group summary.
2729 * @return this object for method chaining
2730 */
2731 public Builder setGroupSummary(boolean isGroupSummary) {
2732 setFlag(FLAG_GROUP_SUMMARY, isGroupSummary);
2733 return this;
2734 }
2735
2736 /**
2737 * Set a sort key that orders this notification among other notifications from the
2738 * same package. This can be useful if an external sort was already applied and an app
2739 * would like to preserve this. Notifications will be sorted lexicographically using this
2740 * value, although providing different priorities in addition to providing sort key may
2741 * cause this value to be ignored.
2742 *
2743 * <p>This sort key can also be used to order members of a notification group. See
Griff Hazen9e1379f2014-05-20 12:50:51 -07002744 * {@link #setGroup}.
Griff Hazen5cadc3b2014-05-20 09:55:39 -07002745 *
2746 * @see String#compareTo(String)
2747 */
2748 public Builder setSortKey(String sortKey) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002749 mN.mSortKey = sortKey;
Griff Hazen5cadc3b2014-05-20 09:55:39 -07002750 return this;
2751 }
2752
2753 /**
Griff Hazen720042b2014-02-24 15:46:56 -08002754 * Merge additional metadata into this notification.
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002755 *
Griff Hazen720042b2014-02-24 15:46:56 -08002756 * <p>Values within the Bundle will replace existing extras values in this Builder.
2757 *
2758 * @see Notification#extras
2759 */
Griff Hazen959591e2014-05-15 22:26:18 -07002760 public Builder addExtras(Bundle extras) {
2761 if (extras != null) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002762 mUserExtras.putAll(extras);
Griff Hazen720042b2014-02-24 15:46:56 -08002763 }
2764 return this;
2765 }
2766
2767 /**
2768 * Set metadata for this notification.
2769 *
2770 * <p>A reference to the Bundle is held for the lifetime of this Builder, and the Bundle's
Chris Wrenfbd96ba2012-05-01 12:03:58 -04002771 * current contents are copied into the Notification each time {@link #build()} is
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002772 * called.
2773 *
Griff Hazen720042b2014-02-24 15:46:56 -08002774 * <p>Replaces any existing extras values with those from the provided Bundle.
2775 * Use {@link #addExtras} to merge in metadata instead.
2776 *
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002777 * @see Notification#extras
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002778 */
Griff Hazen959591e2014-05-15 22:26:18 -07002779 public Builder setExtras(Bundle extras) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002780 if (extras != null) {
2781 mUserExtras = extras;
2782 }
Daniel Sandler2561b0b2012-02-13 21:04:12 -05002783 return this;
2784 }
2785
Daniel Sandlera0a938c2012-03-15 08:42:37 -04002786 /**
Griff Hazen720042b2014-02-24 15:46:56 -08002787 * Get the current metadata Bundle used by this notification Builder.
2788 *
2789 * <p>The returned Bundle is shared with this Builder.
2790 *
2791 * <p>The current contents of this Bundle are copied into the Notification each time
2792 * {@link #build()} is called.
2793 *
2794 * @see Notification#extras
2795 */
2796 public Bundle getExtras() {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002797 return mUserExtras;
2798 }
2799
2800 private Bundle getAllExtras() {
2801 final Bundle saveExtras = (Bundle) mUserExtras.clone();
2802 saveExtras.putAll(mN.extras);
2803 return saveExtras;
Griff Hazen720042b2014-02-24 15:46:56 -08002804 }
2805
2806 /**
Daniel Sandlera0a938c2012-03-15 08:42:37 -04002807 * Add an action to this notification. Actions are typically displayed by
2808 * the system as a button adjacent to the notification content.
Daniel Sandlercf1d39b2013-09-23 13:35:35 -04002809 * <p>
2810 * Every action must have an icon (32dp square and matching the
2811 * <a href="{@docRoot}design/style/iconography.html#action-bar">Holo
2812 * Dark action bar</a> visual style), a textual label, and a {@link PendingIntent}.
2813 * <p>
2814 * A notification in its expanded form can display up to 3 actions, from left to right in
2815 * the order they were added. Actions will not be displayed when the notification is
2816 * collapsed, however, so be sure that any essential functions may be accessed by the user
2817 * in some other way (for example, in the Activity pointed to by {@link #contentIntent}).
Daniel Sandlera0a938c2012-03-15 08:42:37 -04002818 *
2819 * @param icon Resource ID of a drawable that represents the action.
2820 * @param title Text describing the action.
2821 * @param intent PendingIntent to be fired when the action is invoked.
Dan Sandler86647982015-05-13 23:41:13 -04002822 *
2823 * @deprecated Use {@link #addAction(Action)} instead.
Daniel Sandlera0a938c2012-03-15 08:42:37 -04002824 */
Dan Sandler86647982015-05-13 23:41:13 -04002825 @Deprecated
Daniel Sandlera0a938c2012-03-15 08:42:37 -04002826 public Builder addAction(int icon, CharSequence title, PendingIntent intent) {
Daniel Sandlerdcbaf662013-04-26 16:23:09 -04002827 mActions.add(new Action(icon, safeCharSequence(title), intent));
Daniel Sandlera0a938c2012-03-15 08:42:37 -04002828 return this;
2829 }
2830
Chris Wrenfbd96ba2012-05-01 12:03:58 -04002831 /**
Griff Hazen959591e2014-05-15 22:26:18 -07002832 * Add an action to this notification. Actions are typically displayed by
2833 * the system as a button adjacent to the notification content.
2834 * <p>
2835 * Every action must have an icon (32dp square and matching the
2836 * <a href="{@docRoot}design/style/iconography.html#action-bar">Holo
2837 * Dark action bar</a> visual style), a textual label, and a {@link PendingIntent}.
2838 * <p>
2839 * A notification in its expanded form can display up to 3 actions, from left to right in
2840 * the order they were added. Actions will not be displayed when the notification is
2841 * collapsed, however, so be sure that any essential functions may be accessed by the user
2842 * in some other way (for example, in the Activity pointed to by {@link #contentIntent}).
2843 *
2844 * @param action The action to add.
2845 */
2846 public Builder addAction(Action action) {
2847 mActions.add(action);
2848 return this;
2849 }
2850
2851 /**
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002852 * Alter the complete list of actions attached to this notification.
2853 * @see #addAction(Action).
2854 *
2855 * @param actions
2856 * @return
2857 */
2858 public Builder setActions(Action... actions) {
2859 mActions.clear();
2860 for (int i = 0; i < actions.length; i++) {
2861 mActions.add(actions[i]);
2862 }
2863 return this;
2864 }
2865
2866 /**
Chris Wrenfbd96ba2012-05-01 12:03:58 -04002867 * Add a rich notification style to be applied at build time.
2868 *
2869 * @param style Object responsible for modifying the notification style.
2870 */
2871 public Builder setStyle(Style style) {
2872 if (mStyle != style) {
2873 mStyle = style;
Daniel Sandlerc08dea22012-06-28 08:35:24 -07002874 if (mStyle != null) {
2875 mStyle.setBuilder(this);
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002876 mN.extras.putString(EXTRA_TEMPLATE, style.getClass().getName());
2877 } else {
2878 mN.extras.remove(EXTRA_TEMPLATE);
Daniel Sandlerc08dea22012-06-28 08:35:24 -07002879 }
Chris Wrenfbd96ba2012-05-01 12:03:58 -04002880 }
2881 return this;
2882 }
2883
Dan Sandler0bf2ed82013-12-21 23:33:41 -06002884 /**
2885 * Specify the value of {@link #visibility}.
Griff Hazenb720abe2014-05-20 13:15:30 -07002886 *
Dan Sandler0bf2ed82013-12-21 23:33:41 -06002887 * @param visibility One of {@link #VISIBILITY_PRIVATE} (the default),
2888 * {@link #VISIBILITY_SECRET}, or {@link #VISIBILITY_PUBLIC}.
2889 *
2890 * @return The same Builder.
2891 */
2892 public Builder setVisibility(int visibility) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002893 mN.visibility = visibility;
Dan Sandler0bf2ed82013-12-21 23:33:41 -06002894 return this;
2895 }
2896
2897 /**
2898 * Supply a replacement Notification whose contents should be shown in insecure contexts
2899 * (i.e. atop the secure lockscreen). See {@link #visibility} and {@link #VISIBILITY_PUBLIC}.
2900 * @param n A replacement notification, presumably with some or all info redacted.
2901 * @return The same Builder.
2902 */
2903 public Builder setPublicVersion(Notification n) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002904 if (n != null) {
2905 mN.publicVersion = new Notification();
2906 n.cloneInto(mN.publicVersion, /*heavy=*/ true);
2907 } else {
2908 mN.publicVersion = null;
2909 }
Dan Sandler0bf2ed82013-12-21 23:33:41 -06002910 return this;
2911 }
2912
Griff Hazenb720abe2014-05-20 13:15:30 -07002913 /**
Griff Hazen5cadc3b2014-05-20 09:55:39 -07002914 * Apply an extender to this notification builder. Extenders may be used to add
2915 * metadata or change options on this builder.
2916 */
Griff Hazen61a9e862014-05-22 16:05:19 -07002917 public Builder extend(Extender extender) {
2918 extender.extend(this);
Griff Hazen5cadc3b2014-05-20 09:55:39 -07002919 return this;
2920 }
2921
Dan Sandler4e787062015-06-17 15:09:48 -04002922 /**
2923 * @hide
2924 */
2925 public void setFlag(int mask, boolean value) {
Joe Onorato46439ce2010-11-19 13:56:21 -08002926 if (value) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002927 mN.flags |= mask;
Joe Onorato46439ce2010-11-19 13:56:21 -08002928 } else {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002929 mN.flags &= ~mask;
Joe Onorato46439ce2010-11-19 13:56:21 -08002930 }
2931 }
2932
Dan Sandler26e81cf2014-05-06 10:01:27 -04002933 /**
2934 * Sets {@link Notification#color}.
2935 *
2936 * @param argb The accent color to use
2937 *
2938 * @return The same Builder.
2939 */
Tor Norbye80756e32015-03-02 09:39:27 -08002940 public Builder setColor(@ColorInt int argb) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002941 mN.color = argb;
Julia Reynolds10ee1fc2015-11-09 11:04:55 -05002942 sanitizeColor();
Dan Sandler26e81cf2014-05-06 10:01:27 -04002943 return this;
2944 }
2945
Julia Reynolds74303cf2015-10-16 11:37:55 -04002946 /**
Julia Reynolds054c5dc2015-11-17 15:36:30 -05002947 * Sets the topic of this notification. Topics are typically displayed in Notification
Julia Reynolds74303cf2015-10-16 11:37:55 -04002948 * settings.
2949 * <p>
2950 * Every topic must have an id and a textual label.
2951 *
2952 * @param topic The topic to add.
2953 */
Julia Reynolds054c5dc2015-11-17 15:36:30 -05002954 public Builder setTopic(Topic topic) {
2955 mN.topic = topic;
Julia Reynolds74303cf2015-10-16 11:37:55 -04002956 return this;
2957 }
2958
Jorim Jaggid05aa3e2014-08-28 17:52:27 +02002959 private Drawable getProfileBadgeDrawable() {
Christoph Studer7ac80e62014-08-04 16:01:57 +02002960 // Note: This assumes that the current user can read the profile badge of the
2961 // originating user.
Svetoslavc7d62f02014-09-04 15:39:54 -07002962 return mContext.getPackageManager().getUserBadgeForDensity(
Julia Reynoldsda303542015-11-23 14:00:20 -05002963 new UserHandle(mContext.getUserId()), 0);
Jorim Jaggid05aa3e2014-08-28 17:52:27 +02002964 }
2965
2966 private Bitmap getProfileBadge() {
2967 Drawable badge = getProfileBadgeDrawable();
Kenny Guy8a0101b2014-05-08 23:34:12 +01002968 if (badge == null) {
2969 return null;
2970 }
Jorim Jaggid05aa3e2014-08-28 17:52:27 +02002971 final int size = mContext.getResources().getDimensionPixelSize(
2972 R.dimen.notification_badge_size);
2973 Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
Kenny Guy8a0101b2014-05-08 23:34:12 +01002974 Canvas canvas = new Canvas(bitmap);
Jorim Jaggid05aa3e2014-08-28 17:52:27 +02002975 badge.setBounds(0, 0, size, size);
Kenny Guy8a0101b2014-05-08 23:34:12 +01002976 badge.draw(canvas);
2977 return bitmap;
2978 }
2979
Kenny Guy98193ea2014-07-24 19:54:37 +01002980 private boolean addProfileBadge(RemoteViews contentView, int resId) {
2981 Bitmap profileBadge = getProfileBadge();
2982
2983 contentView.setViewVisibility(R.id.profile_badge_large_template, View.GONE);
Kenny Guy98193ea2014-07-24 19:54:37 +01002984 contentView.setViewVisibility(R.id.profile_badge_line3, View.GONE);
2985
2986 if (profileBadge != null) {
2987 contentView.setImageViewBitmap(resId, profileBadge);
2988 contentView.setViewVisibility(resId, View.VISIBLE);
2989
2990 // Make sure Line 3 is visible. As badge will be here if there
2991 // is no text to display.
2992 if (resId == R.id.profile_badge_line3) {
2993 contentView.setViewVisibility(R.id.line3, View.VISIBLE);
2994 }
2995 return true;
2996 }
2997 return false;
2998 }
2999
Christoph Studerfe718432014-09-01 18:21:18 +02003000 private void resetStandardTemplate(RemoteViews contentView) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08003001 resetNotificationHeader(contentView);
Selim Cinek65b2e7c2015-10-26 14:11:31 -07003002 resetContentMargins(contentView);
Christoph Studerfe718432014-09-01 18:21:18 +02003003 contentView.setViewVisibility(R.id.right_icon, View.GONE);
Selim Cinek860b6da2015-12-16 19:02:19 -08003004 contentView.setViewVisibility(R.id.title, View.GONE);
Christoph Studerfe718432014-09-01 18:21:18 +02003005 contentView.setTextViewText(R.id.title, null);
3006 contentView.setTextViewText(R.id.text, null);
Christoph Studerfe718432014-09-01 18:21:18 +02003007 contentView.setViewVisibility(R.id.line3, View.GONE);
Selim Cinek29603462015-11-17 19:04:39 -08003008 contentView.setViewVisibility(R.id.text_line_1, View.GONE);
Christoph Studerfe718432014-09-01 18:21:18 +02003009 contentView.setViewVisibility(R.id.progress, View.GONE);
Selim Cinek65b2e7c2015-10-26 14:11:31 -07003010 }
3011
Selim Cinekeaa29ca2015-11-23 13:51:13 -08003012 /**
3013 * Resets the notification header to its original state
3014 */
3015 private void resetNotificationHeader(RemoteViews contentView) {
Selim Cinek65b2e7c2015-10-26 14:11:31 -07003016 contentView.setImageViewResource(R.id.icon, 0);
Selim Cinek7b836392015-12-04 20:02:59 -08003017 contentView.setBoolean(R.id.notification_header, "setExpanded", false);
Selim Cinek65b2e7c2015-10-26 14:11:31 -07003018 contentView.setTextViewText(R.id.app_name_text, null);
Christoph Studerca1db712014-09-10 17:31:33 +02003019 contentView.setViewVisibility(R.id.chronometer, View.GONE);
Selim Cinek65b2e7c2015-10-26 14:11:31 -07003020 contentView.setViewVisibility(R.id.header_sub_text, View.GONE);
Selim Cinek29603462015-11-17 19:04:39 -08003021 contentView.setViewVisibility(R.id.header_content_info, View.GONE);
Selim Cinek65b2e7c2015-10-26 14:11:31 -07003022 contentView.setViewVisibility(R.id.number_of_children, View.GONE);
Selim Cinek29603462015-11-17 19:04:39 -08003023 contentView.setViewVisibility(R.id.sub_text_divider, View.GONE);
3024 contentView.setViewVisibility(R.id.content_info_divider, View.GONE);
3025 contentView.setViewVisibility(R.id.time_divider, View.GONE);
Selim Cinek65b2e7c2015-10-26 14:11:31 -07003026 }
3027
3028 private void resetContentMargins(RemoteViews contentView) {
3029 contentView.setViewLayoutMarginEnd(R.id.line1, 0);
Selim Cinek65b2e7c2015-10-26 14:11:31 -07003030 contentView.setViewLayoutMarginEnd(R.id.line3, 0);
Christoph Studerfe718432014-09-01 18:21:18 +02003031 }
3032
Jorim Jaggi445d3c02014-08-19 22:33:42 +02003033 private RemoteViews applyStandardTemplate(int resId) {
Jorim Jaggi17ee3ec2014-08-29 03:47:31 +02003034 return applyStandardTemplate(resId, true /* hasProgress */);
3035 }
3036
3037 /**
3038 * @param hasProgress whether the progress bar should be shown and set
3039 */
3040 private RemoteViews applyStandardTemplate(int resId, boolean hasProgress) {
Kenny Guy77320062014-08-27 21:37:15 +01003041 RemoteViews contentView = new BuilderRemoteViews(mContext.getApplicationInfo(), resId);
Dan Sandler539aad42014-08-04 00:43:39 -04003042
Christoph Studerfe718432014-09-01 18:21:18 +02003043 resetStandardTemplate(contentView);
3044
Daniel Sandler9f7936a2012-05-21 16:14:28 -04003045 boolean showLine3 = false;
Julia Reynoldsd9228f12015-10-20 10:37:27 -04003046 final Bundle ex = mN.extras;
Dan Sandler190d58d2014-05-15 09:33:39 -04003047
Selim Cinek65b2e7c2015-10-26 14:11:31 -07003048 bindNotificationHeader(contentView);
3049 bindLargeIcon(contentView);
Julia Reynoldsd9228f12015-10-20 10:37:27 -04003050 if (ex.getCharSequence(EXTRA_TITLE) != null) {
Selim Cinek860b6da2015-12-16 19:02:19 -08003051 contentView.setViewVisibility(R.id.title, View.VISIBLE);
Julia Reynoldsd9228f12015-10-20 10:37:27 -04003052 contentView.setTextViewText(R.id.title,
3053 processLegacyText(ex.getCharSequence(EXTRA_TITLE)));
Joe Onorato561d3852010-11-20 18:09:34 -08003054 }
Selim Cinek29603462015-11-17 19:04:39 -08003055 boolean showProgress = handleProgressBar(hasProgress, contentView, ex);
Julia Reynoldsd9228f12015-10-20 10:37:27 -04003056 if (ex.getCharSequence(EXTRA_TEXT) != null) {
Selim Cinek29603462015-11-17 19:04:39 -08003057 contentView.setTextViewText(showProgress ? R.id.text_line_1 : R.id.text,
Julia Reynoldsd9228f12015-10-20 10:37:27 -04003058 processLegacyText(ex.getCharSequence(EXTRA_TEXT)));
Selim Cinek29603462015-11-17 19:04:39 -08003059 if (showProgress) {
3060 contentView.setViewVisibility(R.id.text_line_1, View.VISIBLE);
Joe Onorato059a2f82011-01-04 10:27:01 -08003061 }
Selim Cinek29603462015-11-17 19:04:39 -08003062 showLine3 = !showProgress;
Joe Onorato561d3852010-11-20 18:09:34 -08003063 }
Selim Cinek29603462015-11-17 19:04:39 -08003064 // We want to add badge to first line of text.
3065 if (addProfileBadge(contentView, R.id.profile_badge_line3)) {
3066 showLine3 = true;
3067 }
3068 // Note getStandardView may hide line 3 again.
3069 contentView.setViewVisibility(R.id.line3, showLine3 ? View.VISIBLE : View.GONE);
Selim Cinek860b6da2015-12-16 19:02:19 -08003070 setContentMinHeight(contentView, showProgress || mN.mLargeIcon != null);
Daniel Sandlerf3b73432012-03-27 15:01:25 -04003071
Selim Cinek29603462015-11-17 19:04:39 -08003072 return contentView;
3073 }
3074
Selim Cinek860b6da2015-12-16 19:02:19 -08003075 /**
3076 * @param remoteView the remote view to update the minheight in
3077 * @param hasMinHeight does it have a mimHeight
3078 * @hide
3079 */
3080 void setContentMinHeight(RemoteViews remoteView, boolean hasMinHeight) {
3081 int minHeight = 0;
3082 if (hasMinHeight) {
3083 // we need to set the minHeight of the notification
3084 minHeight = mContext.getResources().getDimensionPixelSize(
3085 com.android.internal.R.dimen.notification_min_content_height);
3086 }
3087 remoteView.setInt(R.id.notification_main_column, "setMinimumHeight", minHeight);
3088 }
3089
Selim Cinek29603462015-11-17 19:04:39 -08003090 private boolean handleProgressBar(boolean hasProgress, RemoteViews contentView, Bundle ex) {
Selim Cinek65b2e7c2015-10-26 14:11:31 -07003091 final int max = ex.getInt(EXTRA_PROGRESS_MAX, 0);
3092 final int progress = ex.getInt(EXTRA_PROGRESS, 0);
3093 final boolean ind = ex.getBoolean(EXTRA_PROGRESS_INDETERMINATE);
3094 if (hasProgress && (max != 0 || ind)) {
Selim Cinek29603462015-11-17 19:04:39 -08003095 contentView.setViewVisibility(com.android.internal.R.id.progress, View.VISIBLE);
Selim Cinek65b2e7c2015-10-26 14:11:31 -07003096 contentView.setProgressBar(
Selim Cinek29603462015-11-17 19:04:39 -08003097 R.id.progress, max, progress, ind);
Selim Cinek65b2e7c2015-10-26 14:11:31 -07003098 contentView.setProgressBackgroundTintList(
3099 R.id.progress, ColorStateList.valueOf(mContext.getColor(
3100 R.color.notification_progress_background_color)));
Selim Cinek29603462015-11-17 19:04:39 -08003101 if (mN.color != COLOR_DEFAULT) {
3102 ColorStateList colorStateList = ColorStateList.valueOf(mN.color);
Selim Cinek65b2e7c2015-10-26 14:11:31 -07003103 contentView.setProgressTintList(R.id.progress, colorStateList);
3104 contentView.setProgressIndeterminateTintList(R.id.progress, colorStateList);
Daniel Sandlerf3b73432012-03-27 15:01:25 -04003105 }
Selim Cinek29603462015-11-17 19:04:39 -08003106 return true;
Selim Cinek65b2e7c2015-10-26 14:11:31 -07003107 } else {
3108 contentView.setViewVisibility(R.id.progress, View.GONE);
Selim Cinek29603462015-11-17 19:04:39 -08003109 return false;
Jeff Sharkey1c400132011-08-05 14:50:13 -07003110 }
Joe Onorato561d3852010-11-20 18:09:34 -08003111 }
3112
Selim Cinek65b2e7c2015-10-26 14:11:31 -07003113 private void bindLargeIcon(RemoteViews contentView) {
3114 if (mN.mLargeIcon != null) {
3115 contentView.setViewVisibility(R.id.right_icon, View.VISIBLE);
3116 contentView.setImageViewIcon(R.id.right_icon, mN.mLargeIcon);
3117 processLargeLegacyIcon(mN.mLargeIcon, contentView);
3118 int endMargin = mContext.getResources().getDimensionPixelSize(
3119 R.dimen.notification_content_picture_margin);
3120 contentView.setViewLayoutMarginEnd(R.id.line1, endMargin);
Selim Cinek65b2e7c2015-10-26 14:11:31 -07003121 contentView.setViewLayoutMarginEnd(R.id.line3, endMargin);
Selim Cinek29603462015-11-17 19:04:39 -08003122 contentView.setViewLayoutMarginEnd(R.id.progress, endMargin);
Selim Cinek65b2e7c2015-10-26 14:11:31 -07003123 }
3124 }
3125
3126 private void bindNotificationHeader(RemoteViews contentView) {
3127 bindSmallIcon(contentView);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08003128 bindChildCountColor(contentView);
Selim Cinek65b2e7c2015-10-26 14:11:31 -07003129 bindHeaderAppName(contentView);
Selim Cinek03d0d652015-11-13 13:18:09 -05003130 bindHeaderSubText(contentView);
Selim Cinek29603462015-11-17 19:04:39 -08003131 bindContentInfo(contentView);
Selim Cinek65b2e7c2015-10-26 14:11:31 -07003132 bindHeaderChronometerAndTime(contentView);
3133 bindExpandButton(contentView);
3134 }
3135
Selim Cinekeaa29ca2015-11-23 13:51:13 -08003136 private void bindChildCountColor(RemoteViews contentView) {
3137 contentView.setTextColor(R.id.number_of_children, resolveColor());
3138 }
3139
Selim Cinek29603462015-11-17 19:04:39 -08003140 private void bindContentInfo(RemoteViews contentView) {
3141 boolean visible = false;
3142 if (mN.extras.getCharSequence(EXTRA_INFO_TEXT) != null) {
3143 contentView.setTextViewText(R.id.header_content_info,
3144 processLegacyText(mN.extras.getCharSequence(EXTRA_INFO_TEXT)));
3145 contentView.setViewVisibility(R.id.header_content_info, View.VISIBLE);
3146 visible = true;
3147 } else if (mN.number > 0) {
3148 final int tooBig = mContext.getResources().getInteger(
3149 R.integer.status_bar_notification_info_maxnum);
3150 if (mN.number > tooBig) {
3151 contentView.setTextViewText(R.id.header_content_info, processLegacyText(
3152 mContext.getResources().getString(
3153 R.string.status_bar_notification_info_overflow)));
3154 } else {
3155 contentView.setTextViewText(R.id.header_content_info,
3156 processLegacyText(String.valueOf(mN.number)));
3157 }
3158 contentView.setViewVisibility(R.id.header_content_info, View.VISIBLE);
3159 visible = true;
3160 }
3161 if (visible) {
3162 contentView.setViewVisibility(R.id.content_info_divider, View.VISIBLE);
3163 }
3164 }
3165
Selim Cinek65b2e7c2015-10-26 14:11:31 -07003166 private void bindExpandButton(RemoteViews contentView) {
3167 contentView.setDrawableParameters(R.id.expand_button, false, -1, resolveColor(),
3168 PorterDuff.Mode.SRC_ATOP, -1);
Selim Cinekea4bef72015-12-02 15:51:10 -08003169 contentView.setInt(R.id.notification_header, "setOriginalNotificationColor",
3170 resolveColor());
Selim Cinek65b2e7c2015-10-26 14:11:31 -07003171 }
3172
3173 private void bindHeaderChronometerAndTime(RemoteViews contentView) {
3174 if (showsTimeOrChronometer()) {
Selim Cinek29603462015-11-17 19:04:39 -08003175 contentView.setViewVisibility(R.id.time_divider, View.VISIBLE);
Selim Cinek65b2e7c2015-10-26 14:11:31 -07003176 if (mN.extras.getBoolean(EXTRA_SHOW_CHRONOMETER)) {
3177 contentView.setViewVisibility(R.id.chronometer, View.VISIBLE);
3178 contentView.setLong(R.id.chronometer, "setBase",
3179 mN.when + (SystemClock.elapsedRealtime() - System.currentTimeMillis()));
3180 contentView.setBoolean(R.id.chronometer, "setStarted", true);
3181 } else {
3182 contentView.setViewVisibility(R.id.time, View.VISIBLE);
3183 contentView.setLong(R.id.time, "setTime", mN.when);
3184 }
3185 }
3186 }
3187
Selim Cinek03d0d652015-11-13 13:18:09 -05003188 private void bindHeaderSubText(RemoteViews contentView) {
3189 CharSequence subText = mN.extras.getCharSequence(EXTRA_SUB_TEXT);
3190 if (subText == null && mStyle != null && mStyle.mSummaryTextSet
3191 && mStyle.hasSummaryInHeader()) {
3192 subText = mStyle.mSummaryText;
3193 }
Selim Cinek65b2e7c2015-10-26 14:11:31 -07003194 if (subText != null) {
3195 // TODO: Remove the span entirely to only have the string with propper formating.
3196 contentView.setTextViewText(R.id.header_sub_text, processLegacyText(subText));
3197 contentView.setViewVisibility(R.id.header_sub_text, View.VISIBLE);
Selim Cinek29603462015-11-17 19:04:39 -08003198 contentView.setViewVisibility(R.id.sub_text_divider, View.VISIBLE);
Selim Cinek65b2e7c2015-10-26 14:11:31 -07003199 }
3200 }
3201
3202 private void bindHeaderAppName(RemoteViews contentView) {
3203 PackageManager packageManager = mContext.getPackageManager();
3204 ApplicationInfo info = null;
3205 try {
3206 info = packageManager.getApplicationInfo(mContext.getApplicationInfo().packageName,
3207 0);
3208 } catch (final NameNotFoundException e) {
3209 return;
3210 }
3211 CharSequence appName = info != null ? packageManager.getApplicationLabel(info)
3212 : null;
3213 if (TextUtils.isEmpty(appName)) {
3214 return;
3215 }
3216 contentView.setTextViewText(R.id.app_name_text, appName);
3217 }
3218
3219 private void bindSmallIcon(RemoteViews contentView) {
3220 contentView.setImageViewIcon(R.id.icon, mN.mSmallIcon);
3221 processSmallIconColor(mN.mSmallIcon, contentView);
3222 }
3223
Jorim Jaggi445d3c02014-08-19 22:33:42 +02003224 /**
Jorim Jaggi17ee3ec2014-08-29 03:47:31 +02003225 * @return true if the built notification will show the time or the chronometer; false
3226 * otherwise
3227 */
3228 private boolean showsTimeOrChronometer() {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04003229 return mN.when != 0 && mN.extras.getBoolean(EXTRA_SHOW_WHEN);
Jorim Jaggi17ee3ec2014-08-29 03:47:31 +02003230 }
3231
Christoph Studerfe718432014-09-01 18:21:18 +02003232 private void resetStandardTemplateWithActions(RemoteViews big) {
3233 big.setViewVisibility(R.id.actions, View.GONE);
Christoph Studerfe718432014-09-01 18:21:18 +02003234 big.removeAllViews(R.id.actions);
3235 }
3236
Daniel Sandler96fd7c12012-03-30 16:37:36 -04003237 private RemoteViews applyStandardTemplateWithActions(int layoutId) {
Jorim Jaggi445d3c02014-08-19 22:33:42 +02003238 RemoteViews big = applyStandardTemplate(layoutId);
Daniel Sandler96fd7c12012-03-30 16:37:36 -04003239
Christoph Studerfe718432014-09-01 18:21:18 +02003240 resetStandardTemplateWithActions(big);
3241
Daniel Sandler96fd7c12012-03-30 16:37:36 -04003242 int N = mActions.size();
3243 if (N > 0) {
Daniel Sandler96fd7c12012-03-30 16:37:36 -04003244 big.setViewVisibility(R.id.actions, View.VISIBLE);
Daniel Sandler8680bf82012-05-15 16:52:52 -04003245 if (N>MAX_ACTION_BUTTONS) N=MAX_ACTION_BUTTONS;
Daniel Sandler96fd7c12012-03-30 16:37:36 -04003246 for (int i=0; i<N; i++) {
3247 final RemoteViews button = generateActionButton(mActions.get(i));
Daniel Sandler96fd7c12012-03-30 16:37:36 -04003248 big.addView(R.id.actions, button);
3249 }
3250 }
3251 return big;
3252 }
3253
Julia Reynoldsd9228f12015-10-20 10:37:27 -04003254 /**
3255 * Construct a RemoteViews for the final 1U notification layout. In order:
3256 * 1. Custom contentView from the caller
3257 * 2. Style's proposed content view
3258 * 3. Standard template view
3259 */
3260 public RemoteViews makeContentView() {
3261 if (mN.contentView != null) {
3262 return mN.contentView;
3263 } else if (mStyle != null) {
3264 final RemoteViews styleView = mStyle.makeContentView();
3265 if (styleView != null) {
3266 return styleView;
3267 }
Joe Onorato46439ce2010-11-19 13:56:21 -08003268 }
Julia Reynoldsd9228f12015-10-20 10:37:27 -04003269 return applyStandardTemplate(getBaseLayoutResource());
Joe Onorato46439ce2010-11-19 13:56:21 -08003270 }
3271
Julia Reynoldsd9228f12015-10-20 10:37:27 -04003272 /**
3273 * Construct a RemoteViews for the final big notification layout.
3274 */
3275 public RemoteViews makeBigContentView() {
Selim Cinek850a8542015-11-11 11:48:36 -05003276 RemoteViews result = null;
Julia Reynolds089e3e42015-11-18 09:59:57 -05003277 if (mN.bigContentView != null) {
3278 return mN.bigContentView;
3279 } else if (mStyle != null) {
Selim Cinek850a8542015-11-11 11:48:36 -05003280 result = mStyle.makeBigContentView();
Julia Reynolds089e3e42015-11-18 09:59:57 -05003281 } else if (mActions.size() == 0) {
3282 return null;
3283 }
Selim Cinek850a8542015-11-11 11:48:36 -05003284 if (result == null) {
3285 result = applyStandardTemplateWithActions(getBigBaseLayoutResource());
Selim Cinek90dcf6d2015-11-18 20:24:13 -08003286 } else {
3287 hideLine1Text(result);
Selim Cinek850a8542015-11-11 11:48:36 -05003288 }
3289 adaptNotificationHeaderForBigContentView(result);
3290 return result;
3291 }
Daniel Sandler96fd7c12012-03-30 16:37:36 -04003292
Selim Cinekeaa29ca2015-11-23 13:51:13 -08003293 /**
3294 * Construct a RemoteViews for the final notification header only
3295 *
3296 * @hide
3297 */
3298 public RemoteViews makeNotificationHeader() {
3299 RemoteViews header = new BuilderRemoteViews(mContext.getApplicationInfo(),
3300 R.layout.notification_template_header);
3301 resetNotificationHeader(header);
3302 bindNotificationHeader(header);
3303 return header;
3304 }
3305
Selim Cinek29603462015-11-17 19:04:39 -08003306 private void hideLine1Text(RemoteViews result) {
3307 result.setViewVisibility(R.id.text_line_1, View.GONE);
3308 }
3309
Selim Cinek850a8542015-11-11 11:48:36 -05003310 private void adaptNotificationHeaderForBigContentView(RemoteViews result) {
Selim Cinek7b836392015-12-04 20:02:59 -08003311 result.setBoolean(R.id.notification_header, "setExpanded", true);
Daniel Sandler96fd7c12012-03-30 16:37:36 -04003312 }
3313
Julia Reynoldsd9228f12015-10-20 10:37:27 -04003314 /**
3315 * Construct a RemoteViews for the final heads-up notification layout.
3316 */
3317 public RemoteViews makeHeadsUpContentView() {
Julia Reynolds089e3e42015-11-18 09:59:57 -05003318 if (mN.headsUpContentView != null) {
3319 return mN.headsUpContentView;
3320 } else if (mStyle != null) {
3321 final RemoteViews styleView = mStyle.makeHeadsUpContentView();
3322 if (styleView != null) {
3323 return styleView;
3324 }
3325 } else if (mActions.size() == 0) {
3326 return null;
3327 }
3328
Chris Wren8fd39ec2014-02-27 17:43:26 -05003329
Jorim Jaggi39fa59f2014-02-25 15:38:45 +01003330 return applyStandardTemplateWithActions(getBigBaseLayoutResource());
Chris Wren8fd39ec2014-02-27 17:43:26 -05003331 }
3332
Selim Cinek624c02db2015-12-14 21:00:02 -08003333 /**
3334 * Construct a RemoteViews for the display in public contexts like on the lockscreen.
3335 *
3336 * @hide
3337 */
3338 public RemoteViews makePublicContentView() {
3339 if (mN.publicVersion != null) {
3340 final Builder builder = recoverBuilder(mContext, mN.publicVersion);
3341 return builder.makeContentView();
3342 }
3343 Bundle savedBundle = mN.extras;
3344 Style style = mStyle;
3345 mStyle = null;
3346 Icon largeIcon = mN.mLargeIcon;
3347 mN.mLargeIcon = null;
3348 Bundle publicExtras = new Bundle();
3349 publicExtras.putBoolean(EXTRA_SHOW_WHEN,
3350 savedBundle.getBoolean(EXTRA_SHOW_WHEN));
3351 publicExtras.putBoolean(EXTRA_SHOW_CHRONOMETER,
3352 savedBundle.getBoolean(EXTRA_SHOW_CHRONOMETER));
3353 publicExtras.putCharSequence(EXTRA_TITLE,
3354 mContext.getString(R.string.notification_hidden_text));
3355 mN.extras = publicExtras;
3356 final RemoteViews publicView = applyStandardTemplate(getBaseLayoutResource());
3357 mN.extras = savedBundle;
3358 mN.mLargeIcon = largeIcon;
3359 mStyle = style;
3360 return publicView;
3361 }
3362
3363
Chris Wren8fd39ec2014-02-27 17:43:26 -05003364
Daniel Sandler96fd7c12012-03-30 16:37:36 -04003365 private RemoteViews generateActionButton(Action action) {
Daniel Sandler8680bf82012-05-15 16:52:52 -04003366 final boolean tombstone = (action.actionIntent == null);
Selim Cinekf33b1112015-07-15 17:45:11 -07003367 RemoteViews button = new BuilderRemoteViews(mContext.getApplicationInfo(),
Jorim Jaggi39fa59f2014-02-25 15:38:45 +01003368 tombstone ? getActionTombstoneLayoutResource()
3369 : getActionLayoutResource());
Dan Sandler68079d52015-07-22 10:45:30 -04003370 final Icon ai = action.getIcon();
Jorim Jaggi5c2d8462014-03-21 17:37:00 +01003371 button.setTextViewText(R.id.action0, processLegacyText(action.title));
Daniel Sandler8680bf82012-05-15 16:52:52 -04003372 if (!tombstone) {
Daniel Sandlere5518842012-05-10 16:20:40 -04003373 button.setOnClickPendingIntent(R.id.action0, action.actionIntent);
Daniel Sandlere5518842012-05-10 16:20:40 -04003374 }
Daniel Sandler96fd7c12012-03-30 16:37:36 -04003375 button.setContentDescription(R.id.action0, action.title);
Adrian Roosfe84e1f2015-11-04 15:55:39 -08003376 if (action.mRemoteInputs != null) {
3377 button.setRemoteInputs(R.id.action0, action.mRemoteInputs);
3378 }
3379 if (mN.color != COLOR_DEFAULT) {
3380 button.setTextColor(R.id.action0, mN.color);
3381 }
Daniel Sandler96fd7c12012-03-30 16:37:36 -04003382 return button;
3383 }
3384
Joe Onoratocb109a02011-01-18 17:57:41 -08003385 /**
Jorim Jaggi5c2d8462014-03-21 17:37:00 +01003386 * @return Whether we are currently building a notification from a legacy (an app that
Alan Viverette3cb07a462014-06-06 14:19:53 -07003387 * doesn't create material notifications by itself) app.
Jorim Jaggi5c2d8462014-03-21 17:37:00 +01003388 */
3389 private boolean isLegacy() {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04003390 return getColorUtil() != null;
Jorim Jaggi5c2d8462014-03-21 17:37:00 +01003391 }
3392
Jorim Jaggi5c2d8462014-03-21 17:37:00 +01003393 private CharSequence processLegacyText(CharSequence charSequence) {
3394 if (isLegacy()) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04003395 return getColorUtil().invertCharSequenceColors(charSequence);
Jorim Jaggi5c2d8462014-03-21 17:37:00 +01003396 } else {
3397 return charSequence;
3398 }
3399 }
3400
Dan Sandler26e81cf2014-05-06 10:01:27 -04003401 /**
Selim Cinek65b2e7c2015-10-26 14:11:31 -07003402 * Apply any necessariy colors to the small icon
Dan Sandler26e81cf2014-05-06 10:01:27 -04003403 */
Selim Cinek65b2e7c2015-10-26 14:11:31 -07003404 private void processSmallIconColor(Icon smallIcon, RemoteViews contentView) {
Selim Cinekea4bef72015-12-02 15:51:10 -08003405 boolean colorable = !isLegacy() || getColorUtil().isGrayscaleIcon(mContext, smallIcon);
3406 if (colorable) {
Selim Cinek65b2e7c2015-10-26 14:11:31 -07003407 contentView.setDrawableParameters(R.id.icon, false, -1, resolveColor(),
Jorim Jaggi92df1f22014-12-16 19:44:41 +01003408 PorterDuff.Mode.SRC_ATOP, -1);
Selim Cinekea4bef72015-12-02 15:51:10 -08003409
Jorim Jaggi5c2d8462014-03-21 17:37:00 +01003410 }
Selim Cinekea4bef72015-12-02 15:51:10 -08003411 contentView.setInt(R.id.notification_header, "setOriginalIconColor",
3412 colorable ? resolveColor() : NotificationHeaderView.NO_COLOR);
Jorim Jaggi5c2d8462014-03-21 17:37:00 +01003413 }
3414
Dan Sandler26e81cf2014-05-06 10:01:27 -04003415 /**
Selim Cinek65b2e7c2015-10-26 14:11:31 -07003416 * Make the largeIcon dark if it's a fake smallIcon (that is,
Dan Sandler26e81cf2014-05-06 10:01:27 -04003417 * if it's grayscale).
3418 */
3419 // TODO: also check bounds, transparency, that sort of thing.
Dan Sandlerd63f9322015-05-06 15:18:49 -04003420 private void processLargeLegacyIcon(Icon largeIcon, RemoteViews contentView) {
3421 if (largeIcon != null && isLegacy()
Julia Reynoldsd9228f12015-10-20 10:37:27 -04003422 && getColorUtil().isGrayscaleIcon(mContext, largeIcon)) {
Selim Cinek65b2e7c2015-10-26 14:11:31 -07003423 // resolve color will fall back to the default when legacy
3424 contentView.setDrawableParameters(R.id.icon, false, -1, resolveColor(),
Dan Sandler190d58d2014-05-15 09:33:39 -04003425 PorterDuff.Mode.SRC_ATOP, -1);
Jorim Jaggi92df1f22014-12-16 19:44:41 +01003426 }
Jorim Jaggi5c2d8462014-03-21 17:37:00 +01003427 }
3428
Julia Reynolds10ee1fc2015-11-09 11:04:55 -05003429 private void sanitizeColor() {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04003430 if (mN.color != COLOR_DEFAULT) {
3431 mN.color |= 0xFF000000; // no alpha for custom colors
Jorim Jaggi74419312014-06-10 20:57:21 +02003432 }
Jorim Jaggi74419312014-06-10 20:57:21 +02003433 }
3434
Selim Cinek5bf069a2015-11-10 19:14:27 -05003435 int resolveColor() {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04003436 if (mN.color == COLOR_DEFAULT) {
Selim Cinek65b2e7c2015-10-26 14:11:31 -07003437 return mContext.getColor(R.color.notification_icon_default_color);
Dan Sandler26e81cf2014-05-06 10:01:27 -04003438 }
Julia Reynoldsd9228f12015-10-20 10:37:27 -04003439 return mN.color;
Dan Sandler26e81cf2014-05-06 10:01:27 -04003440 }
3441
Jorim Jaggi5c2d8462014-03-21 17:37:00 +01003442 /**
Chris Wrenfbd96ba2012-05-01 12:03:58 -04003443 * Apply the unstyled operations and return a new {@link Notification} object.
Daniel Sandlercf1d39b2013-09-23 13:35:35 -04003444 * @hide
Joe Onoratocb109a02011-01-18 17:57:41 -08003445 */
Daniel Sandlercf1d39b2013-09-23 13:35:35 -04003446 public Notification buildUnstyled() {
Daniel Sandlera0a938c2012-03-15 08:42:37 -04003447 if (mActions.size() > 0) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04003448 mN.actions = new Action[mActions.size()];
3449 mActions.toArray(mN.actions);
Daniel Sandlera0a938c2012-03-15 08:42:37 -04003450 }
Julia Reynoldsd9228f12015-10-20 10:37:27 -04003451 if (!mPersonList.isEmpty()) {
3452 mN.extras.putStringArray(EXTRA_PEOPLE,
3453 mPersonList.toArray(new String[mPersonList.size()]));
Dan Sandler0bf2ed82013-12-21 23:33:41 -06003454 }
Julia Reynoldsd9228f12015-10-20 10:37:27 -04003455 return mN;
Joe Onorato46439ce2010-11-19 13:56:21 -08003456 }
Chris Wrenfbd96ba2012-05-01 12:03:58 -04003457
Julia Reynoldsd9228f12015-10-20 10:37:27 -04003458 public static Notification.Builder recoverBuilder(Context context, Notification n) {
Christoph Studer4600f9b2014-07-22 22:44:43 +02003459 // Re-create notification context so we can access app resources.
Julia Reynoldsd9228f12015-10-20 10:37:27 -04003460 ApplicationInfo applicationInfo = n.extras.getParcelable(
3461 EXTRA_BUILDER_APPLICATION_INFO);
Christoph Studer4600f9b2014-07-22 22:44:43 +02003462 Context builderContext;
Julia Reynoldsda303542015-11-23 14:00:20 -05003463 if (applicationInfo != null) {
3464 try {
3465 builderContext = context.createApplicationContext(applicationInfo,
3466 Context.CONTEXT_RESTRICTED);
3467 } catch (NameNotFoundException e) {
3468 Log.e(TAG, "ApplicationInfo " + applicationInfo + " not found");
3469 builderContext = context; // try with our context
3470 }
3471 } else {
3472 builderContext = context; // try with given context
Christoph Studer4600f9b2014-07-22 22:44:43 +02003473 }
3474
Julia Reynoldsd9228f12015-10-20 10:37:27 -04003475 return new Builder(builderContext, n);
Christoph Studer4600f9b2014-07-22 22:44:43 +02003476 }
3477
3478 private static Class<? extends Style> getNotificationStyleClass(String templateClass) {
3479 Class<? extends Style>[] classes = new Class[]{
3480 BigTextStyle.class, BigPictureStyle.class, InboxStyle.class, MediaStyle.class};
3481 for (Class<? extends Style> innerClass : classes) {
3482 if (templateClass.equals(innerClass.getName())) {
3483 return innerClass;
3484 }
3485 }
3486 return null;
3487 }
3488
3489 private void setBuilderContentView(Notification n, RemoteViews contentView) {
3490 n.contentView = contentView;
Christoph Studer4600f9b2014-07-22 22:44:43 +02003491 }
3492
3493 private void setBuilderBigContentView(Notification n, RemoteViews bigContentView) {
3494 n.bigContentView = bigContentView;
Christoph Studer4600f9b2014-07-22 22:44:43 +02003495 }
3496
3497 private void setBuilderHeadsUpContentView(Notification n,
3498 RemoteViews headsUpContentView) {
3499 n.headsUpContentView = headsUpContentView;
Daniel Sandlerf45564e2013-04-15 15:05:08 -04003500 }
3501
3502 /**
Chris Wrenfbd96ba2012-05-01 12:03:58 -04003503 * @deprecated Use {@link #build()} instead.
3504 */
3505 @Deprecated
3506 public Notification getNotification() {
3507 return build();
3508 }
3509
3510 /**
3511 * Combine all of the options that have been set and return a new {@link Notification}
3512 * object.
3513 */
3514 public Notification build() {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04003515 // first, add any extras from the calling code
3516 if (mUserExtras != null) {
3517 mN.extras = getAllExtras();
Jorim Jaggia0d58ae2015-06-03 11:48:13 -07003518 }
Julia Reynoldsd9228f12015-10-20 10:37:27 -04003519
3520 // lazy stuff from mContext; see comment in Builder(Context, Notification)
Julia Reynoldsda303542015-11-23 14:00:20 -05003521 Notification.addFieldsFromContext(mContext, mN);
Christoph Studer943aa672014-08-03 20:31:16 +02003522
Julia Reynoldsd9228f12015-10-20 10:37:27 -04003523 buildUnstyled();
Daniel Sandlerf45564e2013-04-15 15:05:08 -04003524
Chris Wrenfbd96ba2012-05-01 12:03:58 -04003525 if (mStyle != null) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04003526 mStyle.buildStyled(mN);
Chris Wrenfbd96ba2012-05-01 12:03:58 -04003527 }
Daniel Sandlerf45564e2013-04-15 15:05:08 -04003528
Julia Reynoldsd9228f12015-10-20 10:37:27 -04003529 return mN;
Chris Wrenfbd96ba2012-05-01 12:03:58 -04003530 }
Daniel Sandlerbe6e7e02013-02-01 17:49:11 -05003531
3532 /**
3533 * Apply this Builder to an existing {@link Notification} object.
3534 *
3535 * @hide
3536 */
3537 public Notification buildInto(Notification n) {
Daniel Sandler1a497d32013-04-18 14:52:45 -04003538 build().cloneInto(n, true);
Daniel Sandlerbe6e7e02013-02-01 17:49:11 -05003539 return n;
3540 }
Jorim Jaggi39fa59f2014-02-25 15:38:45 +01003541
Jorim Jaggi39fa59f2014-02-25 15:38:45 +01003542 private int getBaseLayoutResource() {
Alan Viverette3cb07a462014-06-06 14:19:53 -07003543 return R.layout.notification_template_material_base;
Jorim Jaggi39fa59f2014-02-25 15:38:45 +01003544 }
3545
3546 private int getBigBaseLayoutResource() {
Alan Viverette3cb07a462014-06-06 14:19:53 -07003547 return R.layout.notification_template_material_big_base;
Jorim Jaggi39fa59f2014-02-25 15:38:45 +01003548 }
3549
3550 private int getBigPictureLayoutResource() {
Alan Viverette3cb07a462014-06-06 14:19:53 -07003551 return R.layout.notification_template_material_big_picture;
Jorim Jaggi39fa59f2014-02-25 15:38:45 +01003552 }
3553
3554 private int getBigTextLayoutResource() {
Jorim Jaggi445d3c02014-08-19 22:33:42 +02003555 return R.layout.notification_template_material_big_text;
Jorim Jaggi39fa59f2014-02-25 15:38:45 +01003556 }
3557
3558 private int getInboxLayoutResource() {
Alan Viverette3cb07a462014-06-06 14:19:53 -07003559 return R.layout.notification_template_material_inbox;
Jorim Jaggi39fa59f2014-02-25 15:38:45 +01003560 }
3561
3562 private int getActionLayoutResource() {
Alan Viverette3cb07a462014-06-06 14:19:53 -07003563 return R.layout.notification_material_action;
Jorim Jaggi39fa59f2014-02-25 15:38:45 +01003564 }
3565
3566 private int getActionTombstoneLayoutResource() {
Alan Viverette3cb07a462014-06-06 14:19:53 -07003567 return R.layout.notification_material_action_tombstone;
Jorim Jaggi39fa59f2014-02-25 15:38:45 +01003568 }
Chris Wrenfbd96ba2012-05-01 12:03:58 -04003569 }
3570
Chris Wrenfbd96ba2012-05-01 12:03:58 -04003571 /**
3572 * An object that can apply a rich notification style to a {@link Notification.Builder}
3573 * object.
3574 */
Griff Hazendfcb0802014-02-11 12:00:00 -08003575 public static abstract class Style {
Chris Wrend6297db2012-05-03 16:20:13 -04003576 private CharSequence mBigContentTitle;
Jorim Jaggi457a10d2014-09-08 16:18:23 +02003577
3578 /**
3579 * @hide
3580 */
3581 protected CharSequence mSummaryText = null;
3582
3583 /**
3584 * @hide
3585 */
3586 protected boolean mSummaryTextSet = false;
Chris Wrend6297db2012-05-03 16:20:13 -04003587
Chris Wrenfbd96ba2012-05-01 12:03:58 -04003588 protected Builder mBuilder;
3589
Chris Wrend6297db2012-05-03 16:20:13 -04003590 /**
3591 * Overrides ContentTitle in the big form of the template.
3592 * This defaults to the value passed to setContentTitle().
3593 */
3594 protected void internalSetBigContentTitle(CharSequence title) {
3595 mBigContentTitle = title;
3596 }
3597
3598 /**
3599 * Set the first line of text after the detail section in the big form of the template.
3600 */
3601 protected void internalSetSummaryText(CharSequence cs) {
3602 mSummaryText = cs;
Daniel Sandler619738c2012-06-07 16:33:08 -04003603 mSummaryTextSet = true;
Chris Wrend6297db2012-05-03 16:20:13 -04003604 }
3605
Chris Wrenfbd96ba2012-05-01 12:03:58 -04003606 public void setBuilder(Builder builder) {
3607 if (mBuilder != builder) {
3608 mBuilder = builder;
Daniel Sandlerc08dea22012-06-28 08:35:24 -07003609 if (mBuilder != null) {
3610 mBuilder.setStyle(this);
3611 }
Chris Wrenfbd96ba2012-05-01 12:03:58 -04003612 }
3613 }
3614
Chris Wrend6297db2012-05-03 16:20:13 -04003615 protected void checkBuilder() {
Chris Wrenfbd96ba2012-05-01 12:03:58 -04003616 if (mBuilder == null) {
3617 throw new IllegalArgumentException("Style requires a valid Builder object");
3618 }
Chris Wrenfbd96ba2012-05-01 12:03:58 -04003619 }
Chris Wrend6297db2012-05-03 16:20:13 -04003620
3621 protected RemoteViews getStandardView(int layoutId) {
3622 checkBuilder();
3623
Christoph Studer4600f9b2014-07-22 22:44:43 +02003624 // Nasty.
Julia Reynoldsd9228f12015-10-20 10:37:27 -04003625 CharSequence oldBuilderContentTitle =
3626 mBuilder.getAllExtras().getCharSequence(EXTRA_TITLE);
Chris Wrend6297db2012-05-03 16:20:13 -04003627 if (mBigContentTitle != null) {
3628 mBuilder.setContentTitle(mBigContentTitle);
3629 }
3630
Chris Wrend6297db2012-05-03 16:20:13 -04003631 RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(layoutId);
3632
Julia Reynoldsd9228f12015-10-20 10:37:27 -04003633 mBuilder.getAllExtras().putCharSequence(EXTRA_TITLE, oldBuilderContentTitle);
Christoph Studer4600f9b2014-07-22 22:44:43 +02003634
Chris Wrend6297db2012-05-03 16:20:13 -04003635 if (mBigContentTitle != null && mBigContentTitle.equals("")) {
3636 contentView.setViewVisibility(R.id.line1, View.GONE);
Chris Wren67dc9a02012-05-16 01:03:20 -04003637 } else {
3638 contentView.setViewVisibility(R.id.line1, View.VISIBLE);
Chris Wrend6297db2012-05-03 16:20:13 -04003639 }
3640
Selim Cinek9d9fc6e2015-11-12 15:49:14 -05003641 // Clear text in case we use the line to show the profile badge.
3642 contentView.setTextViewText(com.android.internal.R.id.text, "");
3643 contentView.setViewVisibility(com.android.internal.R.id.line3, View.GONE);
3644
Chris Wrend6297db2012-05-03 16:20:13 -04003645 return contentView;
3646 }
3647
Daniel Sandlerf45564e2013-04-15 15:05:08 -04003648 /**
Julia Reynoldsd9228f12015-10-20 10:37:27 -04003649 * Construct a Style-specific RemoteViews for the final 1U notification layout.
3650 * The default implementation has nothing additional to add.
3651 * @hide
3652 */
3653 public RemoteViews makeContentView() {
3654 return null;
3655 }
3656
3657 /**
3658 * Construct a Style-specific RemoteViews for the final big notification layout.
3659 * @hide
3660 */
3661 public RemoteViews makeBigContentView() {
3662 return null;
3663 }
3664
3665 /**
3666 * Construct a Style-specific RemoteViews for the final HUN layout.
3667 * @hide
3668 */
3669 public RemoteViews makeHeadsUpContentView() {
3670 return null;
3671 }
3672
3673 /**
Julia Reynoldsd9228f12015-10-20 10:37:27 -04003674 * Apply any style-specific extras to this notification before shipping it out.
Daniel Sandlerf45564e2013-04-15 15:05:08 -04003675 * @hide
3676 */
3677 public void addExtras(Bundle extras) {
3678 if (mSummaryTextSet) {
3679 extras.putCharSequence(EXTRA_SUMMARY_TEXT, mSummaryText);
3680 }
3681 if (mBigContentTitle != null) {
3682 extras.putCharSequence(EXTRA_TITLE_BIG, mBigContentTitle);
3683 }
Chris Wren91ad5632013-06-05 15:05:57 -04003684 extras.putString(EXTRA_TEMPLATE, this.getClass().getName());
Daniel Sandlerf45564e2013-04-15 15:05:08 -04003685 }
3686
Daniel Sandlercf1d39b2013-09-23 13:35:35 -04003687 /**
Julia Reynoldsd9228f12015-10-20 10:37:27 -04003688 * Reconstruct the internal state of this Style object from extras.
Daniel Sandlercf1d39b2013-09-23 13:35:35 -04003689 * @hide
3690 */
Christoph Studer4600f9b2014-07-22 22:44:43 +02003691 protected void restoreFromExtras(Bundle extras) {
3692 if (extras.containsKey(EXTRA_SUMMARY_TEXT)) {
3693 mSummaryText = extras.getCharSequence(EXTRA_SUMMARY_TEXT);
3694 mSummaryTextSet = true;
3695 }
3696 if (extras.containsKey(EXTRA_TITLE_BIG)) {
3697 mBigContentTitle = extras.getCharSequence(EXTRA_TITLE_BIG);
3698 }
3699 }
3700
3701
3702 /**
3703 * @hide
3704 */
3705 public Notification buildStyled(Notification wip) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04003706 addExtras(wip.extras);
Christoph Studer4600f9b2014-07-22 22:44:43 +02003707 return wip;
3708 }
3709
Daniel Sandler0ec46202015-06-24 01:27:05 -04003710 /**
3711 * @hide
3712 */
Jorim Jaggia0d58ae2015-06-03 11:48:13 -07003713 public void purgeResources() {}
3714
Daniel Sandlercf1d39b2013-09-23 13:35:35 -04003715 /**
3716 * Calls {@link android.app.Notification.Builder#build()} on the Builder this Style is
3717 * attached to.
3718 *
3719 * @return the fully constructed Notification.
3720 */
3721 public Notification build() {
3722 checkBuilder();
3723 return mBuilder.build();
3724 }
Jorim Jaggi17ee3ec2014-08-29 03:47:31 +02003725
3726 /**
3727 * @hide
3728 * @return true if the style positions the progress bar on the second line; false if the
3729 * style hides the progress bar
3730 */
3731 protected boolean hasProgress() {
3732 return true;
3733 }
Selim Cinek03d0d652015-11-13 13:18:09 -05003734
3735 /**
3736 * @hide
3737 * @return Whether we should put the summary be put into the notification header
3738 */
3739 public boolean hasSummaryInHeader() {
3740 return true;
3741 }
Joe Onorato46439ce2010-11-19 13:56:21 -08003742 }
Daniel Sandlerf3b73432012-03-27 15:01:25 -04003743
3744 /**
Daniel Sandler4dfbe832012-04-11 14:51:46 -04003745 * Helper class for generating large-format notifications that include a large image attachment.
Joe Malin8d40d042012-11-05 11:36:40 -08003746 *
Robert Ly91c5ce32014-06-08 15:37:00 -07003747 * Here's how you'd set the <code>BigPictureStyle</code> on a notification:
Daniel Sandlerf3b73432012-03-27 15:01:25 -04003748 * <pre class="prettyprint">
Robert Ly91c5ce32014-06-08 15:37:00 -07003749 * Notification notif = new Notification.Builder(mContext)
3750 * .setContentTitle(&quot;New photo from &quot; + sender.toString())
3751 * .setContentText(subject)
3752 * .setSmallIcon(R.drawable.new_post)
3753 * .setLargeIcon(aBitmap)
3754 * .setStyle(new Notification.BigPictureStyle()
3755 * .bigPicture(aBigBitmap))
3756 * .build();
Daniel Sandlerf3b73432012-03-27 15:01:25 -04003757 * </pre>
Joe Malin8d40d042012-11-05 11:36:40 -08003758 *
Daniel Sandler4dfbe832012-04-11 14:51:46 -04003759 * @see Notification#bigContentView
Daniel Sandlerf3b73432012-03-27 15:01:25 -04003760 */
Chris Wrenfbd96ba2012-05-01 12:03:58 -04003761 public static class BigPictureStyle extends Style {
Daniel Sandlerf3b73432012-03-27 15:01:25 -04003762 private Bitmap mPicture;
Dan Sandlerd63f9322015-05-06 15:18:49 -04003763 private Icon mBigLargeIcon;
Chris Wren3745a3d2012-05-22 15:11:52 -04003764 private boolean mBigLargeIconSet = false;
Daniel Sandlerf3b73432012-03-27 15:01:25 -04003765
Chris Wrenfbd96ba2012-05-01 12:03:58 -04003766 public BigPictureStyle() {
3767 }
3768
Daniel Sandlerf3b73432012-03-27 15:01:25 -04003769 public BigPictureStyle(Builder builder) {
Chris Wrenfbd96ba2012-05-01 12:03:58 -04003770 setBuilder(builder);
Daniel Sandlerf3b73432012-03-27 15:01:25 -04003771 }
3772
Chris Wrend6297db2012-05-03 16:20:13 -04003773 /**
3774 * Overrides ContentTitle in the big form of the template.
3775 * This defaults to the value passed to setContentTitle().
3776 */
3777 public BigPictureStyle setBigContentTitle(CharSequence title) {
Daniel Sandlerdcbaf662013-04-26 16:23:09 -04003778 internalSetBigContentTitle(safeCharSequence(title));
Chris Wrend6297db2012-05-03 16:20:13 -04003779 return this;
3780 }
3781
3782 /**
3783 * Set the first line of text after the detail section in the big form of the template.
3784 */
3785 public BigPictureStyle setSummaryText(CharSequence cs) {
Daniel Sandlerdcbaf662013-04-26 16:23:09 -04003786 internalSetSummaryText(safeCharSequence(cs));
Chris Wrend6297db2012-05-03 16:20:13 -04003787 return this;
3788 }
3789
Chris Wren0bd664d2012-08-01 13:56:56 -04003790 /**
3791 * Provide the bitmap to be used as the payload for the BigPicture notification.
3792 */
Daniel Sandlerf3b73432012-03-27 15:01:25 -04003793 public BigPictureStyle bigPicture(Bitmap b) {
3794 mPicture = b;
3795 return this;
3796 }
3797
Chris Wren3745a3d2012-05-22 15:11:52 -04003798 /**
Chris Wren3745a3d2012-05-22 15:11:52 -04003799 * Override the large icon when the big notification is shown.
3800 */
3801 public BigPictureStyle bigLargeIcon(Bitmap b) {
Dan Sandlerd63f9322015-05-06 15:18:49 -04003802 return bigLargeIcon(b != null ? Icon.createWithBitmap(b) : null);
3803 }
3804
3805 /**
3806 * Override the large icon when the big notification is shown.
3807 */
3808 public BigPictureStyle bigLargeIcon(Icon icon) {
Chris Wren3745a3d2012-05-22 15:11:52 -04003809 mBigLargeIconSet = true;
Dan Sandlerd63f9322015-05-06 15:18:49 -04003810 mBigLargeIcon = icon;
Chris Wren3745a3d2012-05-22 15:11:52 -04003811 return this;
3812 }
3813
Riley Andrews0394a0c2015-11-03 23:36:52 -08003814 /** @hide */
3815 public static final int MIN_ASHMEM_BITMAP_SIZE = 128 * (1 << 10);
3816
Daniel Sandler0ec46202015-06-24 01:27:05 -04003817 /**
3818 * @hide
3819 */
Jorim Jaggia0d58ae2015-06-03 11:48:13 -07003820 @Override
3821 public void purgeResources() {
3822 super.purgeResources();
Riley Andrews8cee7c12015-11-01 23:36:04 -08003823 if (mPicture != null &&
3824 mPicture.isMutable() &&
Riley Andrews0394a0c2015-11-03 23:36:52 -08003825 mPicture.getAllocationByteCount() >= MIN_ASHMEM_BITMAP_SIZE) {
Jorim Jaggia0d58ae2015-06-03 11:48:13 -07003826 mPicture = mPicture.createAshmemBitmap();
3827 }
3828 if (mBigLargeIcon != null) {
3829 mBigLargeIcon.convertToAshmem();
3830 }
3831 }
Christoph Studer5c510ee2014-12-15 16:32:27 +01003832
Julia Reynoldsd9228f12015-10-20 10:37:27 -04003833 /**
3834 * @hide
3835 */
3836 public RemoteViews makeBigContentView() {
3837 // Replace mN.mLargeIcon with mBigLargeIcon if mBigLargeIconSet
Christoph Studer5c510ee2014-12-15 16:32:27 +01003838 // This covers the following cases:
3839 // 1. mBigLargeIconSet -> mBigLargeIcon (null or non-null) applies, overrides
Julia Reynoldsd9228f12015-10-20 10:37:27 -04003840 // mN.mLargeIcon
3841 // 2. !mBigLargeIconSet -> mN.mLargeIcon applies
Dan Sandlerd63f9322015-05-06 15:18:49 -04003842 Icon oldLargeIcon = null;
Christoph Studer5c510ee2014-12-15 16:32:27 +01003843 if (mBigLargeIconSet) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04003844 oldLargeIcon = mBuilder.mN.mLargeIcon;
3845 mBuilder.mN.mLargeIcon = mBigLargeIcon;
Christoph Studer5c510ee2014-12-15 16:32:27 +01003846 }
3847
Jorim Jaggi39fa59f2014-02-25 15:38:45 +01003848 RemoteViews contentView = getStandardView(mBuilder.getBigPictureLayoutResource());
Selim Cinek03d0d652015-11-13 13:18:09 -05003849 if (mSummaryTextSet) {
3850 contentView.setTextViewText(R.id.text, mBuilder.processLegacyText(mSummaryText));
3851 contentView.setViewVisibility(R.id.line3, View.VISIBLE);
3852 }
Selim Cinek860b6da2015-12-16 19:02:19 -08003853 mBuilder.setContentMinHeight(contentView, mBuilder.mN.mLargeIcon != null);
Selim Cinek53e64a42015-11-16 10:40:56 -08003854
Christoph Studer5c510ee2014-12-15 16:32:27 +01003855 if (mBigLargeIconSet) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04003856 mBuilder.mN.mLargeIcon = oldLargeIcon;
Christoph Studer5c510ee2014-12-15 16:32:27 +01003857 }
3858
Daniel Sandlerf3b73432012-03-27 15:01:25 -04003859 contentView.setImageViewBitmap(R.id.big_picture, mPicture);
3860
Selim Cinek29603462015-11-17 19:04:39 -08003861 mBuilder.addProfileBadge(contentView, R.id.profile_badge_line3);
Daniel Sandlerf3b73432012-03-27 15:01:25 -04003862 return contentView;
3863 }
3864
Daniel Sandlerf45564e2013-04-15 15:05:08 -04003865 /**
3866 * @hide
3867 */
3868 public void addExtras(Bundle extras) {
3869 super.addExtras(extras);
3870
3871 if (mBigLargeIconSet) {
3872 extras.putParcelable(EXTRA_LARGE_ICON_BIG, mBigLargeIcon);
3873 }
3874 extras.putParcelable(EXTRA_PICTURE, mPicture);
3875 }
3876
Daniel Sandlercf1d39b2013-09-23 13:35:35 -04003877 /**
3878 * @hide
3879 */
Chris Wrenfbd96ba2012-05-01 12:03:58 -04003880 @Override
Christoph Studer4600f9b2014-07-22 22:44:43 +02003881 protected void restoreFromExtras(Bundle extras) {
3882 super.restoreFromExtras(extras);
3883
3884 if (extras.containsKey(EXTRA_LARGE_ICON_BIG)) {
Christoph Studer5c510ee2014-12-15 16:32:27 +01003885 mBigLargeIconSet = true;
Christoph Studer4600f9b2014-07-22 22:44:43 +02003886 mBigLargeIcon = extras.getParcelable(EXTRA_LARGE_ICON_BIG);
Chris Wren3745a3d2012-05-22 15:11:52 -04003887 }
Christoph Studer4600f9b2014-07-22 22:44:43 +02003888 mPicture = extras.getParcelable(EXTRA_PICTURE);
3889 }
Selim Cinek03d0d652015-11-13 13:18:09 -05003890
3891 /**
3892 * @hide
3893 */
3894 @Override
3895 public boolean hasSummaryInHeader() {
3896 return false;
3897 }
Daniel Sandlerf3b73432012-03-27 15:01:25 -04003898 }
3899
3900 /**
Daniel Sandler4dfbe832012-04-11 14:51:46 -04003901 * Helper class for generating large-format notifications that include a lot of text.
Joe Malin8d40d042012-11-05 11:36:40 -08003902 *
Robert Ly91c5ce32014-06-08 15:37:00 -07003903 * Here's how you'd set the <code>BigTextStyle</code> on a notification:
Daniel Sandlerf3b73432012-03-27 15:01:25 -04003904 * <pre class="prettyprint">
Robert Ly91c5ce32014-06-08 15:37:00 -07003905 * Notification notif = new Notification.Builder(mContext)
3906 * .setContentTitle(&quot;New mail from &quot; + sender.toString())
3907 * .setContentText(subject)
3908 * .setSmallIcon(R.drawable.new_mail)
3909 * .setLargeIcon(aBitmap)
3910 * .setStyle(new Notification.BigTextStyle()
3911 * .bigText(aVeryLongString))
3912 * .build();
Daniel Sandlerf3b73432012-03-27 15:01:25 -04003913 * </pre>
Joe Malin8d40d042012-11-05 11:36:40 -08003914 *
Daniel Sandler4dfbe832012-04-11 14:51:46 -04003915 * @see Notification#bigContentView
Daniel Sandlerf3b73432012-03-27 15:01:25 -04003916 */
Chris Wrenfbd96ba2012-05-01 12:03:58 -04003917 public static class BigTextStyle extends Style {
Jorim Jaggi457a10d2014-09-08 16:18:23 +02003918
3919 private static final int MAX_LINES = 13;
Selim Cinek3a2c4b92015-12-17 17:01:17 -08003920 private static final int LINES_CONSUMED_BY_ACTIONS = 4;
Jorim Jaggi457a10d2014-09-08 16:18:23 +02003921
Daniel Sandlerf3b73432012-03-27 15:01:25 -04003922 private CharSequence mBigText;
3923
Chris Wrenfbd96ba2012-05-01 12:03:58 -04003924 public BigTextStyle() {
3925 }
3926
Daniel Sandlerf3b73432012-03-27 15:01:25 -04003927 public BigTextStyle(Builder builder) {
Chris Wrenfbd96ba2012-05-01 12:03:58 -04003928 setBuilder(builder);
Daniel Sandlerf3b73432012-03-27 15:01:25 -04003929 }
3930
Chris Wrend6297db2012-05-03 16:20:13 -04003931 /**
3932 * Overrides ContentTitle in the big form of the template.
3933 * This defaults to the value passed to setContentTitle().
3934 */
3935 public BigTextStyle setBigContentTitle(CharSequence title) {
Daniel Sandlerdcbaf662013-04-26 16:23:09 -04003936 internalSetBigContentTitle(safeCharSequence(title));
Chris Wrend6297db2012-05-03 16:20:13 -04003937 return this;
3938 }
3939
3940 /**
3941 * Set the first line of text after the detail section in the big form of the template.
3942 */
3943 public BigTextStyle setSummaryText(CharSequence cs) {
Daniel Sandlerdcbaf662013-04-26 16:23:09 -04003944 internalSetSummaryText(safeCharSequence(cs));
Chris Wrend6297db2012-05-03 16:20:13 -04003945 return this;
3946 }
3947
Chris Wren0bd664d2012-08-01 13:56:56 -04003948 /**
3949 * Provide the longer text to be displayed in the big form of the
3950 * template in place of the content text.
3951 */
Daniel Sandlerf3b73432012-03-27 15:01:25 -04003952 public BigTextStyle bigText(CharSequence cs) {
Daniel Sandlerdcbaf662013-04-26 16:23:09 -04003953 mBigText = safeCharSequence(cs);
Daniel Sandlerf3b73432012-03-27 15:01:25 -04003954 return this;
3955 }
3956
Daniel Sandlerf45564e2013-04-15 15:05:08 -04003957 /**
3958 * @hide
3959 */
3960 public void addExtras(Bundle extras) {
3961 super.addExtras(extras);
3962
Christoph Studer4600f9b2014-07-22 22:44:43 +02003963 extras.putCharSequence(EXTRA_BIG_TEXT, mBigText);
3964 }
3965
3966 /**
3967 * @hide
3968 */
3969 @Override
3970 protected void restoreFromExtras(Bundle extras) {
3971 super.restoreFromExtras(extras);
3972
3973 mBigText = extras.getCharSequence(EXTRA_BIG_TEXT);
Daniel Sandlerf45564e2013-04-15 15:05:08 -04003974 }
3975
Julia Reynoldsd9228f12015-10-20 10:37:27 -04003976 /**
3977 * @hide
3978 */
3979 public RemoteViews makeBigContentView() {
Christoph Studer4600f9b2014-07-22 22:44:43 +02003980
3981 // Nasty
Julia Reynoldsd9228f12015-10-20 10:37:27 -04003982 CharSequence oldBuilderContentText =
3983 mBuilder.getAllExtras().getCharSequence(EXTRA_TEXT);
3984 mBuilder.getAllExtras().putCharSequence(EXTRA_TEXT, null);
Daniel Sandler916ad912012-06-13 12:17:07 -04003985
Jorim Jaggi39fa59f2014-02-25 15:38:45 +01003986 RemoteViews contentView = getStandardView(mBuilder.getBigTextLayoutResource());
Joe Malin8d40d042012-11-05 11:36:40 -08003987
Julia Reynoldsd9228f12015-10-20 10:37:27 -04003988 mBuilder.getAllExtras().putCharSequence(EXTRA_TEXT, oldBuilderContentText);
Christoph Studer4600f9b2014-07-22 22:44:43 +02003989
Selim Cinek3a2c4b92015-12-17 17:01:17 -08003990 CharSequence bigTextText = mBuilder.processLegacyText(mBigText);
3991 contentView.setTextViewText(R.id.big_text, bigTextText);
3992 contentView.setViewVisibility(R.id.big_text,
3993 TextUtils.isEmpty(bigTextText) ? View.GONE : View.VISIBLE);
Jorim Jaggi457a10d2014-09-08 16:18:23 +02003994 contentView.setInt(R.id.big_text, "setMaxLines", calculateMaxLines());
Jorim Jaggid05aa3e2014-08-28 17:52:27 +02003995
Kenny Guy98193ea2014-07-24 19:54:37 +01003996 mBuilder.addProfileBadge(contentView, R.id.profile_badge_large_template);
3997
Selim Cinek4fb12d32015-11-19 18:10:48 -08003998 contentView.setBoolean(R.id.big_text, "setHasImage", mBuilder.mN.mLargeIcon != null);
3999
Daniel Sandlerf3b73432012-03-27 15:01:25 -04004000 return contentView;
4001 }
4002
Jorim Jaggi457a10d2014-09-08 16:18:23 +02004003 private int calculateMaxLines() {
4004 int lineCount = MAX_LINES;
4005 boolean hasActions = mBuilder.mActions.size() > 0;
Jorim Jaggi457a10d2014-09-08 16:18:23 +02004006 if (hasActions) {
4007 lineCount -= LINES_CONSUMED_BY_ACTIONS;
4008 }
Jorim Jaggi457a10d2014-09-08 16:18:23 +02004009 return lineCount;
4010 }
Daniel Sandlerf3b73432012-03-27 15:01:25 -04004011 }
Daniel Sandler879c5e02012-04-17 16:46:51 -04004012
4013 /**
4014 * Helper class for generating large-format notifications that include a list of (up to 5) strings.
Joe Malin8d40d042012-11-05 11:36:40 -08004015 *
Robert Ly91c5ce32014-06-08 15:37:00 -07004016 * Here's how you'd set the <code>InboxStyle</code> on a notification:
Daniel Sandler879c5e02012-04-17 16:46:51 -04004017 * <pre class="prettyprint">
Robert Ly91c5ce32014-06-08 15:37:00 -07004018 * Notification notif = new Notification.Builder(mContext)
4019 * .setContentTitle(&quot;5 New mails from &quot; + sender.toString())
4020 * .setContentText(subject)
4021 * .setSmallIcon(R.drawable.new_mail)
4022 * .setLargeIcon(aBitmap)
4023 * .setStyle(new Notification.InboxStyle()
4024 * .addLine(str1)
4025 * .addLine(str2)
4026 * .setContentTitle(&quot;&quot;)
4027 * .setSummaryText(&quot;+3 more&quot;))
4028 * .build();
Daniel Sandler879c5e02012-04-17 16:46:51 -04004029 * </pre>
Joe Malin8d40d042012-11-05 11:36:40 -08004030 *
Daniel Sandler879c5e02012-04-17 16:46:51 -04004031 * @see Notification#bigContentView
4032 */
Chris Wrenfbd96ba2012-05-01 12:03:58 -04004033 public static class InboxStyle extends Style {
Daniel Sandler879c5e02012-04-17 16:46:51 -04004034 private ArrayList<CharSequence> mTexts = new ArrayList<CharSequence>(5);
4035
Chris Wrenfbd96ba2012-05-01 12:03:58 -04004036 public InboxStyle() {
4037 }
4038
Daniel Sandler879c5e02012-04-17 16:46:51 -04004039 public InboxStyle(Builder builder) {
Chris Wrenfbd96ba2012-05-01 12:03:58 -04004040 setBuilder(builder);
Daniel Sandler879c5e02012-04-17 16:46:51 -04004041 }
4042
Chris Wrend6297db2012-05-03 16:20:13 -04004043 /**
4044 * Overrides ContentTitle in the big form of the template.
4045 * This defaults to the value passed to setContentTitle().
4046 */
4047 public InboxStyle setBigContentTitle(CharSequence title) {
Daniel Sandlerdcbaf662013-04-26 16:23:09 -04004048 internalSetBigContentTitle(safeCharSequence(title));
Chris Wrend6297db2012-05-03 16:20:13 -04004049 return this;
4050 }
4051
4052 /**
4053 * Set the first line of text after the detail section in the big form of the template.
4054 */
4055 public InboxStyle setSummaryText(CharSequence cs) {
Daniel Sandlerdcbaf662013-04-26 16:23:09 -04004056 internalSetSummaryText(safeCharSequence(cs));
Chris Wrend6297db2012-05-03 16:20:13 -04004057 return this;
4058 }
4059
Chris Wren0bd664d2012-08-01 13:56:56 -04004060 /**
4061 * Append a line to the digest section of the Inbox notification.
4062 */
Daniel Sandler879c5e02012-04-17 16:46:51 -04004063 public InboxStyle addLine(CharSequence cs) {
Daniel Sandlerdcbaf662013-04-26 16:23:09 -04004064 mTexts.add(safeCharSequence(cs));
Daniel Sandler879c5e02012-04-17 16:46:51 -04004065 return this;
4066 }
4067
Daniel Sandlerf45564e2013-04-15 15:05:08 -04004068 /**
4069 * @hide
4070 */
4071 public void addExtras(Bundle extras) {
4072 super.addExtras(extras);
Christoph Studer4600f9b2014-07-22 22:44:43 +02004073
Daniel Sandlerf45564e2013-04-15 15:05:08 -04004074 CharSequence[] a = new CharSequence[mTexts.size()];
4075 extras.putCharSequenceArray(EXTRA_TEXT_LINES, mTexts.toArray(a));
4076 }
4077
Christoph Studer4600f9b2014-07-22 22:44:43 +02004078 /**
4079 * @hide
4080 */
4081 @Override
4082 protected void restoreFromExtras(Bundle extras) {
4083 super.restoreFromExtras(extras);
4084
4085 mTexts.clear();
4086 if (extras.containsKey(EXTRA_TEXT_LINES)) {
4087 Collections.addAll(mTexts, extras.getCharSequenceArray(EXTRA_TEXT_LINES));
4088 }
4089 }
4090
Julia Reynoldsd9228f12015-10-20 10:37:27 -04004091 /**
4092 * @hide
4093 */
4094 public RemoteViews makeBigContentView() {
Daniel Sandler619738c2012-06-07 16:33:08 -04004095 // Remove the content text so line3 disappears unless you have a summary
Christoph Studer4600f9b2014-07-22 22:44:43 +02004096 // Nasty
Julia Reynoldsd9228f12015-10-20 10:37:27 -04004097 CharSequence oldBuilderContentText = mBuilder.mN.extras.getCharSequence(EXTRA_TEXT);
4098 mBuilder.getAllExtras().putCharSequence(EXTRA_TEXT, null);
Christoph Studer4600f9b2014-07-22 22:44:43 +02004099
Jorim Jaggi39fa59f2014-02-25 15:38:45 +01004100 RemoteViews contentView = getStandardView(mBuilder.getInboxLayoutResource());
Daniel Sandler619738c2012-06-07 16:33:08 -04004101
Julia Reynoldsd9228f12015-10-20 10:37:27 -04004102 mBuilder.getAllExtras().putCharSequence(EXTRA_TEXT, oldBuilderContentText);
Christoph Studer4600f9b2014-07-22 22:44:43 +02004103
Chris Wrend6297db2012-05-03 16:20:13 -04004104 int[] rowIds = {R.id.inbox_text0, R.id.inbox_text1, R.id.inbox_text2, R.id.inbox_text3,
Chris Wren29bb6d92012-05-17 18:09:42 -04004105 R.id.inbox_text4, R.id.inbox_text5, R.id.inbox_text6};
Chris Wrend6297db2012-05-03 16:20:13 -04004106
Chris Wren4ed80d52012-05-17 09:30:03 -04004107 // Make sure all rows are gone in case we reuse a view.
4108 for (int rowId : rowIds) {
4109 contentView.setViewVisibility(rowId, View.GONE);
4110 }
4111
Jorim Jaggi445d3c02014-08-19 22:33:42 +02004112 final boolean largeText =
4113 mBuilder.mContext.getResources().getConfiguration().fontScale > 1f;
4114 final float subTextSize = mBuilder.mContext.getResources().getDimensionPixelSize(
4115 R.dimen.notification_subtext_size);
Daniel Sandler879c5e02012-04-17 16:46:51 -04004116 int i=0;
Selim Cinek9d9fc6e2015-11-12 15:49:14 -05004117 final float density = mBuilder.mContext.getResources().getDisplayMetrics().density;
4118 int topPadding = (int) (5 * density);
4119 int bottomPadding = (int) (13 * density);
Daniel Sandler879c5e02012-04-17 16:46:51 -04004120 while (i < mTexts.size() && i < rowIds.length) {
4121 CharSequence str = mTexts.get(i);
4122 if (str != null && !str.equals("")) {
4123 contentView.setViewVisibility(rowIds[i], View.VISIBLE);
Jorim Jaggi5c2d8462014-03-21 17:37:00 +01004124 contentView.setTextViewText(rowIds[i], mBuilder.processLegacyText(str));
Jorim Jaggi445d3c02014-08-19 22:33:42 +02004125 if (largeText) {
4126 contentView.setTextViewTextSize(rowIds[i], TypedValue.COMPLEX_UNIT_PX,
4127 subTextSize);
4128 }
Selim Cinek9d9fc6e2015-11-12 15:49:14 -05004129 contentView.setViewPadding(rowIds[i], 0, topPadding, 0,
4130 i == rowIds.length - 1 || i == mTexts.size() - 1 ? bottomPadding : 0);
Daniel Sandler879c5e02012-04-17 16:46:51 -04004131 }
4132 i++;
4133 }
Kenny Guy98193ea2014-07-24 19:54:37 +01004134 mBuilder.addProfileBadge(contentView, R.id.profile_badge_large_template);
4135
Selim Cinek1e0bf612015-11-20 15:57:26 -08004136 handleInboxImageMargin(contentView, rowIds[0]);
4137
Daniel Sandler879c5e02012-04-17 16:46:51 -04004138 return contentView;
4139 }
Selim Cinek1e0bf612015-11-20 15:57:26 -08004140
4141 private void handleInboxImageMargin(RemoteViews contentView, int id) {
4142 final int max = mBuilder.mN.extras.getInt(EXTRA_PROGRESS_MAX, 0);
4143 final boolean ind = mBuilder.mN.extras.getBoolean(EXTRA_PROGRESS_INDETERMINATE);
4144 boolean hasProgress = max != 0 || ind;
4145 int endMargin = 0;
4146 if (mTexts.size() > 0 && mBuilder.mN.mLargeIcon != null && !hasProgress) {
4147 endMargin = mBuilder.mContext.getResources().getDimensionPixelSize(
4148 R.dimen.notification_content_picture_margin);
4149 }
4150 contentView.setViewLayoutMarginEnd(id, endMargin);
4151 }
Daniel Sandler879c5e02012-04-17 16:46:51 -04004152 }
Dan Sandler842dd772014-05-15 09:36:47 -04004153
4154 /**
4155 * Notification style for media playback notifications.
4156 *
4157 * In the expanded form, {@link Notification#bigContentView}, up to 5
4158 * {@link Notification.Action}s specified with
Dan Sandler86647982015-05-13 23:41:13 -04004159 * {@link Notification.Builder#addAction(Action) addAction} will be
Dan Sandler842dd772014-05-15 09:36:47 -04004160 * shown as icon-only pushbuttons, suitable for transport controls. The Bitmap given to
4161 * {@link Notification.Builder#setLargeIcon(android.graphics.Bitmap) setLargeIcon()} will be
4162 * treated as album artwork.
4163 *
4164 * Unlike the other styles provided here, MediaStyle can also modify the standard-size
4165 * {@link Notification#contentView}; by providing action indices to
Christoph Studerfde6f4d2014-12-12 13:23:26 +01004166 * {@link #setShowActionsInCompactView(int...)} you can promote up to 3 actions to be displayed
Dan Sandler842dd772014-05-15 09:36:47 -04004167 * in the standard view alongside the usual content.
4168 *
Bryan Mawhinney6be8de32014-07-18 10:35:12 +01004169 * Notifications created with MediaStyle will have their category set to
4170 * {@link Notification#CATEGORY_TRANSPORT CATEGORY_TRANSPORT} unless you set a different
4171 * category using {@link Notification.Builder#setCategory(String) setCategory()}.
4172 *
Jeff Browndba34ba2014-06-24 20:46:03 -07004173 * Finally, if you attach a {@link android.media.session.MediaSession.Token} using
4174 * {@link android.app.Notification.MediaStyle#setMediaSession(MediaSession.Token)},
Dan Sandler842dd772014-05-15 09:36:47 -04004175 * the System UI can identify this as a notification representing an active media session
4176 * and respond accordingly (by showing album artwork in the lockscreen, for example).
4177 *
4178 * To use this style with your Notification, feed it to
4179 * {@link Notification.Builder#setStyle(android.app.Notification.Style)} like so:
4180 * <pre class="prettyprint">
4181 * Notification noti = new Notification.Builder()
4182 * .setSmallIcon(R.drawable.ic_stat_player)
Christoph Studere935fe92014-11-24 14:18:06 +01004183 * .setContentTitle(&quot;Track title&quot;)
4184 * .setContentText(&quot;Artist - Album&quot;)
4185 * .setLargeIcon(albumArtBitmap))
Bryan Mawhinney6be8de32014-07-18 10:35:12 +01004186 * .setStyle(<b>new Notification.MediaStyle()</b>
4187 * .setMediaSession(mySession))
Dan Sandler842dd772014-05-15 09:36:47 -04004188 * .build();
4189 * </pre>
4190 *
4191 * @see Notification#bigContentView
4192 */
4193 public static class MediaStyle extends Style {
Jorim Jaggi17ee3ec2014-08-29 03:47:31 +02004194 static final int MAX_MEDIA_BUTTONS_IN_COMPACT = 3;
Dan Sandler842dd772014-05-15 09:36:47 -04004195 static final int MAX_MEDIA_BUTTONS = 5;
4196
4197 private int[] mActionsToShowInCompact = null;
Jeff Browndba34ba2014-06-24 20:46:03 -07004198 private MediaSession.Token mToken;
Dan Sandler842dd772014-05-15 09:36:47 -04004199
4200 public MediaStyle() {
4201 }
4202
4203 public MediaStyle(Builder builder) {
4204 setBuilder(builder);
4205 }
4206
4207 /**
Jorim Jaggi17ee3ec2014-08-29 03:47:31 +02004208 * Request up to 3 actions (by index in the order of addition) to be shown in the compact
Dan Sandler842dd772014-05-15 09:36:47 -04004209 * notification view.
Jorim Jaggi17ee3ec2014-08-29 03:47:31 +02004210 *
4211 * @param actions the indices of the actions to show in the compact notification view
Dan Sandler842dd772014-05-15 09:36:47 -04004212 */
4213 public MediaStyle setShowActionsInCompactView(int...actions) {
4214 mActionsToShowInCompact = actions;
4215 return this;
4216 }
4217
4218 /**
Jeff Browndba34ba2014-06-24 20:46:03 -07004219 * Attach a {@link android.media.session.MediaSession.Token} to this Notification
4220 * to provide additional playback information and control to the SystemUI.
Dan Sandler842dd772014-05-15 09:36:47 -04004221 */
Jeff Browndba34ba2014-06-24 20:46:03 -07004222 public MediaStyle setMediaSession(MediaSession.Token token) {
Dan Sandler842dd772014-05-15 09:36:47 -04004223 mToken = token;
4224 return this;
4225 }
4226
Christoph Studer4600f9b2014-07-22 22:44:43 +02004227 /**
4228 * @hide
4229 */
Dan Sandler842dd772014-05-15 09:36:47 -04004230 @Override
4231 public Notification buildStyled(Notification wip) {
Christoph Studer4600f9b2014-07-22 22:44:43 +02004232 super.buildStyled(wip);
Bryan Mawhinney6be8de32014-07-18 10:35:12 +01004233 if (wip.category == null) {
4234 wip.category = Notification.CATEGORY_TRANSPORT;
4235 }
Dan Sandler842dd772014-05-15 09:36:47 -04004236 return wip;
4237 }
4238
Christoph Studer4600f9b2014-07-22 22:44:43 +02004239 /**
4240 * @hide
4241 */
4242 @Override
Julia Reynoldsd9228f12015-10-20 10:37:27 -04004243 public RemoteViews makeContentView() {
4244 return makeMediaContentView();
Christoph Studer4600f9b2014-07-22 22:44:43 +02004245 }
4246
4247 /**
4248 * @hide
4249 */
4250 @Override
Julia Reynoldsd9228f12015-10-20 10:37:27 -04004251 public RemoteViews makeBigContentView() {
4252 return makeMediaBigContentView();
Christoph Studer4600f9b2014-07-22 22:44:43 +02004253 }
4254
Dan Sandler842dd772014-05-15 09:36:47 -04004255 /** @hide */
4256 @Override
4257 public void addExtras(Bundle extras) {
4258 super.addExtras(extras);
4259
4260 if (mToken != null) {
4261 extras.putParcelable(EXTRA_MEDIA_SESSION, mToken);
4262 }
Bryan Mawhinneye191f902014-07-22 12:50:09 +01004263 if (mActionsToShowInCompact != null) {
4264 extras.putIntArray(EXTRA_COMPACT_ACTIONS, mActionsToShowInCompact);
4265 }
Dan Sandler842dd772014-05-15 09:36:47 -04004266 }
4267
Christoph Studer4600f9b2014-07-22 22:44:43 +02004268 /**
4269 * @hide
4270 */
4271 @Override
4272 protected void restoreFromExtras(Bundle extras) {
4273 super.restoreFromExtras(extras);
4274
4275 if (extras.containsKey(EXTRA_MEDIA_SESSION)) {
4276 mToken = extras.getParcelable(EXTRA_MEDIA_SESSION);
4277 }
4278 if (extras.containsKey(EXTRA_COMPACT_ACTIONS)) {
4279 mActionsToShowInCompact = extras.getIntArray(EXTRA_COMPACT_ACTIONS);
4280 }
4281 }
4282
Selim Cinek5bf069a2015-11-10 19:14:27 -05004283 private RemoteViews generateMediaActionButton(Action action, int color) {
Dan Sandler842dd772014-05-15 09:36:47 -04004284 final boolean tombstone = (action.actionIntent == null);
Selim Cinekf33b1112015-07-15 17:45:11 -07004285 RemoteViews button = new BuilderRemoteViews(mBuilder.mContext.getApplicationInfo(),
Alan Viverette3cb07a462014-06-06 14:19:53 -07004286 R.layout.notification_material_media_action);
Dan Sandler68079d52015-07-22 10:45:30 -04004287 button.setImageViewIcon(R.id.action0, action.getIcon());
Selim Cinek5bf069a2015-11-10 19:14:27 -05004288 button.setDrawableParameters(R.id.action0, false, -1, color, PorterDuff.Mode.SRC_ATOP,
4289 -1);
Dan Sandler842dd772014-05-15 09:36:47 -04004290 if (!tombstone) {
4291 button.setOnClickPendingIntent(R.id.action0, action.actionIntent);
4292 }
4293 button.setContentDescription(R.id.action0, action.title);
4294 return button;
4295 }
4296
4297 private RemoteViews makeMediaContentView() {
4298 RemoteViews view = mBuilder.applyStandardTemplate(
Jorim Jaggi17ee3ec2014-08-29 03:47:31 +02004299 R.layout.notification_template_material_media, false /* hasProgress */);
Dan Sandler842dd772014-05-15 09:36:47 -04004300
4301 final int numActions = mBuilder.mActions.size();
4302 final int N = mActionsToShowInCompact == null
4303 ? 0
4304 : Math.min(mActionsToShowInCompact.length, MAX_MEDIA_BUTTONS_IN_COMPACT);
4305 if (N > 0) {
Jorim Jaggi17ee3ec2014-08-29 03:47:31 +02004306 view.removeAllViews(com.android.internal.R.id.media_actions);
Dan Sandler842dd772014-05-15 09:36:47 -04004307 for (int i = 0; i < N; i++) {
4308 if (i >= numActions) {
4309 throw new IllegalArgumentException(String.format(
4310 "setShowActionsInCompactView: action %d out of bounds (max %d)",
4311 i, numActions - 1));
4312 }
4313
4314 final Action action = mBuilder.mActions.get(mActionsToShowInCompact[i]);
Selim Cinek5bf069a2015-11-10 19:14:27 -05004315 final RemoteViews button = generateMediaActionButton(action,
4316 mBuilder.resolveColor());
Jorim Jaggi17ee3ec2014-08-29 03:47:31 +02004317 view.addView(com.android.internal.R.id.media_actions, button);
Dan Sandler842dd772014-05-15 09:36:47 -04004318 }
4319 }
Selim Cinek5bf069a2015-11-10 19:14:27 -05004320 handleImage(view /* addPaddingToMainColumn */);
Dan Sandler842dd772014-05-15 09:36:47 -04004321 return view;
4322 }
4323
4324 private RemoteViews makeMediaBigContentView() {
Jorim Jaggi17ee3ec2014-08-29 03:47:31 +02004325 final int actionCount = Math.min(mBuilder.mActions.size(), MAX_MEDIA_BUTTONS);
Selim Cinek5bf069a2015-11-10 19:14:27 -05004326 RemoteViews big = mBuilder.applyStandardTemplate(
4327 R.layout.notification_template_material_big_media,
4328 false);
Dan Sandler842dd772014-05-15 09:36:47 -04004329
Jorim Jaggi17ee3ec2014-08-29 03:47:31 +02004330 if (actionCount > 0) {
4331 big.removeAllViews(com.android.internal.R.id.media_actions);
4332 for (int i = 0; i < actionCount; i++) {
Selim Cinek5bf069a2015-11-10 19:14:27 -05004333 final RemoteViews button = generateMediaActionButton(mBuilder.mActions.get(i),
4334 mBuilder.resolveColor());
Jorim Jaggi17ee3ec2014-08-29 03:47:31 +02004335 big.addView(com.android.internal.R.id.media_actions, button);
Dan Sandler842dd772014-05-15 09:36:47 -04004336 }
4337 }
Selim Cinek5bf069a2015-11-10 19:14:27 -05004338 handleImage(big);
Dan Sandler842dd772014-05-15 09:36:47 -04004339 return big;
4340 }
Jorim Jaggi17ee3ec2014-08-29 03:47:31 +02004341
Selim Cinek5bf069a2015-11-10 19:14:27 -05004342 private void handleImage(RemoteViews contentView) {
4343 if (mBuilder.mN.mLargeIcon != null) {
4344 contentView.setViewLayoutMarginEnd(R.id.line1, 0);
Selim Cinek5bf069a2015-11-10 19:14:27 -05004345 contentView.setViewLayoutMarginEnd(R.id.line3, 0);
Jorim Jaggi17ee3ec2014-08-29 03:47:31 +02004346 }
4347 }
4348
Jorim Jaggi17ee3ec2014-08-29 03:47:31 +02004349 /**
4350 * @hide
4351 */
4352 @Override
4353 protected boolean hasProgress() {
4354 return false;
4355 }
Dan Sandler842dd772014-05-15 09:36:47 -04004356 }
Griff Hazen61a9e862014-05-22 16:05:19 -07004357
Christoph Studer4600f9b2014-07-22 22:44:43 +02004358 // When adding a new Style subclass here, don't forget to update
4359 // Builder.getNotificationStyleClass.
4360
Griff Hazen61a9e862014-05-22 16:05:19 -07004361 /**
4362 * Extender interface for use with {@link Builder#extend}. Extenders may be used to add
4363 * metadata or change options on a notification builder.
4364 */
4365 public interface Extender {
4366 /**
4367 * Apply this extender to a notification builder.
4368 * @param builder the builder to be modified.
4369 * @return the build object for chaining.
4370 */
4371 public Builder extend(Builder builder);
4372 }
4373
4374 /**
4375 * Helper class to add wearable extensions to notifications.
4376 * <p class="note"> See
4377 * <a href="{@docRoot}wear/notifications/creating.html">Creating Notifications
4378 * for Android Wear</a> for more information on how to use this class.
4379 * <p>
4380 * To create a notification with wearable extensions:
4381 * <ol>
4382 * <li>Create a {@link android.app.Notification.Builder}, setting any desired
4383 * properties.
4384 * <li>Create a {@link android.app.Notification.WearableExtender}.
4385 * <li>Set wearable-specific properties using the
4386 * {@code add} and {@code set} methods of {@link android.app.Notification.WearableExtender}.
4387 * <li>Call {@link android.app.Notification.Builder#extend} to apply the extensions to a
4388 * notification.
4389 * <li>Post the notification to the notification system with the
4390 * {@code NotificationManager.notify(...)} methods.
4391 * </ol>
4392 *
4393 * <pre class="prettyprint">
4394 * Notification notif = new Notification.Builder(mContext)
4395 * .setContentTitle(&quot;New mail from &quot; + sender.toString())
4396 * .setContentText(subject)
4397 * .setSmallIcon(R.drawable.new_mail)
4398 * .extend(new Notification.WearableExtender()
4399 * .setContentIcon(R.drawable.new_mail))
4400 * .build();
4401 * NotificationManager notificationManger =
4402 * (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
4403 * notificationManger.notify(0, notif);</pre>
4404 *
4405 * <p>Wearable extensions can be accessed on an existing notification by using the
4406 * {@code WearableExtender(Notification)} constructor,
4407 * and then using the {@code get} methods to access values.
4408 *
4409 * <pre class="prettyprint">
4410 * Notification.WearableExtender wearableExtender = new Notification.WearableExtender(
4411 * notification);
Griff Hazen14f57992014-05-26 09:07:14 -07004412 * List&lt;Notification&gt; pages = wearableExtender.getPages();</pre>
Griff Hazen61a9e862014-05-22 16:05:19 -07004413 */
4414 public static final class WearableExtender implements Extender {
4415 /**
4416 * Sentinel value for an action index that is unset.
4417 */
4418 public static final int UNSET_ACTION_INDEX = -1;
4419
4420 /**
4421 * Size value for use with {@link #setCustomSizePreset} to show this notification with
4422 * default sizing.
4423 * <p>For custom display notifications created using {@link #setDisplayIntent},
Paul Soulosaa4f4bf2015-08-04 11:59:45 -07004424 * the default is {@link #SIZE_MEDIUM}. All other notifications size automatically based
Griff Hazen61a9e862014-05-22 16:05:19 -07004425 * on their content.
4426 */
4427 public static final int SIZE_DEFAULT = 0;
4428
4429 /**
4430 * Size value for use with {@link #setCustomSizePreset} to show this notification
4431 * with an extra small size.
4432 * <p>This value is only applicable for custom display notifications created using
4433 * {@link #setDisplayIntent}.
4434 */
4435 public static final int SIZE_XSMALL = 1;
4436
4437 /**
4438 * Size value for use with {@link #setCustomSizePreset} to show this notification
4439 * with a small size.
4440 * <p>This value is only applicable for custom display notifications created using
4441 * {@link #setDisplayIntent}.
4442 */
4443 public static final int SIZE_SMALL = 2;
4444
4445 /**
4446 * Size value for use with {@link #setCustomSizePreset} to show this notification
4447 * with a medium size.
4448 * <p>This value is only applicable for custom display notifications created using
4449 * {@link #setDisplayIntent}.
4450 */
4451 public static final int SIZE_MEDIUM = 3;
4452
4453 /**
4454 * Size value for use with {@link #setCustomSizePreset} to show this notification
4455 * with a large size.
4456 * <p>This value is only applicable for custom display notifications created using
4457 * {@link #setDisplayIntent}.
4458 */
4459 public static final int SIZE_LARGE = 4;
4460
Griff Hazend5f11f92014-05-27 15:40:09 -07004461 /**
4462 * Size value for use with {@link #setCustomSizePreset} to show this notification
4463 * full screen.
4464 * <p>This value is only applicable for custom display notifications created using
4465 * {@link #setDisplayIntent}.
4466 */
4467 public static final int SIZE_FULL_SCREEN = 5;
4468
Griff Hazen5f2edfc2014-09-29 16:28:44 -07004469 /**
4470 * Sentinel value for use with {@link #setHintScreenTimeout} to keep the screen on for a
4471 * short amount of time when this notification is displayed on the screen. This
4472 * is the default value.
4473 */
4474 public static final int SCREEN_TIMEOUT_SHORT = 0;
4475
4476 /**
4477 * Sentinel value for use with {@link #setHintScreenTimeout} to keep the screen on
4478 * for a longer amount of time when this notification is displayed on the screen.
4479 */
4480 public static final int SCREEN_TIMEOUT_LONG = -1;
4481
Griff Hazen61a9e862014-05-22 16:05:19 -07004482 /** Notification extra which contains wearable extensions */
4483 private static final String EXTRA_WEARABLE_EXTENSIONS = "android.wearable.EXTENSIONS";
4484
Pete Gastaf6781d2014-10-07 15:17:05 -04004485 // Keys within EXTRA_WEARABLE_EXTENSIONS for wearable options.
Griff Hazen61a9e862014-05-22 16:05:19 -07004486 private static final String KEY_ACTIONS = "actions";
4487 private static final String KEY_FLAGS = "flags";
4488 private static final String KEY_DISPLAY_INTENT = "displayIntent";
4489 private static final String KEY_PAGES = "pages";
4490 private static final String KEY_BACKGROUND = "background";
4491 private static final String KEY_CONTENT_ICON = "contentIcon";
4492 private static final String KEY_CONTENT_ICON_GRAVITY = "contentIconGravity";
4493 private static final String KEY_CONTENT_ACTION_INDEX = "contentActionIndex";
4494 private static final String KEY_CUSTOM_SIZE_PRESET = "customSizePreset";
4495 private static final String KEY_CUSTOM_CONTENT_HEIGHT = "customContentHeight";
4496 private static final String KEY_GRAVITY = "gravity";
Griff Hazen5f2edfc2014-09-29 16:28:44 -07004497 private static final String KEY_HINT_SCREEN_TIMEOUT = "hintScreenTimeout";
Griff Hazen61a9e862014-05-22 16:05:19 -07004498
4499 // Flags bitwise-ored to mFlags
4500 private static final int FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE = 0x1;
4501 private static final int FLAG_HINT_HIDE_ICON = 1 << 1;
4502 private static final int FLAG_HINT_SHOW_BACKGROUND_ONLY = 1 << 2;
4503 private static final int FLAG_START_SCROLL_BOTTOM = 1 << 3;
Griff Hazen5f2edfc2014-09-29 16:28:44 -07004504 private static final int FLAG_HINT_AVOID_BACKGROUND_CLIPPING = 1 << 4;
Griff Hazen61a9e862014-05-22 16:05:19 -07004505
4506 // Default value for flags integer
4507 private static final int DEFAULT_FLAGS = FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE;
4508
4509 private static final int DEFAULT_CONTENT_ICON_GRAVITY = Gravity.END;
4510 private static final int DEFAULT_GRAVITY = Gravity.BOTTOM;
4511
4512 private ArrayList<Action> mActions = new ArrayList<Action>();
4513 private int mFlags = DEFAULT_FLAGS;
4514 private PendingIntent mDisplayIntent;
4515 private ArrayList<Notification> mPages = new ArrayList<Notification>();
4516 private Bitmap mBackground;
4517 private int mContentIcon;
4518 private int mContentIconGravity = DEFAULT_CONTENT_ICON_GRAVITY;
4519 private int mContentActionIndex = UNSET_ACTION_INDEX;
4520 private int mCustomSizePreset = SIZE_DEFAULT;
4521 private int mCustomContentHeight;
4522 private int mGravity = DEFAULT_GRAVITY;
Griff Hazen5f2edfc2014-09-29 16:28:44 -07004523 private int mHintScreenTimeout;
Griff Hazen61a9e862014-05-22 16:05:19 -07004524
4525 /**
4526 * Create a {@link android.app.Notification.WearableExtender} with default
4527 * options.
4528 */
4529 public WearableExtender() {
4530 }
4531
4532 public WearableExtender(Notification notif) {
4533 Bundle wearableBundle = notif.extras.getBundle(EXTRA_WEARABLE_EXTENSIONS);
4534 if (wearableBundle != null) {
4535 List<Action> actions = wearableBundle.getParcelableArrayList(KEY_ACTIONS);
4536 if (actions != null) {
4537 mActions.addAll(actions);
4538 }
4539
4540 mFlags = wearableBundle.getInt(KEY_FLAGS, DEFAULT_FLAGS);
4541 mDisplayIntent = wearableBundle.getParcelable(KEY_DISPLAY_INTENT);
4542
4543 Notification[] pages = getNotificationArrayFromBundle(
4544 wearableBundle, KEY_PAGES);
4545 if (pages != null) {
4546 Collections.addAll(mPages, pages);
4547 }
4548
4549 mBackground = wearableBundle.getParcelable(KEY_BACKGROUND);
4550 mContentIcon = wearableBundle.getInt(KEY_CONTENT_ICON);
4551 mContentIconGravity = wearableBundle.getInt(KEY_CONTENT_ICON_GRAVITY,
4552 DEFAULT_CONTENT_ICON_GRAVITY);
4553 mContentActionIndex = wearableBundle.getInt(KEY_CONTENT_ACTION_INDEX,
4554 UNSET_ACTION_INDEX);
4555 mCustomSizePreset = wearableBundle.getInt(KEY_CUSTOM_SIZE_PRESET,
4556 SIZE_DEFAULT);
4557 mCustomContentHeight = wearableBundle.getInt(KEY_CUSTOM_CONTENT_HEIGHT);
4558 mGravity = wearableBundle.getInt(KEY_GRAVITY, DEFAULT_GRAVITY);
Griff Hazen5f2edfc2014-09-29 16:28:44 -07004559 mHintScreenTimeout = wearableBundle.getInt(KEY_HINT_SCREEN_TIMEOUT);
Griff Hazen61a9e862014-05-22 16:05:19 -07004560 }
4561 }
4562
4563 /**
4564 * Apply wearable extensions to a notification that is being built. This is typically
4565 * called by the {@link android.app.Notification.Builder#extend} method of
4566 * {@link android.app.Notification.Builder}.
4567 */
4568 @Override
4569 public Notification.Builder extend(Notification.Builder builder) {
4570 Bundle wearableBundle = new Bundle();
4571
4572 if (!mActions.isEmpty()) {
4573 wearableBundle.putParcelableArrayList(KEY_ACTIONS, mActions);
4574 }
4575 if (mFlags != DEFAULT_FLAGS) {
4576 wearableBundle.putInt(KEY_FLAGS, mFlags);
4577 }
4578 if (mDisplayIntent != null) {
4579 wearableBundle.putParcelable(KEY_DISPLAY_INTENT, mDisplayIntent);
4580 }
4581 if (!mPages.isEmpty()) {
4582 wearableBundle.putParcelableArray(KEY_PAGES, mPages.toArray(
4583 new Notification[mPages.size()]));
4584 }
4585 if (mBackground != null) {
4586 wearableBundle.putParcelable(KEY_BACKGROUND, mBackground);
4587 }
4588 if (mContentIcon != 0) {
4589 wearableBundle.putInt(KEY_CONTENT_ICON, mContentIcon);
4590 }
4591 if (mContentIconGravity != DEFAULT_CONTENT_ICON_GRAVITY) {
4592 wearableBundle.putInt(KEY_CONTENT_ICON_GRAVITY, mContentIconGravity);
4593 }
4594 if (mContentActionIndex != UNSET_ACTION_INDEX) {
4595 wearableBundle.putInt(KEY_CONTENT_ACTION_INDEX,
4596 mContentActionIndex);
4597 }
4598 if (mCustomSizePreset != SIZE_DEFAULT) {
4599 wearableBundle.putInt(KEY_CUSTOM_SIZE_PRESET, mCustomSizePreset);
4600 }
4601 if (mCustomContentHeight != 0) {
4602 wearableBundle.putInt(KEY_CUSTOM_CONTENT_HEIGHT, mCustomContentHeight);
4603 }
4604 if (mGravity != DEFAULT_GRAVITY) {
4605 wearableBundle.putInt(KEY_GRAVITY, mGravity);
4606 }
Griff Hazen5f2edfc2014-09-29 16:28:44 -07004607 if (mHintScreenTimeout != 0) {
4608 wearableBundle.putInt(KEY_HINT_SCREEN_TIMEOUT, mHintScreenTimeout);
4609 }
Griff Hazen61a9e862014-05-22 16:05:19 -07004610
4611 builder.getExtras().putBundle(EXTRA_WEARABLE_EXTENSIONS, wearableBundle);
4612 return builder;
4613 }
4614
4615 @Override
4616 public WearableExtender clone() {
4617 WearableExtender that = new WearableExtender();
4618 that.mActions = new ArrayList<Action>(this.mActions);
4619 that.mFlags = this.mFlags;
4620 that.mDisplayIntent = this.mDisplayIntent;
4621 that.mPages = new ArrayList<Notification>(this.mPages);
4622 that.mBackground = this.mBackground;
4623 that.mContentIcon = this.mContentIcon;
4624 that.mContentIconGravity = this.mContentIconGravity;
4625 that.mContentActionIndex = this.mContentActionIndex;
4626 that.mCustomSizePreset = this.mCustomSizePreset;
4627 that.mCustomContentHeight = this.mCustomContentHeight;
4628 that.mGravity = this.mGravity;
Griff Hazen5f2edfc2014-09-29 16:28:44 -07004629 that.mHintScreenTimeout = this.mHintScreenTimeout;
Griff Hazen61a9e862014-05-22 16:05:19 -07004630 return that;
4631 }
4632
4633 /**
4634 * Add a wearable action to this notification.
4635 *
4636 * <p>When wearable actions are added using this method, the set of actions that
4637 * show on a wearable device splits from devices that only show actions added
4638 * using {@link android.app.Notification.Builder#addAction}. This allows for customization
4639 * of which actions display on different devices.
4640 *
4641 * @param action the action to add to this notification
4642 * @return this object for method chaining
4643 * @see android.app.Notification.Action
4644 */
4645 public WearableExtender addAction(Action action) {
4646 mActions.add(action);
4647 return this;
4648 }
4649
4650 /**
4651 * Adds wearable actions to this notification.
4652 *
4653 * <p>When wearable actions are added using this method, the set of actions that
4654 * show on a wearable device splits from devices that only show actions added
4655 * using {@link android.app.Notification.Builder#addAction}. This allows for customization
4656 * of which actions display on different devices.
4657 *
4658 * @param actions the actions to add to this notification
4659 * @return this object for method chaining
4660 * @see android.app.Notification.Action
4661 */
4662 public WearableExtender addActions(List<Action> actions) {
4663 mActions.addAll(actions);
4664 return this;
4665 }
4666
4667 /**
4668 * Clear all wearable actions present on this builder.
4669 * @return this object for method chaining.
4670 * @see #addAction
4671 */
4672 public WearableExtender clearActions() {
4673 mActions.clear();
4674 return this;
4675 }
4676
4677 /**
4678 * Get the wearable actions present on this notification.
4679 */
4680 public List<Action> getActions() {
4681 return mActions;
4682 }
4683
4684 /**
4685 * Set an intent to launch inside of an activity view when displaying
Griff Hazen14f57992014-05-26 09:07:14 -07004686 * this notification. The {@link PendingIntent} provided should be for an activity.
4687 *
4688 * <pre class="prettyprint">
4689 * Intent displayIntent = new Intent(context, MyDisplayActivity.class);
4690 * PendingIntent displayPendingIntent = PendingIntent.getActivity(context,
4691 * 0, displayIntent, PendingIntent.FLAG_UPDATE_CURRENT);
4692 * Notification notif = new Notification.Builder(context)
4693 * .extend(new Notification.WearableExtender()
4694 * .setDisplayIntent(displayPendingIntent)
4695 * .setCustomSizePreset(Notification.WearableExtender.SIZE_MEDIUM))
4696 * .build();</pre>
4697 *
4698 * <p>The activity to launch needs to allow embedding, must be exported, and
Griff Hazen831ca9d2014-06-17 00:38:38 -07004699 * should have an empty task affinity. It is also recommended to use the device
4700 * default light theme.
Griff Hazen14f57992014-05-26 09:07:14 -07004701 *
4702 * <p>Example AndroidManifest.xml entry:
4703 * <pre class="prettyprint">
4704 * &lt;activity android:name=&quot;com.example.MyDisplayActivity&quot;
4705 * android:exported=&quot;true&quot;
4706 * android:allowEmbedded=&quot;true&quot;
Griff Hazen831ca9d2014-06-17 00:38:38 -07004707 * android:taskAffinity=&quot;&quot;
4708 * android:theme=&quot;@android:style/Theme.DeviceDefault.Light&quot; /&gt;</pre>
Griff Hazen61a9e862014-05-22 16:05:19 -07004709 *
4710 * @param intent the {@link PendingIntent} for an activity
4711 * @return this object for method chaining
4712 * @see android.app.Notification.WearableExtender#getDisplayIntent
4713 */
4714 public WearableExtender setDisplayIntent(PendingIntent intent) {
4715 mDisplayIntent = intent;
4716 return this;
4717 }
4718
4719 /**
4720 * Get the intent to launch inside of an activity view when displaying this
4721 * notification. This {@code PendingIntent} should be for an activity.
4722 */
4723 public PendingIntent getDisplayIntent() {
4724 return mDisplayIntent;
4725 }
4726
4727 /**
4728 * Add an additional page of content to display with this notification. The current
4729 * notification forms the first page, and pages added using this function form
4730 * subsequent pages. This field can be used to separate a notification into multiple
4731 * sections.
4732 *
4733 * @param page the notification to add as another page
4734 * @return this object for method chaining
4735 * @see android.app.Notification.WearableExtender#getPages
4736 */
4737 public WearableExtender addPage(Notification page) {
4738 mPages.add(page);
4739 return this;
4740 }
4741
4742 /**
4743 * Add additional pages of content to display with this notification. The current
4744 * notification forms the first page, and pages added using this function form
4745 * subsequent pages. This field can be used to separate a notification into multiple
4746 * sections.
4747 *
4748 * @param pages a list of notifications
4749 * @return this object for method chaining
4750 * @see android.app.Notification.WearableExtender#getPages
4751 */
4752 public WearableExtender addPages(List<Notification> pages) {
4753 mPages.addAll(pages);
4754 return this;
4755 }
4756
4757 /**
4758 * Clear all additional pages present on this builder.
4759 * @return this object for method chaining.
4760 * @see #addPage
4761 */
4762 public WearableExtender clearPages() {
4763 mPages.clear();
4764 return this;
4765 }
4766
4767 /**
4768 * Get the array of additional pages of content for displaying this notification. The
4769 * current notification forms the first page, and elements within this array form
4770 * subsequent pages. This field can be used to separate a notification into multiple
4771 * sections.
4772 * @return the pages for this notification
4773 */
4774 public List<Notification> getPages() {
4775 return mPages;
4776 }
4777
4778 /**
4779 * Set a background image to be displayed behind the notification content.
4780 * Contrary to the {@link android.app.Notification.BigPictureStyle}, this background
4781 * will work with any notification style.
4782 *
4783 * @param background the background bitmap
4784 * @return this object for method chaining
4785 * @see android.app.Notification.WearableExtender#getBackground
4786 */
4787 public WearableExtender setBackground(Bitmap background) {
4788 mBackground = background;
4789 return this;
4790 }
4791
4792 /**
4793 * Get a background image to be displayed behind the notification content.
4794 * Contrary to the {@link android.app.Notification.BigPictureStyle}, this background
4795 * will work with any notification style.
4796 *
4797 * @return the background image
4798 * @see android.app.Notification.WearableExtender#setBackground
4799 */
4800 public Bitmap getBackground() {
4801 return mBackground;
4802 }
4803
4804 /**
4805 * Set an icon that goes with the content of this notification.
4806 */
4807 public WearableExtender setContentIcon(int icon) {
4808 mContentIcon = icon;
4809 return this;
4810 }
4811
4812 /**
4813 * Get an icon that goes with the content of this notification.
4814 */
4815 public int getContentIcon() {
4816 return mContentIcon;
4817 }
4818
4819 /**
4820 * Set the gravity that the content icon should have within the notification display.
4821 * Supported values include {@link android.view.Gravity#START} and
4822 * {@link android.view.Gravity#END}. The default value is {@link android.view.Gravity#END}.
4823 * @see #setContentIcon
4824 */
4825 public WearableExtender setContentIconGravity(int contentIconGravity) {
4826 mContentIconGravity = contentIconGravity;
4827 return this;
4828 }
4829
4830 /**
4831 * Get the gravity that the content icon should have within the notification display.
4832 * Supported values include {@link android.view.Gravity#START} and
4833 * {@link android.view.Gravity#END}. The default value is {@link android.view.Gravity#END}.
4834 * @see #getContentIcon
4835 */
4836 public int getContentIconGravity() {
4837 return mContentIconGravity;
4838 }
4839
4840 /**
4841 * Set an action from this notification's actions to be clickable with the content of
Griff Hazen14f57992014-05-26 09:07:14 -07004842 * this notification. This action will no longer display separately from the
4843 * notification's content.
4844 *
Griff Hazenca48d352014-05-28 22:37:13 -07004845 * <p>For notifications with multiple pages, child pages can also have content actions
Griff Hazen14f57992014-05-26 09:07:14 -07004846 * set, although the list of available actions comes from the main notification and not
4847 * from the child page's notification.
4848 *
4849 * @param actionIndex The index of the action to hoist onto the current notification page.
4850 * If wearable actions were added to the main notification, this index
4851 * will apply to that list, otherwise it will apply to the regular
4852 * actions list.
Griff Hazen61a9e862014-05-22 16:05:19 -07004853 */
4854 public WearableExtender setContentAction(int actionIndex) {
4855 mContentActionIndex = actionIndex;
4856 return this;
4857 }
4858
4859 /**
Griff Hazenca48d352014-05-28 22:37:13 -07004860 * Get the index of the notification action, if any, that was specified as being clickable
4861 * with the content of this notification. This action will no longer display separately
Griff Hazen14f57992014-05-26 09:07:14 -07004862 * from the notification's content.
Griff Hazen61a9e862014-05-22 16:05:19 -07004863 *
Griff Hazenca48d352014-05-28 22:37:13 -07004864 * <p>For notifications with multiple pages, child pages can also have content actions
Griff Hazen14f57992014-05-26 09:07:14 -07004865 * set, although the list of available actions comes from the main notification and not
4866 * from the child page's notification.
4867 *
4868 * <p>If wearable specific actions were added to the main notification, this index will
4869 * apply to that list, otherwise it will apply to the regular actions list.
Griff Hazenca48d352014-05-28 22:37:13 -07004870 *
4871 * @return the action index or {@link #UNSET_ACTION_INDEX} if no action was selected.
Griff Hazen61a9e862014-05-22 16:05:19 -07004872 */
4873 public int getContentAction() {
4874 return mContentActionIndex;
4875 }
4876
4877 /**
4878 * Set the gravity that this notification should have within the available viewport space.
4879 * Supported values include {@link android.view.Gravity#TOP},
4880 * {@link android.view.Gravity#CENTER_VERTICAL} and {@link android.view.Gravity#BOTTOM}.
4881 * The default value is {@link android.view.Gravity#BOTTOM}.
4882 */
4883 public WearableExtender setGravity(int gravity) {
4884 mGravity = gravity;
4885 return this;
4886 }
4887
4888 /**
4889 * Get the gravity that this notification should have within the available viewport space.
4890 * Supported values include {@link android.view.Gravity#TOP},
4891 * {@link android.view.Gravity#CENTER_VERTICAL} and {@link android.view.Gravity#BOTTOM}.
4892 * The default value is {@link android.view.Gravity#BOTTOM}.
4893 */
4894 public int getGravity() {
4895 return mGravity;
4896 }
4897
4898 /**
4899 * Set the custom size preset for the display of this notification out of the available
4900 * presets found in {@link android.app.Notification.WearableExtender}, e.g.
4901 * {@link #SIZE_LARGE}.
4902 * <p>Some custom size presets are only applicable for custom display notifications created
4903 * using {@link android.app.Notification.WearableExtender#setDisplayIntent}. Check the
4904 * documentation for the preset in question. See also
4905 * {@link #setCustomContentHeight} and {@link #getCustomSizePreset}.
4906 */
4907 public WearableExtender setCustomSizePreset(int sizePreset) {
4908 mCustomSizePreset = sizePreset;
4909 return this;
4910 }
4911
4912 /**
4913 * Get the custom size preset for the display of this notification out of the available
4914 * presets found in {@link android.app.Notification.WearableExtender}, e.g.
4915 * {@link #SIZE_LARGE}.
4916 * <p>Some custom size presets are only applicable for custom display notifications created
4917 * using {@link #setDisplayIntent}. Check the documentation for the preset in question.
4918 * See also {@link #setCustomContentHeight} and {@link #setCustomSizePreset}.
4919 */
4920 public int getCustomSizePreset() {
4921 return mCustomSizePreset;
4922 }
4923
4924 /**
4925 * Set the custom height in pixels for the display of this notification's content.
4926 * <p>This option is only available for custom display notifications created
4927 * using {@link android.app.Notification.WearableExtender#setDisplayIntent}. See also
4928 * {@link android.app.Notification.WearableExtender#setCustomSizePreset} and
4929 * {@link #getCustomContentHeight}.
4930 */
4931 public WearableExtender setCustomContentHeight(int height) {
4932 mCustomContentHeight = height;
4933 return this;
4934 }
4935
4936 /**
4937 * Get the custom height in pixels for the display of this notification's content.
4938 * <p>This option is only available for custom display notifications created
4939 * using {@link #setDisplayIntent}. See also {@link #setCustomSizePreset} and
4940 * {@link #setCustomContentHeight}.
4941 */
4942 public int getCustomContentHeight() {
4943 return mCustomContentHeight;
4944 }
4945
4946 /**
4947 * Set whether the scrolling position for the contents of this notification should start
4948 * at the bottom of the contents instead of the top when the contents are too long to
4949 * display within the screen. Default is false (start scroll at the top).
4950 */
4951 public WearableExtender setStartScrollBottom(boolean startScrollBottom) {
4952 setFlag(FLAG_START_SCROLL_BOTTOM, startScrollBottom);
4953 return this;
4954 }
4955
4956 /**
4957 * Get whether the scrolling position for the contents of this notification should start
4958 * at the bottom of the contents instead of the top when the contents are too long to
4959 * display within the screen. Default is false (start scroll at the top).
4960 */
4961 public boolean getStartScrollBottom() {
4962 return (mFlags & FLAG_START_SCROLL_BOTTOM) != 0;
4963 }
4964
4965 /**
4966 * Set whether the content intent is available when the wearable device is not connected
4967 * to a companion device. The user can still trigger this intent when the wearable device
4968 * is offline, but a visual hint will indicate that the content intent may not be available.
4969 * Defaults to true.
4970 */
4971 public WearableExtender setContentIntentAvailableOffline(
4972 boolean contentIntentAvailableOffline) {
4973 setFlag(FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE, contentIntentAvailableOffline);
4974 return this;
4975 }
4976
4977 /**
4978 * Get whether the content intent is available when the wearable device is not connected
4979 * to a companion device. The user can still trigger this intent when the wearable device
4980 * is offline, but a visual hint will indicate that the content intent may not be available.
4981 * Defaults to true.
4982 */
4983 public boolean getContentIntentAvailableOffline() {
4984 return (mFlags & FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE) != 0;
4985 }
4986
4987 /**
4988 * Set a hint that this notification's icon should not be displayed.
4989 * @param hintHideIcon {@code true} to hide the icon, {@code false} otherwise.
4990 * @return this object for method chaining
4991 */
4992 public WearableExtender setHintHideIcon(boolean hintHideIcon) {
4993 setFlag(FLAG_HINT_HIDE_ICON, hintHideIcon);
4994 return this;
4995 }
4996
4997 /**
4998 * Get a hint that this notification's icon should not be displayed.
4999 * @return {@code true} if this icon should not be displayed, false otherwise.
5000 * The default value is {@code false} if this was never set.
5001 */
5002 public boolean getHintHideIcon() {
5003 return (mFlags & FLAG_HINT_HIDE_ICON) != 0;
5004 }
5005
5006 /**
5007 * Set a visual hint that only the background image of this notification should be
5008 * displayed, and other semantic content should be hidden. This hint is only applicable
5009 * to sub-pages added using {@link #addPage}.
5010 */
5011 public WearableExtender setHintShowBackgroundOnly(boolean hintShowBackgroundOnly) {
5012 setFlag(FLAG_HINT_SHOW_BACKGROUND_ONLY, hintShowBackgroundOnly);
5013 return this;
5014 }
5015
5016 /**
5017 * Get a visual hint that only the background image of this notification should be
5018 * displayed, and other semantic content should be hidden. This hint is only applicable
5019 * to sub-pages added using {@link android.app.Notification.WearableExtender#addPage}.
5020 */
5021 public boolean getHintShowBackgroundOnly() {
5022 return (mFlags & FLAG_HINT_SHOW_BACKGROUND_ONLY) != 0;
5023 }
5024
Griff Hazen5f2edfc2014-09-29 16:28:44 -07005025 /**
Griff Hazen9c5be4e2014-11-17 17:47:50 -08005026 * Set a hint that this notification's background should not be clipped if possible,
5027 * and should instead be resized to fully display on the screen, retaining the aspect
5028 * ratio of the image. This can be useful for images like barcodes or qr codes.
Griff Hazen5f2edfc2014-09-29 16:28:44 -07005029 * @param hintAvoidBackgroundClipping {@code true} to avoid clipping if possible.
5030 * @return this object for method chaining
5031 */
5032 public WearableExtender setHintAvoidBackgroundClipping(
5033 boolean hintAvoidBackgroundClipping) {
5034 setFlag(FLAG_HINT_AVOID_BACKGROUND_CLIPPING, hintAvoidBackgroundClipping);
5035 return this;
5036 }
5037
5038 /**
Griff Hazen9c5be4e2014-11-17 17:47:50 -08005039 * Get a hint that this notification's background should not be clipped if possible,
5040 * and should instead be resized to fully display on the screen, retaining the aspect
5041 * ratio of the image. This can be useful for images like barcodes or qr codes.
Griff Hazen5f2edfc2014-09-29 16:28:44 -07005042 * @return {@code true} if it's ok if the background is clipped on the screen, false
5043 * otherwise. The default value is {@code false} if this was never set.
5044 */
5045 public boolean getHintAvoidBackgroundClipping() {
5046 return (mFlags & FLAG_HINT_AVOID_BACKGROUND_CLIPPING) != 0;
5047 }
5048
5049 /**
5050 * Set a hint that the screen should remain on for at least this duration when
5051 * this notification is displayed on the screen.
5052 * @param timeout The requested screen timeout in milliseconds. Can also be either
5053 * {@link #SCREEN_TIMEOUT_SHORT} or {@link #SCREEN_TIMEOUT_LONG}.
5054 * @return this object for method chaining
5055 */
5056 public WearableExtender setHintScreenTimeout(int timeout) {
5057 mHintScreenTimeout = timeout;
5058 return this;
5059 }
5060
5061 /**
5062 * Get the duration, in milliseconds, that the screen should remain on for
5063 * when this notification is displayed.
5064 * @return the duration in milliseconds if > 0, or either one of the sentinel values
5065 * {@link #SCREEN_TIMEOUT_SHORT} or {@link #SCREEN_TIMEOUT_LONG}.
5066 */
5067 public int getHintScreenTimeout() {
5068 return mHintScreenTimeout;
5069 }
5070
Griff Hazen61a9e862014-05-22 16:05:19 -07005071 private void setFlag(int mask, boolean value) {
5072 if (value) {
5073 mFlags |= mask;
5074 } else {
5075 mFlags &= ~mask;
5076 }
5077 }
5078 }
5079
5080 /**
Zhen Yu Song9d5528b2014-11-14 15:34:39 -08005081 * <p>Helper class to add Android Auto extensions to notifications. To create a notification
5082 * with car extensions:
5083 *
5084 * <ol>
5085 * <li>Create an {@link Notification.Builder}, setting any desired
5086 * properties.
5087 * <li>Create a {@link CarExtender}.
5088 * <li>Set car-specific properties using the {@code add} and {@code set} methods of
5089 * {@link CarExtender}.
5090 * <li>Call {@link Notification.Builder#extend(Notification.Extender)}
5091 * to apply the extensions to a notification.
5092 * </ol>
5093 *
5094 * <pre class="prettyprint">
5095 * Notification notification = new Notification.Builder(context)
5096 * ...
5097 * .extend(new CarExtender()
5098 * .set*(...))
5099 * .build();
5100 * </pre>
5101 *
5102 * <p>Car extensions can be accessed on an existing notification by using the
5103 * {@code CarExtender(Notification)} constructor, and then using the {@code get} methods
5104 * to access values.
5105 */
5106 public static final class CarExtender implements Extender {
5107 private static final String TAG = "CarExtender";
5108
5109 private static final String EXTRA_CAR_EXTENDER = "android.car.EXTENSIONS";
5110 private static final String EXTRA_LARGE_ICON = "large_icon";
5111 private static final String EXTRA_CONVERSATION = "car_conversation";
5112 private static final String EXTRA_COLOR = "app_color";
5113
5114 private Bitmap mLargeIcon;
5115 private UnreadConversation mUnreadConversation;
5116 private int mColor = Notification.COLOR_DEFAULT;
5117
5118 /**
5119 * Create a {@link CarExtender} with default options.
5120 */
5121 public CarExtender() {
5122 }
5123
5124 /**
5125 * Create a {@link CarExtender} from the CarExtender options of an existing Notification.
5126 *
5127 * @param notif The notification from which to copy options.
5128 */
5129 public CarExtender(Notification notif) {
5130 Bundle carBundle = notif.extras == null ?
5131 null : notif.extras.getBundle(EXTRA_CAR_EXTENDER);
5132 if (carBundle != null) {
5133 mLargeIcon = carBundle.getParcelable(EXTRA_LARGE_ICON);
5134 mColor = carBundle.getInt(EXTRA_COLOR, Notification.COLOR_DEFAULT);
5135
5136 Bundle b = carBundle.getBundle(EXTRA_CONVERSATION);
5137 mUnreadConversation = UnreadConversation.getUnreadConversationFromBundle(b);
5138 }
5139 }
5140
5141 /**
5142 * Apply car extensions to a notification that is being built. This is typically called by
5143 * the {@link Notification.Builder#extend(Notification.Extender)}
5144 * method of {@link Notification.Builder}.
5145 */
5146 @Override
5147 public Notification.Builder extend(Notification.Builder builder) {
5148 Bundle carExtensions = new Bundle();
5149
5150 if (mLargeIcon != null) {
5151 carExtensions.putParcelable(EXTRA_LARGE_ICON, mLargeIcon);
5152 }
5153 if (mColor != Notification.COLOR_DEFAULT) {
5154 carExtensions.putInt(EXTRA_COLOR, mColor);
5155 }
5156
5157 if (mUnreadConversation != null) {
5158 Bundle b = mUnreadConversation.getBundleForUnreadConversation();
5159 carExtensions.putBundle(EXTRA_CONVERSATION, b);
5160 }
5161
5162 builder.getExtras().putBundle(EXTRA_CAR_EXTENDER, carExtensions);
5163 return builder;
5164 }
5165
5166 /**
5167 * Sets the accent color to use when Android Auto presents the notification.
5168 *
5169 * Android Auto uses the color set with {@link Notification.Builder#setColor(int)}
5170 * to accent the displayed notification. However, not all colors are acceptable in an
5171 * automotive setting. This method can be used to override the color provided in the
5172 * notification in such a situation.
5173 */
Tor Norbye80756e32015-03-02 09:39:27 -08005174 public CarExtender setColor(@ColorInt int color) {
Zhen Yu Song9d5528b2014-11-14 15:34:39 -08005175 mColor = color;
5176 return this;
5177 }
5178
5179 /**
5180 * Gets the accent color.
5181 *
Julia Reynoldsd9228f12015-10-20 10:37:27 -04005182 * @see #setColor
Zhen Yu Song9d5528b2014-11-14 15:34:39 -08005183 */
Tor Norbye80756e32015-03-02 09:39:27 -08005184 @ColorInt
Zhen Yu Song9d5528b2014-11-14 15:34:39 -08005185 public int getColor() {
5186 return mColor;
5187 }
5188
5189 /**
5190 * Sets the large icon of the car notification.
5191 *
5192 * If no large icon is set in the extender, Android Auto will display the icon
5193 * specified by {@link Notification.Builder#setLargeIcon(android.graphics.Bitmap)}
5194 *
5195 * @param largeIcon The large icon to use in the car notification.
5196 * @return This object for method chaining.
5197 */
5198 public CarExtender setLargeIcon(Bitmap largeIcon) {
5199 mLargeIcon = largeIcon;
5200 return this;
5201 }
5202
5203 /**
5204 * Gets the large icon used in this car notification, or null if no icon has been set.
5205 *
5206 * @return The large icon for the car notification.
5207 * @see CarExtender#setLargeIcon
5208 */
5209 public Bitmap getLargeIcon() {
5210 return mLargeIcon;
5211 }
5212
5213 /**
5214 * Sets the unread conversation in a message notification.
5215 *
5216 * @param unreadConversation The unread part of the conversation this notification conveys.
5217 * @return This object for method chaining.
5218 */
5219 public CarExtender setUnreadConversation(UnreadConversation unreadConversation) {
5220 mUnreadConversation = unreadConversation;
5221 return this;
5222 }
5223
5224 /**
5225 * Returns the unread conversation conveyed by this notification.
5226 * @see #setUnreadConversation(UnreadConversation)
5227 */
5228 public UnreadConversation getUnreadConversation() {
5229 return mUnreadConversation;
5230 }
5231
5232 /**
5233 * A class which holds the unread messages from a conversation.
5234 */
5235 public static class UnreadConversation {
5236 private static final String KEY_AUTHOR = "author";
5237 private static final String KEY_TEXT = "text";
5238 private static final String KEY_MESSAGES = "messages";
5239 private static final String KEY_REMOTE_INPUT = "remote_input";
5240 private static final String KEY_ON_REPLY = "on_reply";
5241 private static final String KEY_ON_READ = "on_read";
5242 private static final String KEY_PARTICIPANTS = "participants";
5243 private static final String KEY_TIMESTAMP = "timestamp";
5244
5245 private final String[] mMessages;
5246 private final RemoteInput mRemoteInput;
5247 private final PendingIntent mReplyPendingIntent;
5248 private final PendingIntent mReadPendingIntent;
5249 private final String[] mParticipants;
5250 private final long mLatestTimestamp;
5251
5252 UnreadConversation(String[] messages, RemoteInput remoteInput,
5253 PendingIntent replyPendingIntent, PendingIntent readPendingIntent,
5254 String[] participants, long latestTimestamp) {
5255 mMessages = messages;
5256 mRemoteInput = remoteInput;
5257 mReadPendingIntent = readPendingIntent;
5258 mReplyPendingIntent = replyPendingIntent;
5259 mParticipants = participants;
5260 mLatestTimestamp = latestTimestamp;
5261 }
5262
5263 /**
5264 * Gets the list of messages conveyed by this notification.
5265 */
5266 public String[] getMessages() {
5267 return mMessages;
5268 }
5269
5270 /**
5271 * Gets the remote input that will be used to convey the response to a message list, or
5272 * null if no such remote input exists.
5273 */
5274 public RemoteInput getRemoteInput() {
5275 return mRemoteInput;
5276 }
5277
5278 /**
5279 * Gets the pending intent that will be triggered when the user replies to this
5280 * notification.
5281 */
5282 public PendingIntent getReplyPendingIntent() {
5283 return mReplyPendingIntent;
5284 }
5285
5286 /**
5287 * Gets the pending intent that Android Auto will send after it reads aloud all messages
5288 * in this object's message list.
5289 */
5290 public PendingIntent getReadPendingIntent() {
5291 return mReadPendingIntent;
5292 }
5293
5294 /**
5295 * Gets the participants in the conversation.
5296 */
5297 public String[] getParticipants() {
5298 return mParticipants;
5299 }
5300
5301 /**
5302 * Gets the firs participant in the conversation.
5303 */
5304 public String getParticipant() {
5305 return mParticipants.length > 0 ? mParticipants[0] : null;
5306 }
5307
5308 /**
5309 * Gets the timestamp of the conversation.
5310 */
5311 public long getLatestTimestamp() {
5312 return mLatestTimestamp;
5313 }
5314
5315 Bundle getBundleForUnreadConversation() {
5316 Bundle b = new Bundle();
5317 String author = null;
5318 if (mParticipants != null && mParticipants.length > 1) {
5319 author = mParticipants[0];
5320 }
5321 Parcelable[] messages = new Parcelable[mMessages.length];
5322 for (int i = 0; i < messages.length; i++) {
5323 Bundle m = new Bundle();
5324 m.putString(KEY_TEXT, mMessages[i]);
5325 m.putString(KEY_AUTHOR, author);
5326 messages[i] = m;
5327 }
5328 b.putParcelableArray(KEY_MESSAGES, messages);
5329 if (mRemoteInput != null) {
5330 b.putParcelable(KEY_REMOTE_INPUT, mRemoteInput);
5331 }
5332 b.putParcelable(KEY_ON_REPLY, mReplyPendingIntent);
5333 b.putParcelable(KEY_ON_READ, mReadPendingIntent);
5334 b.putStringArray(KEY_PARTICIPANTS, mParticipants);
5335 b.putLong(KEY_TIMESTAMP, mLatestTimestamp);
5336 return b;
5337 }
5338
5339 static UnreadConversation getUnreadConversationFromBundle(Bundle b) {
5340 if (b == null) {
5341 return null;
5342 }
5343 Parcelable[] parcelableMessages = b.getParcelableArray(KEY_MESSAGES);
5344 String[] messages = null;
5345 if (parcelableMessages != null) {
5346 String[] tmp = new String[parcelableMessages.length];
5347 boolean success = true;
5348 for (int i = 0; i < tmp.length; i++) {
5349 if (!(parcelableMessages[i] instanceof Bundle)) {
5350 success = false;
5351 break;
5352 }
5353 tmp[i] = ((Bundle) parcelableMessages[i]).getString(KEY_TEXT);
5354 if (tmp[i] == null) {
5355 success = false;
5356 break;
5357 }
5358 }
5359 if (success) {
5360 messages = tmp;
5361 } else {
5362 return null;
5363 }
5364 }
5365
5366 PendingIntent onRead = b.getParcelable(KEY_ON_READ);
5367 PendingIntent onReply = b.getParcelable(KEY_ON_REPLY);
5368
5369 RemoteInput remoteInput = b.getParcelable(KEY_REMOTE_INPUT);
5370
5371 String[] participants = b.getStringArray(KEY_PARTICIPANTS);
5372 if (participants == null || participants.length != 1) {
5373 return null;
5374 }
5375
5376 return new UnreadConversation(messages,
5377 remoteInput,
5378 onReply,
5379 onRead,
5380 participants, b.getLong(KEY_TIMESTAMP));
5381 }
5382 };
5383
5384 /**
5385 * Builder class for {@link CarExtender.UnreadConversation} objects.
5386 */
5387 public static class Builder {
5388 private final List<String> mMessages = new ArrayList<String>();
5389 private final String mParticipant;
5390 private RemoteInput mRemoteInput;
5391 private PendingIntent mReadPendingIntent;
5392 private PendingIntent mReplyPendingIntent;
5393 private long mLatestTimestamp;
5394
5395 /**
5396 * Constructs a new builder for {@link CarExtender.UnreadConversation}.
5397 *
5398 * @param name The name of the other participant in the conversation.
5399 */
5400 public Builder(String name) {
5401 mParticipant = name;
5402 }
5403
5404 /**
5405 * Appends a new unread message to the list of messages for this conversation.
5406 *
5407 * The messages should be added from oldest to newest.
5408 *
5409 * @param message The text of the new unread message.
5410 * @return This object for method chaining.
5411 */
5412 public Builder addMessage(String message) {
5413 mMessages.add(message);
5414 return this;
5415 }
5416
5417 /**
5418 * Sets the pending intent and remote input which will convey the reply to this
5419 * notification.
5420 *
5421 * @param pendingIntent The pending intent which will be triggered on a reply.
5422 * @param remoteInput The remote input parcelable which will carry the reply.
5423 * @return This object for method chaining.
5424 *
5425 * @see CarExtender.UnreadConversation#getRemoteInput
5426 * @see CarExtender.UnreadConversation#getReplyPendingIntent
5427 */
5428 public Builder setReplyAction(
5429 PendingIntent pendingIntent, RemoteInput remoteInput) {
5430 mRemoteInput = remoteInput;
5431 mReplyPendingIntent = pendingIntent;
5432
5433 return this;
5434 }
5435
5436 /**
5437 * Sets the pending intent that will be sent once the messages in this notification
5438 * are read.
5439 *
5440 * @param pendingIntent The pending intent to use.
5441 * @return This object for method chaining.
5442 */
5443 public Builder setReadPendingIntent(PendingIntent pendingIntent) {
5444 mReadPendingIntent = pendingIntent;
5445 return this;
5446 }
5447
5448 /**
5449 * Sets the timestamp of the most recent message in an unread conversation.
5450 *
5451 * If a messaging notification has been posted by your application and has not
5452 * yet been cancelled, posting a later notification with the same id and tag
5453 * but without a newer timestamp may result in Android Auto not displaying a
5454 * heads up notification for the later notification.
5455 *
5456 * @param timestamp The timestamp of the most recent message in the conversation.
5457 * @return This object for method chaining.
5458 */
5459 public Builder setLatestTimestamp(long timestamp) {
5460 mLatestTimestamp = timestamp;
5461 return this;
5462 }
5463
5464 /**
5465 * Builds a new unread conversation object.
5466 *
5467 * @return The new unread conversation object.
5468 */
5469 public UnreadConversation build() {
5470 String[] messages = mMessages.toArray(new String[mMessages.size()]);
5471 String[] participants = { mParticipant };
5472 return new UnreadConversation(messages, mRemoteInput, mReplyPendingIntent,
5473 mReadPendingIntent, participants, mLatestTimestamp);
5474 }
5475 }
5476 }
5477
5478 /**
Griff Hazen61a9e862014-05-22 16:05:19 -07005479 * Get an array of Notification objects from a parcelable array bundle field.
5480 * Update the bundle to have a typed array so fetches in the future don't need
5481 * to do an array copy.
5482 */
5483 private static Notification[] getNotificationArrayFromBundle(Bundle bundle, String key) {
5484 Parcelable[] array = bundle.getParcelableArray(key);
5485 if (array instanceof Notification[] || array == null) {
5486 return (Notification[]) array;
5487 }
5488 Notification[] typedArray = Arrays.copyOf(array, array.length,
5489 Notification[].class);
5490 bundle.putParcelableArray(key, typedArray);
5491 return typedArray;
5492 }
Christoph Studer4600f9b2014-07-22 22:44:43 +02005493
5494 private static class BuilderRemoteViews extends RemoteViews {
5495 public BuilderRemoteViews(Parcel parcel) {
5496 super(parcel);
5497 }
5498
Kenny Guy77320062014-08-27 21:37:15 +01005499 public BuilderRemoteViews(ApplicationInfo appInfo, int layoutId) {
5500 super(appInfo, layoutId);
Christoph Studer4600f9b2014-07-22 22:44:43 +02005501 }
5502
5503 @Override
5504 public BuilderRemoteViews clone() {
5505 Parcel p = Parcel.obtain();
5506 writeToParcel(p, 0);
5507 p.setDataPosition(0);
5508 BuilderRemoteViews brv = new BuilderRemoteViews(p);
5509 p.recycle();
5510 return brv;
5511 }
5512 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005513}