OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package org.chromium.chrome.browser.notifications; | 5 package org.chromium.chrome.browser.notifications; |
6 | 6 |
7 import android.app.Notification; | 7 import android.app.Notification; |
8 import android.app.PendingIntent; | |
9 import android.content.Context; | 8 import android.content.Context; |
10 import android.content.res.Resources; | 9 import android.content.res.Resources; |
11 import android.graphics.Bitmap; | 10 import android.graphics.Bitmap; |
12 import android.graphics.BitmapFactory; | 11 import android.graphics.BitmapFactory; |
13 import android.graphics.drawable.BitmapDrawable; | 12 import android.graphics.drawable.BitmapDrawable; |
14 import android.graphics.drawable.Drawable; | 13 import android.graphics.drawable.Drawable; |
15 import android.os.Build; | 14 import android.os.Build; |
16 import android.support.v4.app.NotificationCompat; | 15 import android.support.v4.app.NotificationCompat; |
17 import android.support.v4.app.NotificationCompat.Action; | 16 import android.support.v4.app.NotificationCompat.Action; |
18 import android.text.format.DateFormat; | 17 import android.text.format.DateFormat; |
19 import android.util.DisplayMetrics; | 18 import android.util.DisplayMetrics; |
20 import android.util.TypedValue; | 19 import android.util.TypedValue; |
21 import android.view.View; | 20 import android.view.View; |
22 import android.widget.RemoteViews; | 21 import android.widget.RemoteViews; |
23 | 22 |
24 import org.chromium.base.ApiCompatibilityUtils; | 23 import org.chromium.base.ApiCompatibilityUtils; |
25 import org.chromium.base.VisibleForTesting; | 24 import org.chromium.base.VisibleForTesting; |
26 import org.chromium.chrome.R; | 25 import org.chromium.chrome.R; |
27 import org.chromium.ui.base.LocalizationUtils; | 26 import org.chromium.ui.base.LocalizationUtils; |
28 | 27 |
29 import java.util.ArrayList; | |
30 import java.util.Arrays; | |
31 import java.util.Date; | 28 import java.util.Date; |
32 import java.util.List; | |
33 | |
34 import javax.annotation.Nullable; | |
35 | 29 |
36 /** | 30 /** |
37 * Builds a notification using the given inputs. Uses RemoteViews to provide a c
ustom layout. | 31 * Builds a notification using the given inputs. Uses RemoteViews to provide a c
ustom layout. |
38 */ | 32 */ |
39 public class CustomNotificationBuilder implements NotificationBuilder { | 33 public class CustomNotificationBuilder extends NotificationBuilderBase { |
40 /** | |
41 * Maximum length of CharSequence inputs to prevent excessive memory consump
tion. At current | |
42 * screen sizes we display about 500 characters at most, so this is a pretty
generous limit, and | |
43 * it matches what NotificationCompat does. | |
44 */ | |
45 @VisibleForTesting static final int MAX_CHARSEQUENCE_LENGTH = 5 * 1024; | |
46 | |
47 /** | |
48 * The maximum number of action buttons. One is for the settings button, and
two more slots are | |
49 * for developer provided buttons. | |
50 */ | |
51 private static final int MAX_ACTION_BUTTONS = 3; | |
52 | |
53 /** | 34 /** |
54 * The maximum number of lines of body text for the expanded state. Fewer li
nes are used when | 35 * The maximum number of lines of body text for the expanded state. Fewer li
nes are used when |
55 * the text is scaled up, with a minimum of one line. | 36 * the text is scaled up, with a minimum of one line. |
56 */ | 37 */ |
57 private static final int MAX_BODY_LINES = 7; | 38 private static final int MAX_BODY_LINES = 7; |
58 | 39 |
59 /** | 40 /** |
60 * The fontScale considered large for the purposes of layout. | 41 * The fontScale considered large for the purposes of layout. |
61 */ | 42 */ |
62 private static final float FONT_SCALE_LARGE = 1.3f; | 43 private static final float FONT_SCALE_LARGE = 1.3f; |
(...skipping 20 matching lines...) Expand all Loading... |
83 */ | 64 */ |
84 private static final int WORK_PROFILE_BADGE_SIZE_DP = 16; | 65 private static final int WORK_PROFILE_BADGE_SIZE_DP = 16; |
85 | 66 |
86 /** | 67 /** |
87 * Material Grey 600 - to be applied to action button icons in the Material
theme. | 68 * Material Grey 600 - to be applied to action button icons in the Material
theme. |
88 */ | 69 */ |
89 private static final int BUTTON_ICON_COLOR_MATERIAL = 0xff757575; | 70 private static final int BUTTON_ICON_COLOR_MATERIAL = 0xff757575; |
90 | 71 |
91 private final Context mContext; | 72 private final Context mContext; |
92 | 73 |
93 private CharSequence mTitle; | |
94 private CharSequence mBody; | |
95 private CharSequence mOrigin; | |
96 private CharSequence mTickerText; | |
97 private Bitmap mLargeIcon; | |
98 private int mSmallIconId; | |
99 private PendingIntent mContentIntent; | |
100 private PendingIntent mDeleteIntent; | |
101 private List<Action> mActions = new ArrayList<>(MAX_ACTION_BUTTONS); | |
102 private Action mSettingsAction; | |
103 private int mDefaults = Notification.DEFAULT_ALL; | |
104 private long[] mVibratePattern; | |
105 | |
106 public CustomNotificationBuilder(Context context) { | 74 public CustomNotificationBuilder(Context context) { |
107 mContext = context; | 75 mContext = context; |
108 } | 76 } |
109 | 77 |
110 @Override | 78 @Override |
111 public Notification build() { | 79 public Notification build() { |
112 // TODO(mvanouwerkerk): Try inheriting from StandardNotificationBuilder
to reduce | |
113 // duplication. | |
114 | |
115 // A note about RemoteViews and updating notifications. When a notificat
ion is passed to the | 80 // A note about RemoteViews and updating notifications. When a notificat
ion is passed to the |
116 // {@code NotificationManager} with the same tag and id as a previous no
tification, an | 81 // {@code NotificationManager} with the same tag and id as a previous no
tification, an |
117 // in-place update will be performed. In that case, the actions of all n
ew | 82 // in-place update will be performed. In that case, the actions of all n
ew |
118 // {@link RemoteViews} will be applied to the views of the old notificat
ion. This is safe | 83 // {@link RemoteViews} will be applied to the views of the old notificat
ion. This is safe |
119 // for actions that overwrite old values such as setting the text of a {
@code TextView}, but | 84 // for actions that overwrite old values such as setting the text of a {
@code TextView}, but |
120 // care must be taken for additive actions. Especially in the case of | 85 // care must be taken for additive actions. Especially in the case of |
121 // {@link RemoteViews#addView} the result could be to append new views b
elow stale ones. In | 86 // {@link RemoteViews#addView} the result could be to append new views b
elow stale ones. In |
122 // that case {@link RemoteViews#removeAllViews} must be called before ad
ding new ones. | 87 // that case {@link RemoteViews#removeAllViews} must be called before ad
ding new ones. |
123 RemoteViews compactView = | 88 RemoteViews compactView = |
124 new RemoteViews(mContext.getPackageName(), R.layout.web_notifica
tion); | 89 new RemoteViews(mContext.getPackageName(), R.layout.web_notifica
tion); |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
171 } | 136 } |
172 if (mSettingsAction != null) { | 137 if (mSettingsAction != null) { |
173 builder.addAction(mSettingsAction); | 138 builder.addAction(mSettingsAction); |
174 } | 139 } |
175 | 140 |
176 Notification notification = builder.build(); | 141 Notification notification = builder.build(); |
177 notification.bigContentView = bigView; | 142 notification.bigContentView = bigView; |
178 return notification; | 143 return notification; |
179 } | 144 } |
180 | 145 |
181 @Override | |
182 public NotificationBuilder setTitle(CharSequence title) { | |
183 mTitle = limitLength(title); | |
184 return this; | |
185 } | |
186 | |
187 @Override | |
188 public NotificationBuilder setBody(CharSequence body) { | |
189 mBody = limitLength(body); | |
190 return this; | |
191 } | |
192 | |
193 @Override | |
194 public NotificationBuilder setOrigin(CharSequence origin) { | |
195 mOrigin = limitLength(origin); | |
196 return this; | |
197 } | |
198 | |
199 @Override | |
200 public NotificationBuilder setTicker(CharSequence tickerText) { | |
201 mTickerText = limitLength(tickerText); | |
202 return this; | |
203 } | |
204 | |
205 @Override | |
206 public NotificationBuilder setLargeIcon(Bitmap icon) { | |
207 mLargeIcon = icon; | |
208 return this; | |
209 } | |
210 | |
211 @Override | |
212 public NotificationBuilder setSmallIcon(int iconId) { | |
213 mSmallIconId = iconId; | |
214 return this; | |
215 } | |
216 | |
217 @Override | |
218 public NotificationBuilder setContentIntent(PendingIntent intent) { | |
219 mContentIntent = intent; | |
220 return this; | |
221 } | |
222 | |
223 @Override | |
224 public NotificationBuilder setDeleteIntent(PendingIntent intent) { | |
225 mDeleteIntent = intent; | |
226 return this; | |
227 } | |
228 | |
229 @Override | |
230 public NotificationBuilder addAction(int iconId, CharSequence title, Pending
Intent intent) { | |
231 if (mActions.size() == MAX_ACTION_BUTTONS) { | |
232 throw new IllegalStateException( | |
233 "Cannot add more than " + MAX_ACTION_BUTTONS + " actions."); | |
234 } | |
235 mActions.add(new Action(iconId, limitLength(title), intent)); | |
236 return this; | |
237 } | |
238 | |
239 @Override | |
240 public NotificationBuilder addSettingsAction( | |
241 int iconId, CharSequence title, PendingIntent intent) { | |
242 mSettingsAction = new Action(iconId, limitLength(title), intent); | |
243 return this; | |
244 } | |
245 | |
246 @Override | |
247 public NotificationBuilder setDefaults(int defaults) { | |
248 mDefaults = defaults; | |
249 return this; | |
250 } | |
251 | |
252 @Override | |
253 public NotificationBuilder setVibrate(long[] pattern) { | |
254 mVibratePattern = Arrays.copyOf(pattern, pattern.length); | |
255 return this; | |
256 } | |
257 | |
258 /** | 146 /** |
259 * If there are actions, shows the button related views, and adds a button f
or each action. | 147 * If there are actions, shows the button related views, and adds a button f
or each action. |
260 */ | 148 */ |
261 private void addActionButtons(RemoteViews bigView) { | 149 private void addActionButtons(RemoteViews bigView) { |
262 // Remove the existing buttons in case an existing notification is being
updated. | 150 // Remove the existing buttons in case an existing notification is being
updated. |
263 bigView.removeAllViews(R.id.buttons); | 151 bigView.removeAllViews(R.id.buttons); |
264 | 152 |
265 // Always set the visibility of the views associated with the action but
tons. The current | 153 // Always set the visibility of the views associated with the action but
tons. The current |
266 // visibility state is not known as perhaps an existing notification is
being updated. | 154 // visibility state is not known as perhaps an existing notification is
being updated. |
267 int visibility = mActions.isEmpty() ? View.GONE : View.VISIBLE; | 155 int visibility = mActions.isEmpty() ? View.GONE : View.VISIBLE; |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
330 | 218 |
331 // The input bitmap is immutable, so the output drawable will be a diffe
rent instance from | 219 // The input bitmap is immutable, so the output drawable will be a diffe
rent instance from |
332 // the input drawable if the work profile badge was applied. | 220 // the input drawable if the work profile badge was applied. |
333 if (inputDrawable != outputDrawable && outputDrawable instanceof BitmapD
rawable) { | 221 if (inputDrawable != outputDrawable && outputDrawable instanceof BitmapD
rawable) { |
334 view.setImageViewBitmap( | 222 view.setImageViewBitmap( |
335 R.id.work_profile_badge, ((BitmapDrawable) outputDrawable).g
etBitmap()); | 223 R.id.work_profile_badge, ((BitmapDrawable) outputDrawable).g
etBitmap()); |
336 view.setViewVisibility(R.id.work_profile_badge, View.VISIBLE); | 224 view.setViewVisibility(R.id.work_profile_badge, View.VISIBLE); |
337 } | 225 } |
338 } | 226 } |
339 | 227 |
340 @Nullable | |
341 private static CharSequence limitLength(@Nullable CharSequence input) { | |
342 if (input == null) { | |
343 return input; | |
344 } | |
345 if (input.length() > MAX_CHARSEQUENCE_LENGTH) { | |
346 return input.subSequence(0, MAX_CHARSEQUENCE_LENGTH); | |
347 } | |
348 return input; | |
349 } | |
350 | |
351 /** | 228 /** |
352 * Scales down the maximum number of displayed lines in the body text if fon
t scaling is greater | 229 * Scales down the maximum number of displayed lines in the body text if fon
t scaling is greater |
353 * than 1.0. Never scales up the number of lines, as on some devices the not
ification text is | 230 * than 1.0. Never scales up the number of lines, as on some devices the not
ification text is |
354 * rendered in dp units (which do not scale) and additional lines could lead
to cropping at the | 231 * rendered in dp units (which do not scale) and additional lines could lead
to cropping at the |
355 * bottom of the notification. | 232 * bottom of the notification. |
356 * | 233 * |
357 * @param fontScale The current system font scaling factor. | 234 * @param fontScale The current system font scaling factor. |
358 * @return The number of lines to be displayed. | 235 * @return The number of lines to be displayed. |
359 */ | 236 */ |
360 @VisibleForTesting | 237 @VisibleForTesting |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
393 TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, di
splayMetrics)); | 270 TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, di
splayMetrics)); |
394 } | 271 } |
395 | 272 |
396 /** | 273 /** |
397 * Whether to use the Material look and feel or fall back to Holo. | 274 * Whether to use the Material look and feel or fall back to Holo. |
398 */ | 275 */ |
399 private static boolean useMaterial() { | 276 private static boolean useMaterial() { |
400 return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP; | 277 return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP; |
401 } | 278 } |
402 } | 279 } |
OLD | NEW |