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.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME; 20 21 import android.graphics.Rect; 22 import android.util.ArraySet; 23 import android.view.RemoteAnimationTarget; 24 25 import androidx.annotation.BinderThread; 26 import androidx.annotation.NonNull; 27 import androidx.annotation.UiThread; 28 29 import com.android.launcher3.Utilities; 30 import com.android.launcher3.util.Preconditions; 31 import com.android.systemui.shared.recents.model.ThumbnailData; 32 import com.android.systemui.shared.system.RecentsAnimationControllerCompat; 33 import com.android.systemui.shared.system.RemoteAnimationTargetCompat; 34 35 import java.util.Arrays; 36 import java.util.HashMap; 37 import java.util.Set; 38 39 /** 40 * Wrapper around {@link com.android.systemui.shared.system.RecentsAnimationListener} which 41 * delegates callbacks to multiple listeners on the main thread 42 */ 43 public class RecentsAnimationCallbacks implements 44 com.android.systemui.shared.system.RecentsAnimationListener { 45 46 private final Set<RecentsAnimationListener> mListeners = new ArraySet<>(); 47 private final SystemUiProxy mSystemUiProxy; 48 private final boolean mAllowMinimizeSplitScreen; 49 50 // TODO(141886704): Remove these references when they are no longer needed 51 private RecentsAnimationController mController; 52 53 private boolean mCancelled; 54 RecentsAnimationCallbacks(SystemUiProxy systemUiProxy, boolean allowMinimizeSplitScreen)55 public RecentsAnimationCallbacks(SystemUiProxy systemUiProxy, 56 boolean allowMinimizeSplitScreen) { 57 mSystemUiProxy = systemUiProxy; 58 mAllowMinimizeSplitScreen = allowMinimizeSplitScreen; 59 } 60 61 @UiThread addListener(RecentsAnimationListener listener)62 public void addListener(RecentsAnimationListener listener) { 63 Preconditions.assertUIThread(); 64 mListeners.add(listener); 65 } 66 67 @UiThread removeListener(RecentsAnimationListener listener)68 public void removeListener(RecentsAnimationListener listener) { 69 Preconditions.assertUIThread(); 70 mListeners.remove(listener); 71 } 72 73 @UiThread removeAllListeners()74 public void removeAllListeners() { 75 Preconditions.assertUIThread(); 76 mListeners.clear(); 77 } 78 notifyAnimationCanceled()79 public void notifyAnimationCanceled() { 80 mCancelled = true; 81 onAnimationCanceled(new HashMap<>()); 82 } 83 84 // Called only in Q platform 85 @BinderThread 86 @Deprecated onAnimationStart(RecentsAnimationControllerCompat controller, RemoteAnimationTargetCompat[] appTargets, Rect homeContentInsets, Rect minimizedHomeBounds)87 public final void onAnimationStart(RecentsAnimationControllerCompat controller, 88 RemoteAnimationTargetCompat[] appTargets, Rect homeContentInsets, 89 Rect minimizedHomeBounds) { 90 onAnimationStart(controller, appTargets, new RemoteAnimationTargetCompat[0], 91 homeContentInsets, minimizedHomeBounds); 92 } 93 94 // Called only in R+ platform 95 @BinderThread onAnimationStart(RecentsAnimationControllerCompat animationController, RemoteAnimationTargetCompat[] appTargets, RemoteAnimationTargetCompat[] wallpaperTargets, Rect homeContentInsets, Rect minimizedHomeBounds)96 public final void onAnimationStart(RecentsAnimationControllerCompat animationController, 97 RemoteAnimationTargetCompat[] appTargets, 98 RemoteAnimationTargetCompat[] wallpaperTargets, 99 Rect homeContentInsets, Rect minimizedHomeBounds) { 100 // Convert appTargets to type RemoteAnimationTarget for all apps except Home app 101 RemoteAnimationTarget[] nonHomeApps = Arrays.stream(appTargets) 102 .filter(remoteAnimationTarget -> 103 remoteAnimationTarget.activityType != ACTIVITY_TYPE_HOME) 104 .map(RemoteAnimationTargetCompat::unwrap) 105 .toArray(RemoteAnimationTarget[]::new); 106 107 RemoteAnimationTarget[] nonAppTargets = 108 mSystemUiProxy.onGoingToRecentsLegacy(mCancelled, nonHomeApps); 109 110 RecentsAnimationTargets targets = new RecentsAnimationTargets(appTargets, 111 wallpaperTargets, RemoteAnimationTargetCompat.wrap(nonAppTargets), 112 homeContentInsets, minimizedHomeBounds); 113 mController = new RecentsAnimationController(animationController, 114 mAllowMinimizeSplitScreen, this::onAnimationFinished); 115 116 if (mCancelled) { 117 Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), 118 mController::finishAnimationToApp); 119 } else { 120 Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> { 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 for (RecentsAnimationListener listener : getListeners()) { 133 listener.onRecentsAnimationCanceled(thumbnailDatas); 134 } 135 }); 136 } 137 138 @BinderThread 139 @Override onTasksAppeared(RemoteAnimationTargetCompat[] apps)140 public void onTasksAppeared(RemoteAnimationTargetCompat[] apps) { 141 Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> { 142 for (RecentsAnimationListener listener : getListeners()) { 143 listener.onTasksAppeared(apps); 144 } 145 }); 146 } 147 onAnimationFinished(RecentsAnimationController controller)148 private final void onAnimationFinished(RecentsAnimationController controller) { 149 Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> { 150 for (RecentsAnimationListener listener : getListeners()) { 151 listener.onRecentsAnimationFinished(controller); 152 } 153 }); 154 } 155 getListeners()156 private RecentsAnimationListener[] getListeners() { 157 return mListeners.toArray(new RecentsAnimationListener[mListeners.size()]); 158 } 159 160 /** 161 * Listener for the recents animation callbacks. 162 */ 163 public interface RecentsAnimationListener { onRecentsAnimationStart(RecentsAnimationController controller, RecentsAnimationTargets targets)164 default void onRecentsAnimationStart(RecentsAnimationController controller, 165 RecentsAnimationTargets targets) {} 166 167 /** 168 * Callback from the system when the recents animation is canceled. {@param thumbnailData} 169 * is passed back for rendering screenshot to replace live tile. 170 */ onRecentsAnimationCanceled( @onNull HashMap<Integer, ThumbnailData> thumbnailDatas)171 default void onRecentsAnimationCanceled( 172 @NonNull HashMap<Integer, ThumbnailData> thumbnailDatas) {} 173 174 /** 175 * Callback made whenever the recents animation is finished. 176 */ onRecentsAnimationFinished(@onNull RecentsAnimationController controller)177 default void onRecentsAnimationFinished(@NonNull RecentsAnimationController controller) {} 178 179 /** 180 * Callback made when a task started from the recents is ready for an app transition. 181 */ onTasksAppeared(@onNull RemoteAnimationTargetCompat[] appearedTaskTarget)182 default void onTasksAppeared(@NonNull RemoteAnimationTargetCompat[] appearedTaskTarget) {} 183 } 184 } 185