| OLD | NEW |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 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.annotation.TargetApi; |
| 8 import android.app.NotificationManager; |
| 7 import android.content.SharedPreferences; | 9 import android.content.SharedPreferences; |
| 8 import android.support.annotation.IntDef; | 10 import android.support.annotation.IntDef; |
| 9 import android.support.v4.app.NotificationManagerCompat; | 11 import android.support.v4.app.NotificationManagerCompat; |
| 10 | 12 |
| 13 import org.chromium.base.BuildInfo; |
| 11 import org.chromium.base.ContextUtils; | 14 import org.chromium.base.ContextUtils; |
| 15 import org.chromium.base.Log; |
| 12 import org.chromium.base.library_loader.LibraryLoader; | 16 import org.chromium.base.library_loader.LibraryLoader; |
| 13 import org.chromium.base.metrics.RecordHistogram; | 17 import org.chromium.base.metrics.RecordHistogram; |
| 14 | 18 |
| 15 import java.lang.annotation.Retention; | 19 import java.lang.annotation.Retention; |
| 16 import java.lang.annotation.RetentionPolicy; | 20 import java.lang.annotation.RetentionPolicy; |
| 21 import java.lang.reflect.InvocationTargetException; |
| 22 import java.lang.reflect.Method; |
| 17 | 23 |
| 18 /** | 24 /** |
| 19 * Helper class to make tracking notification UMA stats easier for various featu
res. Having a | 25 * Helper class to make tracking notification UMA stats easier for various featu
res. Having a |
| 20 * single entry point here to make more complex tracking easier to add in the fu
ture. | 26 * single entry point here to make more complex tracking easier to add in the fu
ture. |
| 21 */ | 27 */ |
| 22 public class NotificationUmaTracker { | 28 public class NotificationUmaTracker { |
| 29 private static final String TAG = "NotifsUMATracker"; |
| 30 |
| 23 @Retention(RetentionPolicy.SOURCE) | 31 @Retention(RetentionPolicy.SOURCE) |
| 24 @IntDef({DOWNLOAD_FILES, DOWNLOAD_PAGES, CLOSE_INCOGNITO, CONTENT_SUGGESTION
, | 32 @IntDef({DOWNLOAD_FILES, DOWNLOAD_PAGES, CLOSE_INCOGNITO, CONTENT_SUGGESTION
, |
| 25 SYSTEM_NOTIFICATION_TYPE_BOUNDARY}) | 33 SYSTEM_NOTIFICATION_TYPE_BOUNDARY}) |
| 26 public @interface SystemNotificationType {} | 34 public @interface SystemNotificationType {} |
| 27 | 35 |
| 28 /* | 36 /* |
| 29 * A list of notification types. To add a type to this list please update | 37 * A list of notification types. To add a type to this list please update |
| 30 * SystemNotificationType in histograms.xml and make sure to keep this list
in sync. Additions | 38 * SystemNotificationType in histograms.xml and make sure to keep this list
in sync. Additions |
| 31 * should be treated as APPEND ONLY to keep the UMA metric semantics the sam
e over time. | 39 * should be treated as APPEND ONLY to keep the UMA metric semantics the sam
e over time. |
| 32 * | 40 * |
| (...skipping 24 matching lines...) Expand all Loading... |
| 57 private NotificationUmaTracker() { | 65 private NotificationUmaTracker() { |
| 58 mSharedPreferences = ContextUtils.getAppSharedPreferences(); | 66 mSharedPreferences = ContextUtils.getAppSharedPreferences(); |
| 59 mNotificationManager = NotificationManagerCompat.from(ContextUtils.getAp
plicationContext()); | 67 mNotificationManager = NotificationManagerCompat.from(ContextUtils.getAp
plicationContext()); |
| 60 } | 68 } |
| 61 | 69 |
| 62 /** | 70 /** |
| 63 * Logs {@link android.app.Notification} usage, categorized into {@link Syst
emNotificationType} | 71 * Logs {@link android.app.Notification} usage, categorized into {@link Syst
emNotificationType} |
| 64 * types. Splits the logs by the global enabled state of notifications and
also logs the last | 72 * types. Splits the logs by the global enabled state of notifications and
also logs the last |
| 65 * notification shown prior to the global notifications state being disabled
by the user. | 73 * notification shown prior to the global notifications state being disabled
by the user. |
| 66 * @param type The type of notification that was shown. | 74 * @param type The type of notification that was shown. |
| 75 * @param channelId The id of the notification channel set on the notificati
on. |
| 67 * @see SystemNotificationType | 76 * @see SystemNotificationType |
| 68 */ | 77 */ |
| 69 public void onNotificationShown(@SystemNotificationType int type) { | 78 public void onNotificationShown( |
| 70 if (mNotificationManager.areNotificationsEnabled()) { | 79 @SystemNotificationType int type, @ChannelDefinitions.ChannelId Stri
ng channelId) { |
| 71 saveLastShownNotification(type); | 80 if (!mNotificationManager.areNotificationsEnabled()) { |
| 72 recordHistogram("Mobile.SystemNotification.Shown", type); | |
| 73 } else { | |
| 74 logPotentialBlockedCause(); | 81 logPotentialBlockedCause(); |
| 75 recordHistogram("Mobile.SystemNotification.Blocked", type); | 82 recordHistogram("Mobile.SystemNotification.Blocked", type); |
| 83 return; |
| 76 } | 84 } |
| 85 if (BuildInfo.isAtLeastO() && isChannelBlocked(channelId)) { |
| 86 recordHistogram("Mobile.SystemNotification.ChannelBlocked", type); |
| 87 return; |
| 88 } |
| 89 saveLastShownNotification(type); |
| 90 recordHistogram("Mobile.SystemNotification.Shown", type); |
| 91 } |
| 92 |
| 93 @TargetApi(26) |
| 94 private boolean isChannelBlocked(@ChannelDefinitions.ChannelId String channe
lId) { |
| 95 // Use non-compat notification manager as compat does not have getNotifi
cationChannel (yet). |
| 96 NotificationManager notificationManager = |
| 97 ContextUtils.getApplicationContext().getSystemService(Notificati
onManager.class); |
| 98 /* |
| 99 The code in the try-block uses reflection in order to compile as it call
s APIs newer than |
| 100 our compileSdkVersion of Android. The equivalent code without reflection
looks like this: |
| 101 |
| 102 NotificationChannel channel = notificationManager.getNotificationCha
nnel(channelId); |
| 103 return (channel.getImportance() == NotificationManager.IMPORTANCE_NO
NE); |
| 104 */ |
| 105 // TODO(crbug.com/707804) Remove the following reflection once compileSd
k is bumped to O. |
| 106 try { |
| 107 Method getNotificationChannel = notificationManager.getClass().getMe
thod( |
| 108 "getNotificationChannel", String.class); |
| 109 Object channel = getNotificationChannel.invoke(notificationManager,
channelId); |
| 110 Method getImportance = channel.getClass().getMethod("getImportance")
; |
| 111 int importance = (int) getImportance.invoke(channel); |
| 112 return (importance == NotificationManager.IMPORTANCE_NONE); |
| 113 } catch (NoSuchMethodException | InvocationTargetException | IllegalAcce
ssException e) { |
| 114 Log.e(TAG, "Error checking channel importance:", e); |
| 115 } |
| 116 return false; |
| 77 } | 117 } |
| 78 | 118 |
| 79 private void saveLastShownNotification(@SystemNotificationType int type) { | 119 private void saveLastShownNotification(@SystemNotificationType int type) { |
| 80 mSharedPreferences.edit().putInt(LAST_SHOWN_NOTIFICATION_TYPE_KEY, type)
.apply(); | 120 mSharedPreferences.edit().putInt(LAST_SHOWN_NOTIFICATION_TYPE_KEY, type)
.apply(); |
| 81 } | 121 } |
| 82 | 122 |
| 83 private void logPotentialBlockedCause() { | 123 private void logPotentialBlockedCause() { |
| 84 int lastType = mSharedPreferences.getInt(LAST_SHOWN_NOTIFICATION_TYPE_KE
Y, -1); | 124 int lastType = mSharedPreferences.getInt(LAST_SHOWN_NOTIFICATION_TYPE_KE
Y, -1); |
| 85 if (lastType == -1) return; | 125 if (lastType == -1) return; |
| 86 mSharedPreferences.edit().remove(LAST_SHOWN_NOTIFICATION_TYPE_KEY).apply
(); | 126 mSharedPreferences.edit().remove(LAST_SHOWN_NOTIFICATION_TYPE_KEY).apply
(); |
| 87 | 127 |
| 88 recordHistogram("Mobile.SystemNotification.BlockedAfterShown", lastType)
; | 128 recordHistogram("Mobile.SystemNotification.BlockedAfterShown", lastType)
; |
| 89 } | 129 } |
| 90 | 130 |
| 91 private static void recordHistogram(String name, @SystemNotificationType int
type) { | 131 private static void recordHistogram(String name, @SystemNotificationType int
type) { |
| 92 if (!LibraryLoader.isInitialized()) return; | 132 if (!LibraryLoader.isInitialized()) return; |
| 93 RecordHistogram.recordEnumeratedHistogram(name, type, SYSTEM_NOTIFICATIO
N_TYPE_BOUNDARY); | 133 RecordHistogram.recordEnumeratedHistogram(name, type, SYSTEM_NOTIFICATIO
N_TYPE_BOUNDARY); |
| 94 } | 134 } |
| 95 } | 135 } |
| OLD | NEW |