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