• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 
17 package com.android.quickstep.util;
18 
19 import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_FULLSCREEN_WITH_KEYBOARD_SHORTCUTS;
20 import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE;
21 
22 import android.animation.Animator;
23 import android.animation.AnimatorListenerAdapter;
24 import android.content.Intent;
25 import android.graphics.Rect;
26 import android.graphics.RectF;
27 import android.os.UserHandle;
28 import android.view.View;
29 
30 import com.android.launcher3.DeviceProfile;
31 import com.android.launcher3.Launcher;
32 import com.android.launcher3.R;
33 import com.android.launcher3.anim.PendingAnimation;
34 import com.android.launcher3.icons.BitmapInfo;
35 import com.android.launcher3.model.data.WorkspaceItemInfo;
36 import com.android.quickstep.views.FloatingTaskView;
37 import com.android.quickstep.views.RecentsView;
38 import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
39 
40 /** Handles when the stage split lands on the home screen. */
41 public class SplitToWorkspaceController {
42 
43     private final Launcher mLauncher;
44     private final DeviceProfile mDP;
45     private final SplitSelectStateController mController;
46 
47     private final int mHalfDividerSize;
48 
SplitToWorkspaceController(Launcher launcher, SplitSelectStateController controller)49     public SplitToWorkspaceController(Launcher launcher, SplitSelectStateController controller) {
50         mLauncher = launcher;
51         mDP = mLauncher.getDeviceProfile();
52         mController = controller;
53 
54         mHalfDividerSize = mLauncher.getResources().getDimensionPixelSize(
55                 R.dimen.multi_window_task_divider_size) / 2;
56     }
57 
58     /**
59      * Handles second app selection from stage split. If the item can't be opened in split or
60      * it's not in stage split state, we pass it onto Launcher's default item click handler.
61      */
handleSecondAppSelectionForSplit(View view)62     public boolean handleSecondAppSelectionForSplit(View view) {
63         if ((!ENABLE_SPLIT_FROM_FULLSCREEN_WITH_KEYBOARD_SHORTCUTS.get()
64                 && !ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get())
65                 || !mController.isSplitSelectActive()) {
66             return false;
67         }
68         Object tag = view.getTag();
69         Intent intent;
70         UserHandle user;
71         BitmapInfo bitmapInfo;
72         if (tag instanceof WorkspaceItemInfo) {
73             final WorkspaceItemInfo workspaceItemInfo = (WorkspaceItemInfo) tag;
74             intent = workspaceItemInfo.intent;
75             user = workspaceItemInfo.user;
76             bitmapInfo = workspaceItemInfo.bitmap;
77         } else if (tag instanceof com.android.launcher3.model.data.AppInfo) {
78             final com.android.launcher3.model.data.AppInfo appInfo =
79                     (com.android.launcher3.model.data.AppInfo) tag;
80             intent = appInfo.intent;
81             user = appInfo.user;
82             bitmapInfo = appInfo.bitmap;
83         } else {
84             return false;
85         }
86 
87         mController.setSecondTask(intent, user);
88 
89         boolean isTablet = mLauncher.getDeviceProfile().isTablet;
90         SplitAnimationTimings timings = AnimUtils.getDeviceSplitToConfirmTimings(isTablet);
91         PendingAnimation pendingAnimation = new PendingAnimation(timings.getDuration());
92 
93         Rect firstTaskStartingBounds = new Rect();
94         Rect firstTaskEndingBounds = new Rect();
95         RectF secondTaskStartingBounds = new RectF();
96         Rect secondTaskEndingBounds = new Rect();
97 
98         RecentsView recentsView = mLauncher.getOverviewPanel();
99         recentsView.getPagedOrientationHandler().getFinalSplitPlaceholderBounds(mHalfDividerSize,
100                 mDP, mController.getActiveSplitStagePosition(), firstTaskEndingBounds,
101                 secondTaskEndingBounds);
102 
103         FloatingTaskView firstFloatingTaskView = mController.getFirstFloatingTaskView();
104         firstFloatingTaskView.getBoundsOnScreen(firstTaskStartingBounds);
105         firstFloatingTaskView.addConfirmAnimation(pendingAnimation,
106                 new RectF(firstTaskStartingBounds), firstTaskEndingBounds,
107                 false /* fadeWithThumbnail */, true /* isStagedTask */);
108 
109         FloatingTaskView secondFloatingTaskView = FloatingTaskView.getFloatingTaskView(mLauncher,
110                 view, null /* thumbnail */, bitmapInfo.newIcon(mLauncher),
111                 secondTaskStartingBounds);
112         secondFloatingTaskView.setAlpha(1);
113         secondFloatingTaskView.addConfirmAnimation(pendingAnimation, secondTaskStartingBounds,
114                 secondTaskEndingBounds, true /* fadeWithThumbnail */, false /* isStagedTask */);
115 
116         pendingAnimation.addListener(new AnimatorListenerAdapter() {
117             private boolean mIsCancelled = false;
118 
119             @Override
120             public void onAnimationCancel(Animator animation) {
121                 mIsCancelled = true;
122                 cleanUp();
123             }
124 
125             @Override
126             public void onAnimationEnd(Animator animation) {
127                 if (!mIsCancelled) {
128                     mController.launchSplitTasks(aBoolean -> cleanUp());
129                     InteractionJankMonitorWrapper.end(
130                             InteractionJankMonitorWrapper.CUJ_SPLIT_SCREEN_ENTER);
131                 }
132             }
133 
134             private void cleanUp() {
135                 mLauncher.getDragLayer().removeView(firstFloatingTaskView);
136                 mLauncher.getDragLayer().removeView(secondFloatingTaskView);
137                 mController.resetState();
138             }
139         });
140         pendingAnimation.buildAnim().start();
141         return true;
142     }
143 }
144