| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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.ntp; | 5 package org.chromium.chrome.browser.ntp; |
| 6 | 6 |
| 7 import android.app.AlarmManager; | 7 import android.app.AlarmManager; |
| 8 import android.app.Notification; | 8 import android.app.Notification; |
| 9 import android.app.NotificationManager; | 9 import android.app.NotificationManager; |
| 10 import android.app.PendingIntent; | 10 import android.app.PendingIntent; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 23 import org.chromium.chrome.R; | 23 import org.chromium.chrome.R; |
| 24 import org.chromium.chrome.browser.ChromeFeatureList; | 24 import org.chromium.chrome.browser.ChromeFeatureList; |
| 25 import org.chromium.chrome.browser.IntentHandler; | 25 import org.chromium.chrome.browser.IntentHandler; |
| 26 import org.chromium.chrome.browser.ShortcutHelper; | 26 import org.chromium.chrome.browser.ShortcutHelper; |
| 27 import org.chromium.chrome.browser.document.ChromeLauncherActivity; | 27 import org.chromium.chrome.browser.document.ChromeLauncherActivity; |
| 28 import org.chromium.chrome.browser.notifications.ChromeNotificationBuilder; | 28 import org.chromium.chrome.browser.notifications.ChromeNotificationBuilder; |
| 29 import org.chromium.chrome.browser.notifications.NotificationBuilderFactory; | 29 import org.chromium.chrome.browser.notifications.NotificationBuilderFactory; |
| 30 import org.chromium.chrome.browser.notifications.NotificationConstants; | 30 import org.chromium.chrome.browser.notifications.NotificationConstants; |
| 31 import org.chromium.chrome.browser.notifications.NotificationUmaTracker; | 31 import org.chromium.chrome.browser.notifications.NotificationUmaTracker; |
| 32 import org.chromium.chrome.browser.ntp.snippets.ContentSuggestionsNotificationAc
tion; | 32 import org.chromium.chrome.browser.ntp.snippets.ContentSuggestionsNotificationAc
tion; |
| 33 import org.chromium.chrome.browser.ntp.snippets.ContentSuggestionsNotificationAc
tion.ContentSuggestionsNotificationActionEnum; |
| 34 import org.chromium.chrome.browser.ntp.snippets.ContentSuggestionsNotificationOp
tOut.ContentSuggestionsNotificationOptOutEnum; |
| 33 import org.chromium.chrome.browser.preferences.ContentSuggestionsPreferences; | 35 import org.chromium.chrome.browser.preferences.ContentSuggestionsPreferences; |
| 34 import org.chromium.chrome.browser.preferences.PreferencesLauncher; | |
| 35 | 36 |
| 36 import java.util.Collection; | 37 import java.util.Collection; |
| 37 import java.util.Collections; | 38 import java.util.Collections; |
| 38 import java.util.HashSet; | 39 import java.util.HashSet; |
| 39 import java.util.Set; | 40 import java.util.Set; |
| 40 | 41 |
| 41 /** | 42 /** |
| 42 * Provides functionality needed for content suggestion notifications. | 43 * Provides functionality needed for content suggestion notifications. |
| 43 * | 44 * |
| 44 * Exposes helper functions to native C++ code. | 45 * Exposes helper functions to native C++ code. |
| (...skipping 22 matching lines...) Expand all Loading... |
| 67 private static final String PREF_CACHED_CONSECUTIVE_IGNORED = | 68 private static final String PREF_CACHED_CONSECUTIVE_IGNORED = |
| 68 "ntp.content_suggestions.notification.cached_consecutive_ignored"; | 69 "ntp.content_suggestions.notification.cached_consecutive_ignored"; |
| 69 | 70 |
| 70 // Tracks which URIs there is an active notification for. | 71 // Tracks which URIs there is an active notification for. |
| 71 private static final String PREF_ACTIVE_NOTIFICATIONS = | 72 private static final String PREF_ACTIVE_NOTIFICATIONS = |
| 72 "ntp.content_suggestions.notification.active"; | 73 "ntp.content_suggestions.notification.active"; |
| 73 | 74 |
| 74 private ContentSuggestionsNotificationHelper() {} // Prevent instantiation | 75 private ContentSuggestionsNotificationHelper() {} // Prevent instantiation |
| 75 | 76 |
| 76 /** | 77 /** |
| 78 * Records the reason why Content Suggestions notifications have been opted
out. |
| 79 * @see ContentSuggestionsNotificationOptOutEnum; |
| 80 */ |
| 81 public static void recordNotificationOptOut( |
| 82 @ContentSuggestionsNotificationOptOutEnum int reason) { |
| 83 nativeRecordNotificationOptOut(reason); |
| 84 } |
| 85 |
| 86 /** |
| 87 * Records an action performed on a Content Suggestions notification. |
| 88 * @see ContentSuggestionsNotificationActionEnum; |
| 89 */ |
| 90 public static void recordNotificationAction( |
| 91 @ContentSuggestionsNotificationActionEnum int action) { |
| 92 nativeRecordNotificationAction(action); |
| 93 } |
| 94 |
| 95 /** |
| 77 * Opens the content suggestion when notification is tapped. | 96 * Opens the content suggestion when notification is tapped. |
| 78 */ | 97 */ |
| 79 public static final class OpenUrlReceiver extends BroadcastReceiver { | 98 public static final class OpenUrlReceiver extends BroadcastReceiver { |
| 80 @Override | 99 @Override |
| 81 public void onReceive(Context context, Intent intent) { | 100 public void onReceive(Context context, Intent intent) { |
| 82 int category = intent.getIntExtra(NOTIFICATION_CATEGORY_EXTRA, -1); | 101 int category = intent.getIntExtra(NOTIFICATION_CATEGORY_EXTRA, -1); |
| 83 String idWithinCategory = intent.getStringExtra(NOTIFICATION_ID_WITH
IN_CATEGORY_EXTRA); | 102 String idWithinCategory = intent.getStringExtra(NOTIFICATION_ID_WITH
IN_CATEGORY_EXTRA); |
| 84 openUrl(intent.getData()); | 103 openUrl(intent.getData()); |
| 85 recordCachedActionMetric(ContentSuggestionsNotificationAction.CONTEN
T_SUGGESTIONS_TAP); | 104 recordCachedActionMetric(ContentSuggestionsNotificationAction.TAP); |
| 86 removeActiveNotification(category, idWithinCategory); | 105 removeActiveNotification(category, idWithinCategory); |
| 87 } | 106 } |
| 88 } | 107 } |
| 89 | 108 |
| 90 /** | 109 /** |
| 91 * Records dismissal when notification is swiped away. | 110 * Records dismissal when notification is swiped away. |
| 92 */ | 111 */ |
| 93 public static final class DeleteReceiver extends BroadcastReceiver { | 112 public static final class DeleteReceiver extends BroadcastReceiver { |
| 94 @Override | 113 @Override |
| 95 public void onReceive(Context context, Intent intent) { | 114 public void onReceive(Context context, Intent intent) { |
| 96 int category = intent.getIntExtra(NOTIFICATION_CATEGORY_EXTRA, -1); | 115 int category = intent.getIntExtra(NOTIFICATION_CATEGORY_EXTRA, -1); |
| 97 String idWithinCategory = intent.getStringExtra(NOTIFICATION_ID_WITH
IN_CATEGORY_EXTRA); | 116 String idWithinCategory = intent.getStringExtra(NOTIFICATION_ID_WITH
IN_CATEGORY_EXTRA); |
| 98 recordCachedActionMetric( | 117 recordCachedActionMetric(ContentSuggestionsNotificationAction.DISMIS
SAL); |
| 99 ContentSuggestionsNotificationAction.CONTENT_SUGGESTIONS_DIS
MISSAL); | |
| 100 removeActiveNotification(category, idWithinCategory); | 118 removeActiveNotification(category, idWithinCategory); |
| 101 } | 119 } |
| 102 } | 120 } |
| 103 | 121 |
| 104 /** | 122 /** |
| 105 * Removes the notification after a timeout period. | 123 * Removes the notification after a timeout period. |
| 106 */ | 124 */ |
| 107 public static final class TimeoutReceiver extends BroadcastReceiver { | 125 public static final class TimeoutReceiver extends BroadcastReceiver { |
| 108 @Override | 126 @Override |
| 109 public void onReceive(Context context, Intent intent) { | 127 public void onReceive(Context context, Intent intent) { |
| 110 int category = intent.getIntExtra(NOTIFICATION_CATEGORY_EXTRA, -1); | 128 int category = intent.getIntExtra(NOTIFICATION_CATEGORY_EXTRA, -1); |
| 111 String idWithinCategory = intent.getStringExtra(NOTIFICATION_ID_WITH
IN_CATEGORY_EXTRA); | 129 String idWithinCategory = intent.getStringExtra(NOTIFICATION_ID_WITH
IN_CATEGORY_EXTRA); |
| 112 if (findActiveNotification(category, idWithinCategory) == null) { | 130 if (findActiveNotification(category, idWithinCategory) == null) { |
| 113 return; // tapped or swiped | 131 return; // tapped or swiped |
| 114 } | 132 } |
| 115 | 133 |
| 116 hideNotification(category, idWithinCategory, | 134 hideNotification( |
| 117 ContentSuggestionsNotificationAction.CONTENT_SUGGESTIONS_HID
E_DEADLINE); | 135 category, idWithinCategory, ContentSuggestionsNotificationAc
tion.HIDE_DEADLINE); |
| 118 } | 136 } |
| 119 } | 137 } |
| 120 | 138 |
| 121 private static void openUrl(Uri uri) { | 139 private static void openUrl(Uri uri) { |
| 122 Context context = ContextUtils.getApplicationContext(); | 140 Context context = ContextUtils.getApplicationContext(); |
| 123 Intent intent = new Intent() | 141 Intent intent = new Intent() |
| 124 .setAction(Intent.ACTION_VIEW) | 142 .setAction(Intent.ACTION_VIEW) |
| 125 .setData(uri) | 143 .setData(uri) |
| 126 .setClass(context, ChromeLauncherActivity.class) | 144 .setClass(context, ChromeLauncherActivity.class) |
| 127 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) | 145 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 166 .setContentIntent(contentIntent) | 184 .setContentIntent(contentIntent) |
| 167 .setDeleteIntent(deleteIntent) | 185 .setDeleteIntent(deleteIntent) |
| 168 .setContentTitle(title) | 186 .setContentTitle(title) |
| 169 .setContentText(text) | 187 .setContentText(text) |
| 170 .setGroup(NOTIFICATION_TAG) | 188 .setGroup(NOTIFICATION_TAG) |
| 171 .setPriority(priority) | 189 .setPriority(priority) |
| 172 .setLargeIcon(image) | 190 .setLargeIcon(image) |
| 173 .setSmallIcon(R.drawable.ic_chrome); | 191 .setSmallIcon(R.drawable.ic_chrome); |
| 174 if (ChromeFeatureList.isEnabled(ChromeFeatureList.CONTENT_SUGGESTIONS_SE
TTINGS)) { | 192 if (ChromeFeatureList.isEnabled(ChromeFeatureList.CONTENT_SUGGESTIONS_SE
TTINGS)) { |
| 175 PendingIntent settingsIntent = PendingIntent.getActivity(context, 0, | 193 PendingIntent settingsIntent = PendingIntent.getActivity(context, 0, |
| 176 PreferencesLauncher.createIntentForSettingsPage( | 194 ContentSuggestionsPreferences.createLaunchIntent( |
| 177 context, ContentSuggestionsPreferences.class.getName
()), | 195 context, ContentSuggestionsPreferences.LAUNCH_SOURCE
_NOTIFICATION), |
| 178 0); | 196 0); |
| 179 builder.addAction(R.drawable.settings_cog, context.getString(R.strin
g.preferences), | 197 builder.addAction(R.drawable.settings_cog, context.getString(R.strin
g.preferences), |
| 180 settingsIntent); | 198 settingsIntent); |
| 181 } | 199 } |
| 182 if (priority >= 0) { | 200 if (priority >= 0) { |
| 183 builder.setDefaults(Notification.DEFAULT_ALL); | 201 builder.setDefaults(Notification.DEFAULT_ALL); |
| 184 } | 202 } |
| 185 manager.notify(NOTIFICATION_TAG, nextId, builder.build()); | 203 manager.notify(NOTIFICATION_TAG, nextId, builder.build()); |
| 186 NotificationUmaTracker.getInstance().onNotificationShown( | 204 NotificationUmaTracker.getInstance().onNotificationShown( |
| 187 NotificationUmaTracker.CONTENT_SUGGESTION); | 205 NotificationUmaTracker.CONTENT_SUGGESTION); |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 342 Uri notificationUri = Uri.parse(serialized); | 360 Uri notificationUri = Uri.parse(serialized); |
| 343 ActiveNotification activeNotification = ActiveNotification.fromUri(n
otificationUri); | 361 ActiveNotification activeNotification = ActiveNotification.fromUri(n
otificationUri); |
| 344 if ((activeNotification != null) && (activeNotification.mId >= nextI
d)) { | 362 if ((activeNotification != null) && (activeNotification.mId >= nextI
d)) { |
| 345 nextId = activeNotification.mId + 1; | 363 nextId = activeNotification.mId + 1; |
| 346 } | 364 } |
| 347 } | 365 } |
| 348 return nextId; | 366 return nextId; |
| 349 } | 367 } |
| 350 | 368 |
| 351 private static String cachedMetricNameForAction( | 369 private static String cachedMetricNameForAction( |
| 352 @ContentSuggestionsNotificationAction.ContentSuggestionsNotification
ActionEnum | 370 @ContentSuggestionsNotificationActionEnum int action) { |
| 353 int action) { | |
| 354 switch (action) { | 371 switch (action) { |
| 355 case ContentSuggestionsNotificationAction.CONTENT_SUGGESTIONS_TAP: | 372 case ContentSuggestionsNotificationAction.TAP: |
| 356 return PREF_CACHED_ACTION_TAP; | 373 return PREF_CACHED_ACTION_TAP; |
| 357 case ContentSuggestionsNotificationAction.CONTENT_SUGGESTIONS_DISMIS
SAL: | 374 case ContentSuggestionsNotificationAction.DISMISSAL: |
| 358 return PREF_CACHED_ACTION_DISMISSAL; | 375 return PREF_CACHED_ACTION_DISMISSAL; |
| 359 case ContentSuggestionsNotificationAction.CONTENT_SUGGESTIONS_HIDE_D
EADLINE: | 376 case ContentSuggestionsNotificationAction.HIDE_DEADLINE: |
| 360 return PREF_CACHED_ACTION_HIDE_DEADLINE; | 377 return PREF_CACHED_ACTION_HIDE_DEADLINE; |
| 361 case ContentSuggestionsNotificationAction.CONTENT_SUGGESTIONS_HIDE_E
XPIRY: | 378 case ContentSuggestionsNotificationAction.HIDE_EXPIRY: |
| 362 return PREF_CACHED_ACTION_HIDE_EXPIRY; | 379 return PREF_CACHED_ACTION_HIDE_EXPIRY; |
| 363 case ContentSuggestionsNotificationAction.CONTENT_SUGGESTIONS_HIDE_F
RONTMOST: | 380 case ContentSuggestionsNotificationAction.HIDE_FRONTMOST: |
| 364 return PREF_CACHED_ACTION_HIDE_FRONTMOST; | 381 return PREF_CACHED_ACTION_HIDE_FRONTMOST; |
| 365 case ContentSuggestionsNotificationAction.CONTENT_SUGGESTIONS_HIDE_D
ISABLED: | 382 case ContentSuggestionsNotificationAction.HIDE_DISABLED: |
| 366 return PREF_CACHED_ACTION_HIDE_DISABLED; | 383 return PREF_CACHED_ACTION_HIDE_DISABLED; |
| 367 case ContentSuggestionsNotificationAction.CONTENT_SUGGESTIONS_HIDE_S
HUTDOWN: | 384 case ContentSuggestionsNotificationAction.HIDE_SHUTDOWN: |
| 368 return PREF_CACHED_ACTION_HIDE_SHUTDOWN; | 385 return PREF_CACHED_ACTION_HIDE_SHUTDOWN; |
| 369 } | 386 } |
| 370 return ""; | 387 return ""; |
| 371 } | 388 } |
| 372 | 389 |
| 373 /** | 390 /** |
| 374 * Records that an action was performed on a notification. | 391 * Records that an action was performed on a notification. |
| 375 * | 392 * |
| 376 * Also tracks the number of consecutively-ignored notifications, resetting
it on a tap or | 393 * Also tracks the number of consecutively-ignored notifications, resetting
it on a tap or |
| 377 * otherwise incrementing it. | 394 * otherwise incrementing it. |
| 378 * | 395 * |
| 379 * This method may be called when the native library is not loaded. If it is
loaded, the metrics | 396 * This method may be called when the native library is not loaded. If it is
loaded, the metrics |
| 380 * will immediately be sent to C++. If not, it will cache them for a later c
all to | 397 * will immediately be sent to C++. If not, it will cache them for a later c
all to |
| 381 * flushCachedMetrics(). | 398 * flushCachedMetrics(). |
| 382 * | 399 * |
| 383 * @param action The action to update the pref for. | 400 * @param action The action to update the pref for. |
| 384 */ | 401 */ |
| 385 private static void recordCachedActionMetric( | 402 private static void recordCachedActionMetric( |
| 386 @ContentSuggestionsNotificationAction.ContentSuggestionsNotification
ActionEnum | 403 @ContentSuggestionsNotificationActionEnum int action) { |
| 387 int action) { | |
| 388 String prefName = cachedMetricNameForAction(action); | 404 String prefName = cachedMetricNameForAction(action); |
| 389 assert !prefName.isEmpty(); | 405 assert !prefName.isEmpty(); |
| 390 | 406 |
| 391 SharedPreferences prefs = ContextUtils.getAppSharedPreferences(); | 407 SharedPreferences prefs = ContextUtils.getAppSharedPreferences(); |
| 392 int currentValue = prefs.getInt(prefName, 0); | 408 int currentValue = prefs.getInt(prefName, 0); |
| 393 | 409 |
| 394 int consecutiveIgnored = prefs.getInt(PREF_CACHED_CONSECUTIVE_IGNORED, 0
); | 410 int consecutiveIgnored = prefs.getInt(PREF_CACHED_CONSECUTIVE_IGNORED, 0
); |
| 395 switch (action) { | 411 switch (action) { |
| 396 case ContentSuggestionsNotificationAction.CONTENT_SUGGESTIONS_TAP: | 412 case ContentSuggestionsNotificationAction.TAP: |
| 397 consecutiveIgnored = 0; | 413 consecutiveIgnored = 0; |
| 398 break; | 414 break; |
| 399 case ContentSuggestionsNotificationAction.CONTENT_SUGGESTIONS_DISMIS
SAL: | 415 case ContentSuggestionsNotificationAction.DISMISSAL: |
| 400 case ContentSuggestionsNotificationAction.CONTENT_SUGGESTIONS_HIDE_D
EADLINE: | 416 case ContentSuggestionsNotificationAction.HIDE_DEADLINE: |
| 401 case ContentSuggestionsNotificationAction.CONTENT_SUGGESTIONS_HIDE_E
XPIRY: | 417 case ContentSuggestionsNotificationAction.HIDE_EXPIRY: |
| 402 ++consecutiveIgnored; | 418 ++consecutiveIgnored; |
| 403 break; | 419 break; |
| 404 case ContentSuggestionsNotificationAction.CONTENT_SUGGESTIONS_HIDE_F
RONTMOST: | 420 case ContentSuggestionsNotificationAction.HIDE_FRONTMOST: |
| 405 case ContentSuggestionsNotificationAction.CONTENT_SUGGESTIONS_HIDE_D
ISABLED: | 421 case ContentSuggestionsNotificationAction.HIDE_DISABLED: |
| 406 case ContentSuggestionsNotificationAction.CONTENT_SUGGESTIONS_HIDE_S
HUTDOWN: | 422 case ContentSuggestionsNotificationAction.HIDE_SHUTDOWN: |
| 407 break; // no change | 423 break; // no change |
| 408 } | 424 } |
| 409 | 425 |
| 410 prefs.edit() | 426 prefs.edit() |
| 411 .putInt(prefName, currentValue + 1) | 427 .putInt(prefName, currentValue + 1) |
| 412 .putInt(PREF_CACHED_CONSECUTIVE_IGNORED, consecutiveIgnored) | 428 .putInt(PREF_CACHED_CONSECUTIVE_IGNORED, consecutiveIgnored) |
| 413 .apply(); | 429 .apply(); |
| 414 | 430 |
| 415 if (LibraryLoader.isInitialized()) { | 431 if (LibraryLoader.isInitialized()) { |
| 416 flushCachedMetrics(); | 432 flushCachedMetrics(); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 450 .remove(PREF_CACHED_ACTION_HIDE_DISABLED) | 466 .remove(PREF_CACHED_ACTION_HIDE_DISABLED) |
| 451 .remove(PREF_CACHED_ACTION_HIDE_SHUTDOWN) | 467 .remove(PREF_CACHED_ACTION_HIDE_SHUTDOWN) |
| 452 .remove(PREF_CACHED_CONSECUTIVE_IGNORED) | 468 .remove(PREF_CACHED_CONSECUTIVE_IGNORED) |
| 453 .apply(); | 469 .apply(); |
| 454 } | 470 } |
| 455 } | 471 } |
| 456 | 472 |
| 457 private static native void nativeReceiveFlushedMetrics(int tapCount, int dis
missalCount, | 473 private static native void nativeReceiveFlushedMetrics(int tapCount, int dis
missalCount, |
| 458 int hideDeadlineCount, int hideExpiryCount, int hideFrontmostCount, | 474 int hideDeadlineCount, int hideExpiryCount, int hideFrontmostCount, |
| 459 int hideDisabledCount, int hideShutdownCount, int consecutiveIgnored
); | 475 int hideDisabledCount, int hideShutdownCount, int consecutiveIgnored
); |
| 476 private static native void nativeRecordNotificationOptOut( |
| 477 @ContentSuggestionsNotificationOptOutEnum int reason); |
| 478 private static native void nativeRecordNotificationAction( |
| 479 @ContentSuggestionsNotificationActionEnum int action); |
| 460 } | 480 } |
| OLD | NEW |