• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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.common;
18 
19 import android.content.ComponentName;
20 import android.os.RemoteException;
21 import android.util.Slog;
22 import android.util.SparseArray;
23 import android.view.IDisplayWindowInsetsController;
24 import android.view.IWindowManager;
25 import android.view.InsetsSourceControl;
26 import android.view.InsetsState;
27 import android.view.InsetsVisibilities;
28 
29 import androidx.annotation.BinderThread;
30 
31 import com.android.wm.shell.common.annotations.ShellMainThread;
32 import com.android.wm.shell.sysui.ShellInit;
33 
34 import java.util.concurrent.CopyOnWriteArrayList;
35 
36 /**
37  * Manages insets from the core.
38  */
39 public class DisplayInsetsController implements DisplayController.OnDisplaysChangedListener {
40     private static final String TAG = "DisplayInsetsController";
41 
42     private final IWindowManager mWmService;
43     private final ShellExecutor mMainExecutor;
44     private final DisplayController mDisplayController;
45     private final SparseArray<PerDisplay> mInsetsPerDisplay = new SparseArray<>();
46     private final SparseArray<CopyOnWriteArrayList<OnInsetsChangedListener>> mListeners =
47             new SparseArray<>();
48 
DisplayInsetsController(IWindowManager wmService, ShellInit shellInit, DisplayController displayController, ShellExecutor mainExecutor)49     public DisplayInsetsController(IWindowManager wmService,
50             ShellInit shellInit,
51             DisplayController displayController,
52             ShellExecutor mainExecutor) {
53         mWmService = wmService;
54         mDisplayController = displayController;
55         mMainExecutor = mainExecutor;
56         shellInit.addInitCallback(this::onInit, this);
57     }
58 
59     /**
60      * Starts listening for insets for each display.
61      **/
onInit()62     public void onInit() {
63         mDisplayController.addDisplayWindowListener(this);
64     }
65 
66     /**
67      * Adds a callback to listen for insets changes for a particular display.  Note that the
68      * listener will not be updated with the existing state of the insets on that display.
69      */
addInsetsChangedListener(int displayId, OnInsetsChangedListener listener)70     public void addInsetsChangedListener(int displayId, OnInsetsChangedListener listener) {
71         CopyOnWriteArrayList<OnInsetsChangedListener> listeners = mListeners.get(displayId);
72         if (listeners == null) {
73             listeners = new CopyOnWriteArrayList<>();
74             mListeners.put(displayId, listeners);
75         }
76         if (!listeners.contains(listener)) {
77             listeners.add(listener);
78         }
79     }
80 
81     /**
82      * Removes a callback listening for insets changes from a particular display.
83      */
removeInsetsChangedListener(int displayId, OnInsetsChangedListener listener)84     public void removeInsetsChangedListener(int displayId, OnInsetsChangedListener listener) {
85         CopyOnWriteArrayList<OnInsetsChangedListener> listeners = mListeners.get(displayId);
86         if (listeners == null) {
87             return;
88         }
89         listeners.remove(listener);
90     }
91 
92     @Override
onDisplayAdded(int displayId)93     public void onDisplayAdded(int displayId) {
94         PerDisplay pd = new PerDisplay(displayId);
95         pd.register();
96         mInsetsPerDisplay.put(displayId, pd);
97     }
98 
99     @Override
onDisplayRemoved(int displayId)100     public void onDisplayRemoved(int displayId) {
101         PerDisplay pd = mInsetsPerDisplay.get(displayId);
102         if (pd == null) {
103             return;
104         }
105         pd.unregister();
106         mInsetsPerDisplay.remove(displayId);
107     }
108 
109     /**
110      * An implementation of {@link IDisplayWindowInsetsController} for a given display id.
111      **/
112     public class PerDisplay {
113         private final int mDisplayId;
114         private final DisplayWindowInsetsControllerImpl mInsetsControllerImpl =
115                 new DisplayWindowInsetsControllerImpl();
116 
PerDisplay(int displayId)117         public PerDisplay(int displayId) {
118             mDisplayId = displayId;
119         }
120 
register()121         public void register() {
122             try {
123                 mWmService.setDisplayWindowInsetsController(mDisplayId, mInsetsControllerImpl);
124             } catch (RemoteException e) {
125                 Slog.w(TAG, "Unable to set insets controller on display " + mDisplayId);
126             }
127         }
128 
unregister()129         public void unregister() {
130             try {
131                 mWmService.setDisplayWindowInsetsController(mDisplayId, null);
132             } catch (RemoteException e) {
133                 Slog.w(TAG, "Unable to remove insets controller on display " + mDisplayId);
134             }
135         }
136 
insetsChanged(InsetsState insetsState)137         private void insetsChanged(InsetsState insetsState) {
138             CopyOnWriteArrayList<OnInsetsChangedListener> listeners = mListeners.get(mDisplayId);
139             if (listeners == null) {
140                 return;
141             }
142             mDisplayController.updateDisplayInsets(mDisplayId, insetsState);
143             for (OnInsetsChangedListener listener : listeners) {
144                 listener.insetsChanged(insetsState);
145             }
146         }
147 
insetsControlChanged(InsetsState insetsState, InsetsSourceControl[] activeControls)148         private void insetsControlChanged(InsetsState insetsState,
149                 InsetsSourceControl[] activeControls) {
150             CopyOnWriteArrayList<OnInsetsChangedListener> listeners = mListeners.get(mDisplayId);
151             if (listeners == null) {
152                 return;
153             }
154             for (OnInsetsChangedListener listener : listeners) {
155                 listener.insetsControlChanged(insetsState, activeControls);
156             }
157         }
158 
showInsets(int types, boolean fromIme)159         private void showInsets(int types, boolean fromIme) {
160             CopyOnWriteArrayList<OnInsetsChangedListener> listeners = mListeners.get(mDisplayId);
161             if (listeners == null) {
162                 return;
163             }
164             for (OnInsetsChangedListener listener : listeners) {
165                 listener.showInsets(types, fromIme);
166             }
167         }
168 
hideInsets(int types, boolean fromIme)169         private void hideInsets(int types, boolean fromIme) {
170             CopyOnWriteArrayList<OnInsetsChangedListener> listeners = mListeners.get(mDisplayId);
171             if (listeners == null) {
172                 return;
173             }
174             for (OnInsetsChangedListener listener : listeners) {
175                 listener.hideInsets(types, fromIme);
176             }
177         }
178 
topFocusedWindowChanged(ComponentName component, InsetsVisibilities requestedVisibilities)179         private void topFocusedWindowChanged(ComponentName component,
180                 InsetsVisibilities requestedVisibilities) {
181             CopyOnWriteArrayList<OnInsetsChangedListener> listeners = mListeners.get(mDisplayId);
182             if (listeners == null) {
183                 return;
184             }
185             for (OnInsetsChangedListener listener : listeners) {
186                 listener.topFocusedWindowChanged(component, requestedVisibilities);
187             }
188         }
189 
190         @BinderThread
191         private class DisplayWindowInsetsControllerImpl
192                 extends IDisplayWindowInsetsController.Stub {
193             @Override
topFocusedWindowChanged(ComponentName component, InsetsVisibilities requestedVisibilities)194             public void topFocusedWindowChanged(ComponentName component,
195                     InsetsVisibilities requestedVisibilities) throws RemoteException {
196                 mMainExecutor.execute(() -> {
197                     PerDisplay.this.topFocusedWindowChanged(component, requestedVisibilities);
198                 });
199             }
200 
201             @Override
insetsChanged(InsetsState insetsState)202             public void insetsChanged(InsetsState insetsState) throws RemoteException {
203                 mMainExecutor.execute(() -> {
204                     PerDisplay.this.insetsChanged(insetsState);
205                 });
206             }
207 
208             @Override
insetsControlChanged(InsetsState insetsState, InsetsSourceControl[] activeControls)209             public void insetsControlChanged(InsetsState insetsState,
210                     InsetsSourceControl[] activeControls) throws RemoteException {
211                 mMainExecutor.execute(() -> {
212                     PerDisplay.this.insetsControlChanged(insetsState, activeControls);
213                 });
214             }
215 
216             @Override
showInsets(int types, boolean fromIme)217             public void showInsets(int types, boolean fromIme) throws RemoteException {
218                 mMainExecutor.execute(() -> {
219                     PerDisplay.this.showInsets(types, fromIme);
220                 });
221             }
222 
223             @Override
hideInsets(int types, boolean fromIme)224             public void hideInsets(int types, boolean fromIme) throws RemoteException {
225                 mMainExecutor.execute(() -> {
226                     PerDisplay.this.hideInsets(types, fromIme);
227                 });
228             }
229         }
230     }
231 
232     /**
233      * Gets notified whenever the insets change.
234      *
235      * @see IDisplayWindowInsetsController
236      */
237     @ShellMainThread
238     public interface OnInsetsChangedListener {
239         /**
240          * Called when top focused window changes to determine whether or not to take over insets
241          * control. Won't be called if config_remoteInsetsControllerControlsSystemBars is false.
242          * @param component The application component that is open in the top focussed window.
243          * @param requestedVisibilities The insets visibilities requested by the focussed window.
244          */
topFocusedWindowChanged(ComponentName component, InsetsVisibilities requestedVisibilities)245         default void topFocusedWindowChanged(ComponentName component,
246                 InsetsVisibilities requestedVisibilities) {}
247 
248         /**
249          * Called when the window insets configuration has changed.
250          */
insetsChanged(InsetsState insetsState)251         default void insetsChanged(InsetsState insetsState) {}
252 
253         /**
254          * Called when this window retrieved control over a specified set of insets sources.
255          */
insetsControlChanged(InsetsState insetsState, InsetsSourceControl[] activeControls)256         default void insetsControlChanged(InsetsState insetsState,
257                 InsetsSourceControl[] activeControls) {}
258 
259         /**
260          * Called when a set of insets source window should be shown by policy.
261          *
262          * @param types internal insets types (WindowInsets.Type.InsetsType) to show
263          * @param fromIme true if this request originated from IME (InputMethodService).
264          */
showInsets(int types, boolean fromIme)265         default void showInsets(int types, boolean fromIme) {}
266 
267         /**
268          * Called when a set of insets source window should be hidden by policy.
269          *
270          * @param types internal insets types (WindowInsets.Type.InsetsType) to hide
271          * @param fromIme true if this request originated from IME (InputMethodService).
272          */
hideInsets(int types, boolean fromIme)273         default void hideInsets(int types, boolean fromIme) {}
274     }
275 }