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.launcher3.LauncherState.NORMAL; 19 import static com.android.launcher3.LauncherState.QUICK_SWITCH; 20 import static com.android.launcher3.anim.Interpolators.ACCEL_2; 21 import static com.android.launcher3.anim.Interpolators.DEACCEL_2; 22 import static com.android.launcher3.anim.Interpolators.INSTANT; 23 import static com.android.launcher3.anim.Interpolators.LINEAR; 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.Launcher; 42 import com.android.launcher3.LauncherState; 43 import com.android.launcher3.Utilities; 44 import com.android.launcher3.states.StateAnimationConfig; 45 import com.android.launcher3.touch.AbstractStateChangeTouchController; 46 import com.android.launcher3.touch.SingleAxisSwipeDetector; 47 import com.android.quickstep.SysUINavigationMode; 48 import com.android.quickstep.SysUINavigationMode.Mode; 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(Launcher launcher)61 public QuickSwitchTouchController(Launcher launcher) { 62 this(launcher, SingleAxisSwipeDetector.HORIZONTAL); 63 } 64 QuickSwitchTouchController(Launcher l, SingleAxisSwipeDetector.Direction dir)65 protected QuickSwitchTouchController(Launcher l, SingleAxisSwipeDetector.Direction dir) { 66 super(l, dir); 67 mOverviewPanel = l.getOverviewPanel(); 68 } 69 70 @Override canInterceptTouch(MotionEvent ev)71 protected boolean canInterceptTouch(MotionEvent ev) { 72 if (mCurrentAnimation != null) { 73 return true; 74 } 75 if (!mLauncher.isInState(LauncherState.NORMAL)) { 76 return false; 77 } 78 if ((ev.getEdgeFlags() & Utilities.EDGE_NAV_BAR) == 0) { 79 return false; 80 } 81 return true; 82 } 83 84 @Override getTargetState(LauncherState fromState, boolean isDragTowardPositive)85 protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) { 86 int stateFlags = SystemUiProxy.INSTANCE.get(mLauncher).getLastSystemUiStateFlags(); 87 if ((stateFlags & SYSUI_STATE_OVERVIEW_DISABLED) != 0) { 88 return NORMAL; 89 } 90 return isDragTowardPositive ? QUICK_SWITCH : NORMAL; 91 } 92 93 @Override onDragStart(boolean start, float startDisplacement)94 public void onDragStart(boolean start, float startDisplacement) { 95 super.onDragStart(start, startDisplacement); 96 mStartContainerType = LAUNCHER_STATE_BACKGROUND; 97 TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS); 98 } 99 100 @Override onSwipeInteractionCompleted(LauncherState targetState)101 protected void onSwipeInteractionCompleted(LauncherState targetState) { 102 super.onSwipeInteractionCompleted(targetState); 103 } 104 105 @Override initCurrentAnimation()106 protected float initCurrentAnimation() { 107 StateAnimationConfig config = new StateAnimationConfig(); 108 setupInterpolators(config); 109 config.duration = (long) (getShiftRange() * 2); 110 111 // Set RecentView's initial properties for coming in from the side. 112 RECENTS_SCALE_PROPERTY.set(mOverviewPanel, 113 QUICK_SWITCH.getOverviewScaleAndOffset(mLauncher)[0] * 0.85f); 114 ADJACENT_PAGE_HORIZONTAL_OFFSET.set(mOverviewPanel, 1f); 115 mOverviewPanel.setContentAlpha(1); 116 117 mCurrentAnimation = mLauncher.getStateManager() 118 .createAnimationToNewWorkspace(mToState, config); 119 mCurrentAnimation.getTarget().addListener(mClearStateOnCancelListener); 120 mCurrentAnimation.getAnimationPlayer().addUpdateListener(valueAnimator -> 121 updateFullscreenProgress((Float) valueAnimator.getAnimatedValue())); 122 return 1 / getShiftRange(); 123 } 124 setupInterpolators(StateAnimationConfig stateAnimationConfig)125 private void setupInterpolators(StateAnimationConfig stateAnimationConfig) { 126 stateAnimationConfig.setInterpolator(ANIM_WORKSPACE_FADE, DEACCEL_2); 127 stateAnimationConfig.setInterpolator(ANIM_ALL_APPS_FADE, DEACCEL_2); 128 if (SysUINavigationMode.getMode(mLauncher) == Mode.NO_BUTTON) { 129 // Overview lives to the left of workspace, so translate down later than over 130 stateAnimationConfig.setInterpolator(ANIM_WORKSPACE_TRANSLATE, ACCEL_2); 131 stateAnimationConfig.setInterpolator(ANIM_VERTICAL_PROGRESS, ACCEL_2); 132 stateAnimationConfig.setInterpolator(ANIM_OVERVIEW_SCALE, ACCEL_2); 133 stateAnimationConfig.setInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, ACCEL_2); 134 stateAnimationConfig.setInterpolator(ANIM_OVERVIEW_FADE, INSTANT); 135 } else { 136 stateAnimationConfig.setInterpolator(ANIM_WORKSPACE_TRANSLATE, LINEAR); 137 stateAnimationConfig.setInterpolator(ANIM_VERTICAL_PROGRESS, LINEAR); 138 } 139 } 140 141 @Override updateProgress(float progress)142 protected void updateProgress(float progress) { 143 super.updateProgress(progress); 144 updateFullscreenProgress(Utilities.boundToRange(progress, 0, 1)); 145 } 146 updateFullscreenProgress(float progress)147 private void updateFullscreenProgress(float progress) { 148 mOverviewPanel.setFullscreenProgress(progress); 149 if (progress > UPDATE_SYSUI_FLAGS_THRESHOLD) { 150 int sysuiFlags = 0; 151 TaskView tv = mOverviewPanel.getTaskViewAt(0); 152 if (tv != null) { 153 sysuiFlags = tv.getThumbnail().getSysUiStatusNavFlags(); 154 } 155 mLauncher.getSystemUiController().updateUiState(UI_STATE_FULLSCREEN_TASK, sysuiFlags); 156 } else { 157 mLauncher.getSystemUiController().updateUiState(UI_STATE_FULLSCREEN_TASK, 0); 158 } 159 } 160 161 @Override getShiftRange()162 protected float getShiftRange() { 163 return mLauncher.getDeviceProfile().widthPx / 2f; 164 } 165 } 166