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