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

Commit 65b5eb47 authored by Jagrut Desai's avatar Jagrut Desai Committed by Android (Google) Code Review
Browse files

Merge "Unit Testing for TaskbarEduTooltipController" into main

parents 369a5e74 5af1bfbf
Loading
Loading
Loading
Loading
+5 −3
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import android.view.accessibility.AccessibilityNodeInfo
import android.widget.TextView
import androidx.annotation.IntDef
import androidx.annotation.LayoutRes
import androidx.annotation.VisibleForTesting
import androidx.core.text.HtmlCompat
import androidx.core.view.updateLayoutParams
import com.airbnb.lottie.LottieAnimationView
@@ -87,7 +88,7 @@ open class TaskbarEduTooltipController(context: Context) :
                !activityContext.isTinyTaskbar
        }

    private val isOpen: Boolean
    val isTooltipOpen: Boolean
        get() = tooltip?.isOpen ?: false

    val isBeforeTooltipFeaturesStep: Boolean
@@ -96,7 +97,8 @@ open class TaskbarEduTooltipController(context: Context) :
    private lateinit var controllers: TaskbarControllers

    // Keep track of whether the user has seen the Search Edu
    private var userHasSeenSearchEdu: Boolean
    @VisibleForTesting
    var userHasSeenSearchEdu: Boolean
        get() {
            return TASKBAR_SEARCH_EDU_SEEN.get(activityContext)
        }
@@ -409,7 +411,7 @@ open class TaskbarEduTooltipController(context: Context) :
    override fun dumpLogs(prefix: String?, pw: PrintWriter?) {
        pw?.println(prefix + "TaskbarEduTooltipController:")
        pw?.println("$prefix\tisTooltipEnabled=$isTooltipEnabled")
        pw?.println("$prefix\tisOpen=$isOpen")
        pw?.println("$prefix\tisOpen=$isTooltipOpen")
        pw?.println("$prefix\ttooltipStep=$tooltipStep")
    }

+25 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.launcher3.taskbar

import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation

object TaskbarControllerTestUtil {
    inline fun runOnMainSync(crossinline runTest: () -> Unit) {
        getInstrumentation().runOnMainSync { runTest() }
    }
}
+205 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.launcher3.taskbar

import androidx.test.platform.app.InstrumentationRegistry
import com.android.launcher3.Utilities
import com.android.launcher3.taskbar.TaskbarControllerTestUtil.runOnMainSync
import com.android.launcher3.taskbar.rules.TaskbarModeRule
import com.android.launcher3.taskbar.rules.TaskbarModeRule.Mode.PINNED
import com.android.launcher3.taskbar.rules.TaskbarModeRule.Mode.THREE_BUTTONS
import com.android.launcher3.taskbar.rules.TaskbarModeRule.Mode.TRANSIENT
import com.android.launcher3.taskbar.rules.TaskbarModeRule.TaskbarMode
import com.android.launcher3.taskbar.rules.TaskbarPinningPreferenceRule
import com.android.launcher3.taskbar.rules.TaskbarPreferenceRule
import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule
import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule.InjectController
import com.android.launcher3.taskbar.rules.TaskbarWindowSandboxContext
import com.android.launcher3.util.LauncherMultivalentJUnit
import com.android.launcher3.util.LauncherMultivalentJUnit.EmulatedDevices
import com.android.launcher3.util.OnboardingPrefs
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(LauncherMultivalentJUnit::class)
@EmulatedDevices(["pixelFoldable2023", "pixelTablet2023"])
class TaskbarEduTooltipControllerTest {

    private val context =
        TaskbarWindowSandboxContext.create(
            InstrumentationRegistry.getInstrumentation().targetContext
        )

    @get:Rule
    val tooltipStepPreferenceRule =
        TaskbarPreferenceRule(
            context,
            OnboardingPrefs.TASKBAR_EDU_TOOLTIP_STEP.prefItem,
        )

    @get:Rule
    val searchEduPreferenceRule =
        TaskbarPreferenceRule(
            context,
            OnboardingPrefs.TASKBAR_SEARCH_EDU_SEEN,
        )

    @get:Rule val taskbarPinningPreferenceRule = TaskbarPinningPreferenceRule(context)

    @get:Rule val taskbarModeRule = TaskbarModeRule(context)

    @get:Rule val taskbarUnitTestRule = TaskbarUnitTestRule(this, context)

    @InjectController lateinit var taskbarEduTooltipController: TaskbarEduTooltipController

    private val taskbarContext: TaskbarActivityContext
        get() = taskbarUnitTestRule.activityContext

    private val wasInTestHarness = Utilities.isRunningInTestHarness()

    @Before
    fun setUp() {
        Utilities.disableRunningInTestHarnessForTests()
    }

    @After
    fun tearDown() {
        if (wasInTestHarness) {
            Utilities.enableRunningInTestHarnessForTests()
        }
    }

    @Test
    @TaskbarMode(THREE_BUTTONS)
    fun testMaybeShowSwipeEdu_whenTaskbarIsInThreeButtonMode_doesNotShowSwipeEdu() {
        tooltipStepPreferenceRule.value = TOOLTIP_STEP_SWIPE
        assertThat(taskbarEduTooltipController.tooltipStep).isEqualTo(TOOLTIP_STEP_SWIPE)
        runOnMainSync { taskbarEduTooltipController.maybeShowSwipeEdu() }
        assertThat(taskbarEduTooltipController.tooltipStep).isEqualTo(TOOLTIP_STEP_SWIPE)
        assertThat(taskbarEduTooltipController.isTooltipOpen).isFalse()
    }

    @Test
    @TaskbarMode(TRANSIENT)
    fun testMaybeShowSwipeEdu_whenSwipeEduAlreadyShown_doesNotShowSwipeEdu() {
        tooltipStepPreferenceRule.value = TOOLTIP_STEP_FEATURES
        assertThat(taskbarEduTooltipController.tooltipStep).isEqualTo(TOOLTIP_STEP_FEATURES)
        runOnMainSync { taskbarEduTooltipController.maybeShowSwipeEdu() }
        assertThat(taskbarEduTooltipController.tooltipStep).isEqualTo(TOOLTIP_STEP_FEATURES)
        assertThat(taskbarEduTooltipController.isTooltipOpen).isFalse()
    }

    @Test
    @TaskbarMode(TRANSIENT)
    fun testMaybeShowSwipeEdu_whenUserHasNotSeen_doesShowSwipeEdu() {
        tooltipStepPreferenceRule.value = TOOLTIP_STEP_SWIPE
        assertThat(taskbarEduTooltipController.tooltipStep).isEqualTo(TOOLTIP_STEP_SWIPE)
        runOnMainSync { taskbarEduTooltipController.maybeShowSwipeEdu() }
        assertThat(taskbarEduTooltipController.tooltipStep).isEqualTo(TOOLTIP_STEP_FEATURES)
        assertThat(taskbarEduTooltipController.isTooltipOpen).isTrue()
    }

    @Test
    @TaskbarMode(TRANSIENT)
    fun testMaybeShowFeaturesEdu_whenFeatureEduAlreadyShown_doesNotShowFeatureEdu() {
        tooltipStepPreferenceRule.value = TOOLTIP_STEP_NONE
        assertThat(taskbarEduTooltipController.tooltipStep).isEqualTo(TOOLTIP_STEP_NONE)
        runOnMainSync { taskbarEduTooltipController.maybeShowFeaturesEdu() }
        assertThat(taskbarEduTooltipController.tooltipStep).isEqualTo(TOOLTIP_STEP_NONE)
        assertThat(taskbarEduTooltipController.isTooltipOpen).isFalse()
    }

    @Test
    @TaskbarMode(TRANSIENT)
    fun testMaybeShowFeaturesEdu_whenUserHasNotSeen_doesShowFeatureEdu() {
        tooltipStepPreferenceRule.value = TOOLTIP_STEP_FEATURES
        assertThat(taskbarEduTooltipController.tooltipStep).isEqualTo(TOOLTIP_STEP_FEATURES)
        runOnMainSync { taskbarEduTooltipController.maybeShowFeaturesEdu() }
        assertThat(taskbarEduTooltipController.tooltipStep).isEqualTo(TOOLTIP_STEP_NONE)
        assertThat(taskbarEduTooltipController.isTooltipOpen).isTrue()
    }

    @Test
    @TaskbarMode(THREE_BUTTONS)
    fun testMaybeShowPinningEdu_whenTaskbarIsInThreeButtonMode_doesNotShowPinningEdu() {
        tooltipStepPreferenceRule.value = TOOLTIP_STEP_PINNING
        assertThat(taskbarEduTooltipController.tooltipStep).isEqualTo(TOOLTIP_STEP_PINNING)
        runOnMainSync { taskbarEduTooltipController.maybeShowFeaturesEdu() }
        assertThat(taskbarEduTooltipController.tooltipStep).isEqualTo(TOOLTIP_STEP_PINNING)
        assertThat(taskbarEduTooltipController.isTooltipOpen).isFalse()
    }

    @Test
    @TaskbarMode(TRANSIENT)
    fun testMaybeShowPinningEdu_whenUserHasNotSeen_doesShowPinningEdu() {
        // Test standalone pinning edu, where user has seen taskbar edu before, but not pinning edu.
        tooltipStepPreferenceRule.value = TOOLTIP_STEP_PINNING
        assertThat(taskbarEduTooltipController.tooltipStep).isEqualTo(TOOLTIP_STEP_PINNING)
        runOnMainSync { taskbarEduTooltipController.maybeShowFeaturesEdu() }
        assertThat(taskbarEduTooltipController.tooltipStep).isEqualTo(TOOLTIP_STEP_NONE)
        assertThat(taskbarEduTooltipController.isTooltipOpen).isTrue()
    }

    @Test
    @TaskbarMode(TRANSIENT)
    fun testIsBeforeTooltipFeaturesStep_whenUserHasNotSeenFeatureEdu_shouldReturnTrue() {
        tooltipStepPreferenceRule.value = TOOLTIP_STEP_SWIPE
        assertThat(taskbarEduTooltipController.isBeforeTooltipFeaturesStep).isTrue()
    }

    @Test
    @TaskbarMode(TRANSIENT)
    fun testIsBeforeTooltipFeaturesStep_whenUserHasSeenFeatureEdu_shouldReturnFalse() {
        tooltipStepPreferenceRule.value = TOOLTIP_STEP_NONE
        assertThat(taskbarEduTooltipController.isBeforeTooltipFeaturesStep).isFalse()
    }

    @Test
    @TaskbarMode(TRANSIENT)
    fun testHide_whenTooltipIsOpen_shouldCloseTooltip() {
        tooltipStepPreferenceRule.value = TOOLTIP_STEP_SWIPE
        assertThat(taskbarEduTooltipController.tooltipStep).isEqualTo(TOOLTIP_STEP_SWIPE)
        assertThat(taskbarEduTooltipController.isTooltipOpen).isFalse()
        runOnMainSync { taskbarEduTooltipController.maybeShowSwipeEdu() }
        assertThat(taskbarEduTooltipController.isTooltipOpen).isTrue()
        runOnMainSync { taskbarEduTooltipController.hide() }
        assertThat(taskbarEduTooltipController.isTooltipOpen).isFalse()
    }

    @Test
    @TaskbarMode(TRANSIENT)
    fun testMaybeShowSearchEdu_whenTaskbarIsTransient_shouldNotShowSearchEdu() {
        assertThat(taskbarEduTooltipController.isTooltipOpen).isFalse()
        runOnMainSync { taskbarEduTooltipController.init(taskbarContext.controllers) }
        assertThat(taskbarEduTooltipController.isTooltipOpen).isFalse()
    }

    @Test
    @TaskbarMode(PINNED)
    fun testMaybeShowSearchEdu_whenTaskbarIsPinnedAndUserHasSeenSearchEdu_shouldNotShowSearchEdu() {
        searchEduPreferenceRule.value = true
        assertThat(taskbarEduTooltipController.userHasSeenSearchEdu).isTrue()
        runOnMainSync { taskbarEduTooltipController.hide() }
        assertThat(taskbarEduTooltipController.isTooltipOpen).isFalse()
        runOnMainSync { taskbarEduTooltipController.init(taskbarContext.controllers) }
        assertThat(taskbarEduTooltipController.isTooltipOpen).isFalse()
    }
}
+9 −8
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import com.android.launcher3.appprediction.PredictionRowView
import com.android.launcher3.model.data.AppInfo
import com.android.launcher3.model.data.WorkspaceItemInfo
import com.android.launcher3.notification.NotificationKeyData
import com.android.launcher3.taskbar.TaskbarControllerTestUtil.runOnMainSync
import com.android.launcher3.taskbar.overlay.TaskbarOverlayController
import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule
import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule.InjectController
@@ -56,13 +57,13 @@ class TaskbarAllAppsControllerTest {

    @Test
    fun testToggle_once_showsAllApps() {
        getInstrumentation().runOnMainSync { allAppsController.toggle() }
        runOnMainSync { allAppsController.toggle() }
        assertThat(allAppsController.isOpen).isTrue()
    }

    @Test
    fun testToggle_twice_closesAllApps() {
        getInstrumentation().runOnMainSync {
        runOnMainSync {
            allAppsController.toggle()
            allAppsController.toggle()
        }
@@ -71,7 +72,7 @@ class TaskbarAllAppsControllerTest {

    @Test
    fun testToggle_taskbarRecreated_allAppsReopened() {
        getInstrumentation().runOnMainSync { allAppsController.toggle() }
        runOnMainSync { allAppsController.toggle() }
        taskbarUnitTestRule.recreateTaskbar()
        assertThat(allAppsController.isOpen).isTrue()
    }
@@ -138,7 +139,7 @@ class TaskbarAllAppsControllerTest {

    @Test
    fun testUpdateNotificationDots_appInfo_hasDot() {
        getInstrumentation().runOnMainSync {
        runOnMainSync {
            allAppsController.setApps(TEST_APPS, 0, emptyMap())
            allAppsController.toggle()
            taskbarUnitTestRule.activityContext.popupDataProvider.onNotificationPosted(
@@ -162,7 +163,7 @@ class TaskbarAllAppsControllerTest {

    @Test
    fun testUpdateNotificationDots_predictedApp_hasDot() {
        getInstrumentation().runOnMainSync {
        runOnMainSync {
            allAppsController.setPredictedApps(TEST_PREDICTED_APPS)
            allAppsController.toggle()
            taskbarUnitTestRule.activityContext.popupDataProvider.onNotificationPosted(
@@ -185,12 +186,12 @@ class TaskbarAllAppsControllerTest {

    @Test
    fun testToggleSearch_searchEditTextFocused() {
        getInstrumentation().runOnMainSync { allAppsController.toggleSearch() }
        getInstrumentation().runOnMainSync {
        runOnMainSync { allAppsController.toggleSearch() }
        runOnMainSync {
            // All Apps is now attached to window. Open animation is posted but not started.
        }

        getInstrumentation().runOnMainSync {
        runOnMainSync {
            // Animation has started. Advance to end of animation.
            animatorTestRule.advanceTimeBy(overlayController.openDuration.toLong())
        }
+18 −25
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_ALL_APPS
import com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_OVERLAY_PROXY
import com.android.launcher3.AbstractFloatingView.hasOpenView
import com.android.launcher3.taskbar.TaskbarActivityContext
import com.android.launcher3.taskbar.TaskbarControllerTestUtil.runOnMainSync
import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule
import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule.InjectController
import com.android.launcher3.taskbar.rules.TaskbarWindowSandboxContext
@@ -64,7 +65,7 @@ class TaskbarOverlayControllerTest {
    @Test
    fun testRequestWindow_afterHidingExistingWindow_createsNewWindow() {
        val context1 = getOnUiThread { overlayController.requestWindow() }
        getInstrumentation().runOnMainSync { overlayController.hideWindow() }
        runOnMainSync { overlayController.hideWindow() }

        val context2 = getOnUiThread { overlayController.requestWindow() }
        assertThat(context1).isNotSameInstanceAs(context2)
@@ -73,7 +74,7 @@ class TaskbarOverlayControllerTest {
    @Test
    fun testRequestWindow_afterHidingOverlay_createsNewWindow() {
        val context1 = getOnUiThread { overlayController.requestWindow() }
        getInstrumentation().runOnMainSync {
        runOnMainSync {
            TestOverlayView.show(context1)
            overlayController.hideWindow()
        }
@@ -84,16 +85,14 @@ class TaskbarOverlayControllerTest {

    @Test
    fun testRequestWindow_addsProxyView() {
        getInstrumentation().runOnMainSync {
            TestOverlayView.show(overlayController.requestWindow())
        }
        runOnMainSync { TestOverlayView.show(overlayController.requestWindow()) }
        assertThat(hasOpenView(taskbarContext, TYPE_TASKBAR_OVERLAY_PROXY)).isTrue()
    }

    @Test
    fun testRequestWindow_closeProxyView_closesOverlay() {
        val overlay = getOnUiThread { TestOverlayView.show(overlayController.requestWindow()) }
        getInstrumentation().runOnMainSync {
        runOnMainSync {
            AbstractFloatingView.closeOpenContainer(taskbarContext, TYPE_TASKBAR_OVERLAY_PROXY)
        }
        assertThat(overlay.isOpen).isFalse()
@@ -103,13 +102,13 @@ class TaskbarOverlayControllerTest {
    fun testRequestWindow_attachesDragLayer() {
        val dragLayer = getOnUiThread { overlayController.requestWindow().dragLayer }
        // Allow drag layer to attach before checking.
        getInstrumentation().runOnMainSync { assertThat(dragLayer.isAttachedToWindow).isTrue() }
        runOnMainSync { assertThat(dragLayer.isAttachedToWindow).isTrue() }
    }

    @Test
    fun testHideWindow_closesOverlay() {
        val overlay = getOnUiThread { TestOverlayView.show(overlayController.requestWindow()) }
        getInstrumentation().runOnMainSync { overlayController.hideWindow() }
        runOnMainSync { overlayController.hideWindow() }
        assertThat(overlay.isOpen).isFalse()
    }

@@ -118,7 +117,7 @@ class TaskbarOverlayControllerTest {
        val dragLayer = getOnUiThread { overlayController.requestWindow().dragLayer }

        // Wait for drag layer to be attached to window before hiding.
        getInstrumentation().runOnMainSync {
        runOnMainSync {
            overlayController.hideWindow()
            assertThat(dragLayer.isAttachedToWindow).isFalse()
        }
@@ -132,7 +131,7 @@ class TaskbarOverlayControllerTest {
                Pair(TestOverlayView.show(context), TestOverlayView.show(context))
            }

        getInstrumentation().runOnMainSync { overlay1.close(false) }
        runOnMainSync { overlay1.close(false) }
        assertThat(overlay2.isOpen).isTrue()
        assertThat(hasOpenView(taskbarContext, TYPE_TASKBAR_OVERLAY_PROXY)).isTrue()
    }
@@ -145,7 +144,7 @@ class TaskbarOverlayControllerTest {
                Pair(TestOverlayView.show(context), TestOverlayView.show(context))
            }

        getInstrumentation().runOnMainSync {
        runOnMainSync {
            overlay1.close(false)
            overlay2.close(false)
        }
@@ -154,9 +153,7 @@ class TaskbarOverlayControllerTest {

    @Test
    fun testRecreateTaskbar_closesWindow() {
        getInstrumentation().runOnMainSync {
            TestOverlayView.show(overlayController.requestWindow())
        }
        runOnMainSync { TestOverlayView.show(overlayController.requestWindow()) }
        taskbarUnitTestRule.recreateTaskbar()
        assertThat(hasOpenView(taskbarContext, TYPE_TASKBAR_OVERLAY_PROXY)).isFalse()
    }
@@ -166,29 +163,25 @@ class TaskbarOverlayControllerTest {
        val overlay = getOnUiThread { TestOverlayView.show(overlayController.requestWindow()) }
        TaskStackChangeListeners.getInstance().listenerImpl.onTaskMovedToFront(RunningTaskInfo())
        // Make sure TaskStackChangeListeners' Handler posts the callback before checking state.
        getInstrumentation().runOnMainSync { assertThat(overlay.isOpen).isFalse() }
        runOnMainSync { assertThat(overlay.isOpen).isFalse() }
    }

    @Test
    fun testTaskStackChanged_allAppsClosed_overlayStaysOpen() {
        val overlay = getOnUiThread { TestOverlayView.show(overlayController.requestWindow()) }
        getInstrumentation().runOnMainSync {
            taskbarContext.controllers.sharedState?.allAppsVisible = false
        }
        runOnMainSync { taskbarContext.controllers.sharedState?.allAppsVisible = false }

        TaskStackChangeListeners.getInstance().listenerImpl.onTaskStackChanged()
        getInstrumentation().runOnMainSync { assertThat(overlay.isOpen).isTrue() }
        runOnMainSync { assertThat(overlay.isOpen).isTrue() }
    }

    @Test
    fun testTaskStackChanged_allAppsOpen_closesOverlay() {
        val overlay = getOnUiThread { TestOverlayView.show(overlayController.requestWindow()) }
        getInstrumentation().runOnMainSync {
            taskbarContext.controllers.sharedState?.allAppsVisible = true
        }
        runOnMainSync { taskbarContext.controllers.sharedState?.allAppsVisible = true }

        TaskStackChangeListeners.getInstance().listenerImpl.onTaskStackChanged()
        getInstrumentation().runOnMainSync { assertThat(overlay.isOpen).isFalse() }
        runOnMainSync { assertThat(overlay.isOpen).isFalse() }
    }

    @Test
@@ -198,7 +191,7 @@ class TaskbarOverlayControllerTest {
            TestOverlayView.show(context).apply { type = TYPE_OPTIONS_POPUP }
        }

        getInstrumentation().runOnMainSync {
        runOnMainSync {
            overlayController.updateLauncherDeviceProfile(
                overlayController.launcherDeviceProfile
                    .toBuilder(context)
@@ -217,7 +210,7 @@ class TaskbarOverlayControllerTest {
            TestOverlayView.show(context).apply { type = TYPE_TASKBAR_ALL_APPS }
        }

        getInstrumentation().runOnMainSync {
        runOnMainSync {
            overlayController.updateLauncherDeviceProfile(
                overlayController.launcherDeviceProfile
                    .toBuilder(context)
Loading