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; 17 18 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; 19 import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.CANCEL_RECENTS_ANIMATION; 20 import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.START_RECENTS_ANIMATION; 21 22 import android.graphics.Rect; 23 import android.util.ArraySet; 24 import android.view.RemoteAnimationTarget; 25 26 import androidx.annotation.BinderThread; 27 import androidx.annotation.NonNull; 28 import androidx.annotation.UiThread; 29 30 import com.android.launcher3.Utilities; 31 import com.android.launcher3.util.Preconditions; 32 import com.android.quickstep.util.ActiveGestureErrorDetector; 33 import com.android.quickstep.util.ActiveGestureLog; 34 import com.android.systemui.shared.recents.model.ThumbnailData; 35 import com.android.systemui.shared.system.RecentsAnimationControllerCompat; 36 37 import java.util.HashMap; 38 import java.util.Set; 39 40 /** 41 * Wrapper around {@link com.android.systemui.shared.system.RecentsAnimationListener} which 42 * delegates callbacks to multiple listeners on the main thread 43 */ 44 public class RecentsAnimationCallbacks implements 45 com.android.systemui.shared.system.RecentsAnimationListener { 46 47 private final Set<RecentsAnimationListener> mListeners = new ArraySet<>(); 48 private final SystemUiProxy mSystemUiProxy; 49 private final boolean mAllowMinimizeSplitScreen; 50 51 // TODO(141886704): Remove these references when they are no longer needed 52 private RecentsAnimationController mController; 53 54 private boolean mCancelled; 55 RecentsAnimationCallbacks(SystemUiProxy systemUiProxy, boolean allowMinimizeSplitScreen)56 public RecentsAnimationCallbacks(SystemUiProxy systemUiProxy, 57 boolean allowMinimizeSplitScreen) { 58 mSystemUiProxy = systemUiProxy; 59 mAllowMinimizeSplitScreen = allowMinimizeSplitScreen; 60 } 61 62 @UiThread addListener(RecentsAnimationListener listener)63 public void addListener(RecentsAnimationListener listener) { 64 Preconditions.assertUIThread(); 65 mListeners.add(listener); 66 } 67 68 @UiThread removeListener(RecentsAnimationListener listener)69 public void removeListener(RecentsAnimationListener listener) { 70 Preconditions.assertUIThread(); 71 mListeners.remove(listener); 72 } 73 74 @UiThread removeAllListeners()75 public void removeAllListeners() { 76 Preconditions.assertUIThread(); 77 mListeners.clear(); 78 } 79 notifyAnimationCanceled()80 public void notifyAnimationCanceled() { 81 mCancelled = true; 82 onAnimationCanceled(new HashMap<>()); 83 } 84 85 // Called only in Q platform 86 @BinderThread 87 @Deprecated onAnimationStart(RecentsAnimationControllerCompat controller, RemoteAnimationTarget[] appTargets, Rect homeContentInsets, Rect minimizedHomeBounds)88 public final void onAnimationStart(RecentsAnimationControllerCompat controller, 89 RemoteAnimationTarget[] appTargets, Rect homeContentInsets, 90 Rect minimizedHomeBounds) { 91 onAnimationStart(controller, appTargets, new RemoteAnimationTarget[0], 92 homeContentInsets, minimizedHomeBounds); 93 } 94 95 // Called only in R+ platform 96 @BinderThread onAnimationStart(RecentsAnimationControllerCompat animationController, RemoteAnimationTarget[] appTargets, RemoteAnimationTarget[] wallpaperTargets, Rect homeContentInsets, Rect minimizedHomeBounds)97 public final void onAnimationStart(RecentsAnimationControllerCompat animationController, 98 RemoteAnimationTarget[] appTargets, 99 RemoteAnimationTarget[] wallpaperTargets, 100 Rect homeContentInsets, Rect minimizedHomeBounds) { 101 mController = new RecentsAnimationController(animationController, 102 mAllowMinimizeSplitScreen, this::onAnimationFinished); 103 104 if (mCancelled) { 105 Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), 106 mController::finishAnimationToApp); 107 } else { 108 RemoteAnimationTarget[] nonAppTargets = 109 mSystemUiProxy.onGoingToRecentsLegacy(appTargets); 110 if (nonAppTargets == null) { 111 nonAppTargets = new RemoteAnimationTarget[0]; 112 } 113 final RecentsAnimationTargets targets = new RecentsAnimationTargets(appTargets, 114 wallpaperTargets, nonAppTargets, homeContentInsets, minimizedHomeBounds); 115 116 Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> { 117 ActiveGestureLog.INSTANCE.addLog( 118 /* event= */ "RecentsAnimationCallbacks.onAnimationStart", 119 /* extras= */ targets.apps.length, 120 /* gestureEvent= */ START_RECENTS_ANIMATION); 121 for (RecentsAnimationListener listener : getListeners()) { 122 listener.onRecentsAnimationStart(mController, targets); 123 } 124 }); 125 } 126 } 127 128 @BinderThread 129 @Override onAnimationCanceled(HashMap<Integer, ThumbnailData> thumbnailDatas)130 public final void onAnimationCanceled(HashMap<Integer, ThumbnailData> thumbnailDatas) { 131 Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> { 132 ActiveGestureLog.INSTANCE.addLog( 133 /* event= */ "RecentsAnimationCallbacks.onAnimationCanceled", 134 /* gestureEvent= */ CANCEL_RECENTS_ANIMATION); 135 for (RecentsAnimationListener listener : getListeners()) { 136 listener.onRecentsAnimationCanceled(thumbnailDatas); 137 } 138 }); 139 } 140 141 @BinderThread 142 @Override onTasksAppeared(RemoteAnimationTarget[] apps)143 public void onTasksAppeared(RemoteAnimationTarget[] apps) { 144 Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> { 145 ActiveGestureLog.INSTANCE.addLog("RecentsAnimationCallbacks.onTasksAppeared", 146 ActiveGestureErrorDetector.GestureEvent.TASK_APPEARED); 147 for (RecentsAnimationListener listener : getListeners()) { 148 listener.onTasksAppeared(apps); 149 } 150 }); 151 } 152 153 @BinderThread 154 @Override onSwitchToScreenshot(Runnable onFinished)155 public boolean onSwitchToScreenshot(Runnable onFinished) { 156 Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> { 157 for (RecentsAnimationListener listener : getListeners()) { 158 if (listener.onSwitchToScreenshot(onFinished)) return; 159 } 160 onFinished.run(); 161 }); 162 return true; 163 } 164 onAnimationFinished(RecentsAnimationController controller)165 private final void onAnimationFinished(RecentsAnimationController controller) { 166 Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> { 167 ActiveGestureLog.INSTANCE.addLog( 168 /* event= */ "RecentsAnimationCallbacks.onAnimationFinished"); 169 for (RecentsAnimationListener listener : getListeners()) { 170 listener.onRecentsAnimationFinished(controller); 171 } 172 }); 173 } 174 getListeners()175 private RecentsAnimationListener[] getListeners() { 176 return mListeners.toArray(new RecentsAnimationListener[mListeners.size()]); 177 } 178 179 /** 180 * Listener for the recents animation callbacks. 181 */ 182 public interface RecentsAnimationListener { onRecentsAnimationStart(RecentsAnimationController controller, RecentsAnimationTargets targets)183 default void onRecentsAnimationStart(RecentsAnimationController controller, 184 RecentsAnimationTargets targets) {} 185 186 /** 187 * Callback from the system when the recents animation is canceled. {@param thumbnailData} 188 * is passed back for rendering screenshot to replace live tile. 189 */ onRecentsAnimationCanceled( @onNull HashMap<Integer, ThumbnailData> thumbnailDatas)190 default void onRecentsAnimationCanceled( 191 @NonNull HashMap<Integer, ThumbnailData> thumbnailDatas) {} 192 193 /** 194 * Callback made whenever the recents animation is finished. 195 */ onRecentsAnimationFinished(@onNull RecentsAnimationController controller)196 default void onRecentsAnimationFinished(@NonNull RecentsAnimationController controller) {} 197 198 /** 199 * Callback made when a task started from the recents is ready for an app transition. 200 */ onTasksAppeared(@onNull RemoteAnimationTarget[] appearedTaskTarget)201 default void onTasksAppeared(@NonNull RemoteAnimationTarget[] appearedTaskTarget) {} 202 203 /** 204 * @return whether this will call onFinished or not (onFinished should only be called once). 205 */ onSwitchToScreenshot(Runnable onFinished)206 default boolean onSwitchToScreenshot(Runnable onFinished) { 207 return false; 208 } 209 } 210 } 211