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