1 /* 2 * Copyright (C) 2018 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 android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; 19 20 import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS; 21 22 import com.android.systemui.shared.system.RemoteAnimationTargetCompat; 23 24 import java.util.ArrayList; 25 import java.util.concurrent.CopyOnWriteArrayList; 26 27 /** 28 * Holds a collection of RemoteAnimationTargets, filtered by different properties. 29 */ 30 public class RemoteAnimationTargets { 31 32 private final CopyOnWriteArrayList<ReleaseCheck> mReleaseChecks = new CopyOnWriteArrayList<>(); 33 34 public final RemoteAnimationTargetCompat[] unfilteredApps; 35 public final RemoteAnimationTargetCompat[] apps; 36 public final RemoteAnimationTargetCompat[] wallpapers; 37 public final RemoteAnimationTargetCompat[] nonApps; 38 public final int targetMode; 39 public final boolean hasRecents; 40 41 private boolean mReleased = false; 42 RemoteAnimationTargets(RemoteAnimationTargetCompat[] apps, RemoteAnimationTargetCompat[] wallpapers, RemoteAnimationTargetCompat[] nonApps, int targetMode)43 public RemoteAnimationTargets(RemoteAnimationTargetCompat[] apps, 44 RemoteAnimationTargetCompat[] wallpapers, RemoteAnimationTargetCompat[] nonApps, 45 int targetMode) { 46 ArrayList<RemoteAnimationTargetCompat> filteredApps = new ArrayList<>(); 47 boolean hasRecents = false; 48 if (apps != null) { 49 for (RemoteAnimationTargetCompat target : apps) { 50 if (target.mode == targetMode) { 51 filteredApps.add(target); 52 } 53 54 hasRecents |= target.activityType == 55 RemoteAnimationTargetCompat.ACTIVITY_TYPE_RECENTS; 56 } 57 } 58 59 this.unfilteredApps = apps; 60 this.apps = filteredApps.toArray(new RemoteAnimationTargetCompat[filteredApps.size()]); 61 this.wallpapers = wallpapers; 62 this.targetMode = targetMode; 63 this.hasRecents = hasRecents; 64 this.nonApps = nonApps; 65 } 66 findTask(int taskId)67 public RemoteAnimationTargetCompat findTask(int taskId) { 68 for (RemoteAnimationTargetCompat target : apps) { 69 if (target.taskId == taskId) { 70 return target; 71 } 72 } 73 return null; 74 } 75 76 /** 77 * Gets the navigation bar remote animation target if exists. 78 */ getNavBarRemoteAnimationTarget()79 public RemoteAnimationTargetCompat getNavBarRemoteAnimationTarget() { 80 return getNonAppTargetOfType(TYPE_NAVIGATION_BAR); 81 } 82 getNonAppTargetOfType(int type)83 public RemoteAnimationTargetCompat getNonAppTargetOfType(int type) { 84 for (RemoteAnimationTargetCompat target : nonApps) { 85 if (target.windowType == type) { 86 return target; 87 } 88 } 89 return null; 90 } 91 92 /** Returns the first opening app target. */ getFirstAppTarget()93 public RemoteAnimationTargetCompat getFirstAppTarget() { 94 return apps.length > 0 ? apps[0] : null; 95 } 96 97 /** Returns the task id of the first opening app target, or -1 if none is found. */ getFirstAppTargetTaskId()98 public int getFirstAppTargetTaskId() { 99 RemoteAnimationTargetCompat target = getFirstAppTarget(); 100 return target == null ? -1 : target.taskId; 101 } 102 isAnimatingHome()103 public boolean isAnimatingHome() { 104 for (RemoteAnimationTargetCompat target : unfilteredApps) { 105 if (target.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) { 106 return true; 107 } 108 } 109 return false; 110 } 111 addReleaseCheck(ReleaseCheck check)112 public void addReleaseCheck(ReleaseCheck check) { 113 mReleaseChecks.add(check); 114 } 115 release()116 public void release() { 117 if (ENABLE_SHELL_TRANSITIONS) { 118 mReleaseChecks.clear(); 119 return; 120 } 121 if (mReleased) { 122 return; 123 } 124 for (ReleaseCheck check : mReleaseChecks) { 125 if (!check.mCanRelease) { 126 check.addOnSafeToReleaseCallback(this::release); 127 return; 128 } 129 } 130 mReleaseChecks.clear(); 131 mReleased = true; 132 133 for (RemoteAnimationTargetCompat target : unfilteredApps) { 134 target.release(); 135 } 136 for (RemoteAnimationTargetCompat target : wallpapers) { 137 target.release(); 138 } 139 for (RemoteAnimationTargetCompat target : nonApps) { 140 target.release(); 141 } 142 } 143 144 /** 145 * Interface for intercepting surface release method 146 */ 147 public static class ReleaseCheck { 148 149 boolean mCanRelease = false; 150 private Runnable mAfterApplyCallback; 151 setCanRelease(boolean canRelease)152 protected void setCanRelease(boolean canRelease) { 153 mCanRelease = canRelease; 154 if (mCanRelease && mAfterApplyCallback != null) { 155 Runnable r = mAfterApplyCallback; 156 mAfterApplyCallback = null; 157 r.run(); 158 } 159 } 160 161 /** 162 * Adds a callback to notify when the surface can safely be released 163 */ addOnSafeToReleaseCallback(Runnable callback)164 void addOnSafeToReleaseCallback(Runnable callback) { 165 if (mCanRelease) { 166 callback.run(); 167 } else { 168 if (mAfterApplyCallback == null) { 169 mAfterApplyCallback = callback; 170 } else { 171 final Runnable oldCallback = mAfterApplyCallback; 172 mAfterApplyCallback = () -> { 173 callback.run(); 174 oldCallback.run(); 175 }; 176 } 177 } 178 } 179 } 180 } 181