1 /* 2 * Copyright (C) 2021 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 static com.android.app.animation.Interpolators.EMPHASIZED; 19 import static com.android.launcher3.taskbar.TaskbarPinningController.PINNING_PERSISTENT; 20 import static com.android.launcher3.taskbar.TaskbarPinningController.PINNING_TRANSIENT; 21 22 import android.animation.AnimatorSet; 23 import android.animation.ObjectAnimator; 24 import android.content.res.Resources; 25 import android.graphics.Canvas; 26 import android.graphics.Point; 27 import android.graphics.Rect; 28 import android.os.SystemProperties; 29 import android.view.MotionEvent; 30 import android.view.ViewTreeObserver; 31 32 import com.android.launcher3.DeviceProfile; 33 import com.android.launcher3.R; 34 import com.android.launcher3.anim.AnimatedFloat; 35 import com.android.launcher3.anim.AnimatorListeners; 36 import com.android.launcher3.util.DimensionUtils; 37 import com.android.launcher3.util.MultiPropertyFactory.MultiProperty; 38 import com.android.launcher3.util.TouchController; 39 40 import java.io.PrintWriter; 41 42 /** 43 * Handles properties/data collection, then passes the results to TaskbarDragLayer to render. 44 */ 45 public class TaskbarDragLayerController implements TaskbarControllers.LoggableTaskbarController, 46 TaskbarControllers.BackgroundRendererController { 47 48 private static final boolean DEBUG = SystemProperties.getBoolean( 49 "persist.debug.draw_taskbar_debug_ui", false); 50 51 private final TaskbarActivityContext mActivity; 52 private final TaskbarDragLayer mTaskbarDragLayer; 53 private final int mFolderMargin; 54 55 // Alpha properties for taskbar background. 56 private final AnimatedFloat mBgTaskbar = new AnimatedFloat(this::updateBackgroundAlpha); 57 private final AnimatedFloat mBgNavbar = new AnimatedFloat(this::updateBackgroundAlpha); 58 private final AnimatedFloat mKeyguardBgTaskbar = new AnimatedFloat(this::updateBackgroundAlpha); 59 private final AnimatedFloat mNotificationShadeBgTaskbar = new AnimatedFloat( 60 this::updateBackgroundAlpha); 61 private final AnimatedFloat mImeBgTaskbar = new AnimatedFloat(this::updateBackgroundAlpha); 62 private final AnimatedFloat mAssistantBgTaskbar = new AnimatedFloat( 63 this::updateBackgroundAlpha); 64 private final AnimatedFloat mBgTaskbarRecreate = new AnimatedFloat( 65 this::updateBackgroundAlpha); 66 // Used to hide our background color when someone else (e.g. ScrimView) is handling it. 67 private final AnimatedFloat mBgOverride = new AnimatedFloat(this::updateBackgroundAlpha); 68 69 // Translation property for taskbar background. 70 private final AnimatedFloat mBgOffset = new AnimatedFloat(this::updateBackgroundOffset); 71 72 // Used to fade in/out the entirety of the taskbar, for a smooth transition before/after sysui 73 // changes the inset visibility. 74 private final AnimatedFloat mTaskbarAlpha = new AnimatedFloat(this::updateTaskbarAlpha); 75 76 private final AnimatedFloat mTaskbarBackgroundProgress = new AnimatedFloat( 77 this::updateTaskbarBackgroundProgress); 78 79 // Initialized in init. 80 private TaskbarControllers mControllers; 81 private TaskbarStashViaTouchController mTaskbarStashViaTouchController; 82 private AnimatedFloat mOnBackgroundNavButtonColorIntensity; 83 84 private MultiProperty mBackgroundRendererAlpha; 85 private float mLastSetBackgroundAlpha; 86 TaskbarDragLayerController(TaskbarActivityContext activity, TaskbarDragLayer taskbarDragLayer)87 public TaskbarDragLayerController(TaskbarActivityContext activity, 88 TaskbarDragLayer taskbarDragLayer) { 89 mActivity = activity; 90 mTaskbarDragLayer = taskbarDragLayer; 91 mBackgroundRendererAlpha = mTaskbarDragLayer.getBackgroundRendererAlpha(); 92 final Resources resources = mTaskbarDragLayer.getResources(); 93 mFolderMargin = resources.getDimensionPixelSize(R.dimen.taskbar_folder_margin); 94 } 95 96 /** 97 * Init of taskbar drag layer controller 98 */ init(TaskbarControllers controllers, AnimatorSet startAnimation)99 public void init(TaskbarControllers controllers, AnimatorSet startAnimation) { 100 mControllers = controllers; 101 mTaskbarStashViaTouchController = new TaskbarStashViaTouchController(mControllers); 102 mTaskbarDragLayer.init(new TaskbarDragLayerCallbacks()); 103 104 mOnBackgroundNavButtonColorIntensity = mControllers.navbarButtonsViewController 105 .getOnTaskbarBackgroundNavButtonColorOverride(); 106 107 108 if (startAnimation != null) { 109 // set taskbar background render animation boolean 110 if (mActivity.isTransientTaskbar()) { 111 mTaskbarDragLayer.setIsAnimatingTransientTaskbarBackground(true); 112 } else { 113 mTaskbarDragLayer.setIsAnimatingPersistentTaskbarBackground(true); 114 } 115 116 float desiredValue = mActivity.isTransientTaskbar() 117 ? PINNING_TRANSIENT 118 : PINNING_PERSISTENT; 119 120 float nonDesiredvalue = 121 !mActivity.isTransientTaskbar() ? PINNING_TRANSIENT : PINNING_PERSISTENT; 122 123 ObjectAnimator objectAnimator = mTaskbarBackgroundProgress.animateToValue( 124 nonDesiredvalue, desiredValue); 125 objectAnimator.setInterpolator(EMPHASIZED); 126 startAnimation.play(objectAnimator); 127 startAnimation.addListener(AnimatorListeners.forEndCallback(()-> { 128 // reset taskbar background render animation boolean 129 mTaskbarDragLayer.setIsAnimatingPersistentTaskbarBackground(false); 130 mTaskbarDragLayer.setIsAnimatingTransientTaskbarBackground(false); 131 })); 132 133 } else { 134 mTaskbarBackgroundProgress.updateValue( 135 mActivity.isTransientTaskbar() ? PINNING_TRANSIENT : PINNING_PERSISTENT); 136 } 137 138 mBgTaskbar.value = 1; 139 mKeyguardBgTaskbar.value = 1; 140 mNotificationShadeBgTaskbar.value = 1; 141 mImeBgTaskbar.value = 1; 142 mAssistantBgTaskbar.value = 1; 143 mBgTaskbarRecreate.value = 1; 144 mBgOverride.value = 1; 145 updateBackgroundAlpha(); 146 147 mTaskbarAlpha.value = 1; 148 updateTaskbarAlpha(); 149 } 150 151 /** 152 * Called when destroying Taskbar with animation. 153 */ onDestroyAnimation(AnimatorSet animatorSet)154 public void onDestroyAnimation(AnimatorSet animatorSet) { 155 animatorSet.play(mBgTaskbarRecreate.animateToValue(0f)); 156 } 157 onDestroy()158 public void onDestroy() { 159 mTaskbarDragLayer.onDestroy(); 160 } 161 162 /** 163 * @return Bounds (in TaskbarDragLayer coordinates) where an opened Folder can display. 164 */ getFolderBoundingBox()165 public Rect getFolderBoundingBox() { 166 Rect boundingBox = new Rect(0, 0, mTaskbarDragLayer.getWidth(), 167 mTaskbarDragLayer.getHeight() - mActivity.getDeviceProfile().taskbarHeight 168 - mActivity.getDeviceProfile().taskbarBottomMargin); 169 boundingBox.inset(mFolderMargin, mFolderMargin); 170 return boundingBox; 171 } 172 getTaskbarBackgroundAlpha()173 public AnimatedFloat getTaskbarBackgroundAlpha() { 174 return mBgTaskbar; 175 } 176 getNavbarBackgroundAlpha()177 public AnimatedFloat getNavbarBackgroundAlpha() { 178 return mBgNavbar; 179 } 180 getKeyguardBgTaskbar()181 public AnimatedFloat getKeyguardBgTaskbar() { 182 return mKeyguardBgTaskbar; 183 } 184 getNotificationShadeBgTaskbar()185 public AnimatedFloat getNotificationShadeBgTaskbar() { 186 return mNotificationShadeBgTaskbar; 187 } 188 getImeBgTaskbar()189 public AnimatedFloat getImeBgTaskbar() { 190 return mImeBgTaskbar; 191 } 192 getAssistantBgTaskbar()193 public AnimatedFloat getAssistantBgTaskbar() { 194 return mAssistantBgTaskbar; 195 } 196 getTaskbarBackgroundOffset()197 public AnimatedFloat getTaskbarBackgroundOffset() { 198 return mBgOffset; 199 } 200 201 // AnimatedFloat is for animating between pinned and transient taskbar getTaskbarBackgroundProgress()202 public AnimatedFloat getTaskbarBackgroundProgress() { 203 return mTaskbarBackgroundProgress; 204 } 205 getTaskbarAlpha()206 public AnimatedFloat getTaskbarAlpha() { 207 return mTaskbarAlpha; 208 } 209 210 /** 211 * Make updates when configuration changes. 212 */ onConfigurationChanged()213 public void onConfigurationChanged() { 214 mTaskbarStashViaTouchController.updateGestureHeight(); 215 } 216 updateBackgroundAlpha()217 private void updateBackgroundAlpha() { 218 if (mActivity.isPhoneMode() || mActivity.isDestroyed()) { 219 return; 220 } 221 222 final float bgNavbar = mBgNavbar.value; 223 final float bgTaskbar = mBgTaskbar.value * mKeyguardBgTaskbar.value 224 * mNotificationShadeBgTaskbar.value * mImeBgTaskbar.value 225 * mAssistantBgTaskbar.value * mBgTaskbarRecreate.value; 226 mLastSetBackgroundAlpha = mBgOverride.value * Math.max(bgNavbar, bgTaskbar); 227 mBackgroundRendererAlpha.setValue(mLastSetBackgroundAlpha); 228 229 updateOnBackgroundNavButtonColorIntensity(); 230 } 231 getBackgroundRendererAlphaForStash()232 public MultiProperty getBackgroundRendererAlphaForStash() { 233 return mTaskbarDragLayer.getBackgroundRendererAlphaForStash(); 234 } 235 236 /** 237 * Sets the translation of the background during the swipe up gesture. 238 */ setTranslationYForSwipe(float transY)239 public void setTranslationYForSwipe(float transY) { 240 mTaskbarDragLayer.setBackgroundTranslationYForSwipe(transY); 241 } 242 243 /** 244 * Sets the translation of the background for the bubble bar. 245 */ setTranslationXForBubbleBar(float transX)246 public void setTranslationXForBubbleBar(float transX) { 247 mTaskbarDragLayer.setBackgroundTranslationXForBubbleBar(transX); 248 } 249 250 /** 251 * Sets the translation of the background during the spring on stash animation. 252 */ setTranslationYForStash(float transY)253 public void setTranslationYForStash(float transY) { 254 mTaskbarDragLayer.setBackgroundTranslationYForStash(transY); 255 } 256 updateBackgroundOffset()257 private void updateBackgroundOffset() { 258 mTaskbarDragLayer.setTaskbarBackgroundOffset(mBgOffset.value); 259 updateOnBackgroundNavButtonColorIntensity(); 260 } 261 updateTaskbarBackgroundProgress()262 private void updateTaskbarBackgroundProgress() { 263 mTaskbarDragLayer.setTaskbarBackgroundProgress(mTaskbarBackgroundProgress.value); 264 } 265 updateTaskbarAlpha()266 private void updateTaskbarAlpha() { 267 mTaskbarDragLayer.setAlpha(mTaskbarAlpha.value); 268 } 269 270 @Override setCornerRoundness(float cornerRoundness)271 public void setCornerRoundness(float cornerRoundness) { 272 mTaskbarDragLayer.setCornerRoundness(cornerRoundness); 273 } 274 275 /** 276 * Set if another controller is temporarily handling background drawing. In this case we 277 * override our background alpha to be {@code 0}. 278 */ setIsBackgroundDrawnElsewhere(boolean isBackgroundDrawnElsewhere)279 public void setIsBackgroundDrawnElsewhere(boolean isBackgroundDrawnElsewhere) { 280 mBgOverride.updateValue(isBackgroundDrawnElsewhere ? 0 : 1); 281 } 282 updateOnBackgroundNavButtonColorIntensity()283 private void updateOnBackgroundNavButtonColorIntensity() { 284 mOnBackgroundNavButtonColorIntensity.updateValue( 285 mLastSetBackgroundAlpha * (1 - mBgOffset.value)); 286 } 287 288 /** 289 * Sets the width percentage to inset the transient taskbar's background from the left and from 290 * the right. 291 */ setBackgroundHorizontalInsets(float insetPercentage)292 public void setBackgroundHorizontalInsets(float insetPercentage) { 293 mTaskbarDragLayer.setBackgroundHorizontalInsets(insetPercentage); 294 295 } 296 297 @Override dumpLogs(String prefix, PrintWriter pw)298 public void dumpLogs(String prefix, PrintWriter pw) { 299 pw.println(prefix + "TaskbarDragLayerController:"); 300 301 pw.println(prefix + "\tmBgOffset=" + mBgOffset.value); 302 pw.println(prefix + "\tmTaskbarAlpha=" + mTaskbarAlpha.value); 303 pw.println(prefix + "\tmFolderMargin=" + mFolderMargin); 304 pw.println(prefix + "\tmLastSetBackgroundAlpha=" + mLastSetBackgroundAlpha); 305 pw.println(prefix + "\t\tmBgOverride=" + mBgOverride.value); 306 pw.println(prefix + "\t\tmBgNavbar=" + mBgNavbar.value); 307 pw.println(prefix + "\t\tmBgTaskbar=" + mBgTaskbar.value); 308 pw.println(prefix + "\t\tmKeyguardBgTaskbar=" + mKeyguardBgTaskbar.value); 309 pw.println(prefix + "\t\tmNotificationShadeBgTaskbar=" + mNotificationShadeBgTaskbar.value); 310 pw.println(prefix + "\t\tmImeBgTaskbar=" + mImeBgTaskbar.value); 311 pw.println(prefix + "\t\tmAssistantBgTaskbar=" + mAssistantBgTaskbar.value); 312 pw.println(prefix + "\t\tmBgTaskbarRecreate=" + mBgTaskbarRecreate.value); 313 } 314 315 /** 316 * Callbacks for {@link TaskbarDragLayer} to interact with its controller. 317 */ 318 public class TaskbarDragLayerCallbacks { 319 320 /** 321 * Called to update the touchable insets. 322 * @see ViewTreeObserver.InternalInsetsInfo#setTouchableInsets(int) 323 */ updateInsetsTouchability(ViewTreeObserver.InternalInsetsInfo insetsInfo)324 public void updateInsetsTouchability(ViewTreeObserver.InternalInsetsInfo insetsInfo) { 325 mControllers.taskbarInsetsController.updateInsetsTouchability(insetsInfo); 326 } 327 328 /** 329 * Called when an IME inset is changed. 330 */ onImeInsetChanged()331 public void onImeInsetChanged() { 332 mControllers.taskbarStashController.onImeInsetChanged(); 333 } 334 335 /** 336 * Called when a child is removed from TaskbarDragLayer. 337 */ onDragLayerViewRemoved()338 public void onDragLayerViewRemoved() { 339 mActivity.onDragEndOrViewRemoved(); 340 } 341 342 /** 343 * Returns how tall the background should be drawn at the bottom of the screen. 344 */ getTaskbarBackgroundHeight()345 public int getTaskbarBackgroundHeight() { 346 DeviceProfile deviceProfile = mActivity.getDeviceProfile(); 347 if (mActivity.isPhoneMode()) { 348 Resources resources = mActivity.getResources(); 349 Point taskbarDimensions = DimensionUtils.getTaskbarPhoneDimensions(deviceProfile, 350 resources, true /* isPhoneMode */, mActivity.isGestureNav()); 351 return taskbarDimensions.y == -1 ? 352 deviceProfile.getDisplayInfo().currentSize.y : 353 taskbarDimensions.y; 354 } else { 355 return deviceProfile.taskbarHeight; 356 } 357 } 358 359 /** 360 * Returns touch controllers. 361 */ getTouchControllers()362 public TouchController[] getTouchControllers() { 363 return new TouchController[] { 364 mActivity.getDragController(), 365 mControllers.taskbarForceVisibleImmersiveController, 366 mControllers.navbarButtonsViewController.getTouchController(), 367 mTaskbarStashViaTouchController, 368 }; 369 } 370 371 /** 372 * Draws debug UI on top of everything in TaskbarDragLayer. 373 */ drawDebugUi(Canvas canvas)374 public void drawDebugUi(Canvas canvas) { 375 if (!DEBUG) { 376 return; 377 } 378 mControllers.taskbarInsetsController.drawDebugTouchableRegionBounds(canvas); 379 } 380 381 /** Handles any touch event before it is dispatched to the rest of TaskbarDragLayer. */ onDispatchTouchEvent(MotionEvent ev)382 public void onDispatchTouchEvent(MotionEvent ev) { 383 if (mActivity.isThreeButtonNav() && ev.getAction() == MotionEvent.ACTION_OUTSIDE 384 && mControllers.uiController.isAnimatingToHotseat()) { 385 // When touching during animation to home, jump to the end so Hotseat can handle 386 // the touch. (Gesture Navigation handles this in AbsSwipeUpHandler.) 387 mControllers.uiController.endAnimationToHotseat(); 388 } 389 } 390 } 391 } 392