diff options
author | Jagrut Desai <jagrutdesai@google.com> | 2023-12-12 16:19:00 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2023-12-12 16:19:00 +0000 |
commit | 2be2b932560f80287fc1fbfb35db381e6c806c49 (patch) | |
tree | 132ac37ad7b9737de77081a495ed66fc79101924 | |
parent | 2adff1b7c01615d0bded76c02ebdb99f6e95237e (diff) | |
parent | 70de8a4823653634af8475d69271c253562318c9 (diff) | |
download | Launcher3-2be2b932560f80287fc1fbfb35db381e6c806c49.tar.gz |
Merge "TaskbarPinningController Unit Tests" into main
5 files changed, 274 insertions, 35 deletions
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java index fc04d6c6b7..38ee4ac9ba 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java @@ -74,6 +74,7 @@ import androidx.annotation.VisibleForTesting; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.BubbleTextView; import com.android.launcher3.DeviceProfile; +import com.android.launcher3.LauncherPrefs; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.R; import com.android.launcher3.anim.AnimatorPlaybackController; @@ -183,6 +184,8 @@ public class TaskbarActivityContext extends BaseTaskbarContext { private DeviceProfile mPersistentTaskbarDeviceProfile; + private final LauncherPrefs mLauncherPrefs; + public TaskbarActivityContext(Context windowContext, @Nullable Context navigationBarPanelContext, DeviceProfile launcherDp, TaskbarNavButtonController buttonController, ScopedUnfoldTransitionProgressProvider @@ -294,6 +297,8 @@ public class TaskbarActivityContext extends BaseTaskbarContext { new KeyboardQuickSwitchController(), new TaskbarPinningController(this), bubbleControllersOptional); + + mLauncherPrefs = LauncherPrefs.get(this); } /** Updates {@link DeviceProfile} instances for any Taskbar windows. */ @@ -411,6 +416,11 @@ public class TaskbarActivityContext extends BaseTaskbarContext { getDeviceProfile().toSmallString()); } + @NonNull + public LauncherPrefs getLauncherPrefs() { + return mLauncherPrefs; + } + /** * Returns the View bounds of transient taskbar. */ diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt index cbfa0247e8..6cb28eee36 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt @@ -16,7 +16,9 @@ package com.android.launcher3.taskbar import android.animation.AnimatorSet +import android.annotation.SuppressLint import android.view.View +import androidx.annotation.VisibleForTesting import androidx.core.animation.doOnEnd import com.android.launcher3.LauncherPrefs import com.android.launcher3.LauncherPrefs.Companion.TASKBAR_PINNING @@ -31,46 +33,68 @@ class TaskbarPinningController(private val context: TaskbarActivityContext) : private lateinit var controllers: TaskbarControllers private lateinit var taskbarSharedState: TaskbarSharedState - private val launcherPrefs = LauncherPrefs.get(context) + private lateinit var launcherPrefs: LauncherPrefs private val statsLogManager = context.statsLogManager - private var isAnimatingTaskbarPinning = false + @VisibleForTesting var isAnimatingTaskbarPinning = false + @VisibleForTesting lateinit var onCloseCallback: (preferenceChanged: Boolean) -> Unit + @SuppressLint("VisibleForTests") fun init(taskbarControllers: TaskbarControllers, sharedState: TaskbarSharedState) { controllers = taskbarControllers taskbarSharedState = sharedState + launcherPrefs = context.launcherPrefs + onCloseCallback = + fun(didPreferenceChange: Boolean) { + statsLogManager.logger().log(LAUNCHER_TASKBAR_DIVIDER_MENU_CLOSE) + context.dragLayer.post { context.onPopupVisibilityChanged(false) } + + if (!didPreferenceChange) { + return + } + val animateToValue = + if (!launcherPrefs.get(TASKBAR_PINNING)) { + PINNING_PERSISTENT + } else { + PINNING_TRANSIENT + } + taskbarSharedState.taskbarWasPinned = animateToValue == PINNING_TRANSIENT + animateTaskbarPinning(animateToValue) + } } fun showPinningView(view: View) { context.isTaskbarWindowFullscreen = true - view.post { - val popupView = createAndPopulate(view, context) + val popupView = getPopupView(view) popupView.requestFocus() - - popupView.onCloseCallback = - callback@{ didPreferenceChange -> - statsLogManager.logger().log(LAUNCHER_TASKBAR_DIVIDER_MENU_CLOSE) - context.dragLayer.post { context.onPopupVisibilityChanged(false) } - - if (!didPreferenceChange) { - return@callback - } - val animateToValue = - if (!launcherPrefs.get(TASKBAR_PINNING)) { - PINNING_PERSISTENT - } else { - PINNING_TRANSIENT - } - taskbarSharedState.taskbarWasPinned = animateToValue == PINNING_TRANSIENT - animateTaskbarPinning(animateToValue) - } + popupView.onCloseCallback = onCloseCallback context.onPopupVisibilityChanged(true) popupView.show() statsLogManager.logger().log(LAUNCHER_TASKBAR_DIVIDER_MENU_OPEN) } } - private fun animateTaskbarPinning(animateToValue: Float) { + @VisibleForTesting + fun getPopupView(view: View): TaskbarDividerPopupView<*> { + return createAndPopulate(view, context) + } + + @VisibleForTesting + fun animateTaskbarPinning(animateToValue: Float) { + val taskbarViewController = controllers.taskbarViewController + val animatorSet = + getAnimatorSetForTaskbarPinningAnimation(animateToValue).apply { + doOnEnd { recreateTaskbarAndUpdatePinningValue() } + duration = PINNING_ANIMATION_DURATION + } + controllers.taskbarOverlayController.hideWindow() + updateIsAnimatingTaskbarPinningAndNotifyTaskbarDragLayer(true) + taskbarViewController.animateAwayNotificationDotsDuringTaskbarPinningAnimation() + animatorSet.start() + } + + @VisibleForTesting + fun getAnimatorSetForTaskbarPinningAnimation(animateToValue: Float): AnimatorSet { val animatorSet = AnimatorSet() val taskbarViewController = controllers.taskbarViewController val dragLayerController = controllers.taskbarDragLayerController @@ -82,13 +106,7 @@ class TaskbarPinningController(private val context: TaskbarActivityContext) : taskbarViewController.taskbarIconTranslationXForPinning.animateToValue(animateToValue) ) - controllers.taskbarOverlayController.hideWindow() - - animatorSet.doOnEnd { recreateTaskbarAndUpdatePinningValue() } - animatorSet.duration = PINNING_ANIMATION_DURATION - updateIsAnimatingTaskbarPinningAndNotifyTaskbarDragLayer(true) - taskbarViewController.animateAwayNotificationDotsDuringTaskbarPinningAnimation() - animatorSet.start() + return animatorSet } private fun updateIsAnimatingTaskbarPinningAndNotifyTaskbarDragLayer(isAnimating: Boolean) { @@ -96,7 +114,8 @@ class TaskbarPinningController(private val context: TaskbarActivityContext) : context.dragLayer.setAnimatingTaskbarPinning(isAnimating) } - private fun recreateTaskbarAndUpdatePinningValue() { + @VisibleForTesting + fun recreateTaskbarAndUpdatePinningValue() { updateIsAnimatingTaskbarPinningAndNotifyTaskbarDragLayer(false) launcherPrefs.put(TASKBAR_PINNING, !launcherPrefs.get(TASKBAR_PINNING)) } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java index 176a8c5e51..1224b3f064 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java @@ -73,9 +73,17 @@ public class TaskbarSharedState { }; // Allows us to shift translation logic when doing taskbar pinning animation. - public Boolean startTaskbarVariantIsTransient = true; + public boolean startTaskbarVariantIsTransient = true; // To track if taskbar was pinned using taskbar pinning feature at the time of recreate, // so we can unstash transient taskbar when we un-pinning taskbar. - public Boolean taskbarWasPinned = false; + private boolean mTaskbarWasPinned = false; + + public boolean getTaskbarWasPinned() { + return mTaskbarWasPinned; + } + + public void setTaskbarWasPinned(boolean taskbarWasPinned) { + mTaskbarWasPinned = taskbarWasPinned; + } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java index 9c532ec4f8..c74ddcbd21 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java @@ -307,7 +307,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba boolean isTransientTaskbar = DisplayController.isTransientTaskbar(mActivity); boolean isInSetup = !mActivity.isUserSetupComplete() || setupUIVisible; updateStateForFlag(FLAG_STASHED_IN_APP_AUTO, - isTransientTaskbar && !mTaskbarSharedState.taskbarWasPinned); + isTransientTaskbar && !mTaskbarSharedState.getTaskbarWasPinned()); updateStateForFlag(FLAG_STASHED_IN_APP_SETUP, isInSetup); updateStateForFlag(FLAG_IN_SETUP, isInSetup); updateStateForFlag(FLAG_STASHED_SMALL_SCREEN, isPhoneMode() @@ -316,7 +316,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba // us that we're paused until a bit later. This avoids flickering upon recreating taskbar. updateStateForFlag(FLAG_IN_APP, true); applyState(/* duration = */ 0); - if (mTaskbarSharedState.taskbarWasPinned) { + if (mTaskbarSharedState.getTaskbarWasPinned()) { tryStartTaskbarTimeout(); } notifyStashChange(/* visible */ false, /* stashed */ isStashedInApp()); diff --git a/quickstep/tests/src/com/android/quickstep/taskbar/controllers/TaskbarPinningControllerTest.kt b/quickstep/tests/src/com/android/quickstep/taskbar/controllers/TaskbarPinningControllerTest.kt new file mode 100644 index 0000000000..dbe4624e45 --- /dev/null +++ b/quickstep/tests/src/com/android/quickstep/taskbar/controllers/TaskbarPinningControllerTest.kt @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2023 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.quickstep.taskbar.controllers + +import android.animation.AnimatorSet +import android.animation.ObjectAnimator +import android.view.View +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.launcher3.LauncherPrefs +import com.android.launcher3.LauncherPrefs.Companion.TASKBAR_PINNING +import com.android.launcher3.logging.StatsLogManager +import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_DIVIDER_MENU_CLOSE +import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_DIVIDER_MENU_OPEN +import com.android.launcher3.taskbar.TaskbarActivityContext +import com.android.launcher3.taskbar.TaskbarBaseTestCase +import com.android.launcher3.taskbar.TaskbarDividerPopupView +import com.android.launcher3.taskbar.TaskbarDragLayer +import com.android.launcher3.taskbar.TaskbarPinningController +import com.android.launcher3.taskbar.TaskbarPinningController.Companion.PINNING_PERSISTENT +import com.android.launcher3.taskbar.TaskbarPinningController.Companion.PINNING_TRANSIENT +import com.android.launcher3.taskbar.TaskbarSharedState +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.any +import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.doNothing +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.never +import org.mockito.kotlin.spy +import org.mockito.kotlin.times +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever + +@SmallTest +@RunWith(AndroidJUnit4::class) +class TaskbarPinningControllerTest : TaskbarBaseTestCase() { + private val taskbarDragLayer = mock<TaskbarDragLayer>() + private val taskbarSharedState = mock<TaskbarSharedState>() + private val launcherPrefs = mock<LauncherPrefs> { on { get(TASKBAR_PINNING) } doReturn false } + private val statsLogger = mock<StatsLogManager.StatsLogger>() + private val statsLogManager = mock<StatsLogManager> { on { logger() } doReturn statsLogger } + private lateinit var pinningController: TaskbarPinningController + + @Before + override fun setup() { + super.setup() + whenever(taskbarActivityContext.launcherPrefs).thenReturn(launcherPrefs) + whenever(taskbarActivityContext.dragLayer).thenReturn(taskbarDragLayer) + whenever(taskbarActivityContext.statsLogManager).thenReturn(statsLogManager) + pinningController = spy(TaskbarPinningController(taskbarActivityContext)) + pinningController.init(taskbarControllers, taskbarSharedState) + } + + @Test + fun testOnCloseCallback_whenClosingPopupView_shouldLogStatsForClosingPopupMenu() { + pinningController.onCloseCallback(false) + verify(statsLogger, times(1)).log(LAUNCHER_TASKBAR_DIVIDER_MENU_CLOSE) + } + + @Test + fun testOnCloseCallback_whenClosingPopupView_shouldPostVisibilityChangedToDragLayer() { + val argumentCaptor = argumentCaptor<Runnable>() + pinningController.onCloseCallback(false) + verify(taskbarDragLayer, times(1)).post(argumentCaptor.capture()) + + val runnable = argumentCaptor.lastValue + assertThat(runnable).isNotNull() + + runnable.run() + verify(taskbarActivityContext, times(1)).onPopupVisibilityChanged(false) + } + + @Test + fun testOnCloseCallback_whenPreferenceUnchanged_shouldNotAnimateTaskbarPinning() { + pinningController.onCloseCallback(false) + verify(taskbarSharedState, never()).taskbarWasPinned = true + verify(pinningController, never()).animateTaskbarPinning(any()) + } + + @Test + fun testOnCloseCallback_whenPreferenceChanged_shouldAnimateToPinnedTaskbar() { + whenever(launcherPrefs.get(TASKBAR_PINNING)).thenReturn(false) + doNothing().whenever(pinningController).animateTaskbarPinning(any()) + + pinningController.onCloseCallback(true) + + verify(taskbarSharedState, times(1)).taskbarWasPinned = false + verify(pinningController, times(1)).animateTaskbarPinning(PINNING_PERSISTENT) + } + + @Test + fun testOnCloseCallback_whenPreferenceChanged_shouldAnimateToTransientTaskbar() { + whenever(launcherPrefs.get(TASKBAR_PINNING)).thenReturn(true) + doNothing().whenever(pinningController).animateTaskbarPinning(any()) + + pinningController.onCloseCallback(true) + + verify(taskbarSharedState, times(1)).taskbarWasPinned = true + verify(pinningController, times(1)).animateTaskbarPinning(PINNING_TRANSIENT) + } + + @Test + fun testShowPinningView_whenShowingPinningView_shouldSetTaskbarWindowFullscreenAndPostRunnableToView() { + val popupView = + mock<TaskbarDividerPopupView<TaskbarActivityContext>> { + on { requestFocus() } doReturn true + } + val view = mock<View>() + val argumentCaptor = argumentCaptor<Runnable>() + doReturn(popupView).whenever(pinningController).getPopupView(view) + + pinningController.showPinningView(view) + + verify(view, times(1)).post(argumentCaptor.capture()) + + val runnable = argumentCaptor.lastValue + assertThat(runnable).isNotNull() + runnable.run() + + verify(pinningController, times(1)).getPopupView(view) + verify(popupView, times(1)).requestFocus() + verify(popupView, times(1)).onCloseCallback = any() + verify(taskbarActivityContext, times(1)).onPopupVisibilityChanged(true) + verify(popupView, times(1)).show() + verify(statsLogger, times(1)).log(LAUNCHER_TASKBAR_DIVIDER_MENU_OPEN) + } + + @Test + fun testAnimateTaskbarPinning_whenAnimationEnds_shouldInvokeCallbackDoOnEnd() { + val animatorSet = spy(AnimatorSet()) + doReturn(animatorSet) + .whenever(pinningController) + .getAnimatorSetForTaskbarPinningAnimation(PINNING_PERSISTENT) + doNothing().whenever(animatorSet).start() + pinningController.animateTaskbarPinning(PINNING_PERSISTENT) + animatorSet.listeners[0].onAnimationEnd(ObjectAnimator()) + verify(pinningController, times(1)).recreateTaskbarAndUpdatePinningValue() + } + + @Test + fun testAnimateTaskbarPinning_whenAnimatingToPersistentTaskbar_shouldAnimateToPinnedTaskbar() { + val animatorSet = spy(AnimatorSet()) + doReturn(animatorSet) + .whenever(pinningController) + .getAnimatorSetForTaskbarPinningAnimation(PINNING_PERSISTENT) + doNothing().whenever(animatorSet).start() + pinningController.animateTaskbarPinning(PINNING_PERSISTENT) + + verify(taskbarOverlayController, times(1)).hideWindow() + verify(pinningController, times(1)) + .getAnimatorSetForTaskbarPinningAnimation(PINNING_PERSISTENT) + verify(taskbarViewController, times(1)) + .animateAwayNotificationDotsDuringTaskbarPinningAnimation() + verify(taskbarDragLayer, times(1)).setAnimatingTaskbarPinning(true) + assertThat(pinningController.isAnimatingTaskbarPinning).isTrue() + assertThat(animatorSet.listeners).isNotNull() + } + + @Test + fun testAnimateTaskbarPinning_whenAnimatingToTransientTaskbar_shouldAnimateToTransientTaskbar() { + val animatorSet = spy(AnimatorSet()) + doReturn(animatorSet) + .whenever(pinningController) + .getAnimatorSetForTaskbarPinningAnimation(PINNING_TRANSIENT) + doNothing().whenever(animatorSet).start() + pinningController.animateTaskbarPinning(PINNING_TRANSIENT) + + verify(taskbarOverlayController, times(1)).hideWindow() + verify(pinningController, times(1)) + .getAnimatorSetForTaskbarPinningAnimation(PINNING_TRANSIENT) + verify(taskbarDragLayer, times(1)).setAnimatingTaskbarPinning(true) + assertThat(pinningController.isAnimatingTaskbarPinning).isTrue() + verify(taskbarViewController, times(1)) + .animateAwayNotificationDotsDuringTaskbarPinningAnimation() + assertThat(animatorSet.listeners).isNotNull() + } + + @Test + fun testRecreateTaskbarAndUpdatePinningValue_whenAnimationEnds_shouldUpdateTaskbarPinningLauncherPref() { + pinningController.recreateTaskbarAndUpdatePinningValue() + verify(taskbarDragLayer, times(1)).setAnimatingTaskbarPinning(false) + assertThat(pinningController.isAnimatingTaskbarPinning).isFalse() + verify(launcherPrefs, times(1)).put(TASKBAR_PINNING, true) + } +} |