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

Commit 85f7df62 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Make mPendingNotifications truly private"

parents 37a22b6c 294d0a21
Loading
Loading
Loading
Loading
+41 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2018 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;

/**
 * Listener interface for when NotificationEntryManager needs to tell
 * NotificationGroupAlertTransferHelper things. Will eventually grow to be a general-purpose
 * listening interface for the NotificationEntryManager.
 */
public interface AlertTransferListener {
    /**
     * Called when a new notification is posted. At this point, the notification is "pending": its
     * views haven't been inflated yet and most of the system pretends like it doesn't exist yet.
     */
    void onPendingEntryAdded(NotificationData.Entry entry);

    /**
     * Called when an existing notification's views are reinflated (usually due to an update being
     * posted to that notification).
     */
    void onEntryReinflated(NotificationData.Entry entry);

    /**
     * Called when a notification has been removed (either because the user swiped it away or
     * because the developer retracted it).
     */
    void onEntryRemoved(NotificationData.Entry entry);
}
+23 −13
Original line number Original line Diff line number Diff line
@@ -61,7 +61,6 @@ import com.android.systemui.Dependency;
import com.android.systemui.Dumpable;
import com.android.systemui.Dumpable;
import com.android.systemui.EventLogTags;
import com.android.systemui.EventLogTags;
import com.android.systemui.ForegroundServiceController;
import com.android.systemui.ForegroundServiceController;
import com.android.systemui.InitController;
import com.android.systemui.R;
import com.android.systemui.R;
import com.android.systemui.UiOffloadThread;
import com.android.systemui.UiOffloadThread;
import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.bubbles.BubbleController;
@@ -83,7 +82,6 @@ import com.android.systemui.statusbar.notification.row.NotificationInflater;
import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
import com.android.systemui.statusbar.notification.row.RowInflaterTask;
import com.android.systemui.statusbar.notification.row.RowInflaterTask;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -117,8 +115,6 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater.


    private final NotificationGroupManager mGroupManager =
    private final NotificationGroupManager mGroupManager =
            Dependency.get(NotificationGroupManager.class);
            Dependency.get(NotificationGroupManager.class);
    private final NotificationGroupAlertTransferHelper mGroupAlertTransferHelper =
            Dependency.get(NotificationGroupAlertTransferHelper.class);
    private final NotificationGutsManager mGutsManager =
    private final NotificationGutsManager mGutsManager =
            Dependency.get(NotificationGutsManager.class);
            Dependency.get(NotificationGutsManager.class);
    private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
    private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
