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 com.android.server.wm;
18 
19 import android.annotation.Nullable;
20 import android.app.ActivityOptions;
21 import android.os.Handler;
22 import android.os.IBinder;
23 import android.util.ArrayMap;
24 import android.view.RemoteAnimationAdapter;
25 
26 /**
27  * Registry to keep track of remote animations to be run for activity starts from a certain package.
28  *
29  * @see ActivityTaskManagerService#registerRemoteAnimationForNextActivityStart
30  */
31 class PendingRemoteAnimationRegistry {
32 
33     static final long TIMEOUT_MS = 3000;
34 
35     private final ArrayMap<String, Entry> mEntries = new ArrayMap<>();
36     private final Handler mHandler;
37     private final WindowManagerGlobalLock mLock;
38 
PendingRemoteAnimationRegistry(WindowManagerGlobalLock lock, Handler handler)39     PendingRemoteAnimationRegistry(WindowManagerGlobalLock lock, Handler handler) {
40         mLock = lock;
41         mHandler = handler;
42     }
43 
44     /**
45      * Adds a remote animation to be run for all activity starts originating from a certain package.
46      */
addPendingAnimation(String packageName, RemoteAnimationAdapter adapter, @Nullable IBinder launchCookie)47     void addPendingAnimation(String packageName, RemoteAnimationAdapter adapter,
48             @Nullable IBinder launchCookie) {
49         mEntries.put(packageName, new Entry(packageName, adapter, launchCookie));
50     }
51 
52     /**
53      * Overrides the activity options with a registered remote animation for a certain calling
54      * package if such a remote animation is registered.
55      */
overrideOptionsIfNeeded(String callingPackage, @Nullable ActivityOptions options)56     ActivityOptions overrideOptionsIfNeeded(String callingPackage,
57             @Nullable ActivityOptions options) {
58         final Entry entry = mEntries.get(callingPackage);
59         if (entry == null) {
60             return options;
61         }
62         if (options == null) {
63             options = ActivityOptions.makeRemoteAnimation(entry.adapter);
64         } else {
65             options.setRemoteAnimationAdapter(entry.adapter);
66         }
67         IBinder launchCookie = entry.launchCookie;
68         if (launchCookie != null) {
69             options.setLaunchCookie(launchCookie);
70         }
71         mEntries.remove(callingPackage);
72         return options;
73     }
74 
75     private class Entry {
76         final String packageName;
77         final RemoteAnimationAdapter adapter;
78         @Nullable
79         final IBinder launchCookie;
80 
Entry(String packageName, RemoteAnimationAdapter adapter, @Nullable IBinder launchCookie)81         Entry(String packageName, RemoteAnimationAdapter adapter, @Nullable IBinder launchCookie) {
82             this.packageName = packageName;
83             this.adapter = adapter;
84             this.launchCookie = launchCookie;
85             mHandler.postDelayed(() -> {
86                 synchronized (mLock) {
87                     final Entry entry = mEntries.get(packageName);
88                     if (entry == this) {
89                         mEntries.remove(packageName);
90                     }
91                 }
92             }, TIMEOUT_MS);
93         }
94     }
95 }
96