summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/AODPromotedNotificationsInteractorTest.kt147
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/AODPromotedNotificationInteractor.kt28
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/SensitiveNotificationProtectionInteractor.kt48
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorKosmos.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/AODPromotedNotificationInteractorKosmos.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/domain/interactor/SensitiveNotificationProtectionInteractorKosmos.kt25
6 files changed, 250 insertions, 6 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/AODPromotedNotificationsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/AODPromotedNotificationsInteractorTest.kt
new file mode 100644
index 000000000000..bad33a402ff7
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/AODPromotedNotificationsInteractorTest.kt
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2025 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.promoted.domain.interactor
+
+import android.app.Notification
+import android.content.applicationContext
+import android.platform.test.annotations.EnableFlags
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.dumpManager
+import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
+import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.runTest
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.android.systemui.statusbar.chips.notification.domain.interactor.statusBarNotificationChipsInteractor
+import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
+import com.android.systemui.statusbar.core.StatusBarRootModernization
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.buildPromotedOngoingEntry
+import com.android.systemui.statusbar.notification.domain.interactor.renderNotificationListInteractor
+import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi
+import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization
+import com.android.systemui.statusbar.policy.domain.interactor.sensitiveNotificationProtectionInteractor
+import com.android.systemui.statusbar.policy.mockSensitiveNotificationProtectionController
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@EnableFlags(
+ PromotedNotificationUi.FLAG_NAME,
+ StatusBarNotifChips.FLAG_NAME,
+ StatusBarChipsModernization.FLAG_NAME,
+ StatusBarRootModernization.FLAG_NAME,
+)
+class AODPromotedNotificationsInteractorTest : SysuiTestCase() {
+ private val kosmos = testKosmos().useUnconfinedTestDispatcher()
+
+ private val Kosmos.underTest by Fixture {
+ AODPromotedNotificationInteractor(
+ promotedNotificationsInteractor = promotedNotificationsInteractor,
+ keyguardInteractor = keyguardInteractor,
+ sensitiveNotificationProtectionInteractor = sensitiveNotificationProtectionInteractor,
+ dumpManager = dumpManager,
+ )
+ }
+
+ @Before
+ fun setUp() {
+ kosmos.statusBarNotificationChipsInteractor.start()
+ }
+
+ private fun Kosmos.buildPublicPrivatePromotedOngoing(): NotificationEntry =
+ buildPromotedOngoingEntry {
+ modifyNotification(applicationContext)
+ .setContentTitle("SENSITIVE")
+ .setPublicVersion(
+ Notification.Builder(applicationContext, "channel")
+ .setContentTitle("REDACTED")
+ .build()
+ )
+ }
+
+ @Test
+ fun content_sensitive_unlocked() =
+ kosmos.runTest {
+ // GIVEN a promoted entry
+ val ronEntry = buildPublicPrivatePromotedOngoing()
+
+ setKeyguardLocked(false)
+ setScreenSharingProtectionActive(false)
+
+ renderNotificationListInteractor.setRenderedList(listOf(ronEntry))
+
+ // THEN aod content is sensitive
+ val content by collectLastValue(underTest.content)
+ assertThat(content?.title).isEqualTo("SENSITIVE")
+ }
+
+ @Test
+ fun content_sensitive_locked() =
+ kosmos.runTest {
+ // GIVEN a promoted entry
+ val ronEntry = buildPublicPrivatePromotedOngoing()
+
+ setKeyguardLocked(true)
+ setScreenSharingProtectionActive(false)
+
+ renderNotificationListInteractor.setRenderedList(listOf(ronEntry))
+
+ // THEN aod content is sensitive
+ val content by collectLastValue(underTest.content)
+ assertThat(content).isNotNull()
+ assertThat(content?.title).isNull() // SOON: .isEqualTo("REDACTED")
+ }
+
+ @Test
+ fun content_sensitive_unlocked_screensharing() =
+ kosmos.runTest {
+ // GIVEN a promoted entry
+ val ronEntry = buildPublicPrivatePromotedOngoing()
+
+ setKeyguardLocked(false)
+ setScreenSharingProtectionActive(true)
+
+ renderNotificationListInteractor.setRenderedList(listOf(ronEntry))
+
+ // THEN aod content is sensitive
+ val content by collectLastValue(underTest.content)
+ assertThat(content).isNotNull()
+ assertThat(content?.title).isNull() // SOON: .isEqualTo("REDACTED")
+ }
+
+ private fun Kosmos.setKeyguardLocked(locked: Boolean) {
+ fakeKeyguardRepository.setKeyguardDismissible(!locked)
+ }
+
+ private fun Kosmos.setScreenSharingProtectionActive(active: Boolean) {
+ whenever(mockSensitiveNotificationProtectionController.isSensitiveStateActive)
+ .thenReturn(active)
+ whenever(mockSensitiveNotificationProtectionController.shouldProtectNotification(any()))
+ .thenReturn(active)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/AODPromotedNotificationInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/AODPromotedNotificationInteractor.kt
index d9778bdde0a5..fa9a7b9b524e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/AODPromotedNotificationInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/AODPromotedNotificationInteractor.kt
@@ -18,10 +18,13 @@ package com.android.systemui.statusbar.notification.promoted.domain.interactor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
+import com.android.systemui.statusbar.policy.domain.interactor.SensitiveNotificationProtectionInteractor
import com.android.systemui.util.kotlin.FlowDumperImpl
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
@@ -30,14 +33,31 @@ class AODPromotedNotificationInteractor
@Inject
constructor(
promotedNotificationsInteractor: PromotedNotificationsInteractor,
+ keyguardInteractor: KeyguardInteractor,
+ sensitiveNotificationProtectionInteractor: SensitiveNotificationProtectionInteractor,
dumpManager: DumpManager,
) : FlowDumperImpl(dumpManager) {
+
+ /**
+ * Whether the system is unlocked and not screensharing such that private notification content
+ * is allowed to show on the aod
+ */
+ private val canShowPrivateNotificationContent: Flow<Boolean> =
+ combine(
+ keyguardInteractor.isKeyguardDismissible,
+ sensitiveNotificationProtectionInteractor.isSensitiveStateActive,
+ ) { isKeyguardDismissible, isSensitive ->
+ isKeyguardDismissible && !isSensitive
+ }
+
/** The content to show as the promoted notification on AOD */
val content: Flow<PromotedNotificationContentModel?> =
- promotedNotificationsInteractor.aodPromotedNotification
- .map {
- // TODO(b/400991304): show the private version when unlocked
- it?.publicVersion
+ combine(
+ promotedNotificationsInteractor.aodPromotedNotification,
+ canShowPrivateNotificationContent,
+ ) { promotedContent, showPrivateContent ->
+ if (showPrivateContent) promotedContent?.privateVersion
+ else promotedContent?.publicVersion
}
.distinctUntilNewInstance()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/SensitiveNotificationProtectionInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/SensitiveNotificationProtectionInteractor.kt
new file mode 100644
index 000000000000..0a6a4c2e44e7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/SensitiveNotificationProtectionInteractor.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2025 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.policy.domain.interactor
+
+import com.android.server.notification.Flags
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.policy.SensitiveNotificationProtectionController
+import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
+import javax.inject.Inject
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOf
+
+/** A interactor which provides the current sensitive notification protections status */
+@SysUISingleton
+class SensitiveNotificationProtectionInteractor
+@Inject
+constructor(private val controller: SensitiveNotificationProtectionController) {
+
+ /** sensitive notification protections status */
+ val isSensitiveStateActive: Flow<Boolean> =
+ if (Flags.screenshareNotificationHiding()) {
+ conflatedCallbackFlow {
+ val listener = Runnable { trySend(controller.isSensitiveStateActive) }
+ controller.registerSensitiveStateListener(listener)
+ trySend(controller.isSensitiveStateActive)
+ awaitClose { controller.unregisterSensitiveStateListener(listener) }
+ }
+ .distinctUntilChanged()
+ } else {
+ flowOf(false)
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorKosmos.kt
index c4542c4e709b..00b26c944b90 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorKosmos.kt
@@ -19,7 +19,7 @@ package com.android.systemui.statusbar.notification.promoted
import android.app.Notification
import android.content.applicationContext
import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTION_TYPE_NONE
+import com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTION_TYPE_PUBLIC
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.row.RowImageInflater
import com.android.systemui.statusbar.notification.row.shared.skeletonImageTransform
@@ -40,7 +40,7 @@ fun Kosmos.setPromotedContent(entry: NotificationEntry) {
promotedNotificationContentExtractor.extractContent(
entry,
Notification.Builder.recoverBuilder(applicationContext, entry.sbn.notification),
- REDACTION_TYPE_NONE,
+ REDACTION_TYPE_PUBLIC,
RowImageInflater.newInstance(previousIndex = null, reinflating = false)
.useForContentModel(),
)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/AODPromotedNotificationInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/AODPromotedNotificationInteractorKosmos.kt
index fcd484353011..ea459a95728a 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/AODPromotedNotificationInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/AODPromotedNotificationInteractorKosmos.kt
@@ -17,12 +17,16 @@
package com.android.systemui.statusbar.notification.promoted.domain.interactor
import com.android.systemui.dump.dumpManager
+import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.statusbar.policy.domain.interactor.sensitiveNotificationProtectionInteractor
val Kosmos.aodPromotedNotificationInteractor by
Kosmos.Fixture {
AODPromotedNotificationInteractor(
promotedNotificationsInteractor = promotedNotificationsInteractor,
+ keyguardInteractor = keyguardInteractor,
+ sensitiveNotificationProtectionInteractor = sensitiveNotificationProtectionInteractor,
dumpManager = dumpManager,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/domain/interactor/SensitiveNotificationProtectionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/domain/interactor/SensitiveNotificationProtectionInteractorKosmos.kt
new file mode 100644
index 000000000000..ba4410b51b75
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/domain/interactor/SensitiveNotificationProtectionInteractorKosmos.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2025 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.policy.domain.interactor
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.statusbar.policy.sensitiveNotificationProtectionController
+
+var Kosmos.sensitiveNotificationProtectionInteractor: SensitiveNotificationProtectionInteractor by
+ Kosmos.Fixture {
+ SensitiveNotificationProtectionInteractor(sensitiveNotificationProtectionController)
+ }