1 /*
2  * Copyright (C) 2019 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.wm.shell.pip;
18 
19 import android.app.RemoteAction;
20 import android.content.ComponentName;
21 import android.content.pm.ParceledListSlice;
22 import android.os.RemoteException;
23 import android.view.IPinnedTaskListener;
24 import android.view.WindowManagerGlobal;
25 
26 import androidx.annotation.BinderThread;
27 
28 import com.android.wm.shell.common.ShellExecutor;
29 
30 import java.util.ArrayList;
31 
32 /**
33  * PinnedStackListener that simply forwards all calls to each listener added via
34  * {@link #addListener}. This is necessary since calling
35  * {@link com.android.server.wm.WindowManagerService#registerPinnedTaskListener} replaces any
36  * previously set listener.
37  */
38 public class PinnedStackListenerForwarder {
39 
40     private final IPinnedTaskListener mListenerImpl = new PinnedTaskListenerImpl();
41     private final ShellExecutor mMainExecutor;
42     private final ArrayList<PinnedTaskListener> mListeners = new ArrayList<>();
43 
PinnedStackListenerForwarder(ShellExecutor mainExecutor)44     public PinnedStackListenerForwarder(ShellExecutor mainExecutor) {
45         mMainExecutor = mainExecutor;
46     }
47 
48     /** Adds a listener to receive updates from the WindowManagerService. */
addListener(PinnedTaskListener listener)49     public void addListener(PinnedTaskListener listener) {
50         mListeners.add(listener);
51     }
52 
53     /** Removes a listener so it will no longer receive updates from the WindowManagerService. */
removeListener(PinnedTaskListener listener)54     public void removeListener(PinnedTaskListener listener) {
55         mListeners.remove(listener);
56     }
57 
register(int displayId)58     public void register(int displayId) throws RemoteException {
59         WindowManagerGlobal.getWindowManagerService().registerPinnedTaskListener(
60                 displayId, mListenerImpl);
61     }
62 
onMovementBoundsChanged(boolean fromImeAdjustment)63     private void onMovementBoundsChanged(boolean fromImeAdjustment) {
64         for (PinnedTaskListener listener : mListeners) {
65             listener.onMovementBoundsChanged(fromImeAdjustment);
66         }
67     }
68 
onImeVisibilityChanged(boolean imeVisible, int imeHeight)69     private void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
70         for (PinnedTaskListener listener : mListeners) {
71             listener.onImeVisibilityChanged(imeVisible, imeHeight);
72         }
73     }
74 
onActionsChanged(ParceledListSlice<RemoteAction> actions)75     private void onActionsChanged(ParceledListSlice<RemoteAction> actions) {
76         for (PinnedTaskListener listener : mListeners) {
77             listener.onActionsChanged(actions);
78         }
79     }
80 
onActivityHidden(ComponentName componentName)81     private void onActivityHidden(ComponentName componentName) {
82         for (PinnedTaskListener listener : mListeners) {
83             listener.onActivityHidden(componentName);
84         }
85     }
86 
onAspectRatioChanged(float aspectRatio)87     private void onAspectRatioChanged(float aspectRatio) {
88         for (PinnedTaskListener listener : mListeners) {
89             listener.onAspectRatioChanged(aspectRatio);
90         }
91     }
92 
93     @BinderThread
94     private class PinnedTaskListenerImpl extends IPinnedTaskListener.Stub {
95         @Override
onMovementBoundsChanged(boolean fromImeAdjustment)96         public void onMovementBoundsChanged(boolean fromImeAdjustment) {
97             mMainExecutor.execute(() -> {
98                 PinnedStackListenerForwarder.this.onMovementBoundsChanged(fromImeAdjustment);
99             });
100         }
101 
102         @Override
onImeVisibilityChanged(boolean imeVisible, int imeHeight)103         public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
104             mMainExecutor.execute(() -> {
105                 PinnedStackListenerForwarder.this.onImeVisibilityChanged(imeVisible, imeHeight);
106             });
107         }
108 
109         @Override
onActionsChanged(ParceledListSlice<RemoteAction> actions)110         public void onActionsChanged(ParceledListSlice<RemoteAction> actions) {
111             mMainExecutor.execute(() -> {
112                 PinnedStackListenerForwarder.this.onActionsChanged(actions);
113             });
114         }
115 
116         @Override
onActivityHidden(ComponentName componentName)117         public void onActivityHidden(ComponentName componentName) {
118             mMainExecutor.execute(() -> {
119                 PinnedStackListenerForwarder.this.onActivityHidden(componentName);
120             });
121         }
122 
123         @Override
onAspectRatioChanged(float aspectRatio)124         public void onAspectRatioChanged(float aspectRatio) {
125             mMainExecutor.execute(() -> {
126                 PinnedStackListenerForwarder.this.onAspectRatioChanged(aspectRatio);
127             });
128         }
129     }
130 
131     /**
132      * A counterpart of {@link IPinnedTaskListener} with empty implementations.
133      * Subclasses can ignore those methods they do not intend to take action upon.
134      */
135     public static class PinnedTaskListener {
onMovementBoundsChanged(boolean fromImeAdjustment)136         public void onMovementBoundsChanged(boolean fromImeAdjustment) {}
137 
onImeVisibilityChanged(boolean imeVisible, int imeHeight)138         public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {}
139 
onActionsChanged(ParceledListSlice<RemoteAction> actions)140         public void onActionsChanged(ParceledListSlice<RemoteAction> actions) {}
141 
onActivityHidden(ComponentName componentName)142         public void onActivityHidden(ComponentName componentName) {}
143 
onAspectRatioChanged(float aspectRatio)144         public void onAspectRatioChanged(float aspectRatio) {}
145     }
146 }
147