Index: chrome/android/java/src/org/chromium/chrome/browser/ntp/ContentSuggestionsNotificationHelper.java |
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/ContentSuggestionsNotificationHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/ContentSuggestionsNotificationHelper.java |
index 337a3a997a905b558711614896dae30c57f4c9ae..a149fca21d5ad3db39536bae3edcf76d8bef53c3 100644 |
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/ContentSuggestionsNotificationHelper.java |
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/ContentSuggestionsNotificationHelper.java |
@@ -11,6 +11,7 @@ import android.app.PendingIntent; |
import android.content.BroadcastReceiver; |
import android.content.Context; |
import android.content.Intent; |
+import android.content.SharedPreferences; |
import android.graphics.Bitmap; |
import android.net.Uri; |
import android.os.Build; |
@@ -20,6 +21,8 @@ import android.support.v4.app.NotificationCompat; |
import org.chromium.base.ContextUtils; |
import org.chromium.base.annotations.CalledByNative; |
+import org.chromium.base.annotations.JNINamespace; |
+import org.chromium.base.library_loader.LibraryLoader; |
import org.chromium.chrome.R; |
import org.chromium.chrome.browser.IntentHandler; |
import org.chromium.chrome.browser.ShortcutHelper; |
@@ -30,13 +33,42 @@ import org.chromium.chrome.browser.document.ChromeLauncherActivity; |
* |
* Exposes helper functions to native C++ code. |
*/ |
+@JNINamespace("ntp_snippets") |
public class ContentSuggestionsNotificationHelper { |
private static final String NOTIFICATION_TAG = "ContentSuggestionsNotification"; |
private static final String NOTIFICATION_ID_EXTRA = "notification_id"; |
+ private static final String PREF_CACHED_ACTION_TAP = |
+ "ntp.content_suggestions.notification.cached_action_tap"; |
+ private static final String PREF_CACHED_ACTION_DISMISSAL = |
+ "ntp.content_suggestions.notification.cached_action_dismissal"; |
+ private static final String PREF_CACHED_ACTION_HIDE_DEADLINE = |
+ "ntp.content_suggestions.notification.cached_action_hide_deadline"; |
+ private static final String PREF_CACHED_CONSECUTIVE_IGNORED = |
+ "ntp.content_suggestions.notification.cached_consecutive_ignored"; |
+ |
private ContentSuggestionsNotificationHelper() {} // Prevent instantiation |
/** |
+ * Opens the content suggestion when notification is tapped. |
+ */ |
+ public static final class OpenUrlReceiver extends BroadcastReceiver { |
+ public void onReceive(Context context, Intent intent) { |
+ openUrl(intent.getData()); |
+ recordCachedActionMetric(PREF_CACHED_ACTION_TAP); |
+ } |
+ } |
+ |
+ /** |
+ * Records dismissal when notification is swiped away. |
+ */ |
+ public static final class DeleteReceiver extends BroadcastReceiver { |
+ public void onReceive(Context context, Intent intent) { |
+ recordCachedActionMetric(PREF_CACHED_ACTION_DISMISSAL); |
+ } |
+ } |
+ |
+ /** |
* Removes the notification after a timeout period. |
*/ |
public static final class TimeoutReceiver extends BroadcastReceiver { |
@@ -44,19 +76,19 @@ public class ContentSuggestionsNotificationHelper { |
int id = intent.getIntExtra(NOTIFICATION_ID_EXTRA, -1); |
if (id < 0) return; |
hideNotification(id); |
+ recordCachedActionMetric(PREF_CACHED_ACTION_HIDE_DEADLINE); |
} |
} |
- @CalledByNative |
- private static void openUrl(String url) { |
+ private static void openUrl(Uri uri) { |
Context context = ContextUtils.getApplicationContext(); |
- Intent intent = new Intent(); |
- intent.setAction(Intent.ACTION_VIEW); |
- intent.setData(Uri.parse(url)); |
- intent.setClass(context, ChromeLauncherActivity.class); |
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
- intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName()); |
- intent.putExtra(ShortcutHelper.REUSE_URL_MATCHING_TAB_ELSE_NEW_TAB, true); |
+ Intent intent = new Intent() |
+ .setAction(Intent.ACTION_VIEW) |
+ .setData(uri) |
+ .setClass(context, ChromeLauncherActivity.class) |
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) |
+ .putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName()) |
+ .putExtra(ShortcutHelper.REUSE_URL_MATCHING_TAB_ELSE_NEW_TAB, true); |
IntentHandler.addTrustedIntentExtras(intent); |
context.startActivity(intent); |
} |
@@ -81,16 +113,13 @@ public class ContentSuggestionsNotificationHelper { |
} |
} |
- Intent intent = new Intent() |
- .setAction(Intent.ACTION_VIEW) |
- .setData(Uri.parse(url)) |
- .setClass(context, ChromeLauncherActivity.class) |
- .putExtra(ShortcutHelper.REUSE_URL_MATCHING_TAB_ELSE_NEW_TAB, true) |
- .putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName()); |
+ Intent contentIntent = new Intent(context, OpenUrlReceiver.class).setData(Uri.parse(url)); |
+ Intent deleteIntent = new Intent(context, DeleteReceiver.class).setData(Uri.parse(url)); |
NotificationCompat.Builder builder = |
new NotificationCompat.Builder(context) |
.setAutoCancel(true) |
- .setContentIntent(PendingIntent.getActivity(context, 0, intent, 0)) |
+ .setContentIntent(PendingIntent.getBroadcast(context, 0, contentIntent, 0)) |
+ .setDeleteIntent(PendingIntent.getBroadcast(context, 0, deleteIntent, 0)) |
.setContentTitle(title) |
.setContentText(text) |
.setGroup(NOTIFICATION_TAG) |
@@ -134,4 +163,65 @@ public class ContentSuggestionsNotificationHelper { |
manager.cancel(NOTIFICATION_TAG, 0); |
} |
} |
+ |
+ /** |
+ * Records that an action was performed on a notification. |
+ * |
+ * Also tracks the number of consecutively-ignored notifications, resetting it on a tap or |
+ * otherwise incrementing it. |
+ * |
+ * This method may be called when the native library is not loaded. If it is loaded, the metrics |
+ * will immediately be sent to C++. If not, it will cache them for a later call to |
+ * flushCachedMetrics(). |
+ * |
+ * @param prefName The name of the action metric pref to update (<tt>PREF_CACHED_ACTION_*</tt>) |
+ */ |
+ private static void recordCachedActionMetric(String prefName) { |
+ assert prefName.startsWith("ntp.content_suggestions.notification.cached_action_"); |
+ |
+ SharedPreferences prefs = ContextUtils.getAppSharedPreferences(); |
+ int currentValue = prefs.getInt(prefName, 0); |
+ int consecutiveIgnored = 0; |
+ if (!prefName.equals(PREF_CACHED_ACTION_TAP)) { |
+ consecutiveIgnored = 1 + prefs.getInt(PREF_CACHED_CONSECUTIVE_IGNORED, 0); |
+ } |
+ prefs.edit() |
+ .putInt(prefName, currentValue + 1) |
+ .putInt(PREF_CACHED_CONSECUTIVE_IGNORED, consecutiveIgnored) |
+ .apply(); |
+ |
+ if (LibraryLoader.isInitialized()) { |
+ flushCachedMetrics(); |
+ } |
+ } |
+ |
+ /** |
+ * Invokes nativeReceiveFlushedMetrics() with cached metrics and resets them. |
+ * |
+ * It may be called from either native or Java code, as long as the native libray is loaded. |
+ */ |
+ @CalledByNative |
+ private static void flushCachedMetrics() { |
+ assert LibraryLoader.isInitialized(); |
+ |
+ SharedPreferences prefs = ContextUtils.getAppSharedPreferences(); |
+ int tapCount = prefs.getInt(PREF_CACHED_ACTION_TAP, 0); |
+ int dismissalCount = prefs.getInt(PREF_CACHED_ACTION_DISMISSAL, 0); |
+ int hideDeadlineCount = prefs.getInt(PREF_CACHED_ACTION_HIDE_DEADLINE, 0); |
+ int consecutiveIgnored = prefs.getInt(PREF_CACHED_CONSECUTIVE_IGNORED, 0); |
+ |
+ if (tapCount > 0 || dismissalCount > 0 || hideDeadlineCount > 0) { |
+ nativeReceiveFlushedMetrics(tapCount, dismissalCount, hideDeadlineCount, |
+ consecutiveIgnored); |
+ prefs.edit() |
+ .remove(PREF_CACHED_ACTION_TAP) |
+ .remove(PREF_CACHED_ACTION_DISMISSAL) |
+ .remove(PREF_CACHED_ACTION_HIDE_DEADLINE) |
+ .remove(PREF_CACHED_CONSECUTIVE_IGNORED) |
+ .apply(); |
+ } |
+ } |
+ |
+ private static native void nativeReceiveFlushedMetrics( |
+ int tapCount, int dismissalCount, int hideDeadlineCount, int consecutiveIgnored); |
} |