OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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.NotificationManager; | 8 import android.app.NotificationManager; |
9 import android.app.PendingIntent; | 9 import android.app.PendingIntent; |
10 import android.content.Context; | 10 import android.content.Context; |
(...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
298 * @param persistentNotificationId The persistent id of the notification. | 298 * @param persistentNotificationId The persistent id of the notification. |
299 * @param origin The origin to whom the notification belongs. | 299 * @param origin The origin to whom the notification belongs. |
300 * @param actionIndex The zero-based index of the action button, or -1 if no
t applicable. | 300 * @param actionIndex The zero-based index of the action button, or -1 if no
t applicable. |
301 */ | 301 */ |
302 private Uri makeIntentData(long persistentNotificationId, String origin, int
actionIndex) { | 302 private Uri makeIntentData(long persistentNotificationId, String origin, int
actionIndex) { |
303 return Uri.parse(origin).buildUpon().fragment( | 303 return Uri.parse(origin).buildUpon().fragment( |
304 persistentNotificationId + "," + actionIndex).build(); | 304 persistentNotificationId + "," + actionIndex).build(); |
305 } | 305 } |
306 | 306 |
307 /** | 307 /** |
308 * Returns the Intent to create a PendingIntent for completing |action| on t
he notification | 308 * Returns the PendingIntent for completing |action| on the notification ide
ntified by the data |
309 * identified by the data in the other parameters. | 309 * in the other parameters. |
310 * | 310 * |
311 * @param action The action this pending intent will represent. | 311 * @param action The action this pending intent will represent. |
312 * @param persistentNotificationId The persistent id of the notification. | 312 * @param persistentNotificationId The persistent id of the notification. |
313 * @param origin The origin to whom the notification belongs. | 313 * @param origin The origin to whom the notification belongs. |
314 * @param profileId | 314 * @param profileId |
315 * @param incognito | 315 * @param incognito |
316 * @param webApkPackage The package of the WebAPK associated with the notifi
cation. | 316 * @param webApkPackage The package of the WebAPK associated with the notifi
cation. Empty if |
317 * Empty if the notification is not associated with a WebAPK. | 317 * the notification is not associated with a WebAPK. |
318 * @param tag The tag of the notification. May be NULL. | 318 * @param tag The tag of the notification. May be NULL. |
319 * @param actionIndex The zero-based index of the action button, or -1 if no
t applicable. | 319 * @param actionIndex The zero-based index of the action button, or -1 if no
t applicable. |
320 */ | 320 */ |
321 private Intent makeIntent(String action, long persistentNotificationId, Stri
ng origin, | 321 private PendingIntent makePendingIntent(String action, long persistentNotifi
cationId, |
322 String profileId, boolean incognito, @Nullable String webApkPackage, | 322 String origin, String profileId, boolean incognito, @Nullable String
webApkPackage, |
323 @Nullable String tag, int actionIndex) { | 323 @Nullable String tag, int actionIndex) { |
324 Uri intentData = makeIntentData(persistentNotificationId, origin, action
Index); | 324 Uri intentData = makeIntentData(persistentNotificationId, origin, action
Index); |
325 Intent intent = new Intent(action, intentData); | 325 Intent intent = new Intent(action, intentData); |
326 intent.setClass(mAppContext, NotificationService.Receiver.class); | 326 intent.setClass(mAppContext, NotificationService.Receiver.class); |
327 | 327 |
328 intent.putExtra(NotificationConstants.EXTRA_PERSISTENT_NOTIFICATION_ID, | 328 intent.putExtra(NotificationConstants.EXTRA_PERSISTENT_NOTIFICATION_ID, |
329 persistentNotificationId); | 329 persistentNotificationId); |
330 intent.putExtra(NotificationConstants.EXTRA_NOTIFICATION_INFO_ORIGIN, or
igin); | 330 intent.putExtra(NotificationConstants.EXTRA_NOTIFICATION_INFO_ORIGIN, or
igin); |
331 intent.putExtra(NotificationConstants.EXTRA_NOTIFICATION_INFO_PROFILE_ID
, profileId); | 331 intent.putExtra(NotificationConstants.EXTRA_NOTIFICATION_INFO_PROFILE_ID
, profileId); |
332 intent.putExtra(NotificationConstants.EXTRA_NOTIFICATION_INFO_PROFILE_IN
COGNITO, incognito); | 332 intent.putExtra(NotificationConstants.EXTRA_NOTIFICATION_INFO_PROFILE_IN
COGNITO, incognito); |
333 intent.putExtra(NotificationConstants.EXTRA_NOTIFICATION_INFO_TAG, tag); | 333 intent.putExtra(NotificationConstants.EXTRA_NOTIFICATION_INFO_TAG, tag); |
334 intent.putExtra( | 334 intent.putExtra( |
335 NotificationConstants.EXTRA_NOTIFICATION_INFO_WEB_APK_PACKAGE, w
ebApkPackage); | 335 NotificationConstants.EXTRA_NOTIFICATION_INFO_WEB_APK_PACKAGE, w
ebApkPackage); |
336 intent.putExtra(NotificationConstants.EXTRA_NOTIFICATION_INFO_ACTION_IND
EX, actionIndex); | 336 intent.putExtra(NotificationConstants.EXTRA_NOTIFICATION_INFO_ACTION_IND
EX, actionIndex); |
337 | 337 |
338 return intent; | |
339 } | |
340 /** | |
341 * Returns the PendingIntent for completing |action| on the notification ide
ntified by the data | |
342 * in the other parameters. | |
343 * | |
344 * @param action The action this pending intent will represent. | |
345 * @param persistentNotificationId The persistent id of the notification. | |
346 * @param origin The origin to whom the notification belongs. | |
347 * @param tag The tag of the notification. May be NULL. | |
348 * @param actionIndex The zero-based index of the action button, or -1 if no
t applicable. | |
349 */ | |
350 private PendingIntent makePendingIntent(String action, long persistentNotifi
cationId, | |
351 String origin, String profileId, boolean incognito, @Nullable String
tag, | |
352 int actionIndex) { | |
353 Intent intent = makeIntent(action, persistentNotificationId, origin, pro
fileId, incognito, | |
354 null, tag, actionIndex); | |
355 | |
356 return PendingIntent.getBroadcast(mAppContext, PENDING_INTENT_REQUEST_CO
DE, intent, | 338 return PendingIntent.getBroadcast(mAppContext, PENDING_INTENT_REQUEST_CO
DE, intent, |
357 PendingIntent.FLAG_UPDATE_CURRENT); | 339 PendingIntent.FLAG_UPDATE_CURRENT); |
358 } | 340 } |
359 | 341 |
360 /** | 342 /** |
361 * Generates the tag to be passed to the notification manager. | 343 * Generates the tag to be passed to the notification manager. |
362 * | 344 * |
363 * If the generated tag is the same as that of a previous notification, a ne
w notification shown | 345 * If the generated tag is the same as that of a previous notification, a ne
w notification shown |
364 * with this tag will replace it. | 346 * with this tag will replace it. |
365 * | 347 * |
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
497 */ | 479 */ |
498 @CalledByNative | 480 @CalledByNative |
499 private void displayNotification(long persistentNotificationId, String origi
n, String profileId, | 481 private void displayNotification(long persistentNotificationId, String origi
n, String profileId, |
500 boolean incognito, String tag, String webApkPackage, String title, S
tring body, | 482 boolean incognito, String tag, String webApkPackage, String title, S
tring body, |
501 Bitmap icon, Bitmap badge, int[] vibrationPattern, long timestamp, b
oolean renotify, | 483 Bitmap icon, Bitmap badge, int[] vibrationPattern, long timestamp, b
oolean renotify, |
502 boolean silent, String[] actionTitles, Bitmap[] actionIcons) { | 484 boolean silent, String[] actionTitles, Bitmap[] actionIcons) { |
503 if (actionTitles.length != actionIcons.length) { | 485 if (actionTitles.length != actionIcons.length) { |
504 throw new IllegalArgumentException("The number of action titles and
icons must match."); | 486 throw new IllegalArgumentException("The number of action titles and
icons must match."); |
505 } | 487 } |
506 | 488 |
507 final NotificationBuilderBase notificationBuilder = createNotificationBu
ilder(); | 489 Resources res = mAppContext.getResources(); |
508 final String platformTag = makePlatformTag(persistentNotificationId, ori
gin, tag); | |
509 | 490 |
510 // Record whether it's known whether notifications can be shown to the u
ser at all. | 491 // Record whether it's known whether notifications can be shown to the u
ser at all. |
511 RecordHistogram.recordEnumeratedHistogram( | 492 RecordHistogram.recordEnumeratedHistogram( |
512 "Notifications.AppNotificationStatus", | 493 "Notifications.AppNotificationStatus", |
513 NotificationSystemStatusUtil.determineAppNotificationStatus(mApp
Context), | 494 NotificationSystemStatusUtil.determineAppNotificationStatus(mApp
Context), |
514 NotificationSystemStatusUtil.APP_NOTIFICATIONS_STATUS_BOUNDARY); | 495 NotificationSystemStatusUtil.APP_NOTIFICATIONS_STATUS_BOUNDARY); |
515 | 496 |
516 buildNotification(notificationBuilder, | 497 // Set up a pending intent for going to the settings screen for |origin|
. |
517 true /* hasSettings */, actionTitles != null ? actionTitles.leng
th : 0, | 498 Intent settingsIntent = PreferencesLauncher.createIntentForSettingsPage( |
518 persistentNotificationId, origin, profileId, incognito, tag, | 499 mAppContext, SingleWebsitePreferences.class.getName()); |
519 title, body, icon, badge, vibrationPattern, timestamp, renotify,
silent); | 500 settingsIntent.setData( |
| 501 makeIntentData(persistentNotificationId, origin, -1 /* actionInd
ex */)); |
| 502 settingsIntent.putExtra(Preferences.EXTRA_SHOW_FRAGMENT_ARGUMENTS, |
| 503 SingleWebsitePreferences.createFragmentArgsForSite(origin)); |
520 | 504 |
521 if (!webApkPackage.isEmpty()) { | 505 PendingIntent pendingSettingsIntent = PendingIntent.getActivity(mAppCont
ext, |
522 displayNotificationInWebAPK(notificationBuilder, persistentNotificat
ionId, origin, | 506 PENDING_INTENT_REQUEST_CODE, settingsIntent, PendingIntent.FLAG_
UPDATE_CURRENT); |
523 profileId, incognito, tag, webApkPackage, actionTitles, acti
onIcons, | |
524 platformTag); | |
525 return; | |
526 } else { | |
527 PendingIntent clickIntent = makePendingIntent( | |
528 NotificationConstants.ACTION_CLICK_NOTIFICATION, persistentN
otificationId, | |
529 origin, profileId, incognito, tag, -1 /* actionIndex */); | |
530 PendingIntent closeIntent = makePendingIntent( | |
531 NotificationConstants.ACTION_CLOSE_NOTIFICATION, persistentN
otificationId, | |
532 origin, profileId, incognito, tag, -1 /* actionIndex */); | |
533 notificationBuilder.setContentIntent(clickIntent) | |
534 .setDeleteIntent(closeIntent); | |
535 | 507 |
536 PendingIntent[] actionIntents = null; | 508 PendingIntent clickIntent = makePendingIntent( |
537 if (actionTitles.length > 0) { | 509 NotificationConstants.ACTION_CLICK_NOTIFICATION, persistentNotif
icationId, origin, |
538 actionIntents = new PendingIntent[actionTitles.length]; | 510 profileId, incognito, webApkPackage, tag, -1 /* actionIndex */); |
539 for (int actionIndex = 0; actionIndex < actionTitles.length; | 511 PendingIntent closeIntent = makePendingIntent( |
540 actionIndex++) { | 512 NotificationConstants.ACTION_CLOSE_NOTIFICATION, persistentNotif
icationId, |
541 notificationBuilder.addAction(actionIcons[actionIndex], | 513 origin, profileId, incognito, webApkPackage, tag, -1 /* actionIn
dex */); |
542 actionTitles[actionIndex], | |
543 makePendingIntent(NotificationConstants.ACTION_CLICK
_NOTIFICATION, | |
544 persistentNotificationId, origin, profileId, | |
545 incognito, tag, actionIndex)); | |
546 } | |
547 } | |
548 mNotificationManager.notify(platformTag, PLATFORM_ID, notificationBu
ilder.build()); | |
549 } | |
550 } | |
551 | 514 |
552 /** | 515 NotificationBuilderBase notificationBuilder = |
553 * Build and format a notification to display. Every fields (except PendingI
ntents) are set | 516 createNotificationBuilder() |
554 * to the notification builder within this function. | 517 .setTitle(title) |
555 */ | 518 .setBody(body) |
556 private void buildNotification(NotificationBuilderBase notificationBuilder, | 519 .setLargeIcon(ensureNormalizedIcon(icon, origin)) |
557 boolean hasSettings, int actionLength, | 520 .setSmallIcon(R.drawable.ic_chrome) |
558 long persistentNotificationId, String origin, String profileId, | 521 .setSmallIcon(badge) |
559 boolean incognito, String tag, String title, String body, Bitmap ico
n, Bitmap badge, | 522 .setContentIntent(clickIntent) |
560 int[] vibrationPattern, long timestamp, boolean renotify, boolean si
lent) { | 523 .setDeleteIntent(closeIntent) |
561 Resources res = mAppContext.getResources(); | 524 .setTicker(createTickerText(title, body)) |
562 PendingIntent pendingSettingsIntent = null; | 525 .setTimestamp(timestamp) |
563 if (hasSettings) { | 526 .setRenotify(renotify) |
564 // Set up a pending intent for going to the settings screen for |ori
gin|. | 527 .setOrigin(UrlUtilities.formatUrlForSecurityDisplay( |
565 Intent settingsIntent = PreferencesLauncher.createIntentForSettingsP
age( | 528 origin, false /* showScheme */)); |
566 mAppContext, SingleWebsitePreferences.class.getName()); | |
567 settingsIntent.setData( | |
568 makeIntentData(persistentNotificationId, origin, -1 /* actio
nIndex */)); | |
569 settingsIntent.putExtra(Preferences.EXTRA_SHOW_FRAGMENT_ARGUMENTS, | |
570 SingleWebsitePreferences.createFragmentArgsForSite(origin)); | |
571 | 529 |
572 pendingSettingsIntent = PendingIntent.getActivity(mAppContext, | 530 for (int actionIndex = 0; actionIndex < actionTitles.length; actionIndex
++) { |
573 PENDING_INTENT_REQUEST_CODE, settingsIntent, PendingIntent.F
LAG_UPDATE_CURRENT); | 531 notificationBuilder.addAction(actionIcons[actionIndex], actionTitles
[actionIndex], |
574 | 532 makePendingIntent(NotificationConstants.ACTION_CLICK_NOTIFIC
ATION, |
| 533 persistentNotificationId, orig
in, profileId, |
| 534 incognito, webApkPackage, tag,
actionIndex)); |
575 } | 535 } |
576 | 536 |
577 notificationBuilder.setTitle(title) | 537 // If action buttons are displayed, there isn't room for the full Site S
ettings button |
578 .setBody(body) | 538 // label and icon, so abbreviate it. This has the unfortunate side-effec
t of unnecessarily |
579 .setLargeIcon(ensureNormalizedIcon(icon, origin)) | 539 // abbreviating it on Android Wear also (crbug.com/576656). If custom la
youts are enabled, |
580 .setSmallIcon(R.drawable.ic_chrome) | 540 // the label and icon provided here only affect Android Wear, so don't a
bbreviate them. |
581 .setSmallIcon(badge) | 541 boolean abbreviateSiteSettings = actionTitles.length > 0 && !useCustomLa
youts(); |
582 .setTicker(createTickerText(title, body)) | 542 int settingsIconId = abbreviateSiteSettings ? 0 : R.drawable.settings_co
g; |
583 .setTimestamp(timestamp) | 543 CharSequence settingsTitle = abbreviateSiteSettings |
584 .setRenotify(renotify) | 544 ? res.getString(R.string.notification_site_
settings_button) |
585 .setOrigin(UrlUtilities.formatUrlForSecurityDisplay( | 545 : res.getString(R.string.page_info_site_set
tings_button); |
586 origin, false /* showScheme */)); | 546 // If the settings button is displayed together with the other buttons i
t has to be the last |
587 if (hasSettings) { | 547 // one, so add it after the other actions. |
588 // If action buttons are displayed, there isn't room for the full Si
te Settings button | 548 notificationBuilder.addSettingsAction(settingsIconId, settingsTitle, pen
dingSettingsIntent); |
589 // label and icon, so abbreviate it. This has the unfortunate side-e
ffect of | |
590 // unnecessarily abbreviating it on Android Wear also (crbug.com/576
656). | |
591 // If custom layouts are enabled, the label and icon provided here o
nly affect | |
592 // Android Wear, so don't abbreviate them. | |
593 boolean abbreviateSiteSettings = actionLength > 0 && !useCustomLayou
ts(); | |
594 int settingsIconId = abbreviateSiteSettings ? 0 : R.drawable.setting
s_cog; | |
595 CharSequence settingsTitle = abbreviateSiteSettings | |
596 ? res.getString(R.string.notification_site_settings_
button) | |
597 : res.getString(R.string.page_info_site_settings_but
ton); | |
598 // If the settings button is displayed together with the other butto
ns it has to | |
599 // be the last one, so add it after the other actions. | |
600 notificationBuilder.addSettingsAction(settingsIconId, settingsTitle, | |
601 pendingSettingsIntent); | |
602 } | |
603 | 549 |
604 notificationBuilder.setDefaults(makeDefaults(vibrationPattern.length, si
lent)); | 550 notificationBuilder.setDefaults(makeDefaults(vibrationPattern.length, si
lent)); |
605 if (vibrationPattern.length > 0) { | 551 if (vibrationPattern.length > 0) { |
606 notificationBuilder.setVibrate(makeVibrationPattern(vibrationPattern
)); | 552 notificationBuilder.setVibrate(makeVibrationPattern(vibrationPattern
)); |
607 } | 553 } |
608 } | |
609 | 554 |
610 /** | 555 String platformTag = makePlatformTag(persistentNotificationId, origin, t
ag); |
611 * Bind to the Service of required WebAPK, create an notification and displa
y. | 556 if (webApkPackage.isEmpty()) { |
612 */ | 557 mNotificationManager.notify(platformTag, PLATFORM_ID, notificationBu
ilder.build()); |
613 private void displayNotificationInWebAPK(NotificationBuilderBase notificatio
nBuilder, | 558 } else { |
614 long persistentNotificationId, String origin, String profileId, | 559 new NotificationClient().displayNotification( |
615 boolean incognito, String tag, String webApkPackage, String[] action
Titles, | 560 notificationBuilder, platformTag, PLATFORM_ID, webApkPackage
); |
616 Bitmap[] actionIcons, String platformTag) { | |
617 Intent clickIntent = makeIntent(NotificationConstants.ACTION_CLICK_NOTIF
ICATION, | |
618 persistentNotificationId, origin, | |
619 profileId, incognito, webApkPackage, tag, -1 /* actionIndex */); | |
620 Intent closeIntent = makeIntent(NotificationConstants.ACTION_CLOSE_NOTIF
ICATION, | |
621 persistentNotificationId, origin, profileId, incognito, webApkPa
ckage, | |
622 tag, -1 /* actionIndex */); | |
623 Intent[] actionIntents = null; | |
624 if (actionTitles.length > 0) { | |
625 actionIntents = new Intent[actionTitles.length]; | |
626 for (int actionIndex = 0; actionIndex < actionTitles.length; | |
627 actionIndex++) { | |
628 actionIntents[actionIndex] = makeIntent( | |
629 NotificationConstants.ACTION_CLICK_NOTIFICATION, persist
entNotificationId, | |
630 origin, profileId, incognito, webApkPackage, tag, action
Index); | |
631 } | |
632 } | 561 } |
633 NotificationClient client = new NotificationClient(); | |
634 client.displayNotification(PENDING_INTENT_REQUEST_CODE, notificationBuil
der, clickIntent, | |
635 closeIntent, actionIntents, actionTitles, actionIcons, | |
636 PendingIntent.FLAG_UPDATE_CURRENT, platformTag, PLATFORM_ID, web
ApkPackage); | |
637 } | 562 } |
638 | 563 |
639 private NotificationBuilderBase createNotificationBuilder() { | 564 private NotificationBuilderBase createNotificationBuilder() { |
640 if (useCustomLayouts()) { | 565 if (useCustomLayouts()) { |
641 return new CustomNotificationBuilder(mAppContext); | 566 return new CustomNotificationBuilder(mAppContext); |
642 } | 567 } |
643 return new StandardNotificationBuilder(mAppContext); | 568 return new StandardNotificationBuilder(mAppContext); |
644 } | 569 } |
645 | 570 |
646 /** | 571 /** |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
796 | 721 |
797 private static native void nativeInitializeNotificationPlatformBridge(); | 722 private static native void nativeInitializeNotificationPlatformBridge(); |
798 | 723 |
799 private native void nativeOnNotificationClicked(long nativeNotificationPlatf
ormBridgeAndroid, | 724 private native void nativeOnNotificationClicked(long nativeNotificationPlatf
ormBridgeAndroid, |
800 long persistentNotificationId, String origin, String profileId, bool
ean incognito, | 725 long persistentNotificationId, String origin, String profileId, bool
ean incognito, |
801 String webApkPackage, String tag, int actionIndex); | 726 String webApkPackage, String tag, int actionIndex); |
802 private native void nativeOnNotificationClosed(long nativeNotificationPlatfo
rmBridgeAndroid, | 727 private native void nativeOnNotificationClosed(long nativeNotificationPlatfo
rmBridgeAndroid, |
803 long persistentNotificationId, String origin, String profileId, bool
ean incognito, | 728 long persistentNotificationId, String origin, String profileId, bool
ean incognito, |
804 String tag, boolean byUser); | 729 String tag, boolean byUser); |
805 } | 730 } |
OLD | NEW |