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