Loading packages/SystemUI/src/com/android/systemui/ForegroundServiceLifetimeExtender.java +12 −3 Original line number Diff line number Diff line Loading @@ -23,10 +23,13 @@ import android.os.Looper; import android.util.ArraySet; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.statusbar.NotificationInteractionTracker; import com.android.systemui.statusbar.NotificationLifetimeExtender; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.util.time.SystemClock; import javax.inject.Inject; /** * Extends the lifetime of foreground notification services such that they show for at least * five seconds Loading @@ -41,9 +44,14 @@ public class ForegroundServiceLifetimeExtender implements NotificationLifetimeEx private ArraySet<NotificationEntry> mManagedEntries = new ArraySet<>(); private Handler mHandler = new Handler(Looper.getMainLooper()); private final SystemClock mSystemClock; private final NotificationInteractionTracker mInteractionTracker; public ForegroundServiceLifetimeExtender(SystemClock systemClock) { @Inject public ForegroundServiceLifetimeExtender( NotificationInteractionTracker interactionTracker, SystemClock systemClock) { mSystemClock = systemClock; mInteractionTracker = interactionTracker; } @Override Loading @@ -58,8 +66,9 @@ public class ForegroundServiceLifetimeExtender implements NotificationLifetimeEx return false; } long currentTime = mSystemClock.uptimeMillis(); return currentTime - entry.getCreationTime() < MIN_FGS_TIME_MS; boolean hasInteracted = mInteractionTracker.hasUserInteractedWith(entry.getKey()); long aliveTime = mSystemClock.uptimeMillis() - entry.getCreationTime(); return aliveTime < MIN_FGS_TIME_MS && !hasInteracted; } @Override Loading packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java +2 −2 Original line number Diff line number Diff line Loading @@ -51,6 +51,7 @@ public class ForegroundServiceNotificationListener { ForegroundServiceController foregroundServiceController, NotificationEntryManager notificationEntryManager, NotifPipeline notifPipeline, ForegroundServiceLifetimeExtender fgsLifetimeExtender, SystemClock systemClock) { mContext = context; mForegroundServiceController = foregroundServiceController; Loading Loading @@ -78,8 +79,7 @@ public class ForegroundServiceNotificationListener { removeNotification(entry.getSbn()); } }); mEntryManager.addNotificationLifetimeExtender( new ForegroundServiceLifetimeExtender(systemClock)); mEntryManager.addNotificationLifetimeExtender(fgsLifetimeExtender); notifPipeline.addCollectionListener(new NotifCollectionListener() { @Override Loading packages/SystemUI/src/com/android/systemui/statusbar/NotificationClickNotifier.kt 0 → 100644 +87 −0 Original line number Diff line number Diff line package com.android.systemui.statusbar import android.app.Notification import android.os.RemoteException import com.android.internal.statusbar.IStatusBarService import com.android.internal.statusbar.NotificationVisibility import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.util.Assert import java.util.concurrent.Executor import javax.inject.Inject import javax.inject.Singleton /** * Class to shim calls to IStatusBarManager#onNotificationClick/#onNotificationActionClick that * allow an in-process notification to go out (e.g., for tracking interactions) as well as * sending the messages along to system server. * * NOTE: this class eats exceptions from system server, as no current client of these APIs cares * about errors */ @Singleton public class NotificationClickNotifier @Inject constructor( val barService: IStatusBarService, @Main val mainExecutor: Executor ) { val listeners = mutableListOf<NotificationInteractionListener>() fun addNotificationInteractionListener(listener: NotificationInteractionListener) { Assert.isMainThread() listeners.add(listener) } fun removeNotificationInteractionListener(listener: NotificationInteractionListener) { Assert.isMainThread() listeners.remove(listener) } private fun notifyListenersAboutInteraction(key: String) { for (l in listeners) { l.onNotificationInteraction(key) } } fun onNotificationActionClick( key: String, actionIndex: Int, action: Notification.Action, visibility: NotificationVisibility, generatedByAssistant: Boolean ) { try { barService.onNotificationActionClick( key, actionIndex, action, visibility, generatedByAssistant) } catch (e: RemoteException) { // nothing } mainExecutor.execute { notifyListenersAboutInteraction(key) } } fun onNotificationClick( key: String, visibility: NotificationVisibility ) { try { barService.onNotificationClick(key, visibility) } catch (e: RemoteException) { // nothing } mainExecutor.execute { notifyListenersAboutInteraction(key) } } } /** * Interface for listeners to get notified when a notification is interacted with via a click or * interaction with remote input or actions */ interface NotificationInteractionListener { fun onNotificationInteraction(key: String) } private const val TAG = "NotificationClickNotifier" packages/SystemUI/src/com/android/systemui/statusbar/NotificationInteractionTracker.kt 0 → 100644 +40 −0 Original line number Diff line number Diff line package com.android.systemui.statusbar import com.android.systemui.statusbar.notification.NotificationEntryManager import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener import javax.inject.Inject import javax.inject.Singleton /** * Class to track user interaction with notifications. It's a glorified map of key : bool that can * merge multiple "user interacted with notification" signals into a single place. */ @Singleton class NotificationInteractionTracker @Inject constructor( private val clicker: NotificationClickNotifier, private val entryManager: NotificationEntryManager ) : NotifCollectionListener, NotificationInteractionListener { private val interactions = mutableMapOf<String, Boolean>() init { clicker.addNotificationInteractionListener(this) entryManager.addCollectionListener(this) } fun hasUserInteractedWith(key: String): Boolean = key in interactions override fun onEntryAdded(entry: NotificationEntry) { interactions[entry.key] = false } override fun onEntryCleanUp(entry: NotificationEntry) { interactions.remove(entry.key) } override fun onNotificationInteraction(key: String) { interactions[key] = true } } private const val TAG = "NotificationInteractionTracker" packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java +4 −10 Original line number Diff line number Diff line Loading @@ -35,7 +35,6 @@ import android.content.IntentSender; import android.content.pm.UserInfo; import android.database.ContentObserver; import android.os.Handler; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; Loading @@ -43,7 +42,6 @@ import android.util.Log; import android.util.SparseArray; import android.util.SparseBooleanArray; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.NotificationVisibility; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardUpdateMonitor; Loading Loading @@ -92,9 +90,9 @@ public class NotificationLockscreenUserManagerImpl implements private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray(); private final SparseBooleanArray mUsersAllowingNotifications = new SparseBooleanArray(); private final UserManager mUserManager; private final IStatusBarService mBarService; private final List<UserChangedListener> mListeners = new ArrayList<>(); private final BroadcastDispatcher mBroadcastDispatcher; private final NotificationClickNotifier mClickNotifier; private boolean mShowLockscreenNotifications; private boolean mAllowLockscreenRemoteInput; Loading Loading @@ -170,11 +168,7 @@ public class NotificationLockscreenUserManagerImpl implements final NotificationVisibility nv = NotificationVisibility.obtain( notificationKey, rank, count, true, location); try { mBarService.onNotificationClick(notificationKey, nv); } catch (RemoteException exception) { /* ignore */ } mClickNotifier.onNotificationClick(notificationKey, nv); } break; } Loading Loading @@ -203,7 +197,7 @@ public class NotificationLockscreenUserManagerImpl implements BroadcastDispatcher broadcastDispatcher, DevicePolicyManager devicePolicyManager, UserManager userManager, IStatusBarService iStatusBarService, NotificationClickNotifier clickNotifier, KeyguardManager keyguardManager, StatusBarStateController statusBarStateController, @Main Handler mainHandler, Loading @@ -214,7 +208,7 @@ public class NotificationLockscreenUserManagerImpl implements mDevicePolicyManager = devicePolicyManager; mUserManager = userManager; mCurrentUserId = ActivityManager.getCurrentUser(); mBarService = iStatusBarService; mClickNotifier = clickNotifier; statusBarStateController.addCallback(this); mLockPatternUtils = new LockPatternUtils(context); mKeyguardManager = keyguardManager; Loading Loading
packages/SystemUI/src/com/android/systemui/ForegroundServiceLifetimeExtender.java +12 −3 Original line number Diff line number Diff line Loading @@ -23,10 +23,13 @@ import android.os.Looper; import android.util.ArraySet; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.statusbar.NotificationInteractionTracker; import com.android.systemui.statusbar.NotificationLifetimeExtender; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.util.time.SystemClock; import javax.inject.Inject; /** * Extends the lifetime of foreground notification services such that they show for at least * five seconds Loading @@ -41,9 +44,14 @@ public class ForegroundServiceLifetimeExtender implements NotificationLifetimeEx private ArraySet<NotificationEntry> mManagedEntries = new ArraySet<>(); private Handler mHandler = new Handler(Looper.getMainLooper()); private final SystemClock mSystemClock; private final NotificationInteractionTracker mInteractionTracker; public ForegroundServiceLifetimeExtender(SystemClock systemClock) { @Inject public ForegroundServiceLifetimeExtender( NotificationInteractionTracker interactionTracker, SystemClock systemClock) { mSystemClock = systemClock; mInteractionTracker = interactionTracker; } @Override Loading @@ -58,8 +66,9 @@ public class ForegroundServiceLifetimeExtender implements NotificationLifetimeEx return false; } long currentTime = mSystemClock.uptimeMillis(); return currentTime - entry.getCreationTime() < MIN_FGS_TIME_MS; boolean hasInteracted = mInteractionTracker.hasUserInteractedWith(entry.getKey()); long aliveTime = mSystemClock.uptimeMillis() - entry.getCreationTime(); return aliveTime < MIN_FGS_TIME_MS && !hasInteracted; } @Override Loading
packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java +2 −2 Original line number Diff line number Diff line Loading @@ -51,6 +51,7 @@ public class ForegroundServiceNotificationListener { ForegroundServiceController foregroundServiceController, NotificationEntryManager notificationEntryManager, NotifPipeline notifPipeline, ForegroundServiceLifetimeExtender fgsLifetimeExtender, SystemClock systemClock) { mContext = context; mForegroundServiceController = foregroundServiceController; Loading Loading @@ -78,8 +79,7 @@ public class ForegroundServiceNotificationListener { removeNotification(entry.getSbn()); } }); mEntryManager.addNotificationLifetimeExtender( new ForegroundServiceLifetimeExtender(systemClock)); mEntryManager.addNotificationLifetimeExtender(fgsLifetimeExtender); notifPipeline.addCollectionListener(new NotifCollectionListener() { @Override Loading
packages/SystemUI/src/com/android/systemui/statusbar/NotificationClickNotifier.kt 0 → 100644 +87 −0 Original line number Diff line number Diff line package com.android.systemui.statusbar import android.app.Notification import android.os.RemoteException import com.android.internal.statusbar.IStatusBarService import com.android.internal.statusbar.NotificationVisibility import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.util.Assert import java.util.concurrent.Executor import javax.inject.Inject import javax.inject.Singleton /** * Class to shim calls to IStatusBarManager#onNotificationClick/#onNotificationActionClick that * allow an in-process notification to go out (e.g., for tracking interactions) as well as * sending the messages along to system server. * * NOTE: this class eats exceptions from system server, as no current client of these APIs cares * about errors */ @Singleton public class NotificationClickNotifier @Inject constructor( val barService: IStatusBarService, @Main val mainExecutor: Executor ) { val listeners = mutableListOf<NotificationInteractionListener>() fun addNotificationInteractionListener(listener: NotificationInteractionListener) { Assert.isMainThread() listeners.add(listener) } fun removeNotificationInteractionListener(listener: NotificationInteractionListener) { Assert.isMainThread() listeners.remove(listener) } private fun notifyListenersAboutInteraction(key: String) { for (l in listeners) { l.onNotificationInteraction(key) } } fun onNotificationActionClick( key: String, actionIndex: Int, action: Notification.Action, visibility: NotificationVisibility, generatedByAssistant: Boolean ) { try { barService.onNotificationActionClick( key, actionIndex, action, visibility, generatedByAssistant) } catch (e: RemoteException) { // nothing } mainExecutor.execute { notifyListenersAboutInteraction(key) } } fun onNotificationClick( key: String, visibility: NotificationVisibility ) { try { barService.onNotificationClick(key, visibility) } catch (e: RemoteException) { // nothing } mainExecutor.execute { notifyListenersAboutInteraction(key) } } } /** * Interface for listeners to get notified when a notification is interacted with via a click or * interaction with remote input or actions */ interface NotificationInteractionListener { fun onNotificationInteraction(key: String) } private const val TAG = "NotificationClickNotifier"
packages/SystemUI/src/com/android/systemui/statusbar/NotificationInteractionTracker.kt 0 → 100644 +40 −0 Original line number Diff line number Diff line package com.android.systemui.statusbar import com.android.systemui.statusbar.notification.NotificationEntryManager import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener import javax.inject.Inject import javax.inject.Singleton /** * Class to track user interaction with notifications. It's a glorified map of key : bool that can * merge multiple "user interacted with notification" signals into a single place. */ @Singleton class NotificationInteractionTracker @Inject constructor( private val clicker: NotificationClickNotifier, private val entryManager: NotificationEntryManager ) : NotifCollectionListener, NotificationInteractionListener { private val interactions = mutableMapOf<String, Boolean>() init { clicker.addNotificationInteractionListener(this) entryManager.addCollectionListener(this) } fun hasUserInteractedWith(key: String): Boolean = key in interactions override fun onEntryAdded(entry: NotificationEntry) { interactions[entry.key] = false } override fun onEntryCleanUp(entry: NotificationEntry) { interactions.remove(entry.key) } override fun onNotificationInteraction(key: String) { interactions[key] = true } } private const val TAG = "NotificationInteractionTracker"
packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java +4 −10 Original line number Diff line number Diff line Loading @@ -35,7 +35,6 @@ import android.content.IntentSender; import android.content.pm.UserInfo; import android.database.ContentObserver; import android.os.Handler; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; Loading @@ -43,7 +42,6 @@ import android.util.Log; import android.util.SparseArray; import android.util.SparseBooleanArray; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.NotificationVisibility; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardUpdateMonitor; Loading Loading @@ -92,9 +90,9 @@ public class NotificationLockscreenUserManagerImpl implements private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray(); private final SparseBooleanArray mUsersAllowingNotifications = new SparseBooleanArray(); private final UserManager mUserManager; private final IStatusBarService mBarService; private final List<UserChangedListener> mListeners = new ArrayList<>(); private final BroadcastDispatcher mBroadcastDispatcher; private final NotificationClickNotifier mClickNotifier; private boolean mShowLockscreenNotifications; private boolean mAllowLockscreenRemoteInput; Loading Loading @@ -170,11 +168,7 @@ public class NotificationLockscreenUserManagerImpl implements final NotificationVisibility nv = NotificationVisibility.obtain( notificationKey, rank, count, true, location); try { mBarService.onNotificationClick(notificationKey, nv); } catch (RemoteException exception) { /* ignore */ } mClickNotifier.onNotificationClick(notificationKey, nv); } break; } Loading Loading @@ -203,7 +197,7 @@ public class NotificationLockscreenUserManagerImpl implements BroadcastDispatcher broadcastDispatcher, DevicePolicyManager devicePolicyManager, UserManager userManager, IStatusBarService iStatusBarService, NotificationClickNotifier clickNotifier, KeyguardManager keyguardManager, StatusBarStateController statusBarStateController, @Main Handler mainHandler, Loading @@ -214,7 +208,7 @@ public class NotificationLockscreenUserManagerImpl implements mDevicePolicyManager = devicePolicyManager; mUserManager = userManager; mCurrentUserId = ActivityManager.getCurrentUser(); mBarService = iStatusBarService; mClickNotifier = clickNotifier; statusBarStateController.addCallback(this); mLockPatternUtils = new LockPatternUtils(context); mKeyguardManager = keyguardManager; Loading