New Pipeline: Implement lifetime extension for guts
Fixes: 204127880 Bug: 201413978 Test: GutsCoordinatorTest Merged-In: Icaeb83fc41bf92328e66b3a9a6ecc5ba23e515d9 Change-Id: Icaeb83fc41bf92328e66b3a9a6ecc5ba23e515d9
This commit is contained in:
@@ -523,7 +523,9 @@ public class NotifCollection implements Dumpable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onEndLifetimeExtension(NotifLifetimeExtender extender, NotificationEntry entry) {
|
private void onEndLifetimeExtension(
|
||||||
|
@NonNull NotifLifetimeExtender extender,
|
||||||
|
@NonNull NotificationEntry entry) {
|
||||||
Assert.isMainThread();
|
Assert.isMainThread();
|
||||||
if (!mAttached) {
|
if (!mAttached) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -0,0 +1,126 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.android.systemui.statusbar.notification.collection.coordinator
|
||||||
|
|
||||||
|
import android.util.ArraySet
|
||||||
|
import com.android.systemui.Dumpable
|
||||||
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
|
import com.android.systemui.dump.DumpManager
|
||||||
|
import com.android.systemui.statusbar.notification.collection.ListEntry
|
||||||
|
import com.android.systemui.statusbar.notification.collection.NotifPipeline
|
||||||
|
import com.android.systemui.statusbar.notification.collection.NotificationEntry
|
||||||
|
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender
|
||||||
|
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender.OnEndLifetimeExtensionCallback
|
||||||
|
import com.android.systemui.statusbar.notification.row.NotificationGuts
|
||||||
|
import com.android.systemui.statusbar.notification.row.NotificationGutsManager
|
||||||
|
import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewListener
|
||||||
|
import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewManager
|
||||||
|
import java.io.FileDescriptor
|
||||||
|
import java.io.PrintWriter
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
private const val TAG = "GutsCoordinator"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Coordinates the guts displayed by the [NotificationGutsManager] with the pipeline.
|
||||||
|
* Specifically, this just adds the lifetime extension necessary to keep guts from disappearing.
|
||||||
|
*/
|
||||||
|
@SysUISingleton
|
||||||
|
class GutsCoordinator @Inject constructor(
|
||||||
|
private val notifGutsViewManager: NotifGutsViewManager,
|
||||||
|
private val logger: GutsCoordinatorLogger,
|
||||||
|
dumpManager: DumpManager
|
||||||
|
) : Coordinator, Dumpable {
|
||||||
|
|
||||||
|
/** Keys of any Notifications for which we've been told the guts are open */
|
||||||
|
private val notifsWithOpenGuts = ArraySet<String>()
|
||||||
|
|
||||||
|
/** Keys of any Notifications we've extended the lifetime for, based on guts */
|
||||||
|
private val notifsExtendingLifetime = ArraySet<String>()
|
||||||
|
|
||||||
|
/** Callback for ending lifetime extension */
|
||||||
|
private var onEndLifetimeExtensionCallback: OnEndLifetimeExtensionCallback? = null
|
||||||
|
|
||||||
|
init {
|
||||||
|
dumpManager.registerDumpable(TAG, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun attach(pipeline: NotifPipeline) {
|
||||||
|
notifGutsViewManager.setGutsListener(mGutsListener)
|
||||||
|
pipeline.addNotificationLifetimeExtender(mLifetimeExtender)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<String>) {
|
||||||
|
pw.println(" notifsWithOpenGuts: ${notifsWithOpenGuts.size}")
|
||||||
|
for (key in notifsWithOpenGuts) {
|
||||||
|
pw.println(" * $key")
|
||||||
|
}
|
||||||
|
pw.println(" notifsExtendingLifetime: ${notifsExtendingLifetime.size}")
|
||||||
|
for (key in notifsExtendingLifetime) {
|
||||||
|
pw.println(" * $key")
|
||||||
|
}
|
||||||
|
pw.println(" onEndLifetimeExtensionCallback: $onEndLifetimeExtensionCallback")
|
||||||
|
}
|
||||||
|
|
||||||
|
private val mLifetimeExtender: NotifLifetimeExtender = object : NotifLifetimeExtender {
|
||||||
|
override fun getName(): String {
|
||||||
|
return TAG
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setCallback(callback: OnEndLifetimeExtensionCallback) {
|
||||||
|
onEndLifetimeExtensionCallback = callback
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun shouldExtendLifetime(entry: NotificationEntry, reason: Int): Boolean {
|
||||||
|
val isShowingGuts = isCurrentlyShowingGuts(entry)
|
||||||
|
if (isShowingGuts) {
|
||||||
|
notifsExtendingLifetime.add(entry.key)
|
||||||
|
}
|
||||||
|
return isShowingGuts
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun cancelLifetimeExtension(entry: NotificationEntry) {
|
||||||
|
notifsExtendingLifetime.remove(entry.key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val mGutsListener: NotifGutsViewListener = object : NotifGutsViewListener {
|
||||||
|
override fun onGutsOpen(entry: NotificationEntry, guts: NotificationGuts) {
|
||||||
|
logger.logGutsOpened(entry.key, guts)
|
||||||
|
if (guts.isLeavebehind) {
|
||||||
|
// leave-behind guts should not extend the lifetime of the notification
|
||||||
|
closeGutsAndEndLifetimeExtension(entry)
|
||||||
|
} else {
|
||||||
|
notifsWithOpenGuts.add(entry.key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onGutsClose(entry: NotificationEntry) {
|
||||||
|
logger.logGutsClosed(entry.key)
|
||||||
|
closeGutsAndEndLifetimeExtension(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isCurrentlyShowingGuts(entry: ListEntry) =
|
||||||
|
notifsWithOpenGuts.contains(entry.key)
|
||||||
|
|
||||||
|
private fun closeGutsAndEndLifetimeExtension(entry: NotificationEntry) {
|
||||||
|
notifsWithOpenGuts.remove(entry.key)
|
||||||
|
if (notifsExtendingLifetime.remove(entry.key)) {
|
||||||
|
onEndLifetimeExtensionCallback?.onEndLifetimeExtension(mLifetimeExtender, entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package com.android.systemui.statusbar.notification.collection.coordinator
|
||||||
|
|
||||||
|
import com.android.systemui.log.LogBuffer
|
||||||
|
import com.android.systemui.log.LogLevel
|
||||||
|
import com.android.systemui.log.dagger.NotificationLog
|
||||||
|
import com.android.systemui.statusbar.notification.row.NotificationGuts
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
private const val TAG = "GutsCoordinator"
|
||||||
|
|
||||||
|
class GutsCoordinatorLogger @Inject constructor(
|
||||||
|
@NotificationLog private val buffer: LogBuffer
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun logGutsOpened(key: String, guts: NotificationGuts) {
|
||||||
|
buffer.log(TAG, LogLevel.DEBUG, {
|
||||||
|
str1 = key
|
||||||
|
str2 = guts::class.simpleName
|
||||||
|
bool1 = guts.isLeavebehind
|
||||||
|
}, {
|
||||||
|
"Guts of type $str2 (leave behind: $bool1) opened for class $str1"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fun logGutsClosed(key: String) {
|
||||||
|
buffer.log(TAG, LogLevel.DEBUG, {
|
||||||
|
str1 = key
|
||||||
|
}, {
|
||||||
|
"Guts closed for class $str1"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,7 +19,8 @@ package com.android.systemui.statusbar.notification.collection.coordinator;
|
|||||||
import static com.android.systemui.statusbar.NotificationRemoteInputManager.FORCE_REMOTE_INPUT_HISTORY;
|
import static com.android.systemui.statusbar.NotificationRemoteInputManager.FORCE_REMOTE_INPUT_HISTORY;
|
||||||
import static com.android.systemui.statusbar.notification.interruption.HeadsUpController.alertAgain;
|
import static com.android.systemui.statusbar.notification.interruption.HeadsUpController.alertAgain;
|
||||||
|
|
||||||
import android.annotation.Nullable;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import com.android.systemui.dagger.SysUISingleton;
|
import com.android.systemui.dagger.SysUISingleton;
|
||||||
import com.android.systemui.statusbar.NotificationRemoteInputManager;
|
import com.android.systemui.statusbar.NotificationRemoteInputManager;
|
||||||
@@ -164,17 +165,17 @@ public class HeadsUpCoordinator implements Coordinator {
|
|||||||
|
|
||||||
private final NotifLifetimeExtender mLifetimeExtender = new NotifLifetimeExtender() {
|
private final NotifLifetimeExtender mLifetimeExtender = new NotifLifetimeExtender() {
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public @NonNull String getName() {
|
||||||
return TAG;
|
return TAG;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setCallback(OnEndLifetimeExtensionCallback callback) {
|
public void setCallback(@NonNull OnEndLifetimeExtensionCallback callback) {
|
||||||
mEndLifetimeExtension = callback;
|
mEndLifetimeExtension = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldExtendLifetime(NotificationEntry entry, int reason) {
|
public boolean shouldExtendLifetime(@NonNull NotificationEntry entry, int reason) {
|
||||||
boolean isShowingHun = isCurrentlyShowingHun(entry);
|
boolean isShowingHun = isCurrentlyShowingHun(entry);
|
||||||
if (isShowingHun) {
|
if (isShowingHun) {
|
||||||
mNotifExtendingLifetime = entry;
|
mNotifExtendingLifetime = entry;
|
||||||
@@ -183,7 +184,7 @@ public class HeadsUpCoordinator implements Coordinator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void cancelLifetimeExtension(NotificationEntry entry) {
|
public void cancelLifetimeExtension(@NonNull NotificationEntry entry) {
|
||||||
if (Objects.equals(mNotifExtendingLifetime, entry)) {
|
if (Objects.equals(mNotifExtendingLifetime, entry)) {
|
||||||
mNotifExtendingLifetime = null;
|
mNotifExtendingLifetime = null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ public class NotifCoordinators implements Dumpable {
|
|||||||
DeviceProvisionedCoordinator deviceProvisionedCoordinator,
|
DeviceProvisionedCoordinator deviceProvisionedCoordinator,
|
||||||
BubbleCoordinator bubbleCoordinator,
|
BubbleCoordinator bubbleCoordinator,
|
||||||
HeadsUpCoordinator headsUpCoordinator,
|
HeadsUpCoordinator headsUpCoordinator,
|
||||||
|
GutsCoordinator gutsCoordinator,
|
||||||
ConversationCoordinator conversationCoordinator,
|
ConversationCoordinator conversationCoordinator,
|
||||||
PreparationCoordinator preparationCoordinator,
|
PreparationCoordinator preparationCoordinator,
|
||||||
MediaCoordinator mediaCoordinator,
|
MediaCoordinator mediaCoordinator,
|
||||||
@@ -81,6 +82,7 @@ public class NotifCoordinators implements Dumpable {
|
|||||||
|
|
||||||
if (featureFlags.isNewNotifPipelineRenderingEnabled()) {
|
if (featureFlags.isNewNotifPipelineRenderingEnabled()) {
|
||||||
mCoordinators.add(headsUpCoordinator);
|
mCoordinators.add(headsUpCoordinator);
|
||||||
|
mCoordinators.add(gutsCoordinator);
|
||||||
mCoordinators.add(preparationCoordinator);
|
mCoordinators.add(preparationCoordinator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package com.android.systemui.statusbar.notification.collection.notifcollection;
|
package com.android.systemui.statusbar.notification.collection.notifcollection;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import com.android.systemui.statusbar.notification.collection.NotifCollection;
|
import com.android.systemui.statusbar.notification.collection.NotifCollection;
|
||||||
import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason;
|
import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason;
|
||||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||||
@@ -26,14 +28,14 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
|||||||
*/
|
*/
|
||||||
public interface NotifLifetimeExtender {
|
public interface NotifLifetimeExtender {
|
||||||
/** Name to associate with this extender (for the purposes of debugging) */
|
/** Name to associate with this extender (for the purposes of debugging) */
|
||||||
String getName();
|
@NonNull String getName();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called on the extender immediately after it has been registered. The extender should hang on
|
* Called on the extender immediately after it has been registered. The extender should hang on
|
||||||
* to this callback and execute it whenever it no longer needs to extend the lifetime of a
|
* to this callback and execute it whenever it no longer needs to extend the lifetime of a
|
||||||
* notification.
|
* notification.
|
||||||
*/
|
*/
|
||||||
void setCallback(OnEndLifetimeExtensionCallback callback);
|
void setCallback(@NonNull OnEndLifetimeExtensionCallback callback);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by the NotifCollection whenever a notification has been retracted (by the app) or
|
* Called by the NotifCollection whenever a notification has been retracted (by the app) or
|
||||||
@@ -43,7 +45,7 @@ public interface NotifLifetimeExtender {
|
|||||||
* called on all lifetime extenders even if earlier ones return true (in other words, multiple
|
* called on all lifetime extenders even if earlier ones return true (in other words, multiple
|
||||||
* lifetime extenders can be extending a notification at the same time).
|
* lifetime extenders can be extending a notification at the same time).
|
||||||
*/
|
*/
|
||||||
boolean shouldExtendLifetime(NotificationEntry entry, @CancellationReason int reason);
|
boolean shouldExtendLifetime(@NonNull NotificationEntry entry, @CancellationReason int reason);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by the NotifCollection to inform a lifetime extender that its extension of a notif
|
* Called by the NotifCollection to inform a lifetime extender that its extension of a notif
|
||||||
@@ -51,7 +53,7 @@ public interface NotifLifetimeExtender {
|
|||||||
* lifetime extension). The extender should clean up any references it has to the notif in
|
* lifetime extension). The extender should clean up any references it has to the notif in
|
||||||
* question.
|
* question.
|
||||||
*/
|
*/
|
||||||
void cancelLifetimeExtension(NotificationEntry entry);
|
void cancelLifetimeExtension(@NonNull NotificationEntry entry);
|
||||||
|
|
||||||
/** Callback for notifying the NotifCollection that a lifetime extension has expired.*/
|
/** Callback for notifying the NotifCollection that a lifetime extension has expired.*/
|
||||||
interface OnEndLifetimeExtensionCallback {
|
interface OnEndLifetimeExtensionCallback {
|
||||||
@@ -59,6 +61,8 @@ public interface NotifLifetimeExtender {
|
|||||||
* Stop extending the lifetime of `entry` with `extender` and then immediately re-evaluates
|
* Stop extending the lifetime of `entry` with `extender` and then immediately re-evaluates
|
||||||
* whether to continue lifetime extending this notification or to remove it.
|
* whether to continue lifetime extending this notification or to remove it.
|
||||||
*/
|
*/
|
||||||
void onEndLifetimeExtension(NotifLifetimeExtender extender, NotificationEntry entry);
|
void onEndLifetimeExtension(
|
||||||
|
@NonNull NotifLifetimeExtender extender,
|
||||||
|
@NonNull NotificationEntry entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* 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.render
|
||||||
|
|
||||||
|
import com.android.systemui.statusbar.notification.collection.NotificationEntry
|
||||||
|
import com.android.systemui.statusbar.notification.row.NotificationGuts
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for listening to guts open and close events.
|
||||||
|
*/
|
||||||
|
interface NotifGutsViewListener {
|
||||||
|
/** A notification's guts are being opened */
|
||||||
|
fun onGutsOpen(entry: NotificationEntry, guts: NotificationGuts)
|
||||||
|
|
||||||
|
/** A notification's guts are being closed */
|
||||||
|
fun onGutsClose(entry: NotificationEntry)
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* 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.render
|
||||||
|
|
||||||
|
/** A type which provides open and close guts events to a single listener */
|
||||||
|
interface NotifGutsViewManager {
|
||||||
|
/**
|
||||||
|
* @param listener the object that will listen to open and close guts events
|
||||||
|
*/
|
||||||
|
fun setGutsListener(listener: NotifGutsViewListener?)
|
||||||
|
}
|
||||||
@@ -58,6 +58,7 @@ import com.android.systemui.statusbar.notification.collection.render.GroupExpans
|
|||||||
import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManagerImpl;
|
import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManagerImpl;
|
||||||
import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
|
import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
|
||||||
import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManagerImpl;
|
import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManagerImpl;
|
||||||
|
import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewManager;
|
||||||
import com.android.systemui.statusbar.notification.init.NotificationsController;
|
import com.android.systemui.statusbar.notification.init.NotificationsController;
|
||||||
import com.android.systemui.statusbar.notification.init.NotificationsControllerImpl;
|
import com.android.systemui.statusbar.notification.init.NotificationsControllerImpl;
|
||||||
import com.android.systemui.statusbar.notification.init.NotificationsControllerStub;
|
import com.android.systemui.statusbar.notification.init.NotificationsControllerStub;
|
||||||
@@ -169,6 +170,14 @@ public interface NotificationsModule {
|
|||||||
dumpManager);
|
dumpManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Provides an instance of {@link NotifGutsViewManager} */
|
||||||
|
@SysUISingleton
|
||||||
|
@Provides
|
||||||
|
static NotifGutsViewManager provideNotifGutsViewManager(
|
||||||
|
NotificationGutsManager notificationGutsManager) {
|
||||||
|
return notificationGutsManager;
|
||||||
|
}
|
||||||
|
|
||||||
/** Provides an instance of {@link VisualStabilityManager} */
|
/** Provides an instance of {@link VisualStabilityManager} */
|
||||||
@SysUISingleton
|
@SysUISingleton
|
||||||
@Provides
|
@Provides
|
||||||
|
|||||||
@@ -65,6 +65,8 @@ import com.android.systemui.statusbar.notification.NotificationActivityStarter;
|
|||||||
import com.android.systemui.statusbar.notification.NotificationEntryManager;
|
import com.android.systemui.statusbar.notification.NotificationEntryManager;
|
||||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||||
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
|
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
|
||||||
|
import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewListener;
|
||||||
|
import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewManager;
|
||||||
import com.android.systemui.statusbar.notification.dagger.NotificationsModule;
|
import com.android.systemui.statusbar.notification.dagger.NotificationsModule;
|
||||||
import com.android.systemui.statusbar.notification.row.NotificationInfo.CheckSaveListener;
|
import com.android.systemui.statusbar.notification.row.NotificationInfo.CheckSaveListener;
|
||||||
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
|
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
|
||||||
@@ -83,7 +85,8 @@ import dagger.Lazy;
|
|||||||
* Handles various NotificationGuts related tasks, such as binding guts to a row, opening and
|
* Handles various NotificationGuts related tasks, such as binding guts to a row, opening and
|
||||||
* closing guts, and keeping track of the currently exposed notification guts.
|
* closing guts, and keeping track of the currently exposed notification guts.
|
||||||
*/
|
*/
|
||||||
public class NotificationGutsManager implements Dumpable, NotificationLifetimeExtender {
|
public class NotificationGutsManager implements Dumpable, NotificationLifetimeExtender,
|
||||||
|
NotifGutsViewManager {
|
||||||
private static final String TAG = "NotificationGutsManager";
|
private static final String TAG = "NotificationGutsManager";
|
||||||
|
|
||||||
// Must match constant in Settings. Used to highlight preferences when linking to Settings.
|
// Must match constant in Settings. Used to highlight preferences when linking to Settings.
|
||||||
@@ -123,7 +126,6 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
|
|||||||
private final Optional<BubblesManager> mBubblesManagerOptional;
|
private final Optional<BubblesManager> mBubblesManagerOptional;
|
||||||
private Runnable mOpenRunnable;
|
private Runnable mOpenRunnable;
|
||||||
private final INotificationManager mNotificationManager;
|
private final INotificationManager mNotificationManager;
|
||||||
private final NotificationEntryManager mNotificationEntryManager;
|
|
||||||
private final PeopleSpaceWidgetManager mPeopleSpaceWidgetManager;
|
private final PeopleSpaceWidgetManager mPeopleSpaceWidgetManager;
|
||||||
private final LauncherApps mLauncherApps;
|
private final LauncherApps mLauncherApps;
|
||||||
private final ShortcutManager mShortcutManager;
|
private final ShortcutManager mShortcutManager;
|
||||||
@@ -131,6 +133,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
|
|||||||
private final UiEventLogger mUiEventLogger;
|
private final UiEventLogger mUiEventLogger;
|
||||||
private final ShadeController mShadeController;
|
private final ShadeController mShadeController;
|
||||||
private final AppWidgetManager mAppWidgetManager;
|
private final AppWidgetManager mAppWidgetManager;
|
||||||
|
private NotifGutsViewListener mGutsListener;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Injected constructor. See {@link NotificationsModule}.
|
* Injected constructor. See {@link NotificationsModule}.
|
||||||
@@ -161,7 +164,6 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
|
|||||||
mAccessibilityManager = accessibilityManager;
|
mAccessibilityManager = accessibilityManager;
|
||||||
mHighPriorityProvider = highPriorityProvider;
|
mHighPriorityProvider = highPriorityProvider;
|
||||||
mNotificationManager = notificationManager;
|
mNotificationManager = notificationManager;
|
||||||
mNotificationEntryManager = notificationEntryManager;
|
|
||||||
mPeopleSpaceWidgetManager = peopleSpaceWidgetManager;
|
mPeopleSpaceWidgetManager = peopleSpaceWidgetManager;
|
||||||
mLauncherApps = launcherApps;
|
mLauncherApps = launcherApps;
|
||||||
mShortcutManager = shortcutManager;
|
mShortcutManager = shortcutManager;
|
||||||
@@ -258,10 +260,10 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
protected boolean bindGuts(final ExpandableNotificationRow row,
|
protected boolean bindGuts(final ExpandableNotificationRow row,
|
||||||
NotificationMenuRowPlugin.MenuItem item) {
|
NotificationMenuRowPlugin.MenuItem item) {
|
||||||
StatusBarNotification sbn = row.getEntry().getSbn();
|
NotificationEntry entry = row.getEntry();
|
||||||
|
|
||||||
row.setGutsView(item);
|
row.setGutsView(item);
|
||||||
row.setTag(sbn.getPackageName());
|
row.setTag(entry.getSbn().getPackageName());
|
||||||
row.getGuts().setClosedListener((NotificationGuts g) -> {
|
row.getGuts().setClosedListener((NotificationGuts g) -> {
|
||||||
row.onGutsClosed();
|
row.onGutsClosed();
|
||||||
if (!g.willBeRemoved() && !row.isRemoved()) {
|
if (!g.willBeRemoved() && !row.isRemoved()) {
|
||||||
@@ -272,7 +274,10 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
|
|||||||
mNotificationGutsExposed = null;
|
mNotificationGutsExposed = null;
|
||||||
mGutsMenuItem = null;
|
mGutsMenuItem = null;
|
||||||
}
|
}
|
||||||
String key = sbn.getKey();
|
if (mGutsListener != null) {
|
||||||
|
mGutsListener.onGutsClose(entry);
|
||||||
|
}
|
||||||
|
String key = entry.getKey();
|
||||||
if (key.equals(mKeyToRemoveOnGutsClosed)) {
|
if (key.equals(mKeyToRemoveOnGutsClosed)) {
|
||||||
mKeyToRemoveOnGutsClosed = null;
|
mKeyToRemoveOnGutsClosed = null;
|
||||||
if (mNotificationLifetimeFinishedCallback != null) {
|
if (mNotificationLifetimeFinishedCallback != null) {
|
||||||
@@ -650,6 +655,10 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
|
|||||||
needsFalsingProtection,
|
needsFalsingProtection,
|
||||||
row::onGutsOpened);
|
row::onGutsOpened);
|
||||||
|
|
||||||
|
if (mGutsListener != null) {
|
||||||
|
mGutsListener.onGutsOpen(row.getEntry(), guts);
|
||||||
|
}
|
||||||
|
|
||||||
row.closeRemoteInput();
|
row.closeRemoteInput();
|
||||||
mListContainer.onHeightChanged(row, true /* needsAnimation */);
|
mListContainer.onHeightChanged(row, true /* needsAnimation */);
|
||||||
mGutsMenuItem = menuItem;
|
mGutsMenuItem = menuItem;
|
||||||
@@ -695,10 +704,17 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
|
|||||||
@Override
|
@Override
|
||||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||||
pw.println("NotificationGutsManager state:");
|
pw.println("NotificationGutsManager state:");
|
||||||
pw.print(" mKeyToRemoveOnGutsClosed: ");
|
pw.print(" mKeyToRemoveOnGutsClosed (legacy): ");
|
||||||
pw.println(mKeyToRemoveOnGutsClosed);
|
pw.println(mKeyToRemoveOnGutsClosed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param gutsListener the listener for open and close guts events
|
||||||
|
*/
|
||||||
|
public void setGutsListener(NotifGutsViewListener gutsListener) {
|
||||||
|
mGutsListener = gutsListener;
|
||||||
|
}
|
||||||
|
|
||||||
public interface OnSettingsClickListener {
|
public interface OnSettingsClickListener {
|
||||||
public void onSettingsClick(String key);
|
public void onSettingsClick(String key);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ import android.util.ArrayMap;
|
|||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
import com.android.internal.statusbar.IStatusBarService;
|
import com.android.internal.statusbar.IStatusBarService;
|
||||||
@@ -1405,25 +1406,26 @@ public class NotifCollectionTest extends SysuiTestCase {
|
|||||||
mName = name;
|
mName = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return mName;
|
return mName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setCallback(OnEndLifetimeExtensionCallback callback) {
|
public void setCallback(@NonNull OnEndLifetimeExtensionCallback callback) {
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldExtendLifetime(
|
public boolean shouldExtendLifetime(
|
||||||
NotificationEntry entry,
|
@NonNull NotificationEntry entry,
|
||||||
@CancellationReason int reason) {
|
@CancellationReason int reason) {
|
||||||
return shouldExtendLifetime;
|
return shouldExtendLifetime;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void cancelLifetimeExtension(NotificationEntry entry) {
|
public void cancelLifetimeExtension(@NonNull NotificationEntry entry) {
|
||||||
if (onCancelLifetimeExtension != null) {
|
if (onCancelLifetimeExtension != null) {
|
||||||
onCancelLifetimeExtension.run();
|
onCancelLifetimeExtension.run();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
* 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.dump.DumpManager
|
||||||
|
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.notifcollection.NotifLifetimeExtender
|
||||||
|
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender.OnEndLifetimeExtensionCallback
|
||||||
|
import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewListener
|
||||||
|
import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewManager
|
||||||
|
import com.android.systemui.statusbar.notification.row.NotificationGuts
|
||||||
|
import com.android.systemui.util.mockito.argumentCaptor
|
||||||
|
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.mock
|
||||||
|
import org.mockito.Mockito.verify
|
||||||
|
import org.mockito.MockitoAnnotations.initMocks
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidTestingRunner::class)
|
||||||
|
@RunWithLooper
|
||||||
|
class GutsCoordinatorTest : SysuiTestCase() {
|
||||||
|
private lateinit var coordinator: GutsCoordinator
|
||||||
|
private lateinit var notifLifetimeExtender: NotifLifetimeExtender
|
||||||
|
private lateinit var notifGutsViewListener: NotifGutsViewListener
|
||||||
|
|
||||||
|
private lateinit var entry1: NotificationEntry
|
||||||
|
private lateinit var entry2: NotificationEntry
|
||||||
|
|
||||||
|
@Mock private lateinit var notifGutsViewManager: NotifGutsViewManager
|
||||||
|
@Mock private lateinit var pipeline: NotifPipeline
|
||||||
|
@Mock private lateinit var dumpManager: DumpManager
|
||||||
|
@Mock private lateinit var logger: GutsCoordinatorLogger
|
||||||
|
@Mock private lateinit var lifetimeExtenderCallback: OnEndLifetimeExtensionCallback
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
initMocks(this)
|
||||||
|
coordinator = GutsCoordinator(notifGutsViewManager, logger, dumpManager)
|
||||||
|
coordinator.attach(pipeline)
|
||||||
|
notifLifetimeExtender = argumentCaptor<NotifLifetimeExtender>().let {
|
||||||
|
verify(pipeline).addNotificationLifetimeExtender(it.capture())
|
||||||
|
it.value!!
|
||||||
|
}
|
||||||
|
notifGutsViewListener = argumentCaptor<NotifGutsViewListener>().let {
|
||||||
|
verify(notifGutsViewManager).setGutsListener(it.capture())
|
||||||
|
it.value!!
|
||||||
|
}
|
||||||
|
notifLifetimeExtender.setCallback(lifetimeExtenderCallback)
|
||||||
|
entry1 = NotificationEntryBuilder().setId(1).build()
|
||||||
|
entry2 = NotificationEntryBuilder().setId(2).build()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testSimpleLifetimeExtension() {
|
||||||
|
assertThat(notifLifetimeExtender.shouldExtendLifetime(entry1, 0)).isFalse()
|
||||||
|
notifGutsViewListener.onGutsOpen(entry1, mock(NotificationGuts::class.java))
|
||||||
|
assertThat(notifLifetimeExtender.shouldExtendLifetime(entry1, 0)).isTrue()
|
||||||
|
notifGutsViewListener.onGutsClose(entry1)
|
||||||
|
verify(lifetimeExtenderCallback).onEndLifetimeExtension(notifLifetimeExtender, entry1)
|
||||||
|
assertThat(notifLifetimeExtender.shouldExtendLifetime(entry1, 0)).isFalse()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testDoubleOpenLifetimeExtension() {
|
||||||
|
assertThat(notifLifetimeExtender.shouldExtendLifetime(entry1, 0)).isFalse()
|
||||||
|
notifGutsViewListener.onGutsOpen(entry1, mock(NotificationGuts::class.java))
|
||||||
|
assertThat(notifLifetimeExtender.shouldExtendLifetime(entry1, 0)).isTrue()
|
||||||
|
notifGutsViewListener.onGutsOpen(entry1, mock(NotificationGuts::class.java))
|
||||||
|
assertThat(notifLifetimeExtender.shouldExtendLifetime(entry1, 0)).isTrue()
|
||||||
|
notifGutsViewListener.onGutsClose(entry1)
|
||||||
|
verify(lifetimeExtenderCallback).onEndLifetimeExtension(notifLifetimeExtender, entry1)
|
||||||
|
assertThat(notifLifetimeExtender.shouldExtendLifetime(entry1, 0)).isFalse()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testTwoEntryLifetimeExtension() {
|
||||||
|
assertThat(notifLifetimeExtender.shouldExtendLifetime(entry1, 0)).isFalse()
|
||||||
|
assertThat(notifLifetimeExtender.shouldExtendLifetime(entry2, 0)).isFalse()
|
||||||
|
notifGutsViewListener.onGutsOpen(entry1, mock(NotificationGuts::class.java))
|
||||||
|
assertThat(notifLifetimeExtender.shouldExtendLifetime(entry1, 0)).isTrue()
|
||||||
|
assertThat(notifLifetimeExtender.shouldExtendLifetime(entry2, 0)).isFalse()
|
||||||
|
notifGutsViewListener.onGutsOpen(entry2, mock(NotificationGuts::class.java))
|
||||||
|
assertThat(notifLifetimeExtender.shouldExtendLifetime(entry1, 0)).isTrue()
|
||||||
|
assertThat(notifLifetimeExtender.shouldExtendLifetime(entry2, 0)).isTrue()
|
||||||
|
notifGutsViewListener.onGutsClose(entry1)
|
||||||
|
verify(lifetimeExtenderCallback).onEndLifetimeExtension(notifLifetimeExtender, entry1)
|
||||||
|
assertThat(notifLifetimeExtender.shouldExtendLifetime(entry1, 0)).isFalse()
|
||||||
|
assertThat(notifLifetimeExtender.shouldExtendLifetime(entry2, 0)).isTrue()
|
||||||
|
notifGutsViewListener.onGutsClose(entry2)
|
||||||
|
verify(lifetimeExtenderCallback).onEndLifetimeExtension(notifLifetimeExtender, entry2)
|
||||||
|
assertThat(notifLifetimeExtender.shouldExtendLifetime(entry1, 0)).isFalse()
|
||||||
|
assertThat(notifLifetimeExtender.shouldExtendLifetime(entry2, 0)).isFalse()
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user