1 /* 2 * Copyright (C) 2018 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.quickstep.views; 17 18 import static android.app.ActivityTaskManager.INVALID_TASK_ID; 19 20 import static com.android.launcher3.LauncherState.CLEAR_ALL_BUTTON; 21 import static com.android.launcher3.LauncherState.NORMAL; 22 import static com.android.launcher3.LauncherState.OVERVIEW; 23 import static com.android.launcher3.LauncherState.OVERVIEW_MODAL_TASK; 24 import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT; 25 import static com.android.launcher3.LauncherState.SPRING_LOADED; 26 27 import android.annotation.TargetApi; 28 import android.content.Context; 29 import android.os.Build; 30 import android.util.AttributeSet; 31 import android.view.MotionEvent; 32 import android.view.Surface; 33 34 import androidx.annotation.Nullable; 35 36 import com.android.launcher3.AbstractFloatingView; 37 import com.android.launcher3.LauncherState; 38 import com.android.launcher3.logging.StatsLogManager; 39 import com.android.launcher3.statehandlers.DepthController; 40 import com.android.launcher3.statehandlers.DesktopVisibilityController; 41 import com.android.launcher3.statemanager.StateManager.StateListener; 42 import com.android.launcher3.uioverrides.QuickstepLauncher; 43 import com.android.launcher3.util.PendingSplitSelectInfo; 44 import com.android.launcher3.util.SplitConfigurationOptions; 45 import com.android.launcher3.util.SplitConfigurationOptions.SplitSelectSource; 46 import com.android.quickstep.GestureState; 47 import com.android.quickstep.LauncherActivityInterface; 48 import com.android.quickstep.RotationTouchHelper; 49 import com.android.quickstep.SystemUiProxy; 50 import com.android.quickstep.util.SplitSelectStateController; 51 import com.android.systemui.shared.recents.model.Task; 52 53 /** 54 * {@link RecentsView} used in Launcher activity 55 */ 56 @TargetApi(Build.VERSION_CODES.O) 57 public class LauncherRecentsView extends RecentsView<QuickstepLauncher, LauncherState> 58 implements StateListener<LauncherState> { 59 LauncherRecentsView(Context context)60 public LauncherRecentsView(Context context) { 61 this(context, null); 62 } 63 LauncherRecentsView(Context context, @Nullable AttributeSet attrs)64 public LauncherRecentsView(Context context, @Nullable AttributeSet attrs) { 65 this(context, attrs, 0); 66 } 67 LauncherRecentsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr)68 public LauncherRecentsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 69 super(context, attrs, defStyleAttr, LauncherActivityInterface.INSTANCE); 70 mActivity.getStateManager().addStateListener(this); 71 } 72 73 @Override init(OverviewActionsView actionsView, SplitSelectStateController splitPlaceholderView)74 public void init(OverviewActionsView actionsView, 75 SplitSelectStateController splitPlaceholderView) { 76 super.init(actionsView, splitPlaceholderView); 77 setContentAlpha(0); 78 } 79 80 @Override startHome()81 public void startHome() { 82 mActivity.getStateManager().goToState(NORMAL); 83 AbstractFloatingView.closeAllOpenViews(mActivity, mActivity.isStarted()); 84 } 85 86 @Override onTaskLaunchAnimationEnd(boolean success)87 protected void onTaskLaunchAnimationEnd(boolean success) { 88 if (success) { 89 mActivity.getStateManager().moveToRestState(); 90 } else { 91 LauncherState state = mActivity.getStateManager().getState(); 92 mActivity.getAllAppsController().setState(state); 93 } 94 super.onTaskLaunchAnimationEnd(success); 95 } 96 97 @Override onTaskIconChanged(int taskId)98 public void onTaskIconChanged(int taskId) { 99 super.onTaskIconChanged(taskId); 100 // If Launcher needs to return to split select state, do it now, after the icon has updated. 101 if (mActivity.hasPendingSplitSelectInfo()) { 102 PendingSplitSelectInfo recoveryData = mActivity.getPendingSplitSelectInfo(); 103 if (recoveryData.getStagedTaskId() == taskId) { 104 initiateSplitSelect( 105 getTaskViewByTaskId(recoveryData.getStagedTaskId()), 106 recoveryData.getStagePosition(), recoveryData.getSource() 107 ); 108 mActivity.finishSplitSelectRecovery(); 109 } 110 } 111 } 112 113 @Override reset()114 public void reset() { 115 super.reset(); 116 setLayoutRotation(Surface.ROTATION_0, Surface.ROTATION_0); 117 } 118 119 @Override onStateTransitionStart(LauncherState toState)120 public void onStateTransitionStart(LauncherState toState) { 121 setOverviewStateEnabled(toState.overviewUi); 122 setOverviewGridEnabled(toState.displayOverviewTasksAsGrid(mActivity.getDeviceProfile())); 123 setOverviewFullscreenEnabled(toState.getOverviewFullscreenProgress() == 1); 124 if (toState == OVERVIEW_MODAL_TASK) { 125 setOverviewSelectEnabled(true); 126 } 127 setFreezeViewVisibility(true); 128 } 129 130 @Override onStateTransitionComplete(LauncherState finalState)131 public void onStateTransitionComplete(LauncherState finalState) { 132 if (finalState == NORMAL || finalState == SPRING_LOADED) { 133 // Clean-up logic that occurs when recents is no longer in use/visible. 134 reset(); 135 } 136 boolean isOverlayEnabled = finalState == OVERVIEW || finalState == OVERVIEW_MODAL_TASK; 137 setOverlayEnabled(isOverlayEnabled); 138 setFreezeViewVisibility(false); 139 if (finalState != OVERVIEW_MODAL_TASK) { 140 setOverviewSelectEnabled(false); 141 } 142 143 if (isOverlayEnabled) { 144 runActionOnRemoteHandles(remoteTargetHandle -> 145 remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(true)); 146 } 147 } 148 149 @Override setOverviewStateEnabled(boolean enabled)150 public void setOverviewStateEnabled(boolean enabled) { 151 super.setOverviewStateEnabled(enabled); 152 if (enabled) { 153 LauncherState state = mActivity.getStateManager().getState(); 154 boolean hasClearAllButton = (state.getVisibleElements(mActivity) 155 & CLEAR_ALL_BUTTON) != 0; 156 setDisallowScrollToClearAll(!hasClearAllButton); 157 } 158 if (mActivity.getDesktopVisibilityController() != null) { 159 mActivity.getDesktopVisibilityController().setOverviewStateEnabled(enabled); 160 } 161 } 162 163 @Override onTouchEvent(MotionEvent ev)164 public boolean onTouchEvent(MotionEvent ev) { 165 boolean result = super.onTouchEvent(ev); 166 // Do not let touch escape to siblings below this view. 167 return result || mActivity.getStateManager().getState().overviewUi; 168 } 169 170 @Override getDepthController()171 protected DepthController getDepthController() { 172 return mActivity.getDepthController(); 173 } 174 175 @Override setModalStateEnabled(int taskId, boolean animate)176 public void setModalStateEnabled(int taskId, boolean animate) { 177 if (taskId != INVALID_TASK_ID) { 178 setSelectedTask(taskId); 179 mActivity.getStateManager().goToState(LauncherState.OVERVIEW_MODAL_TASK, animate); 180 } else { 181 if (mActivity.isInState(LauncherState.OVERVIEW_MODAL_TASK)) { 182 mActivity.getStateManager().goToState(LauncherState.OVERVIEW, animate); 183 resetModalVisuals(); 184 } 185 } 186 } 187 188 @Override onDismissAnimationEnds()189 protected void onDismissAnimationEnds() { 190 super.onDismissAnimationEnds(); 191 if (mActivity.isInState(OVERVIEW_SPLIT_SELECT)) { 192 // We want to keep the tasks translations in this temporary state 193 // after resetting the rest above 194 setTaskViewsPrimarySplitTranslation(mTaskViewsPrimarySplitTranslation); 195 setTaskViewsSecondarySplitTranslation(mTaskViewsSecondarySplitTranslation); 196 } 197 } 198 199 @Override initiateSplitSelect(TaskView taskView, @SplitConfigurationOptions.StagePosition int stagePosition, StatsLogManager.EventEnum splitEvent)200 public void initiateSplitSelect(TaskView taskView, 201 @SplitConfigurationOptions.StagePosition int stagePosition, 202 StatsLogManager.EventEnum splitEvent) { 203 super.initiateSplitSelect(taskView, stagePosition, splitEvent); 204 mActivity.getStateManager().goToState(LauncherState.OVERVIEW_SPLIT_SELECT); 205 } 206 207 @Override initiateSplitSelect(SplitSelectSource splitSelectSource)208 public void initiateSplitSelect(SplitSelectSource splitSelectSource) { 209 super.initiateSplitSelect(splitSelectSource); 210 mActivity.getStateManager().goToState(LauncherState.OVERVIEW_SPLIT_SELECT); 211 } 212 213 @Override canLaunchFullscreenTask()214 protected boolean canLaunchFullscreenTask() { 215 return !mActivity.isInState(OVERVIEW_SPLIT_SELECT); 216 } 217 218 @Override onGestureAnimationStart(Task[] runningTasks, RotationTouchHelper rotationTouchHelper)219 public void onGestureAnimationStart(Task[] runningTasks, 220 RotationTouchHelper rotationTouchHelper) { 221 super.onGestureAnimationStart(runningTasks, rotationTouchHelper); 222 DesktopVisibilityController desktopVisibilityController = 223 mActivity.getDesktopVisibilityController(); 224 if (desktopVisibilityController != null) { 225 desktopVisibilityController.setGestureInProgress(true); 226 } 227 } 228 229 @Override onGestureAnimationEnd()230 public void onGestureAnimationEnd() { 231 DesktopVisibilityController desktopVisibilityController = null; 232 boolean showDesktopApps = false; 233 if (DesktopTaskView.DESKTOP_MODE_SUPPORTED) { 234 desktopVisibilityController = mActivity.getDesktopVisibilityController(); 235 if (mCurrentGestureEndTarget == GestureState.GestureEndTarget.LAST_TASK 236 && desktopVisibilityController.areFreeformTasksVisible()) { 237 // Recents gesture was cancelled and we are returning to the previous task. 238 // After super class has handled clean up, show desktop apps on top again 239 showDesktopApps = true; 240 } 241 } 242 super.onGestureAnimationEnd(); 243 if (desktopVisibilityController != null) { 244 desktopVisibilityController.setGestureInProgress(false); 245 } 246 if (showDesktopApps) { 247 SystemUiProxy.INSTANCE.get(mActivity).showDesktopApps(); 248 } 249 } 250 } 251