@@ -157,6 +153,7 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater.
            = new ArrayList<>();
            = new ArrayList<>();
    private ExpandableNotificationRow.OnAppOpsClickListener mOnAppOpsClickListener;
    private ExpandableNotificationRow.OnAppOpsClickListener mOnAppOpsClickListener;
    private NotificationViewHierarchyManager.StatusBarStateListener mStatusBarStateListener;
    private NotificationViewHierarchyManager.StatusBarStateListener mStatusBarStateListener;
    @Nullable private AlertTransferListener mAlertTransferListener;


    private final class NotificationClicker implements View.OnClickListener {
    private final class NotificationClicker implements View.OnClickListener {


@@ -258,12 +255,10 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater.
        mMessagingUtil = new NotificationMessagingUtil(context);
        mMessagingUtil = new NotificationMessagingUtil(context);
        mBubbleController.setDismissListener(this /* bubbleEventListener */);
        mBubbleController.setDismissListener(this /* bubbleEventListener */);
        mNotificationData = new NotificationData();
        mNotificationData = new NotificationData();
        Dependency.get(InitController.class).addPostInitTask(this::onPostInit);
    }
    }


    private void onPostInit() {
    public void setAlertTransferListener(AlertTransferListener listener) {
        mGroupAlertTransferHelper.setPendingEntries(mPendingNotifications);
        mAlertTransferListener = listener;
        mGroupManager.addOnGroupChangeListener(mGroupAlertTransferHelper);
    }
    }


    /**
    /**
@@ -587,7 +582,9 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater.
                    mVisualStabilityManager.onLowPriorityUpdated(entry);
                    mVisualStabilityManager.onLowPriorityUpdated(entry);
                    mPresenter.updateNotificationViews();
                    mPresenter.updateNotificationViews();
                }
                }
                mGroupAlertTransferHelper.onInflationFinished(entry);
                if (mAlertTransferListener != null) {
                    mAlertTransferListener.onEntryReinflated(entry);
                }
            }
            }
        }
        }
        entry.setLowPriorityStateUpdated(false);
        entry.setLowPriorityStateUpdated(false);
@@ -600,8 +597,12 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater.


    private void removeNotificationInternal(String key,
    private void removeNotificationInternal(String key,
            @Nullable NotificationListenerService.RankingMap ranking, boolean forceRemove) {
            @Nullable NotificationListenerService.RankingMap ranking, boolean forceRemove) {
        final NotificationData.Entry entry = mNotificationData.get(key);

        abortExistingInflation(key);
        abortExistingInflation(key);
        mGroupAlertTransferHelper.cleanUpPendingAlertInfo(key);
        if (mAlertTransferListener != null) {
            mAlertTransferListener.onEntryRemoved(entry);
        }


        // Attempt to remove notifications from their alert managers (heads up, ambient pulse).
        // Attempt to remove notifications from their alert managers (heads up, ambient pulse).
        // Though the remove itself may fail, it lets the manager know to remove as soon as
        // Though the remove itself may fail, it lets the manager know to remove as soon as
@@ -620,8 +621,6 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater.
            mAmbientPulseManager.removeNotification(key, false /* ignoreEarliestRemovalTime */);
            mAmbientPulseManager.removeNotification(key, false /* ignoreEarliestRemovalTime */);
        }
        }


        NotificationData.Entry entry = mNotificationData.get(key);

        if (entry == null) {
        if (entry == null) {
            mCallback.onNotificationRemoved(key, null /* old */);
            mCallback.onNotificationRemoved(key, null /* old */);
            return;
            return;
@@ -846,7 +845,9 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater.
                mNotificationData.getImportance(key));
                mNotificationData.getImportance(key));


        mPendingNotifications.put(key, shadeEntry);
        mPendingNotifications.put(key, shadeEntry);
        mGroupAlertTransferHelper.onPendingEntryAdded(shadeEntry);
        if (mAlertTransferListener != null) {
            mAlertTransferListener.onPendingEntryAdded(shadeEntry);
        }
    }
    }


    @VisibleForTesting
    @VisibleForTesting
@@ -1230,6 +1231,15 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater.
        }
        }
    }
    }


    /**
     * @return An iterator for all "pending" notifications. Pending notifications are newly-posted
     * notifications whose views have not yet been inflated. In general, the system pretends like
     * these don't exist, although there are a couple exceptions.
     */
    public Iterable<NotificationData.Entry> getPendingNotificationsIterator() {
        return mPendingNotifications.values();
    }

    /**
    /**
     * Callback for NotificationEntryManager.
     * Callback for NotificationEntryManager.
     */
     */
+91 −90
Original line number Original line Diff line number Diff line
@@ -29,7 +29,9 @@ import com.android.systemui.statusbar.AmbientPulseManager.OnAmbientChangedListen
import com.android.systemui.statusbar.InflationTask;
import com.android.systemui.statusbar.InflationTask;
import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.statusbar.notification.AlertTransferListener;
import com.android.systemui.statusbar.notification.NotificationData.Entry;
import com.android.systemui.statusbar.notification.NotificationData.Entry;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.row.NotificationInflater.AsyncInflationTask;
import com.android.systemui.statusbar.notification.row.NotificationInflater.AsyncInflationTask;
import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
import com.android.systemui.statusbar.phone.NotificationGroupManager.NotificationGroup;
import com.android.systemui.statusbar.phone.NotificationGroupManager.NotificationGroup;
@@ -38,8 +40,6 @@ import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;


import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Objects;
import java.util.Objects;


/**
/**
@@ -47,8 +47,8 @@ import java.util.Objects;
 * {@link HeadsUpManager}, {@link AmbientPulseManager}. In particular, this class deals with keeping
 * {@link HeadsUpManager}, {@link AmbientPulseManager}. In particular, this class deals with keeping
 * the correct notification in a group alerting based off the group suppression.
 * the correct notification in a group alerting based off the group suppression.
 */
 */
public class NotificationGroupAlertTransferHelper implements OnGroupChangeListener,
public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedListener,
        OnHeadsUpChangedListener, OnAmbientChangedListener, StateListener {
        OnAmbientChangedListener, StateListener {


    private static final long ALERT_TRANSFER_TIMEOUT = 300;
    private static final long ALERT_TRANSFER_TIMEOUT = 300;


@@ -69,15 +69,7 @@ public class NotificationGroupAlertTransferHelper implements OnGroupChangeListen
    private final NotificationGroupManager mGroupManager =
    private final NotificationGroupManager mGroupManager =
            Dependency.get(NotificationGroupManager.class);
            Dependency.get(NotificationGroupManager.class);


    // TODO(b/119637830): It would be good if GroupManager already had all pending notifications as
    private NotificationEntryManager mEntryManager;
    // normal children (i.e. add notifications to GroupManager before inflation) so that we don't
    // have to have this dependency. We'd also have to worry less about the suppression not being up
    // to date.
    /**
     * Notifications that are currently inflating for the first time. Used to remove an incorrectly
     * alerting notification faster.
     */
    private HashMap<String, Entry> mPendingNotifications;


    private boolean mIsDozing;
    private boolean mIsDozing;


@@ -85,6 +77,23 @@ public class NotificationGroupAlertTransferHelper implements OnGroupChangeListen
        Dependency.get(StatusBarStateController.class).addCallback(this);
        Dependency.get(StatusBarStateController.class).addCallback(this);
    }
    }


    /** Causes the TransferHelper to register itself as a listener to the appropriate classes. */
    public void bind(NotificationEntryManager entryManager,
            NotificationGroupManager groupManager) {
        if (mEntryManager != null) {
            throw new IllegalStateException("Already bound.");
        }

        // TODO(b/119637830): It would be good if GroupManager already had all pending notifications
        // as normal children (i.e. add notifications to GroupManager before inflation) so that we
        // don't have to have this dependency. We'd also have to worry less about the suppression
        // not being up to date.
        mEntryManager = entryManager;

        mEntryManager.setAlertTransferListener(mAlertTransferListener);
        groupManager.addOnGroupChangeListener(mOnGroupChangeListener);
    }

    /**
    /**
     * Whether or not a notification has transferred its alert state to the notification and
     * Whether or not a notification has transferred its alert state to the notification and
     * the notification should alert after inflating.
     * the notification should alert after inflating.
@@ -97,25 +106,10 @@ public class NotificationGroupAlertTransferHelper implements OnGroupChangeListen
        return alertInfo != null && alertInfo.isStillValid();
        return alertInfo != null && alertInfo.isStillValid();
    }
    }


    /**
     * Removes any alerts pending on this entry. Note that this will not stop any inflation tasks
     * started by a transfer, so this should only be used as clean-up for when inflation is stopped
     * and the pending alert no longer needs to happen.
     *
     * @param key notification key that may have info that needs to be cleaned up
     */
    public void cleanUpPendingAlertInfo(@NonNull String key) {
        mPendingAlerts.remove(key);
    }

    public void setHeadsUpManager(HeadsUpManager headsUpManager) {
    public void setHeadsUpManager(HeadsUpManager headsUpManager) {
        mHeadsUpManager = headsUpManager;
        mHeadsUpManager = headsUpManager;
    }
    }


    public void setPendingEntries(HashMap<String, Entry> pendingNotifications) {
        mPendingNotifications = pendingNotifications;
    }

    @Override
    @Override
    public void onStateChanged(int newState) {}
    public void onStateChanged(int newState) {}


@@ -130,6 +124,7 @@ public class NotificationGroupAlertTransferHelper implements OnGroupChangeListen
        mIsDozing = isDozing;
        mIsDozing = isDozing;
    }
    }


    private final OnGroupChangeListener mOnGroupChangeListener = new OnGroupChangeListener() {
        @Override
        @Override
        public void onGroupCreated(NotificationGroup group, String groupKey) {
        public void onGroupCreated(NotificationGroup group, String groupKey) {
            mGroupAlertEntries.put(groupKey, new GroupAlertEntry(group));
            mGroupAlertEntries.put(groupKey, new GroupAlertEntry(group));
@@ -167,6 +162,7 @@ public class NotificationGroupAlertTransferHelper implements OnGroupChangeListen
                }
                }
            }
            }
        }
        }
    };


    @Override
    @Override
    public void onAmbientStateChanged(Entry entry, boolean isAmbient) {
    public void onAmbientStateChanged(Entry entry, boolean isAmbient) {
@@ -185,37 +181,42 @@ public class NotificationGroupAlertTransferHelper implements OnGroupChangeListen
        }
        }
    }
    }


    /**
    private final AlertTransferListener mAlertTransferListener = new AlertTransferListener() {
     * Called when the entry's reinflation has finished. If there is an alert pending, we then
        // Called when a new notification has been posted but is not inflated yet. We use this to
     * show the alert.
        // see as early as we can if we need to abort a transfer.
     *
        @Override
     * @param entry entry whose inflation has finished
        public void onPendingEntryAdded(Entry entry) {
     */
            String groupKey = mGroupManager.getGroupKey(entry.notification);
    public void onInflationFinished(@NonNull Entry entry) {
            GroupAlertEntry groupAlertEntry = mGroupAlertEntries.get(groupKey);
            if (groupAlertEntry != null) {
                checkShouldTransferBack(groupAlertEntry);
            }
        }

        // Called when the entry's reinflation has finished. If there is an alert pending, we
        // then show the alert.
        @Override
        public void onEntryReinflated(Entry entry) {
            PendingAlertInfo alertInfo = mPendingAlerts.remove(entry.key);
            PendingAlertInfo alertInfo = mPendingAlerts.remove(entry.key);
            if (alertInfo != null) {
            if (alertInfo != null) {
                if (alertInfo.isStillValid()) {
                if (alertInfo.isStillValid()) {
                    alertNotificationWhenPossible(entry, getActiveAlertManager());
                    alertNotificationWhenPossible(entry, getActiveAlertManager());
                } else {
                } else {
                    // The transfer is no longer valid. Free the content.
                    // The transfer is no longer valid. Free the content.
                entry.getRow().freeContentViewWhenSafe(alertInfo.mAlertManager.getContentFlag());
                    entry.getRow().freeContentViewWhenSafe(
                            alertInfo.mAlertManager.getContentFlag());
                }
                }
            }
            }
        }
        }


    /**
        @Override
     * Called when a new notification has been posted but is not inflated yet. We use this to see
        public void onEntryRemoved(Entry entry) {
     * as early as we can if we need to abort a transfer.
            // Removes any alerts pending on this entry. Note that this will not stop any inflation
     *
            // tasks started by a transfer, so this should only be used as clean-up for when
     * @param entry entry that has been added
            // inflation is stopped and the pending alert no longer needs to happen.
     */
            mPendingAlerts.remove(entry.key);
    public void onPendingEntryAdded(@NonNull Entry entry) {
        String groupKey = mGroupManager.getGroupKey(entry.notification);
        GroupAlertEntry groupAlertEntry = mGroupAlertEntries.get(groupKey);
        if (groupAlertEntry != null) {
            checkShouldTransferBack(groupAlertEntry);
        }
        }
        }
    };


    /**
    /**
     * Gets the number of new notifications pending inflation that will be added to the group
     * Gets the number of new notifications pending inflation that will be added to the group
@@ -225,11 +226,11 @@ public class NotificationGroupAlertTransferHelper implements OnGroupChangeListen
     * @return the number of new notifications that will be added to the group
     * @return the number of new notifications that will be added to the group
     */
     */
    private int getPendingChildrenNotAlerting(@NonNull NotificationGroup group) {
    private int getPendingChildrenNotAlerting(@NonNull NotificationGroup group) {
        if (mPendingNotifications == null) {
        if (mEntryManager == null) {
            return 0;
            return 0;
        }
        }
        int number = 0;
        int number = 0;
        Collection<Entry> values = mPendingNotifications.values();
        Iterable<Entry> values = mEntryManager.getPendingNotificationsIterator();
        for (Entry entry : values) {
        for (Entry entry : values) {
            if (isPendingNotificationInGroup(entry, group) && onlySummaryAlerts(entry)) {
            if (isPendingNotificationInGroup(entry, group) && onlySummaryAlerts(entry)) {
                number++;
                number++;
@@ -245,10 +246,10 @@ public class NotificationGroupAlertTransferHelper implements OnGroupChangeListen
     * @return true if a pending notification will add to this group
     * @return true if a pending notification will add to this group
     */
     */
    private boolean pendingInflationsWillAddChildren(@NonNull NotificationGroup group) {
    private boolean pendingInflationsWillAddChildren(@NonNull NotificationGroup group) {
        if (mPendingNotifications == null) {
        if (mEntryManager == null) {
            return false;
            return false;
        }
        }
        Collection<Entry> values = mPendingNotifications.values();
        Iterable<Entry> values = mEntryManager.getPendingNotificationsIterator();
        for (Entry entry : values) {
        for (Entry entry : values) {
            if (isPendingNotificationInGroup(entry, group)) {
            if (isPendingNotificationInGroup(entry, group)) {
                return true;
                return true;
+2 −0
Original line number Original line Diff line number Diff line
@@ -628,6 +628,8 @@ public class StatusBar extends SystemUI implements DemoMode,
        mBubbleController = Dependency.get(BubbleController.class);
        mBubbleController = Dependency.get(BubbleController.class);
        mBubbleController.setExpandListener(mBubbleExpandListener);
        mBubbleController.setExpandListener(mBubbleExpandListener);


        mGroupAlertTransferHelper.bind(mEntryManager, mGroupManager);

        mColorExtractor.addOnColorsChangedListener(this);
        mColorExtractor.addOnColorsChangedListener(this);
        mStatusBarStateController.addCallback(this, StatusBarStateController.RANK_STATUS_BAR);
        mStatusBarStateController.addCallback(this, StatusBarStateController.RANK_STATUS_BAR);


+21 −10
Original line number Original line Diff line number Diff line
@@ -32,14 +32,19 @@ import android.testing.TestableLooper;


import com.android.systemui.SysuiTestCase;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.AmbientPulseManager;
import com.android.systemui.statusbar.AmbientPulseManager;
import com.android.systemui.statusbar.notification.AlertTransferListener;
import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationData.Entry;
import com.android.systemui.statusbar.notification.NotificationData.Entry;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.HeadsUpManager;


import org.junit.Before;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.mockito.junit.MockitoRule;


@@ -49,13 +54,15 @@ import java.util.HashMap;
@RunWith(AndroidTestingRunner.class)
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@TestableLooper.RunWithLooper
public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase {
public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase {
    @Rule
    @Rule public MockitoRule rule = MockitoJUnit.rule();
    public MockitoRule rule = MockitoJUnit.rule();


    private NotificationGroupAlertTransferHelper mGroupAlertTransferHelper;
    private NotificationGroupAlertTransferHelper mGroupAlertTransferHelper;
    private NotificationGroupManager mGroupManager;
    private NotificationGroupManager mGroupManager;
    private AmbientPulseManager mAmbientPulseManager;
    private AmbientPulseManager mAmbientPulseManager;
    private HeadsUpManager mHeadsUpManager;
    private HeadsUpManager mHeadsUpManager;
    @Mock private NotificationEntryManager mNotificationEntryManager;
    @Captor private ArgumentCaptor<AlertTransferListener> mListenerCaptor;
    private AlertTransferListener mAlertTransferListener;
    private final HashMap<String, Entry> mPendingEntries = new HashMap<>();
    private final HashMap<String, Entry> mPendingEntries = new HashMap<>();
    private final NotificationGroupTestHelper mGroupTestHelper =
    private final NotificationGroupTestHelper mGroupTestHelper =
            new NotificationGroupTestHelper(mContext);
            new NotificationGroupTestHelper(mContext);
@@ -67,15 +74,19 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase {
        mDependency.injectTestDependency(AmbientPulseManager.class, mAmbientPulseManager);
        mDependency.injectTestDependency(AmbientPulseManager.class, mAmbientPulseManager);
        mHeadsUpManager = new HeadsUpManager(mContext) {};
        mHeadsUpManager = new HeadsUpManager(mContext) {};


        when(mNotificationEntryManager.getPendingNotificationsIterator())
                .thenReturn(mPendingEntries.values());

        mGroupManager = new NotificationGroupManager();
        mGroupManager = new NotificationGroupManager();
        mDependency.injectTestDependency(NotificationGroupManager.class, mGroupManager);
        mDependency.injectTestDependency(NotificationGroupManager.class, mGroupManager);
        mGroupManager.setHeadsUpManager(mHeadsUpManager);
        mGroupManager.setHeadsUpManager(mHeadsUpManager);


        mGroupAlertTransferHelper = new NotificationGroupAlertTransferHelper();
        mGroupAlertTransferHelper = new NotificationGroupAlertTransferHelper();
        mGroupAlertTransferHelper.setHeadsUpManager(mHeadsUpManager);
        mGroupAlertTransferHelper.setHeadsUpManager(mHeadsUpManager);
        mGroupAlertTransferHelper.setPendingEntries(mPendingEntries);


        mGroupManager.addOnGroupChangeListener(mGroupAlertTransferHelper);
        mGroupAlertTransferHelper.bind(mNotificationEntryManager, mGroupManager);
        verify(mNotificationEntryManager).setAlertTransferListener(mListenerCaptor.capture());
        mAlertTransferListener = mListenerCaptor.getValue();
        mHeadsUpManager.addListener(mGroupAlertTransferHelper);
        mHeadsUpManager.addListener(mGroupAlertTransferHelper);
        mAmbientPulseManager.addListener(mGroupAlertTransferHelper);
        mAmbientPulseManager.addListener(mGroupAlertTransferHelper);
    }
    }
@@ -110,7 +121,7 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase {


        // Add second child notification so that summary is no longer suppressed.
        // Add second child notification so that summary is no longer suppressed.
        mPendingEntries.put(childEntry2.key, childEntry2);
        mPendingEntries.put(childEntry2.key, childEntry2);
        mGroupAlertTransferHelper.onPendingEntryAdded(childEntry2);
        mAlertTransferListener.onPendingEntryAdded(childEntry2);
        mGroupManager.onEntryAdded(childEntry2);
        mGroupManager.onEntryAdded(childEntry2);


        // The alert state should transfer back to the summary as there is now more than one
        // The alert state should transfer back to the summary as there is now more than one
@@ -137,7 +148,7 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase {


        // Add second child notification so that summary is no longer suppressed.
        // Add second child notification so that summary is no longer suppressed.
        mPendingEntries.put(childEntry2.key, childEntry2);
        mPendingEntries.put(childEntry2.key, childEntry2);
        mGroupAlertTransferHelper.onPendingEntryAdded(childEntry2);
        mAlertTransferListener.onPendingEntryAdded(childEntry2);
        mGroupManager.onEntryAdded(childEntry2);
        mGroupManager.onEntryAdded(childEntry2);


        // Dozing changed so no reason to re-alert summary.
        // Dozing changed so no reason to re-alert summary.
@@ -175,7 +186,7 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase {


        when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag()))
        when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag()))
            .thenReturn(true);
            .thenReturn(true);
        mGroupAlertTransferHelper.onInflationFinished(childEntry);
        mAlertTransferListener.onEntryReinflated(childEntry);


        // Alert is immediately removed from summary, and we show child as its content is inflated.
        // Alert is immediately removed from summary, and we show child as its content is inflated.
        assertFalse(mHeadsUpManager.isAlerting(summaryEntry.key));
        assertFalse(mHeadsUpManager.isAlerting(summaryEntry.key));
@@ -199,13 +210,13 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase {


        // Add second child notification so that summary is no longer suppressed.
        // Add second child notification so that summary is no longer suppressed.
        mPendingEntries.put(childEntry2.key, childEntry2);
        mPendingEntries.put(childEntry2.key, childEntry2);
        mGroupAlertTransferHelper.onPendingEntryAdded(childEntry2);
        mAlertTransferListener.onPendingEntryAdded(childEntry2);
        mGroupManager.onEntryAdded(childEntry2);
        mGroupManager.onEntryAdded(childEntry2);


        // Child entry finishes its inflation.
        // Child entry finishes its inflation.
        when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag()))
        when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag()))
            .thenReturn(true);
            .thenReturn(true);
        mGroupAlertTransferHelper.onInflationFinished(childEntry);
        mAlertTransferListener.onEntryReinflated(childEntry);


        verify(childEntry.getRow(), times(1)).freeContentViewWhenSafe(mHeadsUpManager
        verify(childEntry.getRow(), times(1)).freeContentViewWhenSafe(mHeadsUpManager
            .getContentFlag());
            .getContentFlag());
@@ -225,7 +236,7 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase {
        mGroupManager.onEntryAdded(summaryEntry);
        mGroupManager.onEntryAdded(summaryEntry);
        mGroupManager.onEntryAdded(childEntry);
        mGroupManager.onEntryAdded(childEntry);


        mGroupAlertTransferHelper.cleanUpPendingAlertInfo(childEntry.key);
        mAlertTransferListener.onEntryRemoved(childEntry);


        assertFalse(mGroupAlertTransferHelper.isAlertTransferPending(childEntry));
        assertFalse(mGroupAlertTransferHelper.isAlertTransferPending(childEntry));
    }
    }