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