Remove access to pipeline outputs from NotifPipeline.
* Add NotifLiveDataStore which provides access to and observation of pipeline outputs. * Adds NotifLiveData which is written to by each of the two pipelines, only when active. * Replaces an instance of NotifPipeline.getShadeListCount() from NotificationsControllerImpl. * Replaces an entry listener in LightsOutNotifController with an observer on this data store. Fixes: 205696003 Test: atest NotifLiveDataImplTest NotificationListenerTest DataStoreCoordinatorTest LightsOutNotifControllerTest Change-Id: I3f190b601bf0f71cb03d155d240268d06049bbf7
This commit is contained in:
@@ -45,6 +45,7 @@ import com.android.systemui.statusbar.NotificationPresenter;
|
||||
import com.android.systemui.statusbar.NotificationRemoteInputManager;
|
||||
import com.android.systemui.statusbar.NotificationRemoveInterceptor;
|
||||
import com.android.systemui.statusbar.NotificationUiAdjustment;
|
||||
import com.android.systemui.statusbar.notification.collection.NotifLiveDataStoreImpl;
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
|
||||
import com.android.systemui.statusbar.notification.collection.legacy.LegacyNotificationRanker;
|
||||
@@ -107,6 +108,7 @@ public class NotificationEntryManager implements
|
||||
private final LeakDetector mLeakDetector;
|
||||
private final ForegroundServiceDismissalFeatureController mFgsFeatureController;
|
||||
private final IStatusBarService mStatusBarService;
|
||||
private final NotifLiveDataStoreImpl mNotifLiveDataStore;
|
||||
private final DumpManager mDumpManager;
|
||||
|
||||
private final Set<NotificationEntry> mAllNotifications = new ArraySet<>();
|
||||
@@ -154,6 +156,7 @@ public class NotificationEntryManager implements
|
||||
LeakDetector leakDetector,
|
||||
ForegroundServiceDismissalFeatureController fgsFeatureController,
|
||||
IStatusBarService statusBarService,
|
||||
NotifLiveDataStoreImpl notifLiveDataStore,
|
||||
DumpManager dumpManager
|
||||
) {
|
||||
mLogger = logger;
|
||||
@@ -164,6 +167,7 @@ public class NotificationEntryManager implements
|
||||
mLeakDetector = leakDetector;
|
||||
mFgsFeatureController = fgsFeatureController;
|
||||
mStatusBarService = statusBarService;
|
||||
mNotifLiveDataStore = notifLiveDataStore;
|
||||
mDumpManager = dumpManager;
|
||||
}
|
||||
|
||||
@@ -725,9 +729,10 @@ public class NotificationEntryManager implements
|
||||
return;
|
||||
}
|
||||
reapplyFilterAndSort(reason);
|
||||
if (mPresenter != null && !mNotifPipelineFlags.isNewPipelineEnabled()) {
|
||||
if (mPresenter != null) {
|
||||
mPresenter.updateNotificationViews(reason);
|
||||
}
|
||||
mNotifLiveDataStore.setActiveNotifList(getVisibleNotifications());
|
||||
}
|
||||
|
||||
public void updateNotificationRanking(RankingMap rankingMap) {
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import androidx.lifecycle.Observer
|
||||
|
||||
/**
|
||||
* An object which provides pieces of information about the notification shade.
|
||||
*
|
||||
* Note that individual fields of this object are updated together before synchronous observers are
|
||||
* notified, so synchronous observers of two fields can be assured that they will see consistent
|
||||
* results: e.g. if [hasActiveNotifs] is false then [activeNotifList] will be empty, and vice versa.
|
||||
*
|
||||
* This interface is read-only.
|
||||
*/
|
||||
interface NotifLiveDataStore {
|
||||
val hasActiveNotifs: NotifLiveData<Boolean>
|
||||
val activeNotifCount: NotifLiveData<Int>
|
||||
val activeNotifList: NotifLiveData<List<NotificationEntry>>
|
||||
}
|
||||
|
||||
/**
|
||||
* An individual value which can be accessed directly, or observed for changes either synchronously
|
||||
* or asynchronously.
|
||||
*
|
||||
* This interface is read-only.
|
||||
*/
|
||||
interface NotifLiveData<T> {
|
||||
/** Access the current value */
|
||||
val value: T
|
||||
/** Add an observer which will be invoked synchronously when the value is changed. */
|
||||
fun addSyncObserver(observer: Observer<T>)
|
||||
/** Add an observer which will be invoked asynchronously after the value has changed */
|
||||
fun addAsyncObserver(observer: Observer<T>)
|
||||
/** Remove an observer previously added with [addSyncObserver] or [addAsyncObserver]. */
|
||||
fun removeObserver(observer: Observer<T>)
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import androidx.lifecycle.Observer
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.dagger.qualifiers.Main
|
||||
import com.android.systemui.util.Assert
|
||||
import com.android.systemui.util.ListenerSet
|
||||
import com.android.systemui.util.isNotEmpty
|
||||
import com.android.systemui.util.traceSection
|
||||
import java.util.Collections.unmodifiableList
|
||||
import java.util.concurrent.Executor
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
import javax.inject.Inject
|
||||
|
||||
/** Writeable implementation of [NotifLiveDataStore] */
|
||||
@SysUISingleton
|
||||
class NotifLiveDataStoreImpl @Inject constructor(
|
||||
@Main private val mainExecutor: Executor
|
||||
) : NotifLiveDataStore {
|
||||
private val hasActiveNotifsPrivate = NotifLiveDataImpl(
|
||||
name = "hasActiveNotifs",
|
||||
initialValue = false,
|
||||
mainExecutor
|
||||
)
|
||||
private val activeNotifCountPrivate = NotifLiveDataImpl(
|
||||
name = "activeNotifCount",
|
||||
initialValue = 0,
|
||||
mainExecutor
|
||||
)
|
||||
private val activeNotifListPrivate = NotifLiveDataImpl(
|
||||
name = "activeNotifList",
|
||||
initialValue = listOf<NotificationEntry>(),
|
||||
mainExecutor
|
||||
)
|
||||
|
||||
override val hasActiveNotifs: NotifLiveData<Boolean> = hasActiveNotifsPrivate
|
||||
override val activeNotifCount: NotifLiveData<Int> = activeNotifCountPrivate
|
||||
override val activeNotifList: NotifLiveData<List<NotificationEntry>> = activeNotifListPrivate
|
||||
|
||||
/** Set the latest flattened list of notification entries. */
|
||||
fun setActiveNotifList(flatEntryList: List<NotificationEntry>) {
|
||||
traceSection("NotifLiveDataStore.setActiveNotifList") {
|
||||
Assert.isMainThread()
|
||||
val unmodifiableCopy = unmodifiableList(flatEntryList.toList())
|
||||
// This ensures we set all values before dispatching to any observers
|
||||
listOf(
|
||||
activeNotifListPrivate.setValueAndProvideDispatcher(unmodifiableCopy),
|
||||
activeNotifCountPrivate.setValueAndProvideDispatcher(unmodifiableCopy.size),
|
||||
hasActiveNotifsPrivate.setValueAndProvideDispatcher(unmodifiableCopy.isNotEmpty())
|
||||
).forEach { dispatcher -> dispatcher.invoke() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Read-write implementation of [NotifLiveData] */
|
||||
class NotifLiveDataImpl<T>(
|
||||
private val name: String,
|
||||
initialValue: T,
|
||||
@Main private val mainExecutor: Executor
|
||||
) : NotifLiveData<T> {
|
||||
private val syncObservers = ListenerSet<Observer<T>>()
|
||||
private val asyncObservers = ListenerSet<Observer<T>>()
|
||||
private val atomicValue = AtomicReference(initialValue)
|
||||
private var lastAsyncValue: T? = null
|
||||
|
||||
private fun dispatchToAsyncObservers() {
|
||||
val value = atomicValue.get()
|
||||
if (lastAsyncValue != value) {
|
||||
lastAsyncValue = value
|
||||
traceSection("NotifLiveData($name).dispatchToAsyncObservers") {
|
||||
asyncObservers.forEach { it.onChanged(value) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Access or set the current value.
|
||||
*
|
||||
* When setting, sync observers will be dispatched synchronously, and a task will be posted to
|
||||
* dispatch the value to async observers.
|
||||
*/
|
||||
override var value: T
|
||||
get() = atomicValue.get()
|
||||
set(value) = setValueAndProvideDispatcher(value).invoke()
|
||||
|
||||
/**
|
||||
* Set the value, and return a function that when invoked will dispatch to the observers.
|
||||
*
|
||||
* This is intended to allow multiple instances with related data to be updated together and
|
||||
* have their dispatchers invoked after all data has been updated.
|
||||
*/
|
||||
fun setValueAndProvideDispatcher(value: T): () -> Unit {
|
||||
val oldValue = atomicValue.getAndSet(value)
|
||||
if (oldValue != value) {
|
||||
return {
|
||||
if (syncObservers.isNotEmpty()) {
|
||||
traceSection("NotifLiveData($name).dispatchToSyncObservers") {
|
||||
syncObservers.forEach { it.onChanged(value) }
|
||||
}
|
||||
}
|
||||
if (asyncObservers.isNotEmpty()) {
|
||||
mainExecutor.execute(::dispatchToAsyncObservers)
|
||||
}
|
||||
}
|
||||
}
|
||||
return {}
|
||||
}
|
||||
|
||||
override fun addSyncObserver(observer: Observer<T>) {
|
||||
syncObservers.addIfAbsent(observer)
|
||||
}
|
||||
|
||||
override fun addAsyncObserver(observer: Observer<T>) {
|
||||
asyncObservers.addIfAbsent(observer)
|
||||
}
|
||||
|
||||
override fun removeObserver(observer: Observer<T>) {
|
||||
syncObservers.remove(observer)
|
||||
asyncObservers.remove(observer)
|
||||
}
|
||||
}
|
||||
@@ -245,36 +245,4 @@ class NotifPipeline @Inject constructor(
|
||||
fun getInternalNotifUpdater(name: String?): InternalNotifUpdater {
|
||||
return mNotifCollection.getInternalNotifUpdater(name)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a read-only view in to the current shade list, i.e. the list of notifications that
|
||||
* are currently present in the shade.
|
||||
* @throws IllegalStateException if called during pipeline execution.
|
||||
*/
|
||||
val shadeList: List<ListEntry>
|
||||
get() = mShadeListBuilder.shadeList
|
||||
|
||||
/**
|
||||
* Constructs a flattened representation of the notification tree, where each group will have
|
||||
* the summary (if present) followed by the children.
|
||||
* @throws IllegalStateException if called during pipeline execution.
|
||||
*/
|
||||
fun getFlatShadeList(): List<NotificationEntry> = shadeList.flatMap { entry ->
|
||||
when (entry) {
|
||||
is NotificationEntry -> sequenceOf(entry)
|
||||
is GroupEntry -> sequenceOf(entry.summary).filterNotNull() + entry.children
|
||||
else -> throw RuntimeException("Unexpected entry $entry")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of notifications currently shown in the shade. This includes all
|
||||
* children and summary notifications.
|
||||
* @throws IllegalStateException if called during pipeline execution.
|
||||
*/
|
||||
fun getShadeListCount(): Int = shadeList.sumOf { entry ->
|
||||
// include the summary in the count
|
||||
if (entry is GroupEntry) 1 + entry.children.size
|
||||
else 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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.GroupEntry
|
||||
import com.android.systemui.statusbar.notification.collection.ListEntry
|
||||
import com.android.systemui.statusbar.notification.collection.NotifLiveDataStoreImpl
|
||||
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.render.requireSummary
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* A small coordinator which updates the notif stack (the view layer which holds notifications)
|
||||
* with high-level data after the stack is populated with the final entries.
|
||||
*/
|
||||
@CoordinatorScope
|
||||
class DataStoreCoordinator @Inject internal constructor(
|
||||
private val notifLiveDataStoreImpl: NotifLiveDataStoreImpl
|
||||
) : Coordinator {
|
||||
|
||||
override fun attach(pipeline: NotifPipeline) {
|
||||
pipeline.addOnAfterRenderListListener { entries, _ -> onAfterRenderList(entries) }
|
||||
}
|
||||
|
||||
fun onAfterRenderList(entries: List<ListEntry>) {
|
||||
val flatEntryList = flattenedEntryList(entries)
|
||||
notifLiveDataStoreImpl.setActiveNotifList(flatEntryList)
|
||||
}
|
||||
|
||||
private fun flattenedEntryList(entries: List<ListEntry>) =
|
||||
mutableListOf<NotificationEntry>().also { list ->
|
||||
entries.forEach { entry ->
|
||||
when (entry) {
|
||||
is NotificationEntry -> list.add(entry)
|
||||
is GroupEntry -> {
|
||||
list.add(entry.requireSummary)
|
||||
list.addAll(entry.children)
|
||||
}
|
||||
else -> error("Unexpected entry $entry")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,7 @@ interface NotifCoordinators : Coordinator, Dumpable
|
||||
class NotifCoordinatorsImpl @Inject constructor(
|
||||
dumpManager: DumpManager,
|
||||
notifPipelineFlags: NotifPipelineFlags,
|
||||
dataStoreCoordinator: DataStoreCoordinator,
|
||||
hideLocallyDismissedNotifsCoordinator: HideLocallyDismissedNotifsCoordinator,
|
||||
hideNotifsForOtherUsersCoordinator: HideNotifsForOtherUsersCoordinator,
|
||||
keyguardCoordinator: KeyguardCoordinator,
|
||||
@@ -44,10 +45,11 @@ class NotifCoordinatorsImpl @Inject constructor(
|
||||
bubbleCoordinator: BubbleCoordinator,
|
||||
headsUpCoordinator: HeadsUpCoordinator,
|
||||
gutsCoordinator: GutsCoordinator,
|
||||
communalCoordinator: CommunalCoordinator,
|
||||
conversationCoordinator: ConversationCoordinator,
|
||||
preparationCoordinator: PreparationCoordinator,
|
||||
groupCountCoordinator: GroupCountCoordinator,
|
||||
mediaCoordinator: MediaCoordinator,
|
||||
preparationCoordinator: PreparationCoordinator,
|
||||
remoteInputCoordinator: RemoteInputCoordinator,
|
||||
rowAppearanceCoordinator: RowAppearanceCoordinator,
|
||||
stackCoordinator: StackCoordinator,
|
||||
@@ -55,7 +57,6 @@ class NotifCoordinatorsImpl @Inject constructor(
|
||||
smartspaceDedupingCoordinator: SmartspaceDedupingCoordinator,
|
||||
viewConfigCoordinator: ViewConfigCoordinator,
|
||||
visualStabilityCoordinator: VisualStabilityCoordinator,
|
||||
communalCoordinator: CommunalCoordinator,
|
||||
sensitiveContentCoordinator: SensitiveContentCoordinator
|
||||
) : NotifCoordinators {
|
||||
|
||||
@@ -67,6 +68,16 @@ class NotifCoordinatorsImpl @Inject constructor(
|
||||
*/
|
||||
init {
|
||||
dumpManager.registerDumpable(TAG, this)
|
||||
|
||||
// TODO(b/208866714): formalize the system by which some coordinators may be required by the
|
||||
// pipeline, such as this DataStoreCoordinator which cannot be removed, as it's a critical
|
||||
// glue between the pipeline and parts of SystemUI which depend on pipeline output via the
|
||||
// NotifLiveDataStore.
|
||||
if (notifPipelineFlags.isNewPipelineEnabled()) {
|
||||
mCoordinators.add(dataStoreCoordinator)
|
||||
}
|
||||
|
||||
// Attach normal coordinators.
|
||||
mCoordinators.add(hideLocallyDismissedNotifsCoordinator)
|
||||
mCoordinators.add(hideNotifsForOtherUsersCoordinator)
|
||||
mCoordinators.add(keyguardCoordinator)
|
||||
@@ -74,6 +85,7 @@ class NotifCoordinatorsImpl @Inject constructor(
|
||||
mCoordinators.add(appOpsCoordinator)
|
||||
mCoordinators.add(deviceProvisionedCoordinator)
|
||||
mCoordinators.add(bubbleCoordinator)
|
||||
mCoordinators.add(communalCoordinator)
|
||||
mCoordinators.add(conversationCoordinator)
|
||||
mCoordinators.add(groupCountCoordinator)
|
||||
mCoordinators.add(mediaCoordinator)
|
||||
@@ -83,7 +95,6 @@ class NotifCoordinatorsImpl @Inject constructor(
|
||||
mCoordinators.add(shadeEventCoordinator)
|
||||
mCoordinators.add(viewConfigCoordinator)
|
||||
mCoordinators.add(visualStabilityCoordinator)
|
||||
mCoordinators.add(communalCoordinator)
|
||||
mCoordinators.add(sensitiveContentCoordinator)
|
||||
if (notifPipelineFlags.isSmartspaceDedupingEnabled()) {
|
||||
mCoordinators.add(smartspaceDedupingCoordinator)
|
||||
|
||||
@@ -19,8 +19,8 @@ package com.android.systemui.statusbar.notification.collection.coordinator
|
||||
import com.android.systemui.statusbar.notification.collection.ListEntry
|
||||
import com.android.systemui.statusbar.notification.collection.NotifPipeline
|
||||
import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
|
||||
import com.android.systemui.statusbar.notification.collection.render.NotifStats
|
||||
import com.android.systemui.statusbar.notification.collection.render.NotifStackController
|
||||
import com.android.systemui.statusbar.notification.collection.render.NotifStats
|
||||
import com.android.systemui.statusbar.notification.stack.BUCKET_SILENT
|
||||
import com.android.systemui.statusbar.phone.NotificationIconAreaController
|
||||
import javax.inject.Inject
|
||||
@@ -49,10 +49,12 @@ class StackCoordinator @Inject internal constructor(
|
||||
var hasNonClearableSilentNotifs = false
|
||||
var hasClearableSilentNotifs = false
|
||||
entries.forEach {
|
||||
val isSilent = it.section!!.bucket == BUCKET_SILENT
|
||||
val section = checkNotNull(it.section) { "Null section for ${it.key}" }
|
||||
val entry = checkNotNull(it.representativeEntry) { "Null notif entry for ${it.key}" }
|
||||
val isSilent = section.bucket == BUCKET_SILENT
|
||||
// NOTE: NotificationEntry.isClearable will internally check group children to ensure
|
||||
// the group itself definitively clearable.
|
||||
val isClearable = it.representativeEntry!!.isClearable
|
||||
val isClearable = entry.isClearable
|
||||
when {
|
||||
isSilent && isClearable -> hasClearableSilentNotifs = true
|
||||
isSilent && !isClearable -> hasNonClearableSilentNotifs = true
|
||||
@@ -60,13 +62,12 @@ class StackCoordinator @Inject internal constructor(
|
||||
!isSilent && !isClearable -> hasNonClearableAlertingNotifs = true
|
||||
}
|
||||
}
|
||||
val stats = NotifStats(
|
||||
return NotifStats(
|
||||
numActiveNotifs = entries.size,
|
||||
hasNonClearableAlertingNotifs = hasNonClearableAlertingNotifs,
|
||||
hasClearableAlertingNotifs = hasClearableAlertingNotifs,
|
||||
hasNonClearableSilentNotifs = hasNonClearableSilentNotifs,
|
||||
hasClearableSilentNotifs = hasClearableSilentNotifs
|
||||
)
|
||||
return stats
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* 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.legacy
|
||||
|
||||
import com.android.internal.statusbar.NotificationVisibility
|
||||
import com.android.systemui.statusbar.notification.NotificationEntryManager
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry
|
||||
import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider
|
||||
import com.android.systemui.statusbar.notification.logging.NotificationLogger
|
||||
import javax.inject.Inject
|
||||
|
||||
/** Legacy pipeline implementation for getting [NotificationVisibility]. */
|
||||
class LegacyNotificationVisibilityProvider @Inject constructor(
|
||||
private val notifEntryManager: NotificationEntryManager
|
||||
) : NotificationVisibilityProvider {
|
||||
override fun obtain(entry: NotificationEntry, visible: Boolean): NotificationVisibility {
|
||||
val count: Int = notifEntryManager.activeNotificationsCount
|
||||
val rank = entry.ranking.rank
|
||||
val hasRow = entry.row != null
|
||||
val location = NotificationLogger.getNotificationLocation(entry)
|
||||
return NotificationVisibility.obtain(entry.key, rank, count, visible && hasRow, location)
|
||||
}
|
||||
|
||||
override fun obtain(key: String, visible: Boolean): NotificationVisibility {
|
||||
val entry: NotificationEntry? = notifEntryManager.getActiveNotificationUnfiltered(key)
|
||||
val count: Int = notifEntryManager.activeNotificationsCount
|
||||
val rank = entry?.ranking?.rank ?: -1
|
||||
val hasRow = entry?.row != null
|
||||
val location = NotificationLogger.getNotificationLocation(entry)
|
||||
return NotificationVisibility.obtain(key, rank, count, visible && hasRow, location)
|
||||
}
|
||||
|
||||
override fun getLocation(key: String): NotificationVisibility.NotificationLocation =
|
||||
NotificationLogger.getNotificationLocation(
|
||||
notifEntryManager.getActiveNotificationUnfiltered(key))
|
||||
}
|
||||
@@ -14,20 +14,24 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.statusbar.notification.collection.render
|
||||
package com.android.systemui.statusbar.notification.collection.provider
|
||||
|
||||
import com.android.internal.statusbar.NotificationVisibility
|
||||
import com.android.systemui.statusbar.notification.collection.NotifPipeline
|
||||
import com.android.systemui.statusbar.notification.collection.NotifLiveDataStore
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry
|
||||
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
|
||||
import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider
|
||||
import com.android.systemui.statusbar.notification.logging.NotificationLogger
|
||||
import javax.inject.Inject
|
||||
|
||||
/** New pipeline implementation for getting [NotificationVisibility]. */
|
||||
/** pipeline-agnostic implementation for getting [NotificationVisibility]. */
|
||||
class NotificationVisibilityProviderImpl @Inject constructor(
|
||||
private val notifPipeline: NotifPipeline
|
||||
private val notifDataStore: NotifLiveDataStore,
|
||||
private val notifCollection: CommonNotifCollection
|
||||
) : NotificationVisibilityProvider {
|
||||
|
||||
override fun obtain(entry: NotificationEntry, visible: Boolean): NotificationVisibility {
|
||||
val count: Int = notifPipeline.getShadeListCount()
|
||||
val count: Int = getCount()
|
||||
val rank = entry.ranking.rank
|
||||
val hasRow = entry.row != null
|
||||
val location = NotificationLogger.getNotificationLocation(entry)
|
||||
@@ -35,9 +39,11 @@ class NotificationVisibilityProviderImpl @Inject constructor(
|
||||
}
|
||||
|
||||
override fun obtain(key: String, visible: Boolean): NotificationVisibility =
|
||||
notifPipeline.getEntry(key)?.let { return obtain(it, visible) }
|
||||
?: NotificationVisibility.obtain(key, -1, notifPipeline.getShadeListCount(), false)
|
||||
notifCollection.getEntry(key)?.let { return obtain(it, visible) }
|
||||
?: NotificationVisibility.obtain(key, -1, getCount(), false)
|
||||
|
||||
override fun getLocation(key: String): NotificationVisibility.NotificationLocation =
|
||||
NotificationLogger.getNotificationLocation(notifPipeline.getEntry(key))
|
||||
NotificationLogger.getNotificationLocation(notifCollection.getEntry(key))
|
||||
|
||||
private fun getCount() = notifDataStore.activeNotifCount.value
|
||||
}
|
||||
@@ -44,6 +44,8 @@ import com.android.systemui.statusbar.notification.NotificationEntryManager;
|
||||
import com.android.systemui.statusbar.notification.NotificationEntryManagerLogger;
|
||||
import com.android.systemui.statusbar.notification.collection.NotifCollection;
|
||||
import com.android.systemui.statusbar.notification.collection.NotifInflaterImpl;
|
||||
import com.android.systemui.statusbar.notification.collection.NotifLiveDataStore;
|
||||
import com.android.systemui.statusbar.notification.collection.NotifLiveDataStoreImpl;
|
||||
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
|
||||
import com.android.systemui.statusbar.notification.collection.coordinator.ShadeEventCoordinator;
|
||||
import com.android.systemui.statusbar.notification.collection.coordinator.VisualStabilityCoordinator;
|
||||
@@ -52,12 +54,12 @@ import com.android.systemui.statusbar.notification.collection.inflation.NotifInf
|
||||
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
|
||||
import com.android.systemui.statusbar.notification.collection.inflation.OnUserInteractionCallbackImpl;
|
||||
import com.android.systemui.statusbar.notification.collection.legacy.LegacyNotificationPresenterExtensions;
|
||||
import com.android.systemui.statusbar.notification.collection.legacy.LegacyNotificationVisibilityProvider;
|
||||
import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
|
||||
import com.android.systemui.statusbar.notification.collection.legacy.OnUserInteractionCallbackImplLegacy;
|
||||
import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
|
||||
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
|
||||
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
|
||||
import com.android.systemui.statusbar.notification.collection.provider.NotificationVisibilityProviderImpl;
|
||||
import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
|
||||
import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManagerImpl;
|
||||
import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
|
||||
@@ -65,7 +67,6 @@ import com.android.systemui.statusbar.notification.collection.render.GroupMember
|
||||
import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewManager;
|
||||
import com.android.systemui.statusbar.notification.collection.render.NotifShadeEventSource;
|
||||
import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
|
||||
import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProviderImpl;
|
||||
import com.android.systemui.statusbar.notification.init.NotificationsController;
|
||||
import com.android.systemui.statusbar.notification.init.NotificationsControllerImpl;
|
||||
import com.android.systemui.statusbar.notification.init.NotificationsControllerStub;
|
||||
@@ -122,6 +123,7 @@ public interface NotificationsModule {
|
||||
LeakDetector leakDetector,
|
||||
ForegroundServiceDismissalFeatureController fgsFeatureController,
|
||||
IStatusBarService statusBarService,
|
||||
NotifLiveDataStoreImpl notifLiveDataStore,
|
||||
DumpManager dumpManager) {
|
||||
return new NotificationEntryManager(
|
||||
logger,
|
||||
@@ -132,6 +134,7 @@ public interface NotificationsModule {
|
||||
leakDetector,
|
||||
fgsFeatureController,
|
||||
statusBarService,
|
||||
notifLiveDataStore,
|
||||
dumpManager);
|
||||
}
|
||||
|
||||
@@ -212,6 +215,7 @@ public interface NotificationsModule {
|
||||
NotificationListener notificationListener,
|
||||
@UiBackground Executor uiBgExecutor,
|
||||
NotifPipelineFlags notifPipelineFlags,
|
||||
NotifLiveDataStore notifLiveDataStore,
|
||||
NotificationVisibilityProvider visibilityProvider,
|
||||
NotificationEntryManager entryManager,
|
||||
NotifPipeline notifPipeline,
|
||||
@@ -222,6 +226,7 @@ public interface NotificationsModule {
|
||||
notificationListener,
|
||||
uiBgExecutor,
|
||||
notifPipelineFlags,
|
||||
notifLiveDataStore,
|
||||
visibilityProvider,
|
||||
entryManager,
|
||||
notifPipeline,
|
||||
@@ -290,16 +295,10 @@ public interface NotificationsModule {
|
||||
/**
|
||||
* Provide the object which can be used to obtain NotificationVisibility objects.
|
||||
*/
|
||||
@Provides
|
||||
@Binds
|
||||
@SysUISingleton
|
||||
static NotificationVisibilityProvider provideNotificationVisibilityProvider(
|
||||
NotifPipelineFlags notifPipelineFlags,
|
||||
Lazy<NotificationVisibilityProviderImpl> newProvider,
|
||||
Lazy<LegacyNotificationVisibilityProvider> legacyProvider) {
|
||||
return notifPipelineFlags.isNewPipelineEnabled()
|
||||
? newProvider.get()
|
||||
: legacyProvider.get();
|
||||
}
|
||||
NotificationVisibilityProvider provideNotificationVisibilityProvider(
|
||||
NotificationVisibilityProviderImpl newProvider);
|
||||
|
||||
/**
|
||||
* Provide the active implementation for presenting notifications.
|
||||
@@ -356,4 +355,8 @@ public interface NotificationsModule {
|
||||
/** */
|
||||
@Binds
|
||||
NotifInflater bindNotifInflater(NotifInflaterImpl notifInflaterImpl);
|
||||
|
||||
/** */
|
||||
@Binds
|
||||
NotifLiveDataStore bindNotifLiveDataStore(NotifLiveDataStoreImpl notifLiveDataStoreImpl);
|
||||
}
|
||||
|
||||
@@ -28,12 +28,14 @@ import com.android.systemui.statusbar.notification.NotificationActivityStarter
|
||||
import com.android.systemui.statusbar.notification.NotificationClicker
|
||||
import com.android.systemui.statusbar.notification.NotificationEntryManager
|
||||
import com.android.systemui.statusbar.notification.NotificationListController
|
||||
import com.android.systemui.statusbar.notification.collection.NotifLiveDataStore
|
||||
import com.android.systemui.statusbar.notification.collection.NotifPipeline
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationRankingManager
|
||||
import com.android.systemui.statusbar.notification.collection.TargetSdkResolver
|
||||
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl
|
||||
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.render.NotifStackController
|
||||
import com.android.systemui.statusbar.notification.interruption.HeadsUpController
|
||||
import com.android.systemui.statusbar.notification.interruption.HeadsUpViewBinder
|
||||
@@ -64,9 +66,11 @@ class NotificationsControllerImpl @Inject constructor(
|
||||
private val notificationListener: NotificationListener,
|
||||
private val entryManager: NotificationEntryManager,
|
||||
private val legacyRanker: NotificationRankingManager,
|
||||
private val commonNotifCollection: Lazy<CommonNotifCollection>,
|
||||
private val notifPipeline: Lazy<NotifPipeline>,
|
||||
private val notifLiveDataStore: NotifLiveDataStore,
|
||||
private val targetSdkResolver: TargetSdkResolver,
|
||||
private val newNotifPipeline: Lazy<NotifPipelineInitializer>,
|
||||
private val newNotifPipelineInitializer: Lazy<NotifPipelineInitializer>,
|
||||
private val notifBindPipelineInitializer: NotifBindPipelineInitializer,
|
||||
private val deviceProvisionedController: DeviceProvisionedController,
|
||||
private val notificationRowBinder: NotificationRowBinderImpl,
|
||||
@@ -111,7 +115,7 @@ class NotificationsControllerImpl @Inject constructor(
|
||||
animatedImageNotificationManager.bind()
|
||||
|
||||
if (INITIALIZE_NEW_PIPELINE) {
|
||||
newNotifPipeline.get().initialize(
|
||||
newNotifPipelineInitializer.get().initialize(
|
||||
notificationListener,
|
||||
notificationRowBinder,
|
||||
listContainer,
|
||||
@@ -155,14 +159,10 @@ class NotificationsControllerImpl @Inject constructor(
|
||||
}
|
||||
|
||||
override fun resetUserExpandedStates() {
|
||||
if (notifPipelineFlags.isNewPipelineEnabled()) {
|
||||
for (entry in notifPipeline.get().allNotifs) {
|
||||
entry.resetUserExpansion()
|
||||
}
|
||||
} else {
|
||||
for (entry in entryManager.visibleNotifications) {
|
||||
entry.resetUserExpansion()
|
||||
}
|
||||
// TODO: this is a view thing that should be done through the views, but that means doing it
|
||||
// both when this event is fired and any time a row is attached.
|
||||
for (entry in commonNotifCollection.get().allNotifs) {
|
||||
entry.resetUserExpansion()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,11 +177,7 @@ class NotificationsControllerImpl @Inject constructor(
|
||||
}
|
||||
|
||||
override fun getActiveNotificationsCount(): Int =
|
||||
if (notifPipelineFlags.isNewPipelineEnabled()) {
|
||||
notifPipeline.get().getShadeListCount()
|
||||
} else {
|
||||
entryManager.activeNotificationsCount
|
||||
}
|
||||
notifLiveDataStore.activeNotifCount.value
|
||||
|
||||
companion object {
|
||||
// NOTE: The new pipeline is always active, even if the old pipeline is *rendering*.
|
||||
|
||||
@@ -42,6 +42,7 @@ import com.android.systemui.statusbar.StatusBarState;
|
||||
import com.android.systemui.statusbar.notification.NotifPipelineFlags;
|
||||
import com.android.systemui.statusbar.notification.NotificationEntryListener;
|
||||
import com.android.systemui.statusbar.notification.NotificationEntryManager;
|
||||
import com.android.systemui.statusbar.notification.collection.NotifLiveDataStore;
|
||||
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
|
||||
@@ -76,7 +77,7 @@ public class NotificationLogger implements StateListener {
|
||||
// Dependencies:
|
||||
private final NotificationListenerService mNotificationListener;
|
||||
private final Executor mUiBgExecutor;
|
||||
private final NotifPipelineFlags mNotifPipelineFlags;
|
||||
private final NotifLiveDataStore mNotifLiveDataStore;
|
||||
private final NotificationVisibilityProvider mVisibilityProvider;
|
||||
private final NotificationEntryManager mEntryManager;
|
||||
private final NotifPipeline mNotifPipeline;
|
||||
@@ -179,11 +180,7 @@ public class NotificationLogger implements StateListener {
|
||||
};
|
||||
|
||||
private List<NotificationEntry> getVisibleNotifications() {
|
||||
if (mNotifPipelineFlags.isNewPipelineEnabled()) {
|
||||
return mNotifPipeline.getFlatShadeList();
|
||||
} else {
|
||||
return mEntryManager.getVisibleNotifications();
|
||||
}
|
||||
return mNotifLiveDataStore.getActiveNotifList().getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -223,6 +220,7 @@ public class NotificationLogger implements StateListener {
|
||||
public NotificationLogger(NotificationListener notificationListener,
|
||||
@UiBackground Executor uiBgExecutor,
|
||||
NotifPipelineFlags notifPipelineFlags,
|
||||
NotifLiveDataStore notifLiveDataStore,
|
||||
NotificationVisibilityProvider visibilityProvider,
|
||||
NotificationEntryManager entryManager,
|
||||
NotifPipeline notifPipeline,
|
||||
@@ -231,7 +229,7 @@ public class NotificationLogger implements StateListener {
|
||||
NotificationPanelLogger notificationPanelLogger) {
|
||||
mNotificationListener = notificationListener;
|
||||
mUiBgExecutor = uiBgExecutor;
|
||||
mNotifPipelineFlags = notifPipelineFlags;
|
||||
mNotifLiveDataStore = notifLiveDataStore;
|
||||
mVisibilityProvider = visibilityProvider;
|
||||
mEntryManager = entryManager;
|
||||
mNotifPipeline = notifPipeline;
|
||||
@@ -242,7 +240,7 @@ public class NotificationLogger implements StateListener {
|
||||
// Not expected to be destroyed, don't need to unsubscribe
|
||||
statusBarStateController.addCallback(this);
|
||||
|
||||
if (mNotifPipelineFlags.isNewPipelineEnabled()) {
|
||||
if (notifPipelineFlags.isNewPipelineEnabled()) {
|
||||
registerNewPipelineListener();
|
||||
} else {
|
||||
registerLegacyListener();
|
||||
|
||||
@@ -22,7 +22,6 @@ import static com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFrag
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.annotation.Nullable;
|
||||
import android.view.InsetsVisibilities;
|
||||
import android.view.View;
|
||||
import android.view.WindowInsetsController.Appearance;
|
||||
@@ -30,13 +29,12 @@ import android.view.WindowInsetsController.Behavior;
|
||||
import android.view.WindowManager;
|
||||
import android.view.animation.AccelerateInterpolator;
|
||||
|
||||
import androidx.lifecycle.Observer;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.statusbar.NotificationVisibility;
|
||||
import com.android.internal.view.AppearanceRegion;
|
||||
import com.android.systemui.statusbar.CommandQueue;
|
||||
import com.android.systemui.statusbar.notification.NotificationEntryListener;
|
||||
import com.android.systemui.statusbar.notification.NotificationEntryManager;
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||
import com.android.systemui.statusbar.notification.collection.NotifLiveDataStore;
|
||||
import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentScope;
|
||||
import com.android.systemui.util.ViewController;
|
||||
|
||||
@@ -44,20 +42,21 @@ import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
/**
|
||||
* Apps can request a low profile mode {@link View.SYSTEM_UI_FLAG_LOW_PROFILE}
|
||||
* Apps can request a low profile mode {@link View#SYSTEM_UI_FLAG_LOW_PROFILE}
|
||||
* where status bar and navigation icons dim. In this mode, a notification dot appears
|
||||
* where the notification icons would appear if they would be shown outside of this mode.
|
||||
*
|
||||
* This controller shows and hides the notification dot in the status bar to indicate
|
||||
* whether there are notifications when the device is in {@link View.SYSTEM_UI_FLAG_LOW_PROFILE}.
|
||||
* whether there are notifications when the device is in {@link View#SYSTEM_UI_FLAG_LOW_PROFILE}.
|
||||
*/
|
||||
@StatusBarFragmentScope
|
||||
public class LightsOutNotifController extends ViewController<View> {
|
||||
private final CommandQueue mCommandQueue;
|
||||
private final NotificationEntryManager mEntryManager;
|
||||
private final NotifLiveDataStore mNotifDataStore;
|
||||
private final WindowManager mWindowManager;
|
||||
private final Observer<Boolean> mObserver = hasNotifs -> updateLightsOutView();
|
||||
|
||||
/** @see android.view.WindowInsetsController#setSystemBarsAppearance(int) */
|
||||
/** @see android.view.WindowInsetsController#setSystemBarsAppearance(int, int) */
|
||||
@VisibleForTesting @Appearance int mAppearance;
|
||||
|
||||
private int mDisplayId;
|
||||
@@ -66,18 +65,18 @@ public class LightsOutNotifController extends ViewController<View> {
|
||||
LightsOutNotifController(
|
||||
@Named(LIGHTS_OUT_NOTIF_VIEW) View lightsOutNotifView,
|
||||
WindowManager windowManager,
|
||||
NotificationEntryManager entryManager,
|
||||
NotifLiveDataStore notifDataStore,
|
||||
CommandQueue commandQueue) {
|
||||
super(lightsOutNotifView);
|
||||
mWindowManager = windowManager;
|
||||
mEntryManager = entryManager;
|
||||
mNotifDataStore = notifDataStore;
|
||||
mCommandQueue = commandQueue;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onViewDetached() {
|
||||
mEntryManager.removeNotificationEntryListener(mEntryListener);
|
||||
mNotifDataStore.getHasActiveNotifs().removeObserver(mObserver);
|
||||
mCommandQueue.removeCallback(mCallback);
|
||||
}
|
||||
|
||||
@@ -87,14 +86,14 @@ public class LightsOutNotifController extends ViewController<View> {
|
||||
mView.setAlpha(0f);
|
||||
|
||||
mDisplayId = mWindowManager.getDefaultDisplay().getDisplayId();
|
||||
mEntryManager.addNotificationEntryListener(mEntryListener);
|
||||
mNotifDataStore.getHasActiveNotifs().addSyncObserver(mObserver);
|
||||
mCommandQueue.addCallback(mCallback);
|
||||
|
||||
updateLightsOutView();
|
||||
}
|
||||
|
||||
private boolean hasActiveNotifications() {
|
||||
return mEntryManager.hasActiveNotifications();
|
||||
return mNotifDataStore.getHasActiveNotifs().getValue();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -153,23 +152,4 @@ public class LightsOutNotifController extends ViewController<View> {
|
||||
updateLightsOutView();
|
||||
}
|
||||
};
|
||||
|
||||
private final NotificationEntryListener mEntryListener = new NotificationEntryListener() {
|
||||
// Cares about notifications post-filtering
|
||||
@Override
|
||||
public void onNotificationAdded(NotificationEntry entry) {
|
||||
updateLightsOutView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPostEntryUpdated(NotificationEntry entry) {
|
||||
updateLightsOutView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEntryRemoved(@Nullable NotificationEntry entry,
|
||||
NotificationVisibility visibility, boolean removedByUser, int reason) {
|
||||
updateLightsOutView();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -660,14 +660,6 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
|
||||
|
||||
// --------------------- NotificationEntryManager/NotifPipeline methods ------------------------
|
||||
|
||||
private int getVisibleNotificationsCount() {
|
||||
if (mNotifPipelineFlags.isNewPipelineEnabled()) {
|
||||
return mNotifPipeline.getShadeListCount();
|
||||
} else {
|
||||
return mEntryManager.getActiveNotificationsCount();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Public builder for {@link StatusBarNotificationActivityStarter}.
|
||||
*/
|
||||
|
||||
@@ -38,6 +38,11 @@ class ListenerSet<E> : Iterable<E> {
|
||||
*/
|
||||
fun remove(element: E): Boolean = listeners.remove(element)
|
||||
|
||||
/**
|
||||
* Determine if the listener set is empty
|
||||
*/
|
||||
fun isEmpty(): Boolean = listeners.isEmpty()
|
||||
|
||||
/**
|
||||
* Returns an iterator over the listeners currently in the set. Note that to ensure
|
||||
* [ConcurrentModificationException] is never thrown, this iterator will not reflect changes
|
||||
@@ -45,3 +50,6 @@ class ListenerSet<E> : Iterable<E> {
|
||||
*/
|
||||
override fun iterator(): Iterator<E> = listeners.iterator()
|
||||
}
|
||||
|
||||
/** Extension to match Collection which is implemented to only be (easily) accessible in kotlin */
|
||||
fun <T> ListenerSet<T>.isNotEmpty(): Boolean = !isEmpty()
|
||||
|
||||
@@ -75,6 +75,7 @@ import com.android.systemui.statusbar.NotificationRemoveInterceptor;
|
||||
import com.android.systemui.statusbar.RankingBuilder;
|
||||
import com.android.systemui.statusbar.SmartReplyController;
|
||||
import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment;
|
||||
import com.android.systemui.statusbar.notification.collection.NotifLiveDataStoreMocksKt;
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
|
||||
@@ -201,6 +202,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
|
||||
mLeakDetector,
|
||||
mock(ForegroundServiceDismissalFeatureController.class),
|
||||
mock(IStatusBarService.class),
|
||||
NotifLiveDataStoreMocksKt.createNotifLiveDataStoreImplMock(),
|
||||
mock(DumpManager.class)
|
||||
);
|
||||
mEntryManager.initialize(
|
||||
|
||||
@@ -18,6 +18,8 @@ package com.android.systemui.statusbar.notification.collection;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -28,6 +30,7 @@ public class GroupEntryBuilder {
|
||||
private String mKey = "test_group_key";
|
||||
private long mCreationTime = 0;
|
||||
@Nullable private GroupEntry mParent = GroupEntry.ROOT_ENTRY;
|
||||
private NotifSection mNotifSection;
|
||||
private NotificationEntry mSummary = null;
|
||||
private List<NotificationEntry> mChildren = new ArrayList<>();
|
||||
|
||||
@@ -35,6 +38,7 @@ public class GroupEntryBuilder {
|
||||
public GroupEntry build() {
|
||||
GroupEntry ge = new GroupEntry(mKey, mCreationTime);
|
||||
ge.setParent(mParent);
|
||||
ge.getAttachState().setSection(mNotifSection);
|
||||
|
||||
ge.setSummary(mSummary);
|
||||
mSummary.setParent(ge);
|
||||
@@ -61,6 +65,11 @@ public class GroupEntryBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public GroupEntryBuilder setSection(@Nullable NotifSection section) {
|
||||
mNotifSection = section;
|
||||
return this;
|
||||
}
|
||||
|
||||
public GroupEntryBuilder setSummary(
|
||||
NotificationEntry summary) {
|
||||
mSummary = summary;
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import android.testing.AndroidTestingRunner
|
||||
import android.testing.TestableLooper.RunWithLooper
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.util.concurrency.FakeExecutor
|
||||
import com.android.systemui.util.mockito.mock
|
||||
import com.android.systemui.util.time.FakeSystemClock
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mockito.eq
|
||||
import org.mockito.Mockito.inOrder
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.Mockito.verifyNoMoreInteractions
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
@RunWithLooper
|
||||
class NotifLiveDataImplTest : SysuiTestCase() {
|
||||
|
||||
private val executor = FakeExecutor(FakeSystemClock())
|
||||
private val liveDataImpl: NotifLiveDataImpl<Int> = NotifLiveDataImpl("tst", 9, executor)
|
||||
private val syncObserver: Observer<Int> = mock()
|
||||
private val asyncObserver: Observer<Int> = mock()
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
allowTestableLooperAsMainThread()
|
||||
liveDataImpl.addSyncObserver(syncObserver)
|
||||
liveDataImpl.addAsyncObserver(asyncObserver)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetInitialValue() {
|
||||
assertThat(liveDataImpl.value).isEqualTo(9)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetModifiedValue() {
|
||||
liveDataImpl.value = 13
|
||||
assertThat(liveDataImpl.value).isEqualTo(13)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetsModifiedValueFromWithinSyncObserver() {
|
||||
liveDataImpl.addSyncObserver { intVal ->
|
||||
assertThat(intVal).isEqualTo(13)
|
||||
assertThat(liveDataImpl.value).isEqualTo(13)
|
||||
}
|
||||
liveDataImpl.value = 13
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDoesNotAlertsRemovedObservers() {
|
||||
liveDataImpl.removeObserver(syncObserver)
|
||||
liveDataImpl.removeObserver(asyncObserver)
|
||||
|
||||
liveDataImpl.value = 13
|
||||
|
||||
// There should be no runnables on the executor
|
||||
assertThat(executor.runAllReady()).isEqualTo(0)
|
||||
|
||||
// And observers should not be called
|
||||
verifyNoMoreInteractions(syncObserver, asyncObserver)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDoesNotAsyncObserversRemovedSinceChange() {
|
||||
liveDataImpl.value = 13
|
||||
liveDataImpl.removeObserver(asyncObserver)
|
||||
|
||||
// There should be a runnable that will get executed...
|
||||
assertThat(executor.runAllReady()).isEqualTo(1)
|
||||
|
||||
// ...but async observers should not be called
|
||||
verifyNoMoreInteractions(asyncObserver)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAlertsObservers() {
|
||||
liveDataImpl.value = 13
|
||||
|
||||
// Verify that the synchronous observer is called immediately
|
||||
verify(syncObserver).onChanged(eq(13))
|
||||
verifyNoMoreInteractions(syncObserver, asyncObserver)
|
||||
|
||||
// Verify that the asynchronous observer is called when the executor runs
|
||||
assertThat(executor.runAllReady()).isEqualTo(1)
|
||||
verify(asyncObserver).onChanged(eq(13))
|
||||
verifyNoMoreInteractions(syncObserver, asyncObserver)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAlertsObserversFromDispatcher() {
|
||||
// GIVEN that we use setValueAndProvideDispatcher()
|
||||
val dispatcher = liveDataImpl.setValueAndProvideDispatcher(13)
|
||||
|
||||
// VERIFY that nothing is done before the dispatcher is called
|
||||
assertThat(executor.numPending()).isEqualTo(0)
|
||||
verifyNoMoreInteractions(syncObserver, asyncObserver)
|
||||
|
||||
// WHEN the dispatcher is invoked...
|
||||
dispatcher.invoke()
|
||||
|
||||
// Verify that the synchronous observer is called immediately
|
||||
verify(syncObserver).onChanged(eq(13))
|
||||
verifyNoMoreInteractions(syncObserver, asyncObserver)
|
||||
|
||||
// Verify that the asynchronous observer is called when the executor runs
|
||||
assertThat(executor.runAllReady()).isEqualTo(1)
|
||||
verify(asyncObserver).onChanged(eq(13))
|
||||
verifyNoMoreInteractions(syncObserver, asyncObserver)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSkipsAllObserversIfValueDidNotChange() {
|
||||
liveDataImpl.value = 9
|
||||
// Does not add a runnable
|
||||
assertThat(executor.runAllReady()).isEqualTo(0)
|
||||
// Setting the current value does not call synchronous observers
|
||||
verifyNoMoreInteractions(syncObserver, asyncObserver)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSkipsAsyncObserversWhenValueTogglesBack() {
|
||||
liveDataImpl.value = 13
|
||||
liveDataImpl.value = 11
|
||||
liveDataImpl.value = 9
|
||||
|
||||
// Synchronous observers will receive every change event immediately
|
||||
inOrder(syncObserver).apply {
|
||||
verify(syncObserver).onChanged(eq(13))
|
||||
verify(syncObserver).onChanged(eq(11))
|
||||
verify(syncObserver).onChanged(eq(9))
|
||||
}
|
||||
verifyNoMoreInteractions(syncObserver, asyncObserver)
|
||||
|
||||
// Running the first runnable on the queue will just emit the most recent value
|
||||
assertThat(executor.runNextReady()).isTrue()
|
||||
verify(asyncObserver).onChanged(eq(9))
|
||||
verifyNoMoreInteractions(syncObserver, asyncObserver)
|
||||
|
||||
// Running the next 2 runnable will have no effect
|
||||
assertThat(executor.runAllReady()).isEqualTo(2)
|
||||
verifyNoMoreInteractions(syncObserver, asyncObserver)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import android.testing.AndroidTestingRunner
|
||||
import android.testing.TestableLooper.RunWithLooper
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.util.concurrency.FakeExecutor
|
||||
import com.android.systemui.util.time.FakeSystemClock
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Assert
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import java.lang.UnsupportedOperationException
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
@RunWithLooper
|
||||
class NotifLiveDataStoreImplTest : SysuiTestCase() {
|
||||
|
||||
private val executor = FakeExecutor(FakeSystemClock())
|
||||
private val liveDataStoreImpl = NotifLiveDataStoreImpl(executor)
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
allowTestableLooperAsMainThread()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAllObserversSeeConsistentValues() {
|
||||
val entry1 = NotificationEntryBuilder().setId(1).build()
|
||||
val entry2 = NotificationEntryBuilder().setId(2).build()
|
||||
val observer: (Any) -> Unit = {
|
||||
assertThat(liveDataStoreImpl.hasActiveNotifs.value).isEqualTo(true)
|
||||
assertThat(liveDataStoreImpl.activeNotifCount.value).isEqualTo(2)
|
||||
assertThat(liveDataStoreImpl.activeNotifList.value).isEqualTo(listOf(entry1, entry2))
|
||||
}
|
||||
liveDataStoreImpl.hasActiveNotifs.addSyncObserver(observer)
|
||||
liveDataStoreImpl.hasActiveNotifs.addAsyncObserver(observer)
|
||||
liveDataStoreImpl.activeNotifCount.addSyncObserver(observer)
|
||||
liveDataStoreImpl.activeNotifCount.addAsyncObserver(observer)
|
||||
liveDataStoreImpl.activeNotifList.addSyncObserver(observer)
|
||||
liveDataStoreImpl.activeNotifList.addAsyncObserver(observer)
|
||||
liveDataStoreImpl.setActiveNotifList(listOf(entry1, entry2))
|
||||
executor.runAllReady()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testOriginalListIsCopied() {
|
||||
val entry1 = NotificationEntryBuilder().setId(1).build()
|
||||
val entry2 = NotificationEntryBuilder().setId(2).build()
|
||||
val mutableInputList = mutableListOf(entry1, entry2)
|
||||
val observer: (Any) -> Unit = {
|
||||
mutableInputList.clear()
|
||||
assertThat(liveDataStoreImpl.hasActiveNotifs.value).isEqualTo(true)
|
||||
assertThat(liveDataStoreImpl.activeNotifCount.value).isEqualTo(2)
|
||||
assertThat(liveDataStoreImpl.activeNotifList.value).isEqualTo(listOf(entry1, entry2))
|
||||
}
|
||||
liveDataStoreImpl.hasActiveNotifs.addSyncObserver(observer)
|
||||
liveDataStoreImpl.hasActiveNotifs.addAsyncObserver(observer)
|
||||
liveDataStoreImpl.activeNotifCount.addSyncObserver(observer)
|
||||
liveDataStoreImpl.activeNotifCount.addAsyncObserver(observer)
|
||||
liveDataStoreImpl.activeNotifList.addSyncObserver(observer)
|
||||
liveDataStoreImpl.activeNotifList.addAsyncObserver(observer)
|
||||
liveDataStoreImpl.setActiveNotifList(mutableInputList)
|
||||
executor.runAllReady()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testProvidedListIsUnmodifiable() {
|
||||
val entry1 = NotificationEntryBuilder().setId(1).build()
|
||||
val entry2 = NotificationEntryBuilder().setId(2).build()
|
||||
val observer: (List<NotificationEntry>) -> Unit = { providedValue ->
|
||||
val provided = providedValue as MutableList<NotificationEntry>
|
||||
Assert.assertThrows(UnsupportedOperationException::class.java) {
|
||||
provided.clear()
|
||||
}
|
||||
val current = liveDataStoreImpl.activeNotifList.value as MutableList<NotificationEntry>
|
||||
Assert.assertThrows(UnsupportedOperationException::class.java) {
|
||||
current.clear()
|
||||
}
|
||||
assertThat(liveDataStoreImpl.activeNotifList.value).isEqualTo(listOf(entry1, entry2))
|
||||
}
|
||||
liveDataStoreImpl.activeNotifList.addSyncObserver(observer)
|
||||
liveDataStoreImpl.activeNotifList.addAsyncObserver(observer)
|
||||
liveDataStoreImpl.setActiveNotifList(mutableListOf(entry1, entry2))
|
||||
executor.runAllReady()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import com.android.systemui.util.mockito.mock
|
||||
import org.mockito.Mockito.`when` as whenever
|
||||
|
||||
/** Creates a mock which returns mocks for the NotifLiveDataImpl fields. */
|
||||
fun createNotifLiveDataStoreImplMock(): NotifLiveDataStoreImpl {
|
||||
val dataStoreImpl: NotifLiveDataStoreImpl = mock()
|
||||
whenever(dataStoreImpl.hasActiveNotifs).thenReturn(mock())
|
||||
whenever(dataStoreImpl.activeNotifCount).thenReturn(mock())
|
||||
whenever(dataStoreImpl.activeNotifList).thenReturn(mock())
|
||||
return dataStoreImpl
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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
|
||||
|
||||
import android.testing.AndroidTestingRunner
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.statusbar.notification.collection.render.RenderStageManager
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mock
|
||||
import org.mockito.MockitoAnnotations
|
||||
import org.mockito.Mockito.`when` as whenever
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
class NotifPipelineTest : SysuiTestCase() {
|
||||
|
||||
@Mock private lateinit var notifCollection: NotifCollection
|
||||
@Mock private lateinit var shadeListBuilder: ShadeListBuilder
|
||||
@Mock private lateinit var renderStageManager: RenderStageManager
|
||||
private lateinit var notifPipeline: NotifPipeline
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
notifPipeline = NotifPipeline(notifCollection, shadeListBuilder, renderStageManager)
|
||||
whenever(shadeListBuilder.shadeList).thenReturn(listOf(
|
||||
NotificationEntryBuilder().setPkg("foo").setId(1).build(),
|
||||
NotificationEntryBuilder().setPkg("foo").setId(2).build(),
|
||||
group(
|
||||
NotificationEntryBuilder().setPkg("bar").setId(1).build(),
|
||||
NotificationEntryBuilder().setPkg("bar").setId(2).build(),
|
||||
NotificationEntryBuilder().setPkg("bar").setId(3).build(),
|
||||
NotificationEntryBuilder().setPkg("bar").setId(4).build()
|
||||
),
|
||||
NotificationEntryBuilder().setPkg("baz").setId(1).build()
|
||||
))
|
||||
}
|
||||
|
||||
private fun group(summary: NotificationEntry, vararg children: NotificationEntry): GroupEntry {
|
||||
return GroupEntry(summary.key, summary.creationTime).also { group ->
|
||||
group.summary = summary
|
||||
for (it in children) {
|
||||
group.addChild(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetShadeListCount() {
|
||||
assertThat(notifPipeline.getShadeListCount()).isEqualTo(7)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetFlatShadeList() {
|
||||
assertThat(notifPipeline.getFlatShadeList().map { it.key }).containsExactly(
|
||||
"0|foo|1|null|0",
|
||||
"0|foo|2|null|0",
|
||||
"0|bar|1|null|0",
|
||||
"0|bar|2|null|0",
|
||||
"0|bar|3|null|0",
|
||||
"0|bar|4|null|0",
|
||||
"0|baz|1|null|0"
|
||||
).inOrder()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* 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 android.testing.AndroidTestingRunner
|
||||
import android.testing.TestableLooper.RunWithLooper
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
|
||||
import com.android.systemui.statusbar.notification.collection.NotifLiveDataStoreImpl
|
||||
import com.android.systemui.statusbar.notification.collection.NotifPipeline
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
|
||||
import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection
|
||||
import com.android.systemui.statusbar.notification.collection.listbuilder.OnAfterRenderListListener
|
||||
import com.android.systemui.statusbar.notification.collection.render.NotifStackController
|
||||
import com.android.systemui.util.mockito.eq
|
||||
import com.android.systemui.util.mockito.withArgCaptor
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.Mockito.verifyNoMoreInteractions
|
||||
import org.mockito.MockitoAnnotations.initMocks
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
@RunWithLooper
|
||||
class DataStoreCoordinatorTest : SysuiTestCase() {
|
||||
private lateinit var coordinator: DataStoreCoordinator
|
||||
private lateinit var afterRenderListListener: OnAfterRenderListListener
|
||||
|
||||
private lateinit var entry: NotificationEntry
|
||||
|
||||
@Mock private lateinit var pipeline: NotifPipeline
|
||||
@Mock private lateinit var notifLiveDataStoreImpl: NotifLiveDataStoreImpl
|
||||
@Mock private lateinit var stackController: NotifStackController
|
||||
@Mock private lateinit var section: NotifSection
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
initMocks(this)
|
||||
entry = NotificationEntryBuilder().setSection(section).build()
|
||||
coordinator = DataStoreCoordinator(notifLiveDataStoreImpl)
|
||||
coordinator.attach(pipeline)
|
||||
afterRenderListListener = withArgCaptor {
|
||||
verify(pipeline).addOnAfterRenderListListener(capture())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testUpdateDataStore_withOneEntry() {
|
||||
afterRenderListListener.onAfterRenderList(listOf(entry), stackController)
|
||||
verify(notifLiveDataStoreImpl).setActiveNotifList(eq(listOf(entry)))
|
||||
verifyNoMoreInteractions(notifLiveDataStoreImpl)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testUpdateDataStore_withGroups() {
|
||||
afterRenderListListener.onAfterRenderList(
|
||||
listOf(
|
||||
notificationEntry("foo", 1),
|
||||
notificationEntry("foo", 2),
|
||||
GroupEntryBuilder().setSummary(
|
||||
notificationEntry("bar", 1)
|
||||
).setChildren(
|
||||
listOf(
|
||||
notificationEntry("bar", 2),
|
||||
notificationEntry("bar", 3),
|
||||
notificationEntry("bar", 4)
|
||||
)
|
||||
).setSection(section).build(),
|
||||
notificationEntry("baz", 1)
|
||||
),
|
||||
stackController
|
||||
)
|
||||
val list: List<NotificationEntry> = withArgCaptor {
|
||||
verify(notifLiveDataStoreImpl).setActiveNotifList(capture())
|
||||
}
|
||||
assertThat(list.map { it.key }).containsExactly(
|
||||
"0|foo|1|null|0",
|
||||
"0|foo|2|null|0",
|
||||
"0|bar|1|null|0",
|
||||
"0|bar|2|null|0",
|
||||
"0|bar|3|null|0",
|
||||
"0|bar|4|null|0",
|
||||
"0|baz|1|null|0"
|
||||
).inOrder()
|
||||
verifyNoMoreInteractions(notifLiveDataStoreImpl)
|
||||
}
|
||||
|
||||
private fun notificationEntry(pkg: String, id: Int) =
|
||||
NotificationEntryBuilder().setPkg(pkg).setId(id).setSection(section).build()
|
||||
|
||||
@Test
|
||||
fun testUpdateDataStore_withZeroEntries_whenNewPipelineEnabled() {
|
||||
afterRenderListListener.onAfterRenderList(listOf(), stackController)
|
||||
verify(notifLiveDataStoreImpl).setActiveNotifList(eq(listOf()))
|
||||
verifyNoMoreInteractions(notifLiveDataStoreImpl)
|
||||
}
|
||||
}
|
||||
@@ -46,6 +46,8 @@ import com.android.systemui.statusbar.StatusBarState;
|
||||
import com.android.systemui.statusbar.StatusBarStateControllerImpl;
|
||||
import com.android.systemui.statusbar.notification.NotifPipelineFlags;
|
||||
import com.android.systemui.statusbar.notification.NotificationEntryManager;
|
||||
import com.android.systemui.statusbar.notification.collection.NotifLiveData;
|
||||
import com.android.systemui.statusbar.notification.collection.NotifLiveDataStore;
|
||||
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
|
||||
@@ -65,6 +67,7 @@ import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
@@ -82,6 +85,8 @@ public class NotificationLoggerLegacyTest extends SysuiTestCase {
|
||||
|
||||
// Dependency mocks:
|
||||
@Mock private NotifPipelineFlags mNotifPipelineFlags;
|
||||
@Mock private NotifLiveDataStore mNotifLiveDataStore;
|
||||
@Mock private NotifLiveData<List<NotificationEntry>> mActiveNotifList;
|
||||
@Mock private NotificationVisibilityProvider mVisibilityProvider;
|
||||
@Mock private NotificationEntryManager mEntryManager;
|
||||
@Mock private NotifPipeline mNotifPipeline;
|
||||
@@ -97,6 +102,7 @@ public class NotificationLoggerLegacyTest extends SysuiTestCase {
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
when(mNotifLiveDataStore.getActiveNotifList()).thenReturn(mActiveNotifList);
|
||||
|
||||
mEntry = new NotificationEntryBuilder()
|
||||
.setPkg(TEST_PACKAGE_NAME)
|
||||
@@ -112,6 +118,7 @@ public class NotificationLoggerLegacyTest extends SysuiTestCase {
|
||||
mListener,
|
||||
mUiBgExecutor,
|
||||
mNotifPipelineFlags,
|
||||
mNotifLiveDataStore,
|
||||
mVisibilityProvider,
|
||||
mEntryManager,
|
||||
mNotifPipeline,
|
||||
@@ -145,7 +152,7 @@ public class NotificationLoggerLegacyTest extends SysuiTestCase {
|
||||
any(NotificationVisibility[].class));
|
||||
|
||||
when(mListContainer.isInVisibleLocation(any())).thenReturn(true);
|
||||
when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(mEntry));
|
||||
when(mActiveNotifList.getValue()).thenReturn(Lists.newArrayList(mEntry));
|
||||
mLogger.getChildLocationsChangedListenerForTest().onChildLocationsChanged();
|
||||
TestableLooper.get(this).processAllMessages();
|
||||
mUiBgExecutor.runAllReady();
|
||||
@@ -167,7 +174,7 @@ public class NotificationLoggerLegacyTest extends SysuiTestCase {
|
||||
public void testStoppingNotificationLoggingReportsCurrentNotifications()
|
||||
throws Exception {
|
||||
when(mListContainer.isInVisibleLocation(any())).thenReturn(true);
|
||||
when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(mEntry));
|
||||
when(mActiveNotifList.getValue()).thenReturn(Lists.newArrayList(mEntry));
|
||||
mLogger.getChildLocationsChangedListenerForTest().onChildLocationsChanged();
|
||||
TestableLooper.get(this).processAllMessages();
|
||||
mUiBgExecutor.runAllReady();
|
||||
@@ -196,7 +203,7 @@ public class NotificationLoggerLegacyTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void testLogPanelShownOnWake() {
|
||||
when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(mEntry));
|
||||
when(mActiveNotifList.getValue()).thenReturn(Lists.newArrayList(mEntry));
|
||||
setStateAsleep();
|
||||
mLogger.onDozingChanged(false); // Wake to lockscreen
|
||||
assertEquals(1, mNotificationPanelLoggerFake.getCalls().size());
|
||||
@@ -212,7 +219,7 @@ public class NotificationLoggerLegacyTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void testLogPanelShownOnShadePull() {
|
||||
when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(mEntry));
|
||||
when(mActiveNotifList.getValue()).thenReturn(Lists.newArrayList(mEntry));
|
||||
setStateAwake();
|
||||
// Now expand panel
|
||||
mLogger.onPanelExpandedChanged(true);
|
||||
@@ -240,7 +247,7 @@ public class NotificationLoggerLegacyTest extends SysuiTestCase {
|
||||
.build();
|
||||
entry.setRow(mRow);
|
||||
|
||||
when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(entry));
|
||||
when(mActiveNotifList.getValue()).thenReturn(Lists.newArrayList(entry));
|
||||
setStateAsleep();
|
||||
mLogger.onDozingChanged(false); // Wake to lockscreen
|
||||
assertEquals(1, mNotificationPanelLoggerFake.getCalls().size());
|
||||
@@ -254,6 +261,7 @@ public class NotificationLoggerLegacyTest extends SysuiTestCase {
|
||||
TestableNotificationLogger(NotificationListener notificationListener,
|
||||
Executor uiBgExecutor,
|
||||
NotifPipelineFlags notifPipelineFlags,
|
||||
NotifLiveDataStore notifLiveDataStore,
|
||||
NotificationVisibilityProvider visibilityProvider,
|
||||
NotificationEntryManager entryManager,
|
||||
NotifPipeline notifPipeline,
|
||||
@@ -264,6 +272,7 @@ public class NotificationLoggerLegacyTest extends SysuiTestCase {
|
||||
notificationListener,
|
||||
uiBgExecutor,
|
||||
notifPipelineFlags,
|
||||
notifLiveDataStore,
|
||||
visibilityProvider,
|
||||
entryManager,
|
||||
notifPipeline,
|
||||
|
||||
@@ -46,6 +46,8 @@ import com.android.systemui.statusbar.StatusBarState;
|
||||
import com.android.systemui.statusbar.StatusBarStateControllerImpl;
|
||||
import com.android.systemui.statusbar.notification.NotifPipelineFlags;
|
||||
import com.android.systemui.statusbar.notification.NotificationEntryManager;
|
||||
import com.android.systemui.statusbar.notification.collection.NotifLiveData;
|
||||
import com.android.systemui.statusbar.notification.collection.NotifLiveDataStore;
|
||||
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
|
||||
@@ -65,6 +67,7 @@ import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
@@ -82,6 +85,8 @@ public class NotificationLoggerTest extends SysuiTestCase {
|
||||
|
||||
// Dependency mocks:
|
||||
@Mock private NotifPipelineFlags mNotifPipelineFlags;
|
||||
@Mock private NotifLiveDataStore mNotifLiveDataStore;
|
||||
@Mock private NotifLiveData<List<NotificationEntry>> mActiveNotifEntries;
|
||||
@Mock private NotificationVisibilityProvider mVisibilityProvider;
|
||||
@Mock private NotificationEntryManager mEntryManager;
|
||||
@Mock private NotifPipeline mNotifPipeline;
|
||||
@@ -98,6 +103,7 @@ public class NotificationLoggerTest extends SysuiTestCase {
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
when(mNotifPipelineFlags.isNewPipelineEnabled()).thenReturn(true);
|
||||
when(mNotifLiveDataStore.getActiveNotifList()).thenReturn(mActiveNotifEntries);
|
||||
|
||||
mEntry = new NotificationEntryBuilder()
|
||||
.setPkg(TEST_PACKAGE_NAME)
|
||||
@@ -113,6 +119,7 @@ public class NotificationLoggerTest extends SysuiTestCase {
|
||||
mListener,
|
||||
mUiBgExecutor,
|
||||
mNotifPipelineFlags,
|
||||
mNotifLiveDataStore,
|
||||
mVisibilityProvider,
|
||||
mEntryManager,
|
||||
mNotifPipeline,
|
||||
@@ -146,7 +153,7 @@ public class NotificationLoggerTest extends SysuiTestCase {
|
||||
any(NotificationVisibility[].class));
|
||||
|
||||
when(mListContainer.isInVisibleLocation(any())).thenReturn(true);
|
||||
when(mNotifPipeline.getFlatShadeList()).thenReturn(Lists.newArrayList(mEntry));
|
||||
when(mActiveNotifEntries.getValue()).thenReturn(Lists.newArrayList(mEntry));
|
||||
mLogger.getChildLocationsChangedListenerForTest().onChildLocationsChanged();
|
||||
TestableLooper.get(this).processAllMessages();
|
||||
mUiBgExecutor.runAllReady();
|
||||
@@ -168,7 +175,7 @@ public class NotificationLoggerTest extends SysuiTestCase {
|
||||
public void testStoppingNotificationLoggingReportsCurrentNotifications()
|
||||
throws Exception {
|
||||
when(mListContainer.isInVisibleLocation(any())).thenReturn(true);
|
||||
when(mNotifPipeline.getFlatShadeList()).thenReturn(Lists.newArrayList(mEntry));
|
||||
when(mActiveNotifEntries.getValue()).thenReturn(Lists.newArrayList(mEntry));
|
||||
mLogger.getChildLocationsChangedListenerForTest().onChildLocationsChanged();
|
||||
TestableLooper.get(this).processAllMessages();
|
||||
mUiBgExecutor.runAllReady();
|
||||
@@ -197,7 +204,7 @@ public class NotificationLoggerTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void testLogPanelShownOnWake() {
|
||||
when(mNotifPipeline.getFlatShadeList()).thenReturn(Lists.newArrayList(mEntry));
|
||||
when(mActiveNotifEntries.getValue()).thenReturn(Lists.newArrayList(mEntry));
|
||||
setStateAsleep();
|
||||
mLogger.onDozingChanged(false); // Wake to lockscreen
|
||||
assertEquals(1, mNotificationPanelLoggerFake.getCalls().size());
|
||||
@@ -213,7 +220,7 @@ public class NotificationLoggerTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void testLogPanelShownOnShadePull() {
|
||||
when(mNotifPipeline.getFlatShadeList()).thenReturn(Lists.newArrayList(mEntry));
|
||||
when(mActiveNotifEntries.getValue()).thenReturn(Lists.newArrayList(mEntry));
|
||||
setStateAwake();
|
||||
// Now expand panel
|
||||
mLogger.onPanelExpandedChanged(true);
|
||||
@@ -241,7 +248,7 @@ public class NotificationLoggerTest extends SysuiTestCase {
|
||||
.build();
|
||||
entry.setRow(mRow);
|
||||
|
||||
when(mNotifPipeline.getFlatShadeList()).thenReturn(Lists.newArrayList(entry));
|
||||
when(mActiveNotifEntries.getValue()).thenReturn(Lists.newArrayList(entry));
|
||||
setStateAsleep();
|
||||
mLogger.onDozingChanged(false); // Wake to lockscreen
|
||||
assertEquals(1, mNotificationPanelLoggerFake.getCalls().size());
|
||||
@@ -255,6 +262,7 @@ public class NotificationLoggerTest extends SysuiTestCase {
|
||||
TestableNotificationLogger(NotificationListener notificationListener,
|
||||
Executor uiBgExecutor,
|
||||
NotifPipelineFlags notifPipelineFlags,
|
||||
NotifLiveDataStore notifLiveDataStore,
|
||||
NotificationVisibilityProvider visibilityProvider,
|
||||
NotificationEntryManager entryManager,
|
||||
NotifPipeline notifPipeline,
|
||||
@@ -265,6 +273,7 @@ public class NotificationLoggerTest extends SysuiTestCase {
|
||||
notificationListener,
|
||||
uiBgExecutor,
|
||||
notifPipelineFlags,
|
||||
notifLiveDataStore,
|
||||
visibilityProvider,
|
||||
entryManager,
|
||||
notifPipeline,
|
||||
|
||||
@@ -68,6 +68,7 @@ import com.android.systemui.statusbar.notification.NotificationEntryManager;
|
||||
import com.android.systemui.statusbar.notification.NotificationEntryManagerLogger;
|
||||
import com.android.systemui.statusbar.notification.NotificationFilter;
|
||||
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
|
||||
import com.android.systemui.statusbar.notification.collection.NotifLiveDataStoreMocksKt;
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
|
||||
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
|
||||
@@ -191,6 +192,7 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase {
|
||||
mLeakDetector,
|
||||
mock(ForegroundServiceDismissalFeatureController.class),
|
||||
mock(IStatusBarService.class),
|
||||
NotifLiveDataStoreMocksKt.createNotifLiveDataStoreImplMock(),
|
||||
mock(DumpManager.class)
|
||||
);
|
||||
mEntryManager.initialize(
|
||||
|
||||
@@ -16,14 +16,12 @@
|
||||
|
||||
package com.android.systemui.statusbar.phone;
|
||||
|
||||
import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
|
||||
import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
|
||||
import static android.view.WindowInsetsController.BEHAVIOR_DEFAULT;
|
||||
|
||||
import static junit.framework.Assert.assertFalse;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@@ -34,13 +32,13 @@ import android.view.View;
|
||||
import android.view.ViewPropertyAnimator;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import androidx.lifecycle.Observer;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.statusbar.CommandQueue;
|
||||
import com.android.systemui.statusbar.notification.NotificationEntryListener;
|
||||
import com.android.systemui.statusbar.notification.NotificationEntryManager;
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||
import com.android.systemui.statusbar.notification.collection.NotifLiveData;
|
||||
import com.android.systemui.statusbar.notification.collection.NotifLiveDataStore;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -59,18 +57,19 @@ public class LightsOutNotifControllerTest extends SysuiTestCase {
|
||||
private static final int LIGHTS_ON = 0;
|
||||
private static final int LIGHTS_OUT = APPEARANCE_LOW_PROFILE_BARS;
|
||||
|
||||
@Mock private NotificationEntryManager mEntryManager;
|
||||
@Mock private NotifLiveData<Boolean> mHasActiveNotifs;
|
||||
@Mock private NotifLiveDataStore mNotifLiveDataStore;
|
||||
@Mock private CommandQueue mCommandQueue;
|
||||
@Mock private WindowManager mWindowManager;
|
||||
@Mock private Display mDisplay;
|
||||
|
||||
@Captor private ArgumentCaptor<NotificationEntryListener> mListenerCaptor;
|
||||
@Captor private ArgumentCaptor<Observer<Boolean>> mObserverCaptor;
|
||||
@Captor private ArgumentCaptor<CommandQueue.Callbacks> mCallbacksCaptor;
|
||||
|
||||
private View mLightsOutView;
|
||||
private LightsOutNotifController mLightsOutNotifController;
|
||||
private int mDisplayId;
|
||||
private NotificationEntryListener mEntryListener;
|
||||
private Observer<Boolean> mHaActiveNotifsObserver;
|
||||
private CommandQueue.Callbacks mCallbacks;
|
||||
|
||||
@Before
|
||||
@@ -80,15 +79,20 @@ public class LightsOutNotifControllerTest extends SysuiTestCase {
|
||||
mLightsOutView = new View(mContext);
|
||||
when(mWindowManager.getDefaultDisplay()).thenReturn(mDisplay);
|
||||
when(mDisplay.getDisplayId()).thenReturn(mDisplayId);
|
||||
when(mNotifLiveDataStore.getHasActiveNotifs()).thenReturn(mHasActiveNotifs);
|
||||
when(mHasActiveNotifs.getValue()).thenReturn(false);
|
||||
|
||||
mLightsOutNotifController = new LightsOutNotifController(
|
||||
mLightsOutView, mWindowManager, mEntryManager, mCommandQueue);
|
||||
mLightsOutView,
|
||||
mWindowManager,
|
||||
mNotifLiveDataStore,
|
||||
mCommandQueue);
|
||||
mLightsOutNotifController.init();
|
||||
mLightsOutNotifController.onViewAttached();
|
||||
|
||||
// Capture the entry listener object so we can simulate events in tests below
|
||||
verify(mEntryManager).addNotificationEntryListener(mListenerCaptor.capture());
|
||||
mEntryListener = Objects.requireNonNull(mListenerCaptor.getValue());
|
||||
verify(mHasActiveNotifs).addSyncObserver(mObserverCaptor.capture());
|
||||
mHaActiveNotifsObserver = Objects.requireNonNull(mObserverCaptor.getValue());
|
||||
|
||||
// Capture the callback object so we can simulate callback events in tests below
|
||||
verify(mCommandQueue).addCallback(mCallbacksCaptor.capture());
|
||||
@@ -138,7 +142,7 @@ public class LightsOutNotifControllerTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void testLightsOut_withNotifs_onSystemBarAttributesChanged() {
|
||||
// GIVEN active visible notifications
|
||||
when(mEntryManager.hasActiveNotifications()).thenReturn(true);
|
||||
when(mHasActiveNotifs.getValue()).thenReturn(true);
|
||||
|
||||
// WHEN lights out
|
||||
mCallbacks.onSystemBarAttributesChanged(
|
||||
@@ -158,7 +162,7 @@ public class LightsOutNotifControllerTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void testLightsOut_withoutNotifs_onSystemBarAttributesChanged() {
|
||||
// GIVEN no active visible notifications
|
||||
when(mEntryManager.hasActiveNotifications()).thenReturn(false);
|
||||
when(mHasActiveNotifs.getValue()).thenReturn(false);
|
||||
|
||||
// WHEN lights out
|
||||
mCallbacks.onSystemBarAttributesChanged(
|
||||
@@ -178,7 +182,7 @@ public class LightsOutNotifControllerTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void testLightsOn_afterLightsOut_onSystemBarAttributesChanged() {
|
||||
// GIVEN active visible notifications
|
||||
when(mEntryManager.hasActiveNotifications()).thenReturn(true);
|
||||
when(mHasActiveNotifs.getValue()).thenReturn(true);
|
||||
|
||||
// WHEN lights on
|
||||
mCallbacks.onSystemBarAttributesChanged(
|
||||
@@ -198,15 +202,15 @@ public class LightsOutNotifControllerTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void testEntryAdded() {
|
||||
// GIVEN no visible notifications and lights out
|
||||
when(mEntryManager.hasActiveNotifications()).thenReturn(false);
|
||||
when(mHasActiveNotifs.getValue()).thenReturn(false);
|
||||
mLightsOutNotifController.mAppearance = LIGHTS_OUT;
|
||||
mLightsOutNotifController.updateLightsOutView();
|
||||
assertIsShowingDot(false);
|
||||
|
||||
// WHEN an active notification is added
|
||||
when(mEntryManager.hasActiveNotifications()).thenReturn(true);
|
||||
when(mHasActiveNotifs.getValue()).thenReturn(true);
|
||||
assertTrue(mLightsOutNotifController.shouldShowDot());
|
||||
mEntryListener.onNotificationAdded(mock(NotificationEntry.class));
|
||||
mHaActiveNotifsObserver.onChanged(true);
|
||||
|
||||
// THEN we should see the dot view
|
||||
assertIsShowingDot(true);
|
||||
@@ -215,38 +219,20 @@ public class LightsOutNotifControllerTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void testEntryRemoved() {
|
||||
// GIVEN a visible notification and lights out
|
||||
when(mEntryManager.hasActiveNotifications()).thenReturn(true);
|
||||
when(mHasActiveNotifs.getValue()).thenReturn(true);
|
||||
mLightsOutNotifController.mAppearance = LIGHTS_OUT;
|
||||
mLightsOutNotifController.updateLightsOutView();
|
||||
assertIsShowingDot(true);
|
||||
|
||||
// WHEN all active notifications are removed
|
||||
when(mEntryManager.hasActiveNotifications()).thenReturn(false);
|
||||
when(mHasActiveNotifs.getValue()).thenReturn(false);
|
||||
assertFalse(mLightsOutNotifController.shouldShowDot());
|
||||
mEntryListener.onEntryRemoved(
|
||||
mock(NotificationEntry.class), null, false, REASON_CANCEL_ALL);
|
||||
mHaActiveNotifsObserver.onChanged(false);
|
||||
|
||||
// THEN we shouldn't see the dot view
|
||||
assertIsShowingDot(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEntryUpdated() {
|
||||
// GIVEN no visible notifications and lights out
|
||||
when(mEntryManager.hasActiveNotifications()).thenReturn(false);
|
||||
mLightsOutNotifController.mAppearance = LIGHTS_OUT;
|
||||
mLightsOutNotifController.updateLightsOutView();
|
||||
assertIsShowingDot(false);
|
||||
|
||||
// WHEN an active notification is added
|
||||
when(mEntryManager.hasActiveNotifications()).thenReturn(true);
|
||||
assertTrue(mLightsOutNotifController.shouldShowDot());
|
||||
mEntryListener.onPostEntryUpdated(mock(NotificationEntry.class));
|
||||
|
||||
// THEN we should see the dot view
|
||||
assertIsShowingDot(true);
|
||||
}
|
||||
|
||||
private void assertIsShowingDot(boolean isShowing) {
|
||||
// cancel the animation so we can check the end state
|
||||
final ViewPropertyAnimator animation = mLightsOutView.animate();
|
||||
|
||||
@@ -119,6 +119,7 @@ import com.android.systemui.statusbar.notification.NotifPipelineFlags;
|
||||
import com.android.systemui.statusbar.notification.NotificationEntryManager;
|
||||
import com.android.systemui.statusbar.notification.NotificationFilter;
|
||||
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
|
||||
import com.android.systemui.statusbar.notification.collection.NotifLiveDataStore;
|
||||
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
|
||||
@@ -274,6 +275,7 @@ public class StatusBarTest extends SysuiTestCase {
|
||||
@Mock private OperatorNameViewController.Factory mOperatorNameViewControllerFactory;
|
||||
@Mock private ActivityLaunchAnimator mActivityLaunchAnimator;
|
||||
@Mock private NotifPipelineFlags mNotifPipelineFlags;
|
||||
@Mock private NotifLiveDataStore mNotifLiveDataStore;
|
||||
private ShadeController mShadeController;
|
||||
private final FakeSystemClock mFakeSystemClock = new FakeSystemClock();
|
||||
private FakeExecutor mMainExecutor = new FakeExecutor(mFakeSystemClock);
|
||||
@@ -306,6 +308,7 @@ public class StatusBarTest extends SysuiTestCase {
|
||||
mNotificationListener,
|
||||
mUiBgExecutor,
|
||||
mNotifPipelineFlags,
|
||||
mNotifLiveDataStore,
|
||||
mVisibilityProvider,
|
||||
mock(NotificationEntryManager.class),
|
||||
mock(NotifPipeline.class),
|
||||
|
||||
Reference in New Issue
Block a user