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.quickstep.util;
17 
18 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
19 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
20 import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
21 
22 import android.graphics.Rect;
23 
24 import com.android.systemui.shared.recents.model.ThumbnailData;
25 import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
26 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
27 
28 import java.util.function.Consumer;
29 
30 /**
31  * Extension of {@link RemoteAnimationTargetSet} with additional information about swipe
32  * up animation
33  */
34 public class SwipeAnimationTargetSet extends RemoteAnimationTargetSet {
35 
36     private final boolean mShouldMinimizeSplitScreen;
37     private final Consumer<SwipeAnimationTargetSet> mOnFinishListener;
38 
39     public final RecentsAnimationControllerCompat controller;
40     public final Rect homeContentInsets;
41     public final Rect minimizedHomeBounds;
42 
SwipeAnimationTargetSet(RecentsAnimationControllerCompat controller, RemoteAnimationTargetCompat[] targets, Rect homeContentInsets, Rect minimizedHomeBounds, boolean shouldMinimizeSplitScreen, Consumer<SwipeAnimationTargetSet> onFinishListener)43     public SwipeAnimationTargetSet(RecentsAnimationControllerCompat controller,
44             RemoteAnimationTargetCompat[] targets, Rect homeContentInsets,
45             Rect minimizedHomeBounds, boolean shouldMinimizeSplitScreen,
46             Consumer<SwipeAnimationTargetSet> onFinishListener) {
47         super(targets, MODE_CLOSING);
48         this.controller = controller;
49         this.homeContentInsets = homeContentInsets;
50         this.minimizedHomeBounds = minimizedHomeBounds;
51         this.mShouldMinimizeSplitScreen = shouldMinimizeSplitScreen;
52         this.mOnFinishListener = onFinishListener;
53     }
54 
hasTargets()55     public boolean hasTargets() {
56         return unfilteredApps.length != 0;
57     }
58 
59     /**
60      * Clones the target set without any actual targets. Used only when continuing a gesture after
61      * the actual recents animation has finished.
62      */
cloneWithoutTargets()63     public SwipeAnimationTargetSet cloneWithoutTargets() {
64         return new SwipeAnimationTargetSet(controller, new RemoteAnimationTargetCompat[0],
65                 homeContentInsets, minimizedHomeBounds, mShouldMinimizeSplitScreen,
66                 mOnFinishListener);
67     }
68 
finishController(boolean toRecents, Runnable callback, boolean sendUserLeaveHint)69     public void finishController(boolean toRecents, Runnable callback, boolean sendUserLeaveHint) {
70         mOnFinishListener.accept(this);
71         UI_HELPER_EXECUTOR.execute(() -> {
72             controller.setInputConsumerEnabled(false);
73             controller.finish(toRecents, sendUserLeaveHint);
74 
75             if (callback != null) {
76                 MAIN_EXECUTOR.execute(callback);
77             }
78         });
79     }
80 
enableInputConsumer()81     public void enableInputConsumer() {
82         UI_HELPER_EXECUTOR.submit(() -> {
83             controller.hideCurrentInputMethod();
84             controller.setInputConsumerEnabled(true);
85         });
86     }
87 
setWindowThresholdCrossed(boolean thresholdCrossed)88     public void setWindowThresholdCrossed(boolean thresholdCrossed) {
89         UI_HELPER_EXECUTOR.execute(() -> {
90             controller.setAnimationTargetsBehindSystemBars(!thresholdCrossed);
91             if (mShouldMinimizeSplitScreen && thresholdCrossed) {
92                 // NOTE: As a workaround for conflicting animations (Launcher animating the task
93                 // leash, and SystemUI resizing the docked stack, which resizes the task), we
94                 // currently only set the minimized mode, and not the inverse.
95                 // TODO: Synchronize the minimize animation with the launcher animation
96                 controller.setSplitScreenMinimized(thresholdCrossed);
97             }
98         });
99     }
100 
screenshotTask(int taskId)101     public ThumbnailData screenshotTask(int taskId) {
102         return controller != null ? controller.screenshotTask(taskId) : null;
103     }
104 
cancelAnimation()105     public void cancelAnimation() {
106         finishController(false /* toRecents */, null, false /* sendUserLeaveHint */);
107     }
108 
finishAnimation()109     public void finishAnimation() {
110         finishController(true /* toRecents */, null, false /* sendUserLeaveHint */);
111     }
112 
113     public interface SwipeAnimationListener {
114 
onRecentsAnimationStart(SwipeAnimationTargetSet targetSet)115         void onRecentsAnimationStart(SwipeAnimationTargetSet targetSet);
116 
onRecentsAnimationCanceled()117         void onRecentsAnimationCanceled();
118     }
119 }
120