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 |