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 
17 package android.view;
18 
19 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
20 
21 import android.annotation.Nullable;
22 import android.app.WindowConfiguration.ActivityType;
23 import android.compat.annotation.UnsupportedAppUsage;
24 import android.os.IBinder;
25 import android.os.Parcel;
26 import android.os.Parcelable;
27 import android.os.RemoteException;
28 import android.util.ArraySet;
29 import android.util.Slog;
30 import android.util.SparseArray;
31 import android.view.WindowManager.TransitionOldType;
32 
33 /**
34  * Defines which animation types should be overridden by which remote animation.
35  *
36  * @hide
37  */
38 public class RemoteAnimationDefinition implements Parcelable {
39 
40     private final SparseArray<RemoteAnimationAdapterEntry> mTransitionAnimationMap;
41 
42     @UnsupportedAppUsage
RemoteAnimationDefinition()43     public RemoteAnimationDefinition() {
44         mTransitionAnimationMap = new SparseArray<>();
45     }
46 
47     /**
48      * Registers a remote animation for a specific transition.
49      *
50      * @param transition The old transition type. Must be one of WindowManager.TRANSIT_OLD_* values.
51      * @param activityTypeFilter The remote animation only runs if an activity with type of this
52      *                           parameter is involved in the transition.
53      * @param adapter The adapter that described how to run the remote animation.
54      */
55     @UnsupportedAppUsage
addRemoteAnimation(@ransitionOldType int transition, @ActivityType int activityTypeFilter, RemoteAnimationAdapter adapter)56     public void addRemoteAnimation(@TransitionOldType int transition,
57             @ActivityType int activityTypeFilter, RemoteAnimationAdapter adapter) {
58         mTransitionAnimationMap.put(transition,
59                 new RemoteAnimationAdapterEntry(adapter, activityTypeFilter));
60     }
61 
62     /**
63      * Registers a remote animation for a specific transition without defining an activity type
64      * filter.
65      *
66      * @param transition The old transition type. Must be one of WindowManager.TRANSIT_OLD_* values.
67      * @param adapter The adapter that described how to run the remote animation.
68      */
69     @UnsupportedAppUsage
addRemoteAnimation(@ransitionOldType int transition, RemoteAnimationAdapter adapter)70     public void addRemoteAnimation(@TransitionOldType int transition,
71             RemoteAnimationAdapter adapter) {
72         addRemoteAnimation(transition, ACTIVITY_TYPE_UNDEFINED, adapter);
73     }
74 
75     /**
76      * Checks whether a remote animation for specific transition is defined.
77      *
78      * @param transition The old transition type. Must be one of WindowManager.TRANSIT_OLD_* values.
79      * @param activityTypes The set of activity types of activities that are involved in the
80      *                      transition. Will be used for filtering.
81      * @return Whether this definition has defined a remote animation for the specified transition.
82      */
hasTransition(@ransitionOldType int transition, ArraySet<Integer> activityTypes)83     public boolean hasTransition(@TransitionOldType int transition,
84             ArraySet<Integer> activityTypes) {
85         return getAdapter(transition, activityTypes) != null;
86     }
87 
88     /**
89      * Retrieves the remote animation for a specific transition.
90      *
91      * @param transition The old transition type. Must be one of WindowManager.TRANSIT_OLD_* values.
92      * @param activityTypes The set of activity types of activities that are involved in the
93      *                      transition. Will be used for filtering.
94      * @return The remote animation adapter for the specified transition.
95      */
getAdapter(@ransitionOldType int transition, ArraySet<Integer> activityTypes)96     public @Nullable RemoteAnimationAdapter getAdapter(@TransitionOldType int transition,
97             ArraySet<Integer> activityTypes) {
98         final RemoteAnimationAdapterEntry entry = mTransitionAnimationMap.get(transition);
99         if (entry == null) {
100             return null;
101         }
102         if (entry.activityTypeFilter == ACTIVITY_TYPE_UNDEFINED
103                 || activityTypes.contains(entry.activityTypeFilter)) {
104             return entry.adapter;
105         } else {
106             return null;
107         }
108     }
109 
RemoteAnimationDefinition(Parcel in)110     public RemoteAnimationDefinition(Parcel in) {
111         final int size = in.readInt();
112         mTransitionAnimationMap = new SparseArray<>(size);
113         for (int i = 0; i < size; i++) {
114             final int transition = in.readInt();
115             final RemoteAnimationAdapterEntry entry = in.readTypedObject(
116                     RemoteAnimationAdapterEntry.CREATOR);
117             mTransitionAnimationMap.put(transition, entry);
118         }
119     }
120 
121     /**
122      * To be called by system_server to keep track which pid is running the remote animations inside
123      * this definition.
124      */
setCallingPidUid(int pid, int uid)125     public void setCallingPidUid(int pid, int uid) {
126         for (int i = mTransitionAnimationMap.size() - 1; i >= 0; i--) {
127             mTransitionAnimationMap.valueAt(i).adapter.setCallingPidUid(pid, uid);
128         }
129     }
130 
131     /**
132      * Links the death of the runner to the provided death recipient.
133      */
linkToDeath(IBinder.DeathRecipient deathRecipient)134     public void linkToDeath(IBinder.DeathRecipient deathRecipient) {
135         try {
136             for (int i = 0; i < mTransitionAnimationMap.size(); i++) {
137                 mTransitionAnimationMap.valueAt(i).adapter.getRunner().asBinder()
138                         .linkToDeath(deathRecipient, 0 /* flags */);
139             }
140         } catch (RemoteException e) {
141             Slog.e("RemoteAnimationDefinition", "Failed to link to death recipient");
142         }
143     }
144 
145     @Override
describeContents()146     public int describeContents() {
147         return 0;
148     }
149 
150     @Override
writeToParcel(Parcel dest, int flags)151     public void writeToParcel(Parcel dest, int flags) {
152         final int size = mTransitionAnimationMap.size();
153         dest.writeInt(size);
154         for (int i = 0; i < size; i++) {
155             dest.writeInt(mTransitionAnimationMap.keyAt(i));
156             dest.writeTypedObject(mTransitionAnimationMap.valueAt(i), flags);
157         }
158     }
159 
160     public static final @android.annotation.NonNull Creator<RemoteAnimationDefinition> CREATOR =
161             new Creator<RemoteAnimationDefinition>() {
162         public RemoteAnimationDefinition createFromParcel(Parcel in) {
163             return new RemoteAnimationDefinition(in);
164         }
165 
166         public RemoteAnimationDefinition[] newArray(int size) {
167             return new RemoteAnimationDefinition[size];
168         }
169     };
170 
171     private static class RemoteAnimationAdapterEntry implements Parcelable {
172 
173         final RemoteAnimationAdapter adapter;
174 
175         /**
176          * Only run the transition if one of the activities matches the filter.
177          * {@link WindowConfiguration.ACTIVITY_TYPE_UNDEFINED} means no filter
178          */
179         @ActivityType final int activityTypeFilter;
180 
RemoteAnimationAdapterEntry(RemoteAnimationAdapter adapter, int activityTypeFilter)181         RemoteAnimationAdapterEntry(RemoteAnimationAdapter adapter, int activityTypeFilter) {
182             this.adapter = adapter;
183             this.activityTypeFilter = activityTypeFilter;
184         }
185 
RemoteAnimationAdapterEntry(Parcel in)186         private RemoteAnimationAdapterEntry(Parcel in) {
187             adapter = in.readTypedObject(RemoteAnimationAdapter.CREATOR);
188             activityTypeFilter = in.readInt();
189         }
190 
191         @Override
writeToParcel(Parcel dest, int flags)192         public void writeToParcel(Parcel dest, int flags) {
193             dest.writeTypedObject(adapter, flags);
194             dest.writeInt(activityTypeFilter);
195         }
196 
197         @Override
describeContents()198         public int describeContents() {
199             return 0;
200         }
201 
202         private static final @android.annotation.NonNull Creator<RemoteAnimationAdapterEntry> CREATOR
203                 = new Creator<RemoteAnimationAdapterEntry>() {
204 
205             @Override
206             public RemoteAnimationAdapterEntry createFromParcel(Parcel in) {
207                 return new RemoteAnimationAdapterEntry(in);
208             }
209 
210             @Override
211             public RemoteAnimationAdapterEntry[] newArray(int size) {
212                 return new RemoteAnimationAdapterEntry[size];
213             }
214         };
215     }
216 }
217