• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.launcher3.taskbar
17 
18 import android.animation.AnimatorSet
19 import android.annotation.SuppressLint
20 import android.view.View
21 import androidx.annotation.VisibleForTesting
22 import androidx.core.animation.doOnEnd
23 import com.android.app.animation.Interpolators
24 import com.android.launcher3.LauncherPrefs
25 import com.android.launcher3.LauncherPrefs.Companion.TASKBAR_PINNING
26 import com.android.launcher3.LauncherPrefs.Companion.TASKBAR_PINNING_IN_DESKTOP_MODE
27 import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_DIVIDER_MENU_CLOSE
28 import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_DIVIDER_MENU_OPEN
29 import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_PINNED
30 import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_UNPINNED
31 import com.android.launcher3.taskbar.TaskbarDividerPopupView.Companion.createAndPopulate
32 import java.io.PrintWriter
33 import kotlin.jvm.optionals.getOrNull
34 
35 /** Controls taskbar pinning through a popup view. */
36 class TaskbarPinningController(private val context: TaskbarActivityContext) :
37     TaskbarControllers.LoggableTaskbarController {
38 
39     private lateinit var controllers: TaskbarControllers
40     private lateinit var taskbarSharedState: TaskbarSharedState
41     private lateinit var launcherPrefs: LauncherPrefs
42     private val statsLogManager = context.statsLogManager
43     @VisibleForTesting var isAnimatingTaskbarPinning = false
44     @VisibleForTesting lateinit var onCloseCallback: (preferenceChanged: Boolean) -> Unit
45 
46     @SuppressLint("VisibleForTests")
initnull47     fun init(taskbarControllers: TaskbarControllers, sharedState: TaskbarSharedState) {
48         controllers = taskbarControllers
49         taskbarSharedState = sharedState
50         launcherPrefs = context.launcherPrefs
51         onCloseCallback =
52             fun(didPreferenceChange: Boolean) {
53                 statsLogManager.logger().log(LAUNCHER_TASKBAR_DIVIDER_MENU_CLOSE)
54                 context.dragLayer.post { context.onPopupVisibilityChanged(false) }
55 
56                 if (!didPreferenceChange) {
57                     return
58                 }
59                 val shouldPinTaskbar =
60                     if (
61                         controllers.taskbarDesktopModeController.isInDesktopModeAndNotInOverview(
62                             context.displayId
63                         )
64                     ) {
65                         !launcherPrefs.get(TASKBAR_PINNING_IN_DESKTOP_MODE)
66                     } else {
67                         !launcherPrefs.get(TASKBAR_PINNING)
68                     }
69 
70                 val animateToValue =
71                     if (shouldPinTaskbar) {
72                         statsLogManager.logger().log(LAUNCHER_TASKBAR_PINNED)
73                         PINNING_PERSISTENT
74                     } else {
75                         statsLogManager.logger().log(LAUNCHER_TASKBAR_UNPINNED)
76                         PINNING_TRANSIENT
77                     }
78 
79                 taskbarSharedState.taskbarWasPinned = animateToValue == PINNING_TRANSIENT
80                 animateTaskbarPinning(animateToValue)
81             }
82     }
83 
showPinningViewnull84     fun showPinningView(view: View, horizontalPosition: Float = -1f) {
85         context.isTaskbarWindowFullscreen = true
86         view.post {
87             val popupView = getPopupView(view, horizontalPosition)
88             popupView.requestFocus()
89             popupView.onCloseCallback = onCloseCallback
90             context.onPopupVisibilityChanged(true)
91             popupView.show()
92             statsLogManager.logger().log(LAUNCHER_TASKBAR_DIVIDER_MENU_OPEN)
93         }
94     }
95 
96     @VisibleForTesting
getPopupViewnull97     fun getPopupView(view: View, horizontalPosition: Float = -1f): TaskbarDividerPopupView<*> {
98         return createAndPopulate(view, context, horizontalPosition)
99     }
100 
101     @VisibleForTesting
animateTaskbarPinningnull102     fun animateTaskbarPinning(animateToValue: Float) {
103         val taskbarViewController = controllers.taskbarViewController
104         val animatorSet =
105             getAnimatorSetForTaskbarPinningAnimation(animateToValue).apply {
106                 doOnEnd { recreateTaskbarAndUpdatePinningValue() }
107                 duration = PINNING_ANIMATION_DURATION
108             }
109         controllers.taskbarOverlayController.hideWindow()
110         updateIsAnimatingTaskbarPinningAndNotifyTaskbarDragLayer(true)
111         taskbarViewController.animateAwayNotificationDotsDuringTaskbarPinningAnimation()
112         animatorSet.start()
113     }
114 
115     @VisibleForTesting
getAnimatorSetForTaskbarPinningAnimationnull116     fun getAnimatorSetForTaskbarPinningAnimation(animateToValue: Float): AnimatorSet {
117         val animatorSet = AnimatorSet()
118         val taskbarViewController = controllers.taskbarViewController
119         val dragLayerController = controllers.taskbarDragLayerController
120 
121         animatorSet.playTogether(
122             dragLayerController.taskbarBackgroundProgress.animateToValue(animateToValue),
123             taskbarViewController.taskbarIconTranslationYForPinning.animateToValue(animateToValue),
124             taskbarViewController.taskbarIconScaleForPinning.animateToValue(animateToValue),
125             taskbarViewController.taskbarIconTranslationXForPinning.animateToValue(animateToValue),
126         )
127         controllers.bubbleControllers.getOrNull()?.bubbleBarViewController?.let {
128             // if bubble bar is not visible no need to add it`s animations
129             if (!it.isBubbleBarVisible) return@let
130             animatorSet.playTogether(it.bubbleBarPinning.animateToValue(animateToValue))
131         }
132         animatorSet.interpolator = Interpolators.EMPHASIZED
133         return animatorSet
134     }
135 
updateIsAnimatingTaskbarPinningAndNotifyTaskbarDragLayernull136     private fun updateIsAnimatingTaskbarPinningAndNotifyTaskbarDragLayer(isAnimating: Boolean) {
137         isAnimatingTaskbarPinning = isAnimating
138         context.dragLayer.setAnimatingTaskbarPinning(isAnimating)
139     }
140 
141     @VisibleForTesting
recreateTaskbarAndUpdatePinningValuenull142     fun recreateTaskbarAndUpdatePinningValue() {
143         updateIsAnimatingTaskbarPinningAndNotifyTaskbarDragLayer(false)
144         if (
145             controllers.taskbarDesktopModeController.isInDesktopModeAndNotInOverview(
146                 context.displayId
147             )
148         ) {
149             launcherPrefs.put(
150                 TASKBAR_PINNING_IN_DESKTOP_MODE,
151                 !launcherPrefs.get(TASKBAR_PINNING_IN_DESKTOP_MODE),
152             )
153         } else {
154             launcherPrefs.put(TASKBAR_PINNING, !launcherPrefs.get(TASKBAR_PINNING))
155         }
156     }
157 
dumpLogsnull158     override fun dumpLogs(prefix: String, pw: PrintWriter) {
159         pw.println(prefix + "TaskbarPinningController:")
160         pw.println("$prefix\tisAnimatingTaskbarPinning=$isAnimatingTaskbarPinning")
161         pw.println("$prefix\tTASKBAR_PINNING shared pref =" + launcherPrefs.get(TASKBAR_PINNING))
162         pw.println(
163             "$prefix\tTASKBAR_PINNING_IN_DESKTOP_MODE shared pref in desktop mode =" +
164                 launcherPrefs.get(TASKBAR_PINNING_IN_DESKTOP_MODE)
165         )
166     }
167 
168     companion object {
169         const val PINNING_PERSISTENT = 1f
170         const val PINNING_TRANSIENT = 0f
171         const val PINNING_ANIMATION_DURATION = 600L
172     }
173 }
174