Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3805b471 authored by Ned Burns's avatar Ned Burns Committed by Android (Google) Code Review
Browse files

Merge "Revamp pipeline view manager"

parents b3838bbb 4fc6f947
Loading
Loading
Loading
Loading
+7 −3
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@ package com.android.systemui.statusbar.notification.collection;
import static com.android.systemui.statusbar.notification.collection.NotifCollection.REASON_NOT_CANCELED;
import static com.android.systemui.statusbar.notification.collection.NotificationEntry.DismissState.NOT_DISMISSED;

import static java.util.Objects.requireNonNull;

import com.android.systemui.statusbar.NotificationInteractionTracker;

import java.util.Arrays;
@@ -56,7 +58,7 @@ public class ListDumper {
                List<NotificationEntry> children = ge.getChildren();
                for (int childIndex = 0;  childIndex < children.size(); childIndex++) {
                    dumpEntry(children.get(childIndex),
                            Integer.toString(topEntryIndex) + "." + Integer.toString(childIndex),
                            topEntryIndex + "." + childIndex,
                            childEntryIndent,
                            sb,
                            true,
@@ -118,7 +120,7 @@ public class ListDumper {
        }

        if (includeRecordKeeping) {
            NotificationEntry notifEntry = entry.getRepresentativeEntry();
            NotificationEntry notifEntry = requireNonNull(entry.getRepresentativeEntry());
            StringBuilder rksb = new StringBuilder();

            if (!notifEntry.mLifetimeExtenders.isEmpty()) {
@@ -165,7 +167,9 @@ public class ListDumper {
                        .append(" ");
            }

            rksb.append("interacted=").append(hasBeenInteractedWith ? "yes" : "no").append(" ");
            if (hasBeenInteractedWith) {
                rksb.append("interacted=yes ");
            }

            String rkString = rksb.toString();
            if (!rkString.isEmpty()) {
+0 −204
Original line number Diff line number Diff line
/*
 * 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.annotation.MainThread
import android.view.ViewGroup

import com.android.systemui.statusbar.FeatureFlags
import com.android.systemui.statusbar.notification.VisualStabilityManager
import com.android.systemui.statusbar.notification.collection.GroupEntry.ROOT_ENTRY
import com.android.systemui.statusbar.notification.stack.NotificationListItem
import com.android.systemui.util.Assert

import java.io.FileDescriptor
import java.io.PrintWriter
import java.lang.IllegalStateException
import javax.inject.Inject
import javax.inject.Singleton

/**
 * A consumer of a Notification tree built by [ShadeListBuilder] which will update the notification
 * presenter with the minimum operations required to make the old tree match the new one
 */
@MainThread
@Singleton
class NotifViewManager @Inject constructor(
    private val rowRegistry: NotifViewBarn,
    private val stabilityManager: VisualStabilityManager,
    private val featureFlags: FeatureFlags
) {
    var currentNotifs = listOf<ListEntry>()

    private lateinit var listContainer: SimpleNotificationListContainer

    fun attach(listBuilder: ShadeListBuilder) {
        if (featureFlags.isNewNotifPipelineRenderingEnabled) {
            listBuilder.setOnRenderListListener { entries: List<ListEntry> ->
                this.onNotifTreeBuilt(entries)
            }
        }
    }

    fun setViewConsumer(consumer: SimpleNotificationListContainer) {
        listContainer = consumer
    }

    /**
     * Callback for when the tree is rebuilt
     */
    fun onNotifTreeBuilt(notifList: List<ListEntry>) {
        Assert.isMainThread()

        /*
         * The assumption here is that anything from the old NotificationViewHierarchyManager that
         * is responsible for filtering is done via the NotifFilter logic. This tree we get should
         * be *the stuff to display* +/- redacted stuff
         */

        detachRows(notifList)
        attachRows(notifList)

        currentNotifs = notifList
    }

    private fun detachRows(entries: List<ListEntry>) {
        // To properly detach rows, we are looking to remove any view in the consumer that is not
        // present in the incoming list.
        //
        // Every listItem was top-level, so it's entry's parent was ROOT_ENTRY, but now
        // there are two possibilities:
        //
        //      1. It is not present in the entry list
        //          1a. It has moved to be a child in the entry list - transfer it
        //          1b. It is gone completely - remove it
        //      2. It is present in the entry list - diff the children
        getListItems(listContainer)
                .filter {
                    // Ignore things that are showing the blocking helper
                    !it.isBlockingHelperShowing
                }
                .forEach { listItem ->
                    val noLongerTopLevel = listItem.entry.parent != ROOT_ENTRY
                    val becameChild = noLongerTopLevel && listItem.entry.parent != null

                    val idx = entries.indexOf(listItem.entry)

                    if (noLongerTopLevel) {
                        // Summaries won't become children; remove the whole group
                        if (listItem.isSummaryWithChildren) {
                            listItem.removeAllChildren()
                        }

                        if (becameChild) {
                            // Top-level element is becoming a child, don't generate an animation
                            listContainer.setChildTransferInProgress(true)
                        }
                        listContainer.removeListItem(listItem)
                        listContainer.setChildTransferInProgress(false)
                    } else if (entries[idx] is GroupEntry) {
                        // A top-level entry exists. If it's a group, diff the children
                        val groupChildren = (entries[idx] as GroupEntry).children
                        listItem.attachedChildren?.forEach { listChild ->
                            if (!groupChildren.contains(listChild.entry)) {
                                listItem.removeChildNotification(listChild)

                                // TODO: the old code only calls this if the notif is gone from
                                // NEM.getActiveNotificationUnfiltered(). Do we care?
                                listContainer.notifyGroupChildRemoved(
                                        listChild.view, listChild.view.parent as ViewGroup)
                            }
                        }
                    }
                }
    }

    /** Convenience method for getting a sequence of [NotificationListItem]s */
    private fun getListItems(container: SimpleNotificationListContainer):
            Sequence<NotificationListItem> {
        return (0 until container.getContainerChildCount()).asSequence()
                .map { container.getContainerChildAt(it) }
                .filterIsInstance<NotificationListItem>()
    }

    private fun attachRows(entries: List<ListEntry>) {

        var orderChanged = false

        // To attach rows we can use _this one weird trick_: if the intended view to add does not
        // have a parent, then simply add it (and its children).
        entries.forEach { entry ->
            // TODO: We should eventually map GroupEntry's themselves to views so that we don't
            // depend on representativeEntry here which may actually be null in the future
            val listItem = rowRegistry.requireView(entry.representativeEntry!!)

            if (listItem.view.parent == null) {
                listContainer.addListItem(listItem)
                stabilityManager.notifyViewAddition(listItem.view)
            }

            if (entry is GroupEntry) {
                for ((idx, childEntry) in entry.children.withIndex()) {
                    val childListItem = rowRegistry.requireView(childEntry)
                    // Child hasn't been added yet. add it!
                    if (listItem.attachedChildren == null ||
                            !listItem.attachedChildren.contains(childListItem)) {
                        // TODO: old code here just Log.wtf()'d here. This might wreak havoc
                        if (childListItem.view.parent != null) {
                            throw IllegalStateException("trying to add a notification child that " +
                                    "already has a parent. class: " +
                                    "${childListItem.view.parent?.javaClass} " +
                                    "\n child: ${childListItem.view}"
                            )
                        }

                        listItem.addChildNotification(childListItem, idx)
                        stabilityManager.notifyViewAddition(childListItem.view)
                        listContainer.notifyGroupChildAdded(childListItem.view)
                    }
                }

                // finally after removing and adding has been performed we can apply the order
                orderChanged = orderChanged ||
                        listItem.applyChildOrder(
                                getChildListFromParent(entry),
                                stabilityManager,
                                null /*TODO: stability callback */
                        )
                listItem.setUntruncatedChildCount(entry.untruncatedChildCount)
            }
        }

        if (orderChanged) {
            listContainer.generateChildOrderChangedEvent()
        }
    }

    private fun getChildListFromParent(parent: ListEntry): List<NotificationListItem> {
        if (parent is GroupEntry) {
            return parent.children.map { child -> rowRegistry.requireView(child) }
                    .toList()
        }

        return emptyList()
    }

    fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<String>) {
    }
}

private const val TAG = "NotifViewDataSource"
 No newline at end of file
+1 −1
Original line number Diff line number Diff line
@@ -865,7 +865,7 @@ public class ShadeListBuilder implements Dumpable {
                }
            };

    private static final String TAG = "NotifListBuilderImpl";
    private static final String TAG = "ShadeListBuilder";

    private static final int MIN_CHILDREN_FOR_GROUP = 2;
}
+0 −43
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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.view.View
import android.view.ViewGroup
import com.android.systemui.statusbar.notification.stack.NotificationListItem

/**
 * Minimal interface of what [NotifViewManager] needs from [NotificationListContainer]
 */
interface SimpleNotificationListContainer {
    /** Called to signify that a top-level element is becoming a child in the shade */
    fun setChildTransferInProgress(b: Boolean)
    /** Used to generate a list of [NotificationListItem] */
    fun getContainerChildAt(i: Int): View
    /** Similar to above */
    fun getContainerChildCount(): Int
    /** Remove a [NotificationListItem] from the container */
    fun removeListItem(li: NotificationListItem)
    /** Add a [NotificationListItem] to the container */
    fun addListItem(li: NotificationListItem)
    /** Allows [NotifViewManager] to notify the container about a group child removal */
    fun notifyGroupChildRemoved(row: View, parent: ViewGroup)
    /** Allows [NotifViewManager] to notify the container about a group child addition */
    fun notifyGroupChildAdded(row: View)
    /** [NotifViewManager] calls this when the order of the children changes */
    fun generateChildOrderChangedEvent()
}
+1 −1
Original line number Diff line number Diff line
@@ -31,13 +31,13 @@ import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.statusbar.notification.collection.GroupEntry;
import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotifViewBarn;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.ShadeListBuilder;
import com.android.systemui.statusbar.notification.collection.inflation.NotifInflater;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeFinalizeFilterListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.collection.render.NotifViewBarn;
import com.android.systemui.statusbar.notification.row.NotifInflationErrorManager;
import com.android.systemui.statusbar.notification.row.NotifInflationErrorManager.NotifInflationErrorListener;

Loading