• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.systemui.wm;
18 
19 import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
20 
21 import android.annotation.NonNull;
22 import android.content.Context;
23 import android.content.res.Configuration;
24 import android.graphics.Point;
25 import android.graphics.Rect;
26 import android.graphics.Region;
27 import android.os.Bundle;
28 import android.os.IBinder;
29 import android.os.ParcelFileDescriptor;
30 import android.os.RemoteException;
31 import android.util.MergedConfiguration;
32 import android.util.Slog;
33 import android.util.SparseArray;
34 import android.view.Display;
35 import android.view.DisplayCutout;
36 import android.view.DragEvent;
37 import android.view.IScrollCaptureController;
38 import android.view.IWindow;
39 import android.view.IWindowManager;
40 import android.view.IWindowSession;
41 import android.view.IWindowSessionCallback;
42 import android.view.InsetsSourceControl;
43 import android.view.InsetsState;
44 import android.view.SurfaceControl;
45 import android.view.SurfaceControlViewHost;
46 import android.view.View;
47 import android.view.ViewGroup;
48 import android.view.WindowManager;
49 import android.view.WindowlessWindowManager;
50 
51 import com.android.internal.os.IResultReceiver;
52 
53 import java.util.HashMap;
54 
55 import javax.inject.Inject;
56 import javax.inject.Singleton;
57 
58 /**
59  * Represents the "windowing" layer of the System-UI. This layer allows system-ui components to
60  * place and manipulate windows without talking to WindowManager.
61  */
62 @Singleton
63 public class SystemWindows {
64     private static final String TAG = "SystemWindows";
65 
66     private final SparseArray<PerDisplay> mPerDisplay = new SparseArray<>();
67     final HashMap<View, SurfaceControlViewHost> mViewRoots = new HashMap<>();
68     Context mContext;
69     IWindowSession mSession;
70     DisplayController mDisplayController;
71     IWindowManager mWmService;
72 
73     private final DisplayController.OnDisplaysChangedListener mDisplayListener =
74             new DisplayController.OnDisplaysChangedListener() {
75                 @Override
76                 public void onDisplayAdded(int displayId) { }
77 
78                 @Override
79                 public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
80                     PerDisplay pd = mPerDisplay.get(displayId);
81                     if (pd == null) {
82                         return;
83                     }
84                     pd.updateConfiguration(newConfig);
85                 }
86 
87                 @Override
88                 public void onDisplayRemoved(int displayId) { }
89             };
90 
91     @Inject
SystemWindows(Context context, DisplayController displayController, IWindowManager wmService)92     public SystemWindows(Context context, DisplayController displayController,
93             IWindowManager wmService) {
94         mContext = context;
95         mWmService = wmService;
96         mDisplayController = displayController;
97         mDisplayController.addDisplayWindowListener(mDisplayListener);
98         try {
99             mSession = wmService.openSession(
100                     new IWindowSessionCallback.Stub() {
101                         @Override
102                         public void onAnimatorScaleChanged(float scale) {}
103                     });
104         } catch (RemoteException e) {
105             Slog.e(TAG, "Unable to create layer", e);
106         }
107     }
108 
109     /**
110      * Adds a view to system-ui window management.
111      */
addView(View view, WindowManager.LayoutParams attrs, int displayId, int windowType)112     public void addView(View view, WindowManager.LayoutParams attrs, int displayId,
113             int windowType) {
114         PerDisplay pd = mPerDisplay.get(displayId);
115         if (pd == null) {
116             pd = new PerDisplay(displayId);
117             mPerDisplay.put(displayId, pd);
118         }
119         pd.addView(view, attrs, windowType);
120     }
121 
122     /**
123      * Removes a view from system-ui window management.
124      * @param view
125      */
removeView(View view)126     public void removeView(View view) {
127         SurfaceControlViewHost root = mViewRoots.remove(view);
128         root.release();
129     }
130 
131     /**
132      * Updates the layout params of a view.
133      */
updateViewLayout(@onNull View view, ViewGroup.LayoutParams params)134     public void updateViewLayout(@NonNull View view, ViewGroup.LayoutParams params) {
135         SurfaceControlViewHost root = mViewRoots.get(view);
136         if (root == null || !(params instanceof WindowManager.LayoutParams)) {
137             return;
138         }
139         view.setLayoutParams(params);
140         root.relayout((WindowManager.LayoutParams) params);
141     }
142 
143     /**
144      * Sets the touchable region of a view's window. This will be cropped to the window size.
145      * @param view
146      * @param region
147      */
setTouchableRegion(@onNull View view, Region region)148     public void setTouchableRegion(@NonNull View view, Region region) {
149         SurfaceControlViewHost root = mViewRoots.get(view);
150         if (root == null) {
151             return;
152         }
153         WindowlessWindowManager wwm = root.getWindowlessWM();
154         if (!(wwm instanceof SysUiWindowManager)) {
155             return;
156         }
157         ((SysUiWindowManager) wwm).setTouchableRegionForWindow(view, region);
158     }
159 
160     /**
161      * Adds a root for system-ui window management with no views. Only useful for IME.
162      */
addRoot(int displayId, int windowType)163     public void addRoot(int displayId, int windowType) {
164         PerDisplay pd = mPerDisplay.get(displayId);
165         if (pd == null) {
166             pd = new PerDisplay(displayId);
167             mPerDisplay.put(displayId, pd);
168         }
169         pd.addRoot(windowType);
170     }
171 
172     /**
173      * Get the IWindow token for a specific root.
174      *
175      * @param windowType A window type from {@link android.view.WindowManager}.
176      */
getWindow(int displayId, int windowType)177     IWindow getWindow(int displayId, int windowType) {
178         PerDisplay pd = mPerDisplay.get(displayId);
179         if (pd == null) {
180             return null;
181         }
182         return pd.getWindow(windowType);
183     }
184 
185     /**
186      * Gets the SurfaceControl associated with a root view. This is the same surface that backs the
187      * ViewRootImpl.
188      */
getViewSurface(View rootView)189     public SurfaceControl getViewSurface(View rootView) {
190         for (int i = 0; i < mPerDisplay.size(); ++i) {
191             for (int iWm = 0; iWm < mPerDisplay.valueAt(i).mWwms.size(); ++iWm) {
192                 SurfaceControl out = mPerDisplay.valueAt(i).mWwms.valueAt(iWm)
193                         .getSurfaceControlForWindow(rootView);
194                 if (out != null) {
195                     return out;
196                 }
197             }
198         }
199         return null;
200     }
201 
202     private class PerDisplay {
203         final int mDisplayId;
204         private final SparseArray<SysUiWindowManager> mWwms = new SparseArray<>();
205 
PerDisplay(int displayId)206         PerDisplay(int displayId) {
207             mDisplayId = displayId;
208         }
209 
addView(View view, WindowManager.LayoutParams attrs, int windowType)210         public void addView(View view, WindowManager.LayoutParams attrs, int windowType) {
211             SysUiWindowManager wwm = addRoot(windowType);
212             if (wwm == null) {
213                 Slog.e(TAG, "Unable to create systemui root");
214                 return;
215             }
216             final Display display = mDisplayController.getDisplay(mDisplayId);
217             SurfaceControlViewHost viewRoot =
218                     new SurfaceControlViewHost(mContext, display, wwm,
219                             true /* useSfChoreographer */);
220             attrs.flags |= FLAG_HARDWARE_ACCELERATED;
221             viewRoot.setView(view, attrs);
222             mViewRoots.put(view, viewRoot);
223 
224             try {
225                 mWmService.setShellRootAccessibilityWindow(mDisplayId, windowType,
226                         viewRoot.getWindowToken());
227             } catch (RemoteException e) {
228                 Slog.e(TAG, "Error setting accessibility window for " + mDisplayId + ":"
229                         + windowType, e);
230             }
231         }
232 
addRoot(int windowType)233         SysUiWindowManager addRoot(int windowType) {
234             SysUiWindowManager wwm = mWwms.get(windowType);
235             if (wwm != null) {
236                 return wwm;
237             }
238             SurfaceControl rootSurface = null;
239             ContainerWindow win = new ContainerWindow();
240             try {
241                 rootSurface = mWmService.addShellRoot(mDisplayId, win, windowType);
242             } catch (RemoteException e) {
243             }
244             if (rootSurface == null) {
245                 Slog.e(TAG, "Unable to get root surfacecontrol for systemui");
246                 return null;
247             }
248             Context displayContext = mDisplayController.getDisplayContext(mDisplayId);
249             wwm = new SysUiWindowManager(mDisplayId, displayContext, rootSurface, win);
250             mWwms.put(windowType, wwm);
251             return wwm;
252         }
253 
getWindow(int windowType)254         IWindow getWindow(int windowType) {
255             SysUiWindowManager wwm = mWwms.get(windowType);
256             if (wwm == null) {
257                 return null;
258             }
259             return wwm.mContainerWindow;
260         }
261 
updateConfiguration(Configuration configuration)262         void updateConfiguration(Configuration configuration) {
263             for (int i = 0; i < mWwms.size(); ++i) {
264                 mWwms.valueAt(i).updateConfiguration(configuration);
265             }
266         }
267     }
268 
269     /**
270      * A subclass of WindowlessWindowManager that provides insets to its viewroots.
271      */
272     public class SysUiWindowManager extends WindowlessWindowManager {
273         final int mDisplayId;
274         ContainerWindow mContainerWindow;
SysUiWindowManager(int displayId, Context ctx, SurfaceControl rootSurface, ContainerWindow container)275         public SysUiWindowManager(int displayId, Context ctx, SurfaceControl rootSurface,
276                 ContainerWindow container) {
277             super(ctx.getResources().getConfiguration(), rootSurface, null /* hostInputToken */);
278             mContainerWindow = container;
279             mDisplayId = displayId;
280         }
281 
282         @Override
relayout(IWindow window, int seq, WindowManager.LayoutParams attrs, int requestedWidth, int requestedHeight, int viewVisibility, int flags, long frameNumber, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets, Rect outVisibleInsets, Rect outStableInsets, DisplayCutout.ParcelableWrapper cutout, MergedConfiguration mergedConfiguration, SurfaceControl outSurfaceControl, InsetsState outInsetsState, InsetsSourceControl[] outActiveControls, Point outSurfaceSize, SurfaceControl outBLASTSurfaceControl)283         public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,
284                 int requestedWidth, int requestedHeight, int viewVisibility, int flags,
285                 long frameNumber, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
286                 Rect outVisibleInsets, Rect outStableInsets,
287                 DisplayCutout.ParcelableWrapper cutout, MergedConfiguration mergedConfiguration,
288                 SurfaceControl outSurfaceControl, InsetsState outInsetsState,
289                 InsetsSourceControl[] outActiveControls, Point outSurfaceSize,
290                 SurfaceControl outBLASTSurfaceControl) {
291             int res = super.relayout(window, seq, attrs, requestedWidth, requestedHeight,
292                     viewVisibility, flags, frameNumber, outFrame, outOverscanInsets,
293                     outContentInsets, outVisibleInsets, outStableInsets,
294                     cutout, mergedConfiguration, outSurfaceControl, outInsetsState,
295                     outActiveControls, outSurfaceSize, outBLASTSurfaceControl);
296             if (res != 0) {
297                 return res;
298             }
299             DisplayLayout dl = mDisplayController.getDisplayLayout(mDisplayId);
300             outStableInsets.set(dl.stableInsets());
301             return 0;
302         }
303 
updateConfiguration(Configuration configuration)304         void updateConfiguration(Configuration configuration) {
305             setConfiguration(configuration);
306         }
307 
getSurfaceControlForWindow(View rootView)308         SurfaceControl getSurfaceControlForWindow(View rootView) {
309             return getSurfaceControl(rootView);
310         }
311 
setTouchableRegionForWindow(View rootView, Region region)312         void setTouchableRegionForWindow(View rootView, Region region) {
313             IBinder token = rootView.getWindowToken();
314             if (token == null) {
315                 return;
316             }
317             setTouchRegion(token, region);
318         }
319     }
320 
321     class ContainerWindow extends IWindow.Stub {
ContainerWindow()322         ContainerWindow() {}
323 
324         @Override
resized(Rect frame, Rect contentInsets, Rect visibleInsets, Rect stableInsets, boolean reportDraw, MergedConfiguration newMergedConfiguration, Rect backDropFrame, boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId, DisplayCutout.ParcelableWrapper displayCutout)325         public void resized(Rect frame, Rect contentInsets, Rect visibleInsets, Rect stableInsets,
326                 boolean reportDraw, MergedConfiguration newMergedConfiguration, Rect backDropFrame,
327                 boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId,
328                 DisplayCutout.ParcelableWrapper displayCutout) {}
329 
330         @Override
locationInParentDisplayChanged(Point offset)331         public void locationInParentDisplayChanged(Point offset) {}
332 
333         @Override
insetsChanged(InsetsState insetsState)334         public void insetsChanged(InsetsState insetsState) {}
335 
336         @Override
insetsControlChanged(InsetsState insetsState, InsetsSourceControl[] activeControls)337         public void insetsControlChanged(InsetsState insetsState,
338                 InsetsSourceControl[] activeControls) {}
339 
340         @Override
showInsets(int types, boolean fromIme)341         public void showInsets(int types, boolean fromIme) {}
342 
343         @Override
hideInsets(int types, boolean fromIme)344         public void hideInsets(int types, boolean fromIme) {}
345 
346         @Override
moved(int newX, int newY)347         public void moved(int newX, int newY) {}
348 
349         @Override
dispatchAppVisibility(boolean visible)350         public void dispatchAppVisibility(boolean visible) {}
351 
352         @Override
dispatchGetNewSurface()353         public void dispatchGetNewSurface() {}
354 
355         @Override
windowFocusChanged(boolean hasFocus, boolean inTouchMode)356         public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {}
357 
358         @Override
executeCommand(String command, String parameters, ParcelFileDescriptor out)359         public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {}
360 
361         @Override
closeSystemDialogs(String reason)362         public void closeSystemDialogs(String reason) {}
363 
364         @Override
dispatchWallpaperOffsets(float x, float y, float xStep, float yStep, float zoom, boolean sync)365         public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
366                 float zoom, boolean sync) {}
367 
368         @Override
dispatchWallpaperCommand(String action, int x, int y, int z, Bundle extras, boolean sync)369         public void dispatchWallpaperCommand(String action, int x, int y,
370                 int z, Bundle extras, boolean sync) {}
371 
372         /* Drag/drop */
373         @Override
dispatchDragEvent(DragEvent event)374         public void dispatchDragEvent(DragEvent event) {}
375 
376         @Override
updatePointerIcon(float x, float y)377         public void updatePointerIcon(float x, float y) {}
378 
379         @Override
dispatchSystemUiVisibilityChanged(int seq, int globalVisibility, int localValue, int localChanges)380         public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
381                 int localValue, int localChanges) {}
382 
383         @Override
dispatchWindowShown()384         public void dispatchWindowShown() {}
385 
386         @Override
requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId)387         public void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId) {}
388 
389         @Override
dispatchPointerCaptureChanged(boolean hasCapture)390         public void dispatchPointerCaptureChanged(boolean hasCapture) {}
391 
392         @Override
requestScrollCapture(IScrollCaptureController controller)393         public void requestScrollCapture(IScrollCaptureController controller) {
394             try {
395                 controller.onClientUnavailable();
396             } catch (RemoteException ex) {
397                 // ignore
398             }
399         }
400     }
401 }
402