1 /* 2 * Copyright (C) 2021 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; 18 19 import android.content.Context; 20 21 import androidx.annotation.Nullable; 22 23 import com.android.launcher3.util.SplitConfigurationOptions.StagedSplitBounds; 24 import com.android.quickstep.util.AnimatorControllerWithResistance; 25 import com.android.quickstep.util.LauncherSplitScreenListener; 26 import com.android.quickstep.util.TaskViewSimulator; 27 import com.android.quickstep.util.TransformParams; 28 import com.android.systemui.shared.system.RemoteAnimationTargetCompat; 29 30 /** 31 * Glues together the necessary components to animate a remote target using a 32 * {@link TaskViewSimulator} 33 */ 34 public class RemoteTargetGluer { 35 private RemoteTargetHandle[] mRemoteTargetHandles; 36 private StagedSplitBounds mStagedSplitBounds; 37 38 /** 39 * Use this constructor if remote targets are split-screen independent 40 */ RemoteTargetGluer(Context context, BaseActivityInterface sizingStrategy, RemoteAnimationTargets targets)41 public RemoteTargetGluer(Context context, BaseActivityInterface sizingStrategy, 42 RemoteAnimationTargets targets) { 43 mRemoteTargetHandles = createHandles(context, sizingStrategy, targets.apps.length); 44 } 45 46 /** 47 * Use this constructor if you want the number of handles created to match the number of active 48 * running tasks 49 */ RemoteTargetGluer(Context context, BaseActivityInterface sizingStrategy)50 public RemoteTargetGluer(Context context, BaseActivityInterface sizingStrategy) { 51 int[] splitIds = LauncherSplitScreenListener.INSTANCE.getNoCreate() 52 .getRunningSplitTaskIds(); 53 mRemoteTargetHandles = createHandles(context, sizingStrategy, splitIds.length == 2 ? 2 : 1); 54 } 55 createHandles(Context context, BaseActivityInterface sizingStrategy, int numHandles)56 private RemoteTargetHandle[] createHandles(Context context, 57 BaseActivityInterface sizingStrategy, int numHandles) { 58 RemoteTargetHandle[] handles = new RemoteTargetHandle[numHandles]; 59 for (int i = 0; i < numHandles; i++) { 60 TaskViewSimulator tvs = new TaskViewSimulator(context, sizingStrategy); 61 TransformParams transformParams = new TransformParams(); 62 handles[i] = new RemoteTargetHandle(tvs, transformParams); 63 } 64 return handles; 65 } 66 67 /** 68 * Pairs together {@link TaskViewSimulator}s and {@link TransformParams} into a 69 * {@link RemoteTargetHandle} 70 * Assigns only the apps associated with {@param targets} into their own TaskViewSimulators. 71 * Length of targets.apps should match that of {@link #mRemoteTargetHandles}. 72 * 73 * If split screen may be active when this is called, you might want to use 74 * {@link #assignTargetsForSplitScreen(RemoteAnimationTargets)} 75 */ assignTargets(RemoteAnimationTargets targets)76 public RemoteTargetHandle[] assignTargets(RemoteAnimationTargets targets) { 77 for (int i = 0; i < mRemoteTargetHandles.length; i++) { 78 RemoteAnimationTargetCompat primaryTaskTarget = targets.apps[i]; 79 mRemoteTargetHandles[i].mTransformParams.setTargetSet( 80 createRemoteAnimationTargetsForTarget(targets, null)); 81 mRemoteTargetHandles[i].mTaskViewSimulator.setPreview(primaryTaskTarget, null); 82 } 83 return mRemoteTargetHandles; 84 } 85 86 /** 87 * Similar to {@link #assignTargets(RemoteAnimationTargets)}, except this matches the 88 * apps in targets.apps to that of the _active_ split screened tasks. 89 * See {@link #assignTargetsForSplitScreen(RemoteAnimationTargets, int[])} 90 */ assignTargetsForSplitScreen(RemoteAnimationTargets targets)91 public RemoteTargetHandle[] assignTargetsForSplitScreen(RemoteAnimationTargets targets) { 92 int[] splitIds = LauncherSplitScreenListener.INSTANCE.getNoCreate() 93 .getRunningSplitTaskIds(); 94 return assignTargetsForSplitScreen(targets, splitIds); 95 } 96 97 /** 98 * Assigns the provided splitIDs to the {@link #mRemoteTargetHandles}, with index 0 will being 99 * the left/top task, index 1 right/bottom 100 */ assignTargetsForSplitScreen(RemoteAnimationTargets targets, int[] splitIds)101 public RemoteTargetHandle[] assignTargetsForSplitScreen(RemoteAnimationTargets targets, 102 int[] splitIds) { 103 RemoteAnimationTargetCompat topLeftTarget; // only one set if single/fullscreen task 104 RemoteAnimationTargetCompat bottomRightTarget; 105 if (mRemoteTargetHandles.length == 1) { 106 // If we're not in split screen, the splitIds count doesn't really matter since we 107 // should always hit this case. 108 mRemoteTargetHandles[0].mTransformParams.setTargetSet(targets); 109 if (targets.apps.length > 0) { 110 // Unclear why/when target.apps length == 0, but it sure does happen :( 111 topLeftTarget = targets.apps[0]; 112 mRemoteTargetHandles[0].mTaskViewSimulator.setPreview(topLeftTarget, null); 113 } 114 } else { 115 // split screen 116 topLeftTarget = targets.findTask(splitIds[0]); 117 bottomRightTarget = targets.findTask(splitIds[1]); 118 119 // remoteTargetHandle[0] denotes topLeft task, so we pass in the bottomRight to exclude, 120 // vice versa 121 mStagedSplitBounds = new StagedSplitBounds( 122 topLeftTarget.screenSpaceBounds, 123 bottomRightTarget.screenSpaceBounds, splitIds[0], splitIds[1]); 124 mRemoteTargetHandles[0].mTransformParams.setTargetSet( 125 createRemoteAnimationTargetsForTarget(targets, bottomRightTarget)); 126 mRemoteTargetHandles[0].mTaskViewSimulator.setPreview(topLeftTarget, 127 mStagedSplitBounds); 128 129 mRemoteTargetHandles[1].mTransformParams.setTargetSet( 130 createRemoteAnimationTargetsForTarget(targets, topLeftTarget)); 131 mRemoteTargetHandles[1].mTaskViewSimulator.setPreview(bottomRightTarget, 132 mStagedSplitBounds); 133 } 134 return mRemoteTargetHandles; 135 } 136 137 /** 138 * Ensures that we aren't excluding ancillary targets such as home/recents 139 * 140 * @param targetToExclude Will be excluded from the resulting return value. 141 * Pass in {@code null} to not exclude anything 142 * @return RemoteAnimationTargets where all the app targets from the passed in 143 * {@param targets} are included except {@param targetToExclude} 144 */ createRemoteAnimationTargetsForTarget( RemoteAnimationTargets targets, @Nullable RemoteAnimationTargetCompat targetToExclude)145 private RemoteAnimationTargets createRemoteAnimationTargetsForTarget( 146 RemoteAnimationTargets targets, 147 @Nullable RemoteAnimationTargetCompat targetToExclude) { 148 int finalLength = targets.unfilteredApps.length - (targetToExclude == null ? 0 : 1); 149 RemoteAnimationTargetCompat[] targetsWithoutExcluded = 150 new RemoteAnimationTargetCompat[finalLength]; 151 int i = 0; 152 for (RemoteAnimationTargetCompat targetCompat : targets.unfilteredApps) { 153 if (targetCompat == targetToExclude) { 154 continue; 155 } 156 targetsWithoutExcluded[i] = targetCompat; 157 i++; 158 } 159 return new RemoteAnimationTargets(targetsWithoutExcluded, 160 targets.wallpapers, targets.nonApps, targets.targetMode); 161 } 162 getRemoteTargetHandles()163 public RemoteTargetHandle[] getRemoteTargetHandles() { 164 return mRemoteTargetHandles; 165 } 166 getStagedSplitBounds()167 public StagedSplitBounds getStagedSplitBounds() { 168 return mStagedSplitBounds; 169 } 170 171 /** 172 * Container to keep together all the associated objects whose properties need to be updated to 173 * animate a single remote app target 174 */ 175 public static class RemoteTargetHandle { 176 private final TaskViewSimulator mTaskViewSimulator; 177 private final TransformParams mTransformParams; 178 @Nullable 179 private AnimatorControllerWithResistance mPlaybackController; 180 RemoteTargetHandle(TaskViewSimulator taskViewSimulator, TransformParams transformParams)181 public RemoteTargetHandle(TaskViewSimulator taskViewSimulator, 182 TransformParams transformParams) { 183 mTransformParams = transformParams; 184 mTaskViewSimulator = taskViewSimulator; 185 } 186 getTaskViewSimulator()187 public TaskViewSimulator getTaskViewSimulator() { 188 return mTaskViewSimulator; 189 } 190 getTransformParams()191 public TransformParams getTransformParams() { 192 return mTransformParams; 193 } 194 195 @Nullable getPlaybackController()196 public AnimatorControllerWithResistance getPlaybackController() { 197 return mPlaybackController; 198 } 199 setPlaybackController( @ullable AnimatorControllerWithResistance playbackController)200 public void setPlaybackController( 201 @Nullable AnimatorControllerWithResistance playbackController) { 202 mPlaybackController = playbackController; 203 } 204 } 205 } 206