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

Commit d66046d7 authored by Ibrahim Yilmaz's avatar Ibrahim Yilmaz Committed by Android (Google) Code Review
Browse files

Merge changes Ide91eb72,I1009e9a3 into main

* changes:
  [HUN] Add NotificationsHeadsUpRefactor to HeadsUpManagerPhoneTest
  [HUN] Convert HeadsUp Manager Phone Test to Kotlin
parents 30838047 1aa096a9
Loading
Loading
Loading
Loading
+0 −243
Original line number 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.policy;

import static com.android.systemui.log.LogBufferHelperKt.logcatLogBuffer;
import static com.android.systemui.util.concurrency.MockExecutorHandlerKt.mockExecutorHandler;

import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;

import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.when;

import android.content.Context;
import android.os.Handler;
import android.platform.test.flag.junit.FlagsParameterization;
import android.testing.TestableLooper;

import androidx.test.filters.SmallTest;

import com.android.internal.logging.UiEventLogger;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.res.R;
import com.android.systemui.shade.domain.interactor.ShadeInteractor;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun;
import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.kotlin.JavaAdapter;
import com.android.systemui.util.settings.GlobalSettings;
import com.android.systemui.util.time.SystemClock;

import kotlinx.coroutines.flow.StateFlowKt;

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

import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
import platform.test.runner.parameterized.Parameters;

import java.util.List;

@SmallTest
@RunWith(ParameterizedAndroidJunit4.class)
@TestableLooper.RunWithLooper
public class HeadsUpManagerPhoneTest extends BaseHeadsUpManagerTest {
    @Rule public MockitoRule rule = MockitoJUnit.rule();

    private final HeadsUpManagerLogger mHeadsUpManagerLogger = new HeadsUpManagerLogger(
            logcatLogBuffer());
    @Mock private GroupMembershipManager mGroupManager;
    @Mock private VisualStabilityProvider mVSProvider;
    @Mock private StatusBarStateController mStatusBarStateController;
    @Mock private KeyguardBypassController mBypassController;
    @Mock private ConfigurationControllerImpl mConfigurationController;
    @Mock private AccessibilityManagerWrapper mAccessibilityManagerWrapper;
    @Mock private UiEventLogger mUiEventLogger;
    @Mock private JavaAdapter mJavaAdapter;
    @Mock private ShadeInteractor mShadeInteractor;
    @Mock private DumpManager dumpManager;
    private AvalancheController mAvalancheController;

    @Mock private Handler mBgHandler;

    private static final class TestableHeadsUpManagerPhone extends HeadsUpManagerPhone {
        TestableHeadsUpManagerPhone(
                Context context,
                HeadsUpManagerLogger headsUpManagerLogger,
                GroupMembershipManager groupManager,
                VisualStabilityProvider visualStabilityProvider,
                StatusBarStateController statusBarStateController,
                KeyguardBypassController keyguardBypassController,
                ConfigurationController configurationController,
                GlobalSettings globalSettings,
                SystemClock systemClock,
                DelayableExecutor executor,
                AccessibilityManagerWrapper accessibilityManagerWrapper,
                UiEventLogger uiEventLogger,
                JavaAdapter javaAdapter,
                ShadeInteractor shadeInteractor,
                AvalancheController avalancheController
        ) {
            super(
                    context,
                    headsUpManagerLogger,
                    statusBarStateController,
                    keyguardBypassController,
                    groupManager,
                    visualStabilityProvider,
                    configurationController,
                    mockExecutorHandler(executor),
                    globalSettings,
                    systemClock,
                    executor,
                    accessibilityManagerWrapper,
                    uiEventLogger,
                    javaAdapter,
                    shadeInteractor,
                    avalancheController
            );
            mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME;
            mAutoDismissTime = TEST_AUTO_DISMISS_TIME;
        }
    }

    private HeadsUpManagerPhone createHeadsUpManagerPhone() {
        return new TestableHeadsUpManagerPhone(
                mContext,
                mHeadsUpManagerLogger,
                mGroupManager,
                mVSProvider,
                mStatusBarStateController,
                mBypassController,
                mConfigurationController,
                mGlobalSettings,
                mSystemClock,
                mExecutor,
                mAccessibilityManagerWrapper,
                mUiEventLogger,
                mJavaAdapter,
                mShadeInteractor,
                mAvalancheController
        );
    }

    @Parameters(name = "{0}")
    public static List<FlagsParameterization> getFlags() {
        return FlagsParameterization.allCombinationsOf(NotificationThrottleHun.FLAG_NAME);
    }

    public HeadsUpManagerPhoneTest(FlagsParameterization flags) {
        super(flags);
    }

    @Before
    public void setUp() {
        when(mShadeInteractor.isAnyExpanded()).thenReturn(StateFlowKt.MutableStateFlow(false));
        final AccessibilityManagerWrapper accessibilityMgr =
                mDependency.injectMockDependency(AccessibilityManagerWrapper.class);
        when(accessibilityMgr.getRecommendedTimeoutMillis(anyInt(), anyInt()))
                .thenReturn(TEST_AUTO_DISMISS_TIME);
        when(mVSProvider.isReorderingAllowed()).thenReturn(true);
        mDependency.injectMockDependency(NotificationShadeWindowController.class);
        mContext.getOrCreateTestableResources().addOverride(
                R.integer.ambient_notification_extension_time, 500);

        mAvalancheController = new AvalancheController(dumpManager, mUiEventLogger, mBgHandler);
    }

    @Test
    public void testSnooze() {
        final HeadsUpManager hmp = createHeadsUpManagerPhone();
        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);

        hmp.showNotification(entry);
        hmp.snooze();

        assertTrue(hmp.isSnoozed(entry.getSbn().getPackageName()));
    }

    @Test
    public void testSwipedOutNotification() {
        final HeadsUpManager hmp = createHeadsUpManagerPhone();
        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);

        hmp.showNotification(entry);
        hmp.addSwipedOutNotification(entry.getKey());

        // Remove should succeed because the notification is swiped out
        final boolean removedImmediately = hmp.removeNotification(entry.getKey(),
                /* releaseImmediately = */ false);

        assertTrue(removedImmediately);
        assertFalse(hmp.isHeadsUpEntry(entry.getKey()));
    }

    @Test
    public void testCanRemoveImmediately_swipedOut() {
        final HeadsUpManager hmp = createHeadsUpManagerPhone();
        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);

        hmp.showNotification(entry);
        hmp.addSwipedOutNotification(entry.getKey());

        // Notification is swiped so it can be immediately removed.
        assertTrue(hmp.canRemoveImmediately(entry.getKey()));
    }

    @Ignore("b/141538055")
    @Test
    public void testCanRemoveImmediately_notTopEntry() {
        final HeadsUpManager hmp = createHeadsUpManagerPhone();
        final NotificationEntry earlierEntry =
                HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
        final NotificationEntry laterEntry =
                HeadsUpManagerTestUtil.createEntry(/* id = */ 1, mContext);
        laterEntry.setRow(mRow);

        hmp.showNotification(earlierEntry);
        hmp.showNotification(laterEntry);

        // Notification is "behind" a higher priority notification so we can remove it immediately.
        assertTrue(hmp.canRemoveImmediately(earlierEntry.getKey()));
    }

    @Test
    public void testExtendHeadsUp() {
        final HeadsUpManagerPhone hmp = createHeadsUpManagerPhone();
        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);

        hmp.showNotification(entry);
        hmp.extendHeadsUp();
        mSystemClock.advanceTime(TEST_AUTO_DISMISS_TIME + hmp.mExtensionTime / 2);

        assertTrue(hmp.isHeadsUpEntry(entry.getKey()));
    }
}
+232 −0
Original line number 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.policy

import android.content.Context
import android.os.Handler
import android.platform.test.flag.junit.FlagsParameterization
import android.testing.TestableLooper.RunWithLooper
import androidx.test.filters.SmallTest
import com.android.internal.logging.UiEventLogger
import com.android.systemui.dump.DumpManager
import com.android.systemui.log.logcatLogBuffer
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.res.R
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.statusbar.NotificationShadeWindowController
import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider
import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager
import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun
import com.android.systemui.statusbar.notification.shared.NotificationsHeadsUpRefactor
import com.android.systemui.statusbar.phone.ConfigurationControllerImpl
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.concurrency.mockExecutorHandler
import com.android.systemui.util.kotlin.JavaAdapter
import com.android.systemui.util.settings.GlobalSettings
import com.android.systemui.util.time.SystemClock
import junit.framework.Assert
import kotlinx.coroutines.flow.MutableStateFlow
import org.junit.Before
import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers
import org.mockito.Mock
import org.mockito.kotlin.whenever
import platform.test.runner.parameterized.ParameterizedAndroidJunit4
import platform.test.runner.parameterized.Parameters

@SmallTest
@RunWith(ParameterizedAndroidJunit4::class)
@RunWithLooper
class HeadsUpManagerPhoneTest(flags: FlagsParameterization) : BaseHeadsUpManagerTest(flags) {

    private val mHeadsUpManagerLogger = HeadsUpManagerLogger(logcatLogBuffer())

    @Mock private lateinit var mGroupManager: GroupMembershipManager

    @Mock private lateinit var mVSProvider: VisualStabilityProvider

    @Mock private lateinit var mStatusBarStateController: StatusBarStateController

    @Mock private lateinit var mBypassController: KeyguardBypassController

    @Mock private lateinit var mConfigurationController: ConfigurationControllerImpl

    @Mock private lateinit var mAccessibilityManagerWrapper: AccessibilityManagerWrapper

    @Mock private lateinit var mUiEventLogger: UiEventLogger

    @Mock private lateinit var mJavaAdapter: JavaAdapter

    @Mock private lateinit var mShadeInteractor: ShadeInteractor

    @Mock private lateinit var dumpManager: DumpManager
    private lateinit var mAvalancheController: AvalancheController

    @Mock private lateinit var mBgHandler: Handler

    private class TestableHeadsUpManagerPhone(
        context: Context,
        headsUpManagerLogger: HeadsUpManagerLogger,
        groupManager: GroupMembershipManager,
        visualStabilityProvider: VisualStabilityProvider,
        statusBarStateController: StatusBarStateController,
        keyguardBypassController: KeyguardBypassController,
        configurationController: ConfigurationController,
        globalSettings: GlobalSettings,
        systemClock: SystemClock,
        executor: DelayableExecutor,
        accessibilityManagerWrapper: AccessibilityManagerWrapper,
        uiEventLogger: UiEventLogger,
        javaAdapter: JavaAdapter,
        shadeInteractor: ShadeInteractor,
        avalancheController: AvalancheController
    ) :
        HeadsUpManagerPhone(
            context,
            headsUpManagerLogger,
            statusBarStateController,
            keyguardBypassController,
            groupManager,
            visualStabilityProvider,
            configurationController,
            mockExecutorHandler(executor),
            globalSettings,
            systemClock,
            executor,
            accessibilityManagerWrapper,
            uiEventLogger,
            javaAdapter,
            shadeInteractor,
            avalancheController
        ) {
        init {
            mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME
            mAutoDismissTime = TEST_AUTO_DISMISS_TIME
        }
    }

    private fun createHeadsUpManagerPhone(): HeadsUpManagerPhone {
        return TestableHeadsUpManagerPhone(
            mContext,
            mHeadsUpManagerLogger,
            mGroupManager,
            mVSProvider,
            mStatusBarStateController,
            mBypassController,
            mConfigurationController,
            mGlobalSettings,
            mSystemClock,
            mExecutor,
            mAccessibilityManagerWrapper,
            mUiEventLogger,
            mJavaAdapter,
            mShadeInteractor,
            mAvalancheController
        )
    }

    @Before
    fun setUp() {
        whenever(mShadeInteractor.isAnyExpanded).thenReturn(MutableStateFlow(false))
        whenever(mVSProvider.isReorderingAllowed).thenReturn(true)
        val accessibilityMgr =
            mDependency.injectMockDependency(AccessibilityManagerWrapper::class.java)
        whenever(
                accessibilityMgr.getRecommendedTimeoutMillis(
                    ArgumentMatchers.anyInt(),
                    ArgumentMatchers.anyInt()
                )
            )
            .thenReturn(TEST_AUTO_DISMISS_TIME)
        mDependency.injectMockDependency(NotificationShadeWindowController::class.java)
        mContext
            .getOrCreateTestableResources()
            .addOverride(R.integer.ambient_notification_extension_time, 500)
        mAvalancheController = AvalancheController(dumpManager, mUiEventLogger, mBgHandler)
    }

    @Test
    fun testSnooze() {
        val hmp: HeadsUpManager = createHeadsUpManagerPhone()
        val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
        hmp.showNotification(entry)
        hmp.snooze()
        Assert.assertTrue(hmp.isSnoozed(entry.sbn.packageName))
    }

    @Test
    fun testSwipedOutNotification() {
        val hmp: HeadsUpManager = createHeadsUpManagerPhone()
        val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
        hmp.showNotification(entry)
        hmp.addSwipedOutNotification(entry.key)

        // Remove should succeed because the notification is swiped out
        val removedImmediately = hmp.removeNotification(entry.key, /* releaseImmediately= */ false)
        Assert.assertTrue(removedImmediately)
        Assert.assertFalse(hmp.isHeadsUpEntry(entry.key))
    }

    @Test
    fun testCanRemoveImmediately_swipedOut() {
        val hmp: HeadsUpManager = createHeadsUpManagerPhone()
        val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
        hmp.showNotification(entry)
        hmp.addSwipedOutNotification(entry.key)

        // Notification is swiped so it can be immediately removed.
        Assert.assertTrue(hmp.canRemoveImmediately(entry.key))
    }

    @Ignore("b/141538055")
    @Test
    fun testCanRemoveImmediately_notTopEntry() {
        val hmp: HeadsUpManager = createHeadsUpManagerPhone()
        val earlierEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
        val laterEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 1, mContext)
        laterEntry.row = mRow
        hmp.showNotification(earlierEntry)
        hmp.showNotification(laterEntry)

        // Notification is "behind" a higher priority notification so we can remove it immediately.
        Assert.assertTrue(hmp.canRemoveImmediately(earlierEntry.key))
    }

    @Test
    fun testExtendHeadsUp() {
        val hmp = createHeadsUpManagerPhone()
        val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
        hmp.showNotification(entry)
        hmp.extendHeadsUp()
        mSystemClock.advanceTime((TEST_AUTO_DISMISS_TIME + hmp.mExtensionTime / 2).toLong())
        Assert.assertTrue(hmp.isHeadsUpEntry(entry.key))
    }

    companion object {
        @get:Parameters(name = "{0}")
        val flags: List<FlagsParameterization>
            get() = buildList {
                addAll(FlagsParameterization.allCombinationsOf(NotificationThrottleHun.FLAG_NAME))
                addAll(
                    FlagsParameterization.allCombinationsOf(NotificationsHeadsUpRefactor.FLAG_NAME)
                )
            }
    }
}