diff options
| author | 2021-12-09 23:06:00 +0000 | |
|---|---|---|
| committer | 2021-12-09 23:06:00 +0000 | |
| commit | af94319d16e9fed27d4dba16508ed8a97f09964d (patch) | |
| tree | 6ded2b31639fc103ba2b8ba4bbbc4a06d39d6b78 | |
| parent | ea3257d77231624f1ceca96a5d261c419dfad752 (diff) | |
| parent | 115db91851ac6a86a862f6b44e27ac5508a0e90e (diff) | |
Merge "Add a debug mode that allows disabling notifications for all packages that aren't allowed."
6 files changed, 197 insertions, 25 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java index 1940cb2e170f..54f13808cdad 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java @@ -34,6 +34,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.collection.provider.DebugModeFilterProvider; import javax.inject.Inject; @@ -44,6 +45,7 @@ import javax.inject.Inject; @SysUISingleton public class NotificationFilter { + private final DebugModeFilterProvider mDebugNotificationFilter; private final StatusBarStateController mStatusBarStateController; private final KeyguardEnvironment mKeyguardEnvironment; private final ForegroundServiceController mForegroundServiceController; @@ -52,11 +54,13 @@ public class NotificationFilter { @Inject public NotificationFilter( + DebugModeFilterProvider debugNotificationFilter, StatusBarStateController statusBarStateController, KeyguardEnvironment keyguardEnvironment, ForegroundServiceController foregroundServiceController, NotificationLockscreenUserManager userManager, MediaFeatureFlag mediaFeatureFlag) { + mDebugNotificationFilter = debugNotificationFilter; mStatusBarStateController = statusBarStateController; mKeyguardEnvironment = keyguardEnvironment; mForegroundServiceController = foregroundServiceController; @@ -69,6 +73,10 @@ public class NotificationFilter { */ public boolean shouldFilterOut(NotificationEntry entry) { final StatusBarNotification sbn = entry.getSbn(); + if (mDebugNotificationFilter.shouldFilterOut(entry)) { + return true; + } + if (!(mKeyguardEnvironment.isDeviceProvisioned() || showNotificationEvenIfUnprovisioned(sbn))) { return true; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DebugModeCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DebugModeCoordinator.kt new file mode 100644 index 000000000000..df54ccd85e73 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DebugModeCoordinator.kt @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.collection.coordinator + +import com.android.systemui.statusbar.notification.collection.NotifPipeline +import com.android.systemui.statusbar.notification.collection.NotificationEntry +import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope +import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter +import com.android.systemui.statusbar.notification.collection.provider.DebugModeFilterProvider +import javax.inject.Inject + +/** A small coordinator which filters out notifications from non-allowed apps. */ +@CoordinatorScope +class DebugModeCoordinator @Inject constructor( + private val debugModeFilterProvider: DebugModeFilterProvider +) : Coordinator { + + override fun attach(pipeline: NotifPipeline) { + pipeline.addPreGroupFilter(preGroupFilter) + debugModeFilterProvider.registerInvalidationListener(preGroupFilter::invalidateList) + } + + private val preGroupFilter = object : NotifFilter("DebugModeCoordinator") { + override fun shouldFilterOut(entry: NotificationEntry, now: Long) = + debugModeFilterProvider.shouldFilterOut(entry) + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt index 02649bad33d3..d21d5a7a358f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt @@ -47,6 +47,7 @@ class NotifCoordinatorsImpl @Inject constructor( gutsCoordinator: GutsCoordinator, communalCoordinator: CommunalCoordinator, conversationCoordinator: ConversationCoordinator, + debugModeCoordinator: DebugModeCoordinator, groupCountCoordinator: GroupCountCoordinator, mediaCoordinator: MediaCoordinator, preparationCoordinator: PreparationCoordinator, @@ -86,6 +87,7 @@ class NotifCoordinatorsImpl @Inject constructor( mCoordinators.add(deviceProvisionedCoordinator) mCoordinators.add(bubbleCoordinator) mCoordinators.add(communalCoordinator) + mCoordinators.add(debugModeCoordinator) mCoordinators.add(conversationCoordinator) mCoordinators.add(groupCountCoordinator) mCoordinators.add(mediaCoordinator) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/DebugModeFilterProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/DebugModeFilterProvider.kt new file mode 100644 index 000000000000..d16d76ad2f9a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/DebugModeFilterProvider.kt @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.collection.provider + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.os.Build +import android.util.Log +import com.android.systemui.Dumpable +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dump.DumpManager +import com.android.systemui.statusbar.notification.collection.NotificationEntry +import com.android.systemui.util.Assert +import com.android.systemui.util.ListenerSet +import com.android.systemui.util.isNotEmpty +import java.io.FileDescriptor +import java.io.PrintWriter +import javax.inject.Inject + +/** + * A debug mode provider which is used by both the legacy and new notification pipelines to + * block unwanted notifications from appearing to the user, primarily for integration testing. + * + * The only configuration is a list of allowed packages. When this list is empty, the feature is + * disabled. When SystemUI starts up, this feature is disabled. + * + * To enabled filtering, provide the list of packages in a comma-separated list using the command: + * + * `$ adb shell am broadcast -a com.android.systemui.action.SET_NOTIF_DEBUG_MODE + * --esal allowed_packages <comma-separated-packages>` + * + * To disable filtering, send the action without a list: + * + * `$ adb shell am broadcast -a com.android.systemui.action.SET_NOTIF_DEBUG_MODE` + * + * NOTE: this feature only works on debug builds, and when the broadcaster is root. + */ +@SysUISingleton +class DebugModeFilterProvider @Inject constructor( + private val context: Context, + dumpManager: DumpManager +) : Dumpable { + private var allowedPackages: List<String> = emptyList() + private val listeners = ListenerSet<Runnable>() + + init { + dumpManager.registerDumpable(this) + } + + /** + * Register a runnable to be invoked when the allowed packages changes, which would mean the + * result of [shouldFilterOut] may have changed for some entries. + */ + fun registerInvalidationListener(listener: Runnable) { + Assert.isMainThread() + if (!Build.isDebuggable()) { + return + } + val needsInitialization = listeners.isEmpty() + listeners.addIfAbsent(listener) + if (needsInitialization) { + val filter = IntentFilter().apply { addAction(ACTION_SET_NOTIF_DEBUG_MODE) } + val permission = NOTIF_DEBUG_MODE_PERMISSION + context.registerReceiver(mReceiver, filter, permission, null) + Log.d(TAG, "Registered: $mReceiver") + } + } + + /** + * Determine if the given entry should be hidden from the user in debug mode. + * Will always return false in release. + */ + fun shouldFilterOut(entry: NotificationEntry): Boolean { + if (allowedPackages.isEmpty()) { + return false + } + return entry.sbn.packageName !in allowedPackages + } + + override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) { + pw.println("initialized: ${listeners.isNotEmpty()}") + pw.println("allowedPackages: ${allowedPackages.size}") + allowedPackages.forEachIndexed { i, pkg -> + pw.println(" [$i]: $pkg") + } + } + + private val mReceiver: BroadcastReceiver = object : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent?) { + val action = intent?.action + if (ACTION_SET_NOTIF_DEBUG_MODE == action) { + allowedPackages = intent.extras?.getStringArrayList(EXTRA_ALLOWED_PACKAGES) + ?: emptyList() + Log.d(TAG, "Updated allowedPackages: $allowedPackages") + listeners.forEach(Runnable::run) + } else { + Log.d(TAG, "Malformed intent: $intent") + } + } + } + + companion object { + private const val TAG = "DebugModeFilterProvider" + private const val ACTION_SET_NOTIF_DEBUG_MODE = + "com.android.systemui.action.SET_NOTIF_DEBUG_MODE" + private const val NOTIF_DEBUG_MODE_PERMISSION = + "com.android.systemui.permission.NOTIF_DEBUG_MODE" + private const val EXTRA_ALLOWED_PACKAGES = "allowed_packages" + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt index 84f09558e022..38f3c39b5b1a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt @@ -36,6 +36,7 @@ import com.android.systemui.statusbar.notification.collection.inflation.Notifica import com.android.systemui.statusbar.notification.collection.init.NotifPipelineInitializer import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection +import com.android.systemui.statusbar.notification.collection.provider.DebugModeFilterProvider import com.android.systemui.statusbar.notification.collection.render.NotifStackController import com.android.systemui.statusbar.notification.interruption.HeadsUpController import com.android.systemui.statusbar.notification.interruption.HeadsUpViewBinder @@ -65,6 +66,7 @@ class NotificationsControllerImpl @Inject constructor( private val notifPipelineFlags: NotifPipelineFlags, private val notificationListener: NotificationListener, private val entryManager: NotificationEntryManager, + private val debugModeFilterProvider: DebugModeFilterProvider, private val legacyRanker: NotificationRankingManager, private val commonNotifCollection: Lazy<CommonNotifCollection>, private val notifPipeline: Lazy<NotifPipeline>, @@ -134,6 +136,9 @@ class NotificationsControllerImpl @Inject constructor( headsUpController.attach(entryManager, headsUpManager) groupManagerLegacy.get().setHeadsUpManager(headsUpManager) groupAlertTransferHelper.setHeadsUpManager(headsUpManager) + debugModeFilterProvider.registerInvalidationListener { + entryManager.updateNotifications("debug mode filter changed") + } entryManager.initialize(notificationListener, legacyRanker) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java index b02a336b4396..ed8b532e7460 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java @@ -37,6 +37,7 @@ import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; +import androidx.annotation.NonNull; import androidx.test.annotation.UiThreadTest; import androidx.test.filters.SmallTest; @@ -50,6 +51,7 @@ import com.android.systemui.statusbar.notification.NotificationEntryManager.Keyg import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; +import com.android.systemui.statusbar.notification.collection.provider.DebugModeFilterProvider; import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationTestHelper; @@ -78,6 +80,8 @@ public class NotificationFilterTest extends SysuiTestCase { mock(StatusBarNotification.class); @Mock + DebugModeFilterProvider mDebugModeFilterProvider; + @Mock StatusBarStateController mStatusBarStateController; @Mock KeyguardEnvironment mEnvironment; @@ -132,7 +136,13 @@ public class NotificationFilterTest extends SysuiTestCase { mDependency, TestableLooper.get(this)); mRow = testHelper.createRow(); - mNotificationFilter = new NotificationFilter( + mNotificationFilter = newNotificationFilter(); + } + + @NonNull + private NotificationFilter newNotificationFilter() { + return new NotificationFilter( + mDebugModeFilterProvider, mStatusBarStateController, mEnvironment, mFsc, @@ -205,12 +215,7 @@ public class NotificationFilterTest extends SysuiTestCase { public void shouldFilterOtherNotificationWhenDisabled() { // GIVEN that the media feature is disabled when(mMediaFeatureFlag.getEnabled()).thenReturn(false); - NotificationFilter filter = new NotificationFilter( - mStatusBarStateController, - mEnvironment, - mFsc, - mUserManager, - mMediaFeatureFlag); + NotificationFilter filter = newNotificationFilter(); // WHEN the media filter is asked about an entry NotificationEntry otherEntry = new NotificationEntryBuilder().build(); final boolean shouldFilter = filter.shouldFilterOut(otherEntry); @@ -222,12 +227,7 @@ public class NotificationFilterTest extends SysuiTestCase { public void shouldFilterOtherNotificationWhenEnabled() { // GIVEN that the media feature is enabled when(mMediaFeatureFlag.getEnabled()).thenReturn(true); - NotificationFilter filter = new NotificationFilter( - mStatusBarStateController, - mEnvironment, - mFsc, - mUserManager, - mMediaFeatureFlag); + NotificationFilter filter = newNotificationFilter(); // WHEN the media filter is asked about an entry NotificationEntry otherEntry = new NotificationEntryBuilder().build(); final boolean shouldFilter = filter.shouldFilterOut(otherEntry); @@ -239,12 +239,7 @@ public class NotificationFilterTest extends SysuiTestCase { public void shouldFilterMediaNotificationWhenDisabled() { // GIVEN that the media feature is disabled when(mMediaFeatureFlag.getEnabled()).thenReturn(false); - NotificationFilter filter = new NotificationFilter( - mStatusBarStateController, - mEnvironment, - mFsc, - mUserManager, - mMediaFeatureFlag); + NotificationFilter filter = newNotificationFilter(); // WHEN the media filter is asked about a media entry final boolean shouldFilter = filter.shouldFilterOut(mMediaEntry); // THEN it shouldn't be filtered @@ -255,12 +250,7 @@ public class NotificationFilterTest extends SysuiTestCase { public void shouldFilterMediaNotificationWhenEnabled() { // GIVEN that the media feature is enabled when(mMediaFeatureFlag.getEnabled()).thenReturn(true); - NotificationFilter filter = new NotificationFilter( - mStatusBarStateController, - mEnvironment, - mFsc, - mUserManager, - mMediaFeatureFlag); + NotificationFilter filter = newNotificationFilter(); // WHEN the media filter is asked about a media entry final boolean shouldFilter = filter.shouldFilterOut(mMediaEntry); // THEN it should be filtered |