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 com.android.systemui.shared.system.RemoteAnimationTargetCompat; 19 20 import java.util.ArrayList; 21 import java.util.concurrent.CopyOnWriteArrayList; 22 23 /** 24 * Holds a collection of RemoteAnimationTargets, filtered by different properties. 25 */ 26 public class RemoteAnimationTargets { 27 28 private final CopyOnWriteArrayList<ReleaseCheck> mReleaseChecks = new CopyOnWriteArrayList<>(); 29 30 public final RemoteAnimationTargetCompat[] unfilteredApps; 31 public final RemoteAnimationTargetCompat[] apps; 32 public final RemoteAnimationTargetCompat[] wallpapers; 33 public final int targetMode; 34 public final boolean hasRecents; 35 36 private boolean mReleased = false; 37 RemoteAnimationTargets(RemoteAnimationTargetCompat[] apps, RemoteAnimationTargetCompat[] wallpapers, int targetMode)38 public RemoteAnimationTargets(RemoteAnimationTargetCompat[] apps, 39 RemoteAnimationTargetCompat[] wallpapers, int targetMode) { 40 ArrayList<RemoteAnimationTargetCompat> filteredApps = new ArrayList<>(); 41 boolean hasRecents = false; 42 if (apps != null) { 43 for (RemoteAnimationTargetCompat target : apps) { 44 if (target.mode == targetMode) { 45 filteredApps.add(target); 46 } 47 48 hasRecents |= target.activityType == 49 RemoteAnimationTargetCompat.ACTIVITY_TYPE_RECENTS; 50 } 51 } 52 53 this.unfilteredApps = apps; 54 this.apps = filteredApps.toArray(new RemoteAnimationTargetCompat[filteredApps.size()]); 55 this.wallpapers = wallpapers; 56 this.targetMode = targetMode; 57 this.hasRecents = hasRecents; 58 } 59 findTask(int taskId)60 public RemoteAnimationTargetCompat findTask(int taskId) { 61 for (RemoteAnimationTargetCompat target : apps) { 62 if (target.taskId == taskId) { 63 return target; 64 } 65 } 66 return null; 67 } 68 isAnimatingHome()69 public boolean isAnimatingHome() { 70 for (RemoteAnimationTargetCompat target : unfilteredApps) { 71 if (target.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) { 72 return true; 73 } 74 } 75 return false; 76 } 77 addReleaseCheck(ReleaseCheck check)78 public void addReleaseCheck(ReleaseCheck check) { 79 mReleaseChecks.add(check); 80 } 81 release()82 public void release() { 83 if (mReleased) { 84 return; 85 } 86 for (ReleaseCheck check : mReleaseChecks) { 87 if (!check.mCanRelease) { 88 check.addOnSafeToReleaseCallback(this::release); 89 return; 90 } 91 } 92 mReleaseChecks.clear(); 93 mReleased = true; 94 95 for (RemoteAnimationTargetCompat target : unfilteredApps) { 96 target.release(); 97 } 98 for (RemoteAnimationTargetCompat target : wallpapers) { 99 target.release(); 100 } 101 } 102 103 /** 104 * Interface for intercepting surface release method 105 */ 106 public static class ReleaseCheck { 107 108 boolean mCanRelease = false; 109 private Runnable mAfterApplyCallback; 110 setCanRelease(boolean canRelease)111 protected void setCanRelease(boolean canRelease) { 112 mCanRelease = canRelease; 113 if (mCanRelease && mAfterApplyCallback != null) { 114 Runnable r = mAfterApplyCallback; 115 mAfterApplyCallback = null; 116 r.run(); 117 } 118 } 119 120 /** 121 * Adds a callback to notify when the surface can safely be released 122 */ addOnSafeToReleaseCallback(Runnable callback)123 void addOnSafeToReleaseCallback(Runnable callback) { 124 if (mCanRelease) { 125 callback.run(); 126 } else { 127 if (mAfterApplyCallback == null) { 128 mAfterApplyCallback = callback; 129 } else { 130 final Runnable oldCallback = mAfterApplyCallback; 131 mAfterApplyCallback = () -> { 132 callback.run(); 133 oldCallback.run(); 134 }; 135 } 136 } 137 } 138 } 139 } 140