Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(25)

Side by Side Diff: chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUIManager.java

Issue 1372163002: Scale large notification icons according to device settings. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationUIManagerTest.java » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
63 private static final int PENDING_INTENT_REQUEST_CODE = 0; 63 private static final int PENDING_INTENT_REQUEST_CODE = 0;
64 64
65 private static NotificationUIManager sInstance; 65 private static NotificationUIManager sInstance;
66 private static NotificationManagerProxy sNotificationManagerOverride; 66 private static NotificationManagerProxy sNotificationManagerOverride;
67 67
68 private final long mNativeNotificationManager; 68 private final long mNativeNotificationManager;
69 69
70 private final Context mAppContext; 70 private final Context mAppContext;
71 private final NotificationManagerProxy mNotificationManager; 71 private final NotificationManagerProxy mNotificationManager;
72 72
73 private RoundedIconGenerator mIconGenerator; 73 @VisibleForTesting public RoundedIconGenerator mIconGenerator;
74 private final int mLargeIconWidthPx;
75 private final int mLargeIconHeightPx;
76 private final float mDensity;
74 77
75 private long mLastNotificationClickMs = 0L; 78 private long mLastNotificationClickMs = 0L;
76 79
77 /** 80 /**
78 * Creates a new instance of the NotificationUIManager. 81 * Creates a new instance of the NotificationUIManager.
79 * 82 *
80 * @param nativeNotificationManager Instance of the NotificationUIManagerAnd roid class. 83 * @param nativeNotificationManager Instance of the NotificationUIManagerAnd roid class.
81 * @param context Application context for this instance of Chrome. 84 * @param context Application context for this instance of Chrome.
82 */ 85 */
83 @CalledByNative 86 @CalledByNative
84 private static NotificationUIManager create(long nativeNotificationManager, Context context) { 87 private static NotificationUIManager create(long nativeNotificationManager, Context context) {
85 if (sInstance != null) { 88 if (sInstance != null) {
86 throw new IllegalStateException("There must only be a single Notific ationUIManager."); 89 throw new IllegalStateException("There must only be a single Notific ationUIManager.");
87 } 90 }
88 91
89 sInstance = new NotificationUIManager(nativeNotificationManager, context ); 92 sInstance = new NotificationUIManager(nativeNotificationManager, context );
90 return sInstance; 93 return sInstance;
91 } 94 }
92 95
93 /** 96 /**
97 * Returns the current instance of the NotificationUIManager. Should only be used by tests.
Miguel Garcia 2015/09/28 17:47:12 Doesn't the @VisibleForTesting annotation already
Peter Beverloo 2015/09/28 18:03:03 Done.
98 *
99 * @return The instance of the NotificationUIManager, if any.
100 */
101 @Nullable
102 @VisibleForTesting
103 public static NotificationUIManager getInstanceForTests() {
104 return sInstance;
105 }
106
107 /**
94 * Overrides the notification manager which is to be used for displaying Not ifications on the 108 * Overrides the notification manager which is to be used for displaying Not ifications on the
95 * Android framework. Should only be used for testing. Tests are expected to clean up after 109 * Android framework. Should only be used for testing. Tests are expected to clean up after
96 * themselves by setting this to NULL again. 110 * themselves by setting this to NULL again.
97 * 111 *
98 * @param proxy The notification manager instance to use instead of the syst em's. 112 * @param proxy The notification manager instance to use instead of the syst em's.
99 */ 113 */
100 @VisibleForTesting 114 @VisibleForTesting
101 public static void overrideNotificationManagerForTesting( 115 public static void overrideNotificationManagerForTesting(
102 NotificationManagerProxy notificationManager) { 116 NotificationManagerProxy notificationManager) {
103 sNotificationManagerOverride = notificationManager; 117 sNotificationManagerOverride = notificationManager;
104 } 118 }
105 119
106 private NotificationUIManager(long nativeNotificationManager, Context contex t) { 120 private NotificationUIManager(long nativeNotificationManager, Context contex t) {
107 mNativeNotificationManager = nativeNotificationManager; 121 mNativeNotificationManager = nativeNotificationManager;
108 mAppContext = context.getApplicationContext(); 122 mAppContext = context.getApplicationContext();
109 123
110 if (sNotificationManagerOverride != null) { 124 if (sNotificationManagerOverride != null) {
111 mNotificationManager = sNotificationManagerOverride; 125 mNotificationManager = sNotificationManagerOverride;
112 } else { 126 } else {
113 mNotificationManager = new NotificationManagerProxyImpl( 127 mNotificationManager = new NotificationManagerProxyImpl(
114 (NotificationManager) context.getSystemService(Context.NOTIF ICATION_SERVICE)); 128 (NotificationManager) context.getSystemService(Context.NOTIF ICATION_SERVICE));
115 } 129 }
130
131 Resources resources = mAppContext.getResources();
132
Miguel Garcia 2015/09/28 17:47:13 nit can you initialize density after line 137 so i
Peter Beverloo 2015/09/28 18:03:03 Done.
133 mDensity = resources.getDisplayMetrics().density;
134 mLargeIconWidthPx =
Miguel Garcia 2015/09/28 17:47:13 I assume neither of this can ever return 0? Otherw
Peter Beverloo 2015/09/28 18:03:03 Stack Overflow would have exploded already if that
135 resources.getDimensionPixelSize(android.R.dimen.notification_large_i con_width);
136 mLargeIconHeightPx =
137 resources.getDimensionPixelSize(android.R.dimen.notification_large_i con_height);
116 } 138 }
117 139
118 /** 140 /**
119 * Marks the current instance as being freed, allowing for a new Notificatio nUIManager 141 * Marks the current instance as being freed, allowing for a new Notificatio nUIManager
120 * object to be initialized. 142 * object to be initialized.
121 */ 143 */
122 @CalledByNative 144 @CalledByNative
123 private void destroy() { 145 private void destroy() {
124 assert sInstance == this; 146 assert sInstance == this;
125 sInstance = null; 147 sInstance = null;
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after
365 * 387 *
366 * @param persistentNotificationId The persistent id of the notification. 388 * @param persistentNotificationId The persistent id of the notification.
367 * @param origin Full text of the origin, including the protocol, owning thi s notification. 389 * @param origin Full text of the origin, including the protocol, owning thi s notification.
368 * @param tag A string identifier for this notification. If the tag is not e mpty, the new 390 * @param tag A string identifier for this notification. If the tag is not e mpty, the new
369 * notification will replace the previous notification with the s ame tag and origin, 391 * notification will replace the previous notification with the s ame tag and origin,
370 * if present. If no matching previous notification is present, t he new one will just 392 * if present. If no matching previous notification is present, t he new one will just
371 * be added. 393 * be added.
372 * @param title Title to be displayed in the notification. 394 * @param title Title to be displayed in the notification.
373 * @param body Message to be displayed in the notification. Will be trimmed to one line of 395 * @param body Message to be displayed in the notification. Will be trimmed to one line of
374 * text by the Android notification system. 396 * text by the Android notification system.
375 * @param icon Icon to be displayed in the notification. When this isn't a v alid Bitmap, a 397 * @param icon Icon to be displayed in the notification. Valid Bitmap icons will be scaled to
376 * default icon will be generated instead. 398 * the platforms, whereas a default icon will be generated for i nvalid Bitmaps.
377 * @param vibrationPattern Vibration pattern following the Web Vibration syn tax. 399 * @param vibrationPattern Vibration pattern following the Web Vibration syn tax.
378 * @param silent Whether the default sound, vibration and lights should be s uppressed. 400 * @param silent Whether the default sound, vibration and lights should be s uppressed.
379 * @param actionTitles Titles of actions to display alongside the notificati on. 401 * @param actionTitles Titles of actions to display alongside the notificati on.
380 * @see https://developer.android.com/reference/android/app/Notification.htm l 402 * @see https://developer.android.com/reference/android/app/Notification.htm l
381 */ 403 */
382 @CalledByNative 404 @CalledByNative
383 private void displayNotification(long persistentNotificationId, String origi n, String tag, 405 private void displayNotification(long persistentNotificationId, String origi n, String tag,
384 String title, String body, Bitmap icon, int[] vibrationPattern, bool ean silent, 406 String title, String body, Bitmap icon, int[] vibrationPattern, bool ean silent,
385 String[] actionTitles) { 407 String[] actionTitles) {
386 if (icon == null || icon.getWidth() == 0) {
387 icon = getIconGenerator().generateIconForUrl(origin, true);
388 }
389
390 Resources res = mAppContext.getResources(); 408 Resources res = mAppContext.getResources();
391 409
392 // Set up a pending intent for going to the settings screen for |origin| . 410 // Set up a pending intent for going to the settings screen for |origin| .
393 Intent settingsIntent = PreferencesLauncher.createIntentForSettingsPage( 411 Intent settingsIntent = PreferencesLauncher.createIntentForSettingsPage(
394 mAppContext, SingleWebsitePreferences.class.getName()); 412 mAppContext, SingleWebsitePreferences.class.getName());
395 settingsIntent.setData(makeIntentData(persistentNotificationId, origin, 413 settingsIntent.setData(makeIntentData(persistentNotificationId, origin,
396 -1 /* actionIndex */)); 414 -1 /* actionIndex */));
397 settingsIntent.putExtra(Preferences.EXTRA_SHOW_FRAGMENT_ARGUMENTS, 415 settingsIntent.putExtra(Preferences.EXTRA_SHOW_FRAGMENT_ARGUMENTS,
398 SingleWebsitePreferences.createFragmentArgsForSite(origin)); 416 SingleWebsitePreferences.createFragmentArgsForSite(origin));
399 417
400 PendingIntent pendingSettingsIntent = PendingIntent.getActivity(mAppCont ext, 418 PendingIntent pendingSettingsIntent = PendingIntent.getActivity(mAppCont ext,
401 PENDING_INTENT_REQUEST_CODE, settingsIntent, PendingIntent.FLAG_ UPDATE_CURRENT); 419 PENDING_INTENT_REQUEST_CODE, settingsIntent, PendingIntent.FLAG_ UPDATE_CURRENT);
402 420
403 NotificationCompat.Builder notificationBuilder = new NotificationCompat. Builder(mAppContext) 421 NotificationCompat.Builder notificationBuilder = new NotificationCompat. Builder(mAppContext)
404 .setContentTitle(title) 422 .setContentTitle(title)
405 .setContentText(body) 423 .setContentText(body)
406 .setStyle(new NotificationCompat.BigTextStyle().bigText(body)) 424 .setStyle(new NotificationCompat.BigTextStyle().bigText(body))
407 .setLargeIcon(icon) 425 .setLargeIcon(ensureNormalizedIcon(icon, origin))
408 .setSmallIcon(R.drawable.ic_chrome) 426 .setSmallIcon(R.drawable.ic_chrome)
409 .setContentIntent(makePendingIntent( 427 .setContentIntent(makePendingIntent(
410 NotificationConstants.ACTION_CLICK_NOTIFICATION, 428 NotificationConstants.ACTION_CLICK_NOTIFICATION,
411 persistentNotificationId, origin, tag, -1 /* actionIndex */)) 429 persistentNotificationId, origin, tag, -1 /* actionIndex */))
412 .setDeleteIntent(makePendingIntent( 430 .setDeleteIntent(makePendingIntent(
413 NotificationConstants.ACTION_CLOSE_NOTIFICATION, 431 NotificationConstants.ACTION_CLOSE_NOTIFICATION,
414 persistentNotificationId, origin, tag, -1 /* actionIndex */)) 432 persistentNotificationId, origin, tag, -1 /* actionIndex */))
415 .setTicker(createTickerText(title, body)) 433 .setTicker(createTickerText(title, body))
416 .setSubText(origin); 434 .setSubText(origin);
417 435
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
452 spannableStringBuilder.append(body); 470 spannableStringBuilder.append(body);
453 471
454 // Mark the title of the notification as being bold. 472 // Mark the title of the notification as being bold.
455 spannableStringBuilder.setSpan(new StyleSpan(android.graphics.Typeface.B OLD), 473 spannableStringBuilder.setSpan(new StyleSpan(android.graphics.Typeface.B OLD),
456 0, title.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE); 474 0, title.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
457 475
458 return spannableStringBuilder; 476 return spannableStringBuilder;
459 } 477 }
460 478
461 /** 479 /**
462 * Ensures the existance of an icon generator, which is created lazily. 480 * Ensures the availability of an icon for the notification.
463 * 481 *
464 * @return The icon generator which can be used. 482 * If |icon| is a valid, non-empty Bitmap, the bitmap will be scaled to be o f an appropriate
483 * size for the current Android device. Otherwise, a default icon will be cr eated based on the
484 * origin the notification is being displayed for.
485 *
486 * @param icon The developer-provided icon they intend to use for the notifi cation.
487 * @param origin The origin the notification is being displayed for.
488 * @return An appropriately sized icon to use for the notification.
465 */ 489 */
466 private RoundedIconGenerator getIconGenerator() { 490 @VisibleForTesting
467 if (mIconGenerator == null) { 491 public Bitmap ensureNormalizedIcon(Bitmap icon, String origin) {
468 mIconGenerator = createRoundedIconGenerator(mAppContext); 492 if (icon == null || icon.getWidth() == 0) {
493 if (mIconGenerator == null) {
494 int cornerRadiusPx = Math.min(mLargeIconWidthPx, mLargeIconHeigh tPx) / 2;
495 mIconGenerator =
496 new RoundedIconGenerator(mLargeIconWidthPx, mLargeIconHe ightPx,
497 cornerRadiusPx,
498 NOTIFICATION_ICON_BG_COLOR,
499 NOTIFICATION_TEXT_SIZE_DP * mDe nsity);
500 }
501
502 return mIconGenerator.generateIconForUrl(origin, true);
469 } 503 }
470 504
471 return mIconGenerator; 505 if (icon.getWidth() > mLargeIconWidthPx || icon.getHeight() > mLargeIcon HeightPx) {
506 return icon.createScaledBitmap(icon, mLargeIconWidthPx, mLargeIconHe ightPx, false);
Miguel Garcia 2015/09/28 17:47:12 can you add /* not filtered */ right after the las
Peter Beverloo 2015/09/28 18:03:03 Done.
507 }
508
509 return icon;
472 } 510 }
473 511
474 /** 512 /**
475 * Creates the rounded icon generator to use for notifications based on the dimensions
476 * and resolution of the device we're running on.
477 *
478 * @param appContext The application context to retrieve resources from.
479 * @return The newly created rounded icon generator.
480 */
481 @VisibleForTesting
482 public static RoundedIconGenerator createRoundedIconGenerator(Context appCon text) {
483 Resources res = appContext.getResources();
484 float density = res.getDisplayMetrics().density;
485
486 int widthPx = res.getDimensionPixelSize(android.R.dimen.notification_lar ge_icon_width);
487 int heightPx =
488 res.getDimensionPixelSize(android.R.dimen.notification_large_ico n_height);
489
490 return new RoundedIconGenerator(
491 widthPx,
492 heightPx,
493 Math.min(widthPx, heightPx) / 2,
494 NOTIFICATION_ICON_BG_COLOR,
495 NOTIFICATION_TEXT_SIZE_DP * density);
496 }
497
498 /**
499 * Returns whether a notification has been clicked in the last 5 seconds. 513 * Returns whether a notification has been clicked in the last 5 seconds.
500 * Used for Startup.BringToForegroundReason UMA histogram. 514 * Used for Startup.BringToForegroundReason UMA histogram.
501 */ 515 */
502 public static boolean wasNotificationRecentlyClicked() { 516 public static boolean wasNotificationRecentlyClicked() {
503 if (sInstance == null) return false; 517 if (sInstance == null) return false;
504 long now = System.currentTimeMillis(); 518 long now = System.currentTimeMillis();
505 return now - sInstance.mLastNotificationClickMs < 5 * 1000; 519 return now - sInstance.mLastNotificationClickMs < 5 * 1000;
506 } 520 }
507 521
508 /** 522 /**
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
550 origin, tag); 564 origin, tag);
551 } 565 }
552 566
553 private static native void nativeInitializeNotificationUIManager(); 567 private static native void nativeInitializeNotificationUIManager();
554 568
555 private native boolean nativeOnNotificationClicked(long nativeNotificationUI ManagerAndroid, 569 private native boolean nativeOnNotificationClicked(long nativeNotificationUI ManagerAndroid,
556 long persistentNotificationId, String origin, String tag, int action Index); 570 long persistentNotificationId, String origin, String tag, int action Index);
557 private native boolean nativeOnNotificationClosed(long nativeNotificationUIM anagerAndroid, 571 private native boolean nativeOnNotificationClosed(long nativeNotificationUIM anagerAndroid,
558 long persistentNotificationId, String origin, String tag); 572 long persistentNotificationId, String origin, String tag);
559 } 573 }
OLDNEW
« no previous file with comments | « no previous file | chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationUIManagerTest.java » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698