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

Commit ba069aee authored by Selim Cinek's avatar Selim Cinek
Browse files

Isolating important conversations

Important conversations are isolated from their groups.
In the old pipeline, we also ensure the visual stability
of the elements while doing so.

Fixes: 152557990
Test: atest SystemUITests
Change-Id: Ic8dfb69f35e8dbf99d0ee20b8a5140bde41c2297
parent 853a84b5
Loading
Loading
Loading
Loading
+25 −5
Original line number Diff line number Diff line
@@ -177,12 +177,32 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
                    currentUserId);
            ent.setSensitive(sensitive, deviceSensitive);
            ent.getRow().setNeedsRedaction(needsRedaction);
            if (mGroupManager.isChildInGroupWithSummary(ent.getSbn())) {
                NotificationEntry summary = mGroupManager.getGroupSummary(ent.getSbn());
                List<NotificationEntry> orderedChildren = mTmpChildOrderMap.get(summary);
            boolean isChildInGroup = mGroupManager.isChildInGroupWithSummary(ent.getSbn());

            boolean groupChangesAllowed = mVisualStabilityManager.areGroupChangesAllowed()
                    || !ent.hasFinishedInitialization();
            NotificationEntry parent = mGroupManager.getGroupSummary(ent.getSbn());
            if (!groupChangesAllowed) {
                // We don't to change groups while the user is looking at them
                boolean wasChildInGroup = ent.isChildInGroup();
                if (isChildInGroup && !wasChildInGroup) {
                    isChildInGroup = wasChildInGroup;
                    mVisualStabilityManager.addGroupChangesAllowedCallback(mEntryManager);
                } else if (!isChildInGroup && wasChildInGroup) {
                    // We allow grouping changes if the group was collapsed
                    if (mGroupManager.isLogicalGroupExpanded(ent.getSbn())) {
                        isChildInGroup = wasChildInGroup;
                        parent = ent.getRow().getNotificationParent().getEntry();
                        mVisualStabilityManager.addGroupChangesAllowedCallback(mEntryManager);
                    }
                }
            }

            if (isChildInGroup) {
                List<NotificationEntry> orderedChildren = mTmpChildOrderMap.get(parent);
                if (orderedChildren == null) {
                    orderedChildren = new ArrayList<>();
                    mTmpChildOrderMap.put(summary, orderedChildren);
                    mTmpChildOrderMap.put(parent, orderedChildren);
                }
                orderedChildren.add(ent);
            } else {
@@ -205,7 +225,7 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
        }

        for (ExpandableNotificationRow viewToRemove : viewsToRemove) {
            if (mGroupManager.isChildInGroupWithSummary(viewToRemove.getEntry().getSbn())) {
            if (mEntryManager.getPendingOrActiveNotif(viewToRemove.getEntry().getKey()) != null) {
                // we are only transferring this notification to its parent, don't generate an
                // animation
                mListContainer.setChildTransferInProgress(true);
+12 −1
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import com.android.internal.widget.ConversationLayout
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.NotificationContentView
import com.android.systemui.statusbar.phone.NotificationGroupManager
import java.util.concurrent.ConcurrentHashMap
import javax.inject.Inject
import javax.inject.Singleton
@@ -60,6 +61,7 @@ class ConversationNotificationProcessor @Inject constructor(
@Singleton
class ConversationNotificationManager @Inject constructor(
    private val notificationEntryManager: NotificationEntryManager,
    private val notificationGroupManager: NotificationGroupManager,
    private val context: Context
) {
    // Need this state to be thread safe, since it's accessed from the ui thread
@@ -81,10 +83,19 @@ class ConversationNotificationManager @Inject constructor(
                            if (rankingMap.getRanking(entry.sbn.key, ranking) &&
                                    ranking.isConversation) {
                                val important = ranking.channel.isImportantConversation
                                var changed = false
                                entry.row?.layouts?.asSequence()
                                        ?.flatMap(::getLayouts)
                                        ?.mapNotNull { it as? ConversationLayout }
                                        ?.forEach { it.setIsImportantConversation(important) }
                                        ?.forEach {
                                            if (important != it.isImportantConversation) {
                                                it.setIsImportantConversation(important)
                                                changed = true
                                            }
                                        }
                                if (changed) {
                                    notificationGroupManager.updateIsolation(entry)
                                }
                            }
                        }
            }
+1 −1
Original line number Diff line number Diff line
@@ -252,7 +252,7 @@ public class NotificationEntryManager implements
    }

    @Override
    public void onReorderingAllowed() {
    public void onChangeAllowed() {
        updateNotifications("reordering is now allowed");
    }

+41 −18
Original line number Diff line number Diff line
@@ -42,12 +42,14 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener, Dumpabl

    private static final long TEMPORARY_REORDERING_ALLOWED_DURATION = 1000;

    private final ArrayList<Callback> mCallbacks =  new ArrayList<>();
    private final ArrayList<Callback> mReorderingAllowedCallbacks = new ArrayList<>();
    private final ArrayList<Callback> mGroupChangesAllowedCallbacks = new ArrayList<>();
    private final Handler mHandler;

    private boolean mPanelExpanded;
    private boolean mScreenOn;
    private boolean mReorderingAllowed;
    private boolean mGroupChangedAllowed;
    private boolean mIsTemporaryReorderingAllowed;
    private long mTemporaryReorderingStart;
    private VisibilityLocationProvider mVisibilityLocationProvider;
@@ -83,13 +85,22 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener, Dumpabl

    /**
     * Add a callback to invoke when reordering is allowed again.
     * @param callback
     */
    public void addReorderingAllowedCallback(Callback callback) {
        if (mCallbacks.contains(callback)) {
        if (mReorderingAllowedCallbacks.contains(callback)) {
            return;
        }
        mCallbacks.add(callback);
        mReorderingAllowedCallbacks.add(callback);
    }

    /**
     * Add a callback to invoke when group changes are allowed again.
     */
    public void addGroupChangesAllowedCallback(Callback callback) {
        if (mGroupChangesAllowedCallbacks.contains(callback)) {
            return;
        }
        mGroupChangesAllowedCallbacks.add(callback);
    }

    /**
@@ -97,7 +108,7 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener, Dumpabl
     */
    public void setPanelExpanded(boolean expanded) {
        mPanelExpanded = expanded;
        updateReorderingAllowed();
        updateAllowedStates();
    }

    /**
@@ -105,7 +116,7 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener, Dumpabl
     */
    public void setScreenOn(boolean screenOn) {
        mScreenOn = screenOn;
        updateReorderingAllowed();
        updateAllowedStates();
    }

    /**
@@ -116,25 +127,30 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener, Dumpabl
            return;
        }
        mPulsing = pulsing;
        updateReorderingAllowed();
        updateAllowedStates();
    }

    private void updateReorderingAllowed() {
    private void updateAllowedStates() {
        boolean reorderingAllowed =
                (!mScreenOn || !mPanelExpanded || mIsTemporaryReorderingAllowed) && !mPulsing;
        boolean changedToTrue = reorderingAllowed && !mReorderingAllowed;
        mReorderingAllowed = reorderingAllowed;
        if (changedToTrue) {
            notifyCallbacks();
            notifyChangeAllowed(mReorderingAllowedCallbacks);
        }
        boolean groupChangesAllowed = (!mScreenOn || !mPanelExpanded) && !mPulsing;
        changedToTrue = groupChangesAllowed && !mGroupChangedAllowed;
        mGroupChangedAllowed = groupChangesAllowed;
        if (changedToTrue) {
            notifyChangeAllowed(mGroupChangesAllowedCallbacks);
        }
    }

    private void notifyCallbacks() {
        for (int i = 0; i < mCallbacks.size(); i++) {
            Callback callback = mCallbacks.get(i);
            callback.onReorderingAllowed();
    private void notifyChangeAllowed(ArrayList<Callback> callbacks) {
        for (int i = 0; i < callbacks.size(); i++) {
            callbacks.get(i).onChangeAllowed();
        }
        mCallbacks.clear();
        callbacks.clear();
    }

    /**
@@ -144,6 +160,13 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener, Dumpabl
        return mReorderingAllowed;
    }

    /**
     * @return whether changes in the grouping should be allowed right now.
     */
    public boolean areGroupChangesAllowed() {
        return mGroupChangedAllowed;
    }

    /**
     * @return whether a specific notification is allowed to reorder. Certain notifications are
     * allowed to reorder even if {@link #isReorderingAllowed()} returns false, like newly added
@@ -197,12 +220,12 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener, Dumpabl
            mTemporaryReorderingStart = SystemClock.elapsedRealtime();
        }
        mIsTemporaryReorderingAllowed = true;
        updateReorderingAllowed();
        updateAllowedStates();
    }

    private final Runnable mOnTemporaryReorderingExpired = () -> {
        mIsTemporaryReorderingAllowed = false;
        updateReorderingAllowed();
        updateAllowedStates();
    };

    /**
@@ -229,9 +252,9 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener, Dumpabl

    public interface Callback {
        /**
         * Called when reordering is allowed again.
         * Called when changing is allowed again.
         */
        void onReorderingAllowed();
        void onChangeAllowed();
    }

}
+1 −2
Original line number Diff line number Diff line
@@ -149,7 +149,6 @@ public final class NotificationEntry extends ListEntry {
     */
    public EditedSuggestionInfo editedSuggestionInfo;

    private NotificationEntry parent; // our parent (if we're in a group)
    private ExpandableNotificationRow row; // the outer expanded view
    private ExpandableNotificationRowController mRowController;

@@ -719,7 +718,7 @@ public final class NotificationEntry extends ListEntry {
    }

    public boolean isChildInGroup() {
        return parent == null;
        return row != null && row.isChildInGroup();
    }

    /**
Loading