1 /* 2 * Copyright (C) 2019 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.uioverrides.touchcontrollers; 17 18 import static com.android.app.animation.Interpolators.ACCELERATE_2; 19 import static com.android.app.animation.Interpolators.DECELERATE_2; 20 import static com.android.app.animation.Interpolators.INSTANT; 21 import static com.android.app.animation.Interpolators.LINEAR; 22 import static com.android.launcher3.LauncherState.NORMAL; 23 import static com.android.launcher3.LauncherState.QUICK_SWITCH_FROM_HOME; 24 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND; 25 import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE; 26 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE; 27 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE; 28 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y; 29 import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS; 30 import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE; 31 import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE; 32 import static com.android.launcher3.util.SystemUiController.UI_STATE_FULLSCREEN_TASK; 33 import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_OFFSET; 34 import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY; 35 import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD; 36 import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS; 37 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED; 38 39 import android.view.MotionEvent; 40 41 import com.android.launcher3.LauncherState; 42 import com.android.launcher3.Utilities; 43 import com.android.launcher3.states.StateAnimationConfig; 44 import com.android.launcher3.touch.AbstractStateChangeTouchController; 45 import com.android.launcher3.touch.SingleAxisSwipeDetector; 46 import com.android.launcher3.uioverrides.QuickstepLauncher; 47 import com.android.launcher3.util.DisplayController; 48 import com.android.launcher3.util.NavigationMode; 49 import com.android.quickstep.SystemUiProxy; 50 import com.android.quickstep.TaskUtils; 51 import com.android.quickstep.views.RecentsView; 52 import com.android.quickstep.views.TaskView; 53 54 /** 55 * Handles quick switching to a recent task from the home screen. 56 */ 57 public class QuickSwitchTouchController extends AbstractStateChangeTouchController { 58 59 protected final RecentsView mOverviewPanel; 60 QuickSwitchTouchController(QuickstepLauncher launcher)61 public QuickSwitchTouchController(QuickstepLauncher launcher) { 62 this(launcher, SingleAxisSwipeDetector.HORIZONTAL); 63 } 64 QuickSwitchTouchController(QuickstepLauncher l, SingleAxisSwipeDetector.Direction dir)65 protected QuickSwitchTouchController(QuickstepLauncher l, 66 SingleAxisSwipeDetector.Direction dir) { 67 super(l, dir); 68 mOverviewPanel = l.getOverviewPanel(); 69 } 70 71 @Override canInterceptTouch(MotionEvent ev)72 protected boolean canInterceptTouch(MotionEvent ev) { 73 if (mCurrentAnimation != null) { 74 return true; 75 } 76 if (!mLauncher.isInState(LauncherState.NORMAL)) { 77 return false; 78 } 79 if ((ev.getEdgeFlags() & Utilities.EDGE_NAV_BAR) == 0) { 80 return false; 81 } 82 return true; 83 } 84 85 @Override getTargetState(LauncherState fromState, boolean isDragTowardPositive)86 protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) { 87 long stateFlags = SystemUiProxy.INSTANCE.get(mLauncher).getLastSystemUiStateFlags(); 88 if ((stateFlags & SYSUI_STATE_OVERVIEW_DISABLED) != 0) { 89 return NORMAL; 90 } 91 return isDragTowardPositive ? QUICK_SWITCH_FROM_HOME : NORMAL; 92 } 93 94 @Override onDragStart(boolean start, float startDisplacement)95 public void onDragStart(boolean start, float startDisplacement) { 96 super.onDragStart(start, startDisplacement); 97 mStartContainerType = LAUNCHER_STATE_BACKGROUND; 98 TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS); 99 } 100 101 @Override onSwipeInteractionCompleted(LauncherState targetState)102 protected void onSwipeInteractionCompleted(LauncherState targetState) { 103 super.onSwipeInteractionCompleted(targetState); 104 } 105 106 @Override initCurrentAnimation()107 protected float initCurrentAnimation() { 108 StateAnimationConfig config = new StateAnimationConfig(); 109 setupInterpolators(config); 110 config.duration = (long) (getShiftRange() * 2); 111 112 // Set RecentView's initial properties for coming in from the side. 113 RECENTS_SCALE_PROPERTY.set(mOverviewPanel, 114 QUICK_SWITCH_FROM_HOME.getOverviewScaleAndOffset(mLauncher)[0] * 0.85f); 115 ADJACENT_PAGE_HORIZONTAL_OFFSET.set(mOverviewPanel, 1f); 116 mOverviewPanel.setContentAlpha(1); 117 118 mCurrentAnimation = mLauncher.getStateManager() 119 .createAnimationToNewWorkspace(mToState, config); 120 mCurrentAnimation.getTarget().addListener(mClearStateOnCancelListener); 121 mCurrentAnimation.getAnimationPlayer().addUpdateListener(valueAnimator -> 122 updateFullscreenProgress((Float) valueAnimator.getAnimatedValue())); 123 return 1 / getShiftRange(); 124 } 125 setupInterpolators(StateAnimationConfig stateAnimationConfig)126 private void setupInterpolators(StateAnimationConfig stateAnimationConfig) { 127 stateAnimationConfig.setInterpolator(ANIM_WORKSPACE_FADE, DECELERATE_2); 128 stateAnimationConfig.setInterpolator(ANIM_ALL_APPS_FADE, DECELERATE_2); 129 if (DisplayController.getNavigationMode(mLauncher) == NavigationMode.NO_BUTTON) { 130 // Overview lives to the left of workspace, so translate down later than over 131 stateAnimationConfig.setInterpolator(ANIM_WORKSPACE_TRANSLATE, ACCELERATE_2); 132 stateAnimationConfig.setInterpolator(ANIM_VERTICAL_PROGRESS, ACCELERATE_2); 133 stateAnimationConfig.setInterpolator(ANIM_OVERVIEW_SCALE, ACCELERATE_2); 134 stateAnimationConfig.setInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, ACCELERATE_2); 135 stateAnimationConfig.setInterpolator(ANIM_OVERVIEW_FADE, INSTANT); 136 } else { 137 stateAnimationConfig.setInterpolator(ANIM_WORKSPACE_TRANSLATE, LINEAR); 138 stateAnimationConfig.setInterpolator(ANIM_VERTICAL_PROGRESS, LINEAR); 139 } 140 } 141 142 @Override updateProgress(float progress)143 protected void updateProgress(float progress) { 144 super.updateProgress(progress); 145 updateFullscreenProgress(Utilities.boundToRange(progress, 0, 1)); 146 } 147 updateFullscreenProgress(float progress)148 private void updateFullscreenProgress(float progress) { 149 mOverviewPanel.setFullscreenProgress(progress); 150 if (progress > UPDATE_SYSUI_FLAGS_THRESHOLD) { 151 int sysuiFlags = 0; 152 TaskView tv = mOverviewPanel.getTaskViewAt(0); 153 if (tv != null) { 154 sysuiFlags = tv.getFirstThumbnailViewDeprecated().getSysUiStatusNavFlags(); 155 } 156 mLauncher.getSystemUiController().updateUiState(UI_STATE_FULLSCREEN_TASK, sysuiFlags); 157 } else { 158 mLauncher.getSystemUiController().updateUiState(UI_STATE_FULLSCREEN_TASK, 0); 159 } 160 } 161 162 @Override getShiftRange()163 protected float getShiftRange() { 164 return mLauncher.getDeviceProfile().widthPx / 2f; 165 } 166 } 167