blob: 93f45c51f0ebcf517f449dba0f33051138d85cf1 [file] [log] [blame]
Evan Rosky22b6bbd2019-09-26 14:29:57 -07001/*
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
17package com.android.systemui.wm;
18
19import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
20
21import android.annotation.NonNull;
22import android.content.Context;
23import android.content.res.Configuration;
24import android.graphics.Point;
25import android.graphics.Rect;
Evan Rosky12837282020-04-27 19:12:25 -070026import android.graphics.Region;
Evan Rosky22b6bbd2019-09-26 14:29:57 -070027import android.os.Bundle;
Evan Rosky12837282020-04-27 19:12:25 -070028import android.os.IBinder;
Evan Rosky22b6bbd2019-09-26 14:29:57 -070029import android.os.ParcelFileDescriptor;
30import android.os.RemoteException;
31import android.util.MergedConfiguration;
32import android.util.Slog;
33import android.util.SparseArray;
34import android.view.Display;
35import android.view.DisplayCutout;
36import android.view.DragEvent;
Mark Renoufa9279292020-04-17 12:22:50 -040037import android.view.IScrollCaptureController;
Evan Rosky22b6bbd2019-09-26 14:29:57 -070038import android.view.IWindow;
39import android.view.IWindowManager;
40import android.view.IWindowSession;
41import android.view.IWindowSessionCallback;
42import android.view.InsetsSourceControl;
43import android.view.InsetsState;
44import android.view.SurfaceControl;
Valerie Hau30360552020-01-14 16:12:01 -080045import android.view.SurfaceControlViewHost;
Evan Rosky22b6bbd2019-09-26 14:29:57 -070046import android.view.View;
47import android.view.ViewGroup;
48import android.view.WindowManager;
Evan Rosky22b6bbd2019-09-26 14:29:57 -070049import android.view.WindowlessWindowManager;
50
51import com.android.internal.os.IResultReceiver;
52
53import java.util.HashMap;
54
55import javax.inject.Inject;
56import 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
63public class SystemWindows {
64 private static final String TAG = "SystemWindows";
65
66 private final SparseArray<PerDisplay> mPerDisplay = new SparseArray<>();
Robert Carr59b18882019-12-18 00:38:40 -080067 final HashMap<View, SurfaceControlViewHost> mViewRoots = new HashMap<>();
Evan Rosky22b6bbd2019-09-26 14:29:57 -070068 Context mContext;
69 IWindowSession mSession;
Winson Chung95c9fca2020-01-22 09:48:40 -080070 DisplayController mDisplayController;
Evan Rosky22b6bbd2019-09-26 14:29:57 -070071 IWindowManager mWmService;
72
Winson Chung95c9fca2020-01-22 09:48:40 -080073 private final DisplayController.OnDisplaysChangedListener mDisplayListener =
74 new DisplayController.OnDisplaysChangedListener() {
Evan Rosky22b6bbd2019-09-26 14:29:57 -070075 @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
Winson Chung95c9fca2020-01-22 09:48:40 -080092 public SystemWindows(Context context, DisplayController displayController,
Evan Rosky22b6bbd2019-09-26 14:29:57 -070093 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 */
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 */
126 public void removeView(View view) {
Robert Carr59b18882019-12-18 00:38:40 -0800127 SurfaceControlViewHost root = mViewRoots.remove(view);
Evan Rosky22b6bbd2019-09-26 14:29:57 -0700128 root.die();
129 }
130
131 /**
132 * Updates the layout params of a view.
133 */
134 public void updateViewLayout(@NonNull View view, ViewGroup.LayoutParams params) {
Robert Carr59b18882019-12-18 00:38:40 -0800135 SurfaceControlViewHost root = mViewRoots.get(view);
Evan Rosky22b6bbd2019-09-26 14:29:57 -0700136 if (root == null || !(params instanceof WindowManager.LayoutParams)) {
137 return;
138 }
139 view.setLayoutParams(params);
140 root.relayout((WindowManager.LayoutParams) params);
141 }
142
143 /**
Evan Rosky12837282020-04-27 19:12:25 -0700144 * Sets the touchable region of a view's window. This will be cropped to the window size.
145 * @param view
146 * @param region
147 */
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 /**
Evan Rosky22b6bbd2019-09-26 14:29:57 -0700161 * Adds a root for system-ui window management with no views. Only useful for IME.
162 */
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 */
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
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000185 /**
186 * Gets the SurfaceControl associated with a root view. This is the same surface that backs the
187 * ViewRootImpl.
188 */
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) {
Tony Huang0f8981d2020-04-20 17:38:37 +0800192 SurfaceControl out = mPerDisplay.valueAt(i).mWwms.valueAt(iWm)
193 .getSurfaceControlForWindow(rootView);
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000194 if (out != null) {
195 return out;
196 }
197 }
198 }
199 return null;
200 }
201
Evan Rosky22b6bbd2019-09-26 14:29:57 -0700202 private class PerDisplay {
203 final int mDisplayId;
204 private final SparseArray<SysUiWindowManager> mWwms = new SparseArray<>();
205
206 PerDisplay(int displayId) {
207 mDisplayId = displayId;
208 }
209
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);
Tony Huang89d580c2020-03-26 14:10:26 +0800217 SurfaceControlViewHost viewRoot =
218 new SurfaceControlViewHost(mContext, display, wwm,
219 true /* useSfChoreographer */);
Evan Rosky22b6bbd2019-09-26 14:29:57 -0700220 attrs.flags |= FLAG_HARDWARE_ACCELERATED;
Robert Carr271d9c72020-03-12 12:39:24 -0700221 viewRoot.setView(view, attrs);
Evan Rosky22b6bbd2019-09-26 14:29:57 -0700222 mViewRoots.put(view, viewRoot);
Evan Roskycff7ebb2020-04-22 16:54:49 -0700223
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 }
Evan Rosky22b6bbd2019-09-26 14:29:57 -0700231 }
232
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
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
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;
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
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,
Valerie Hau30360552020-01-14 16:12:01 -0800288 SurfaceControl outSurfaceControl, InsetsState outInsetsState,
Tiger Huang0426a332020-03-29 01:17:08 +0800289 InsetsSourceControl[] outActiveControls, Point outSurfaceSize,
290 SurfaceControl outBLASTSurfaceControl) {
Evan Rosky22b6bbd2019-09-26 14:29:57 -0700291 int res = super.relayout(window, seq, attrs, requestedWidth, requestedHeight,
292 viewVisibility, flags, frameNumber, outFrame, outOverscanInsets,
293 outContentInsets, outVisibleInsets, outStableInsets,
Valerie Hau30360552020-01-14 16:12:01 -0800294 cutout, mergedConfiguration, outSurfaceControl, outInsetsState,
Tiger Huang0426a332020-03-29 01:17:08 +0800295 outActiveControls, outSurfaceSize, outBLASTSurfaceControl);
Evan Rosky22b6bbd2019-09-26 14:29:57 -0700296 if (res != 0) {
297 return res;
298 }
299 DisplayLayout dl = mDisplayController.getDisplayLayout(mDisplayId);
300 outStableInsets.set(dl.stableInsets());
301 return 0;
302 }
303
304 void updateConfiguration(Configuration configuration) {
305 setConfiguration(configuration);
306 }
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000307
308 SurfaceControl getSurfaceControlForWindow(View rootView) {
309 return getSurfaceControl(rootView);
310 }
Evan Rosky12837282020-04-27 19:12:25 -0700311
312 void setTouchableRegionForWindow(View rootView, Region region) {
313 IBinder token = rootView.getWindowToken();
314 if (token == null) {
315 return;
316 }
317 setTouchRegion(token, region);
318 }
Evan Rosky22b6bbd2019-09-26 14:29:57 -0700319 }
320
321 class ContainerWindow extends IWindow.Stub {
322 ContainerWindow() {}
323
324 @Override
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
331 public void locationInParentDisplayChanged(Point offset) {}
332
333 @Override
334 public void insetsChanged(InsetsState insetsState) {}
335
336 @Override
337 public void insetsControlChanged(InsetsState insetsState,
338 InsetsSourceControl[] activeControls) {}
339
340 @Override
341 public void showInsets(int types, boolean fromIme) {}
342
343 @Override
344 public void hideInsets(int types, boolean fromIme) {}
345
346 @Override
347 public void moved(int newX, int newY) {}
348
349 @Override
350 public void dispatchAppVisibility(boolean visible) {}
351
352 @Override
353 public void dispatchGetNewSurface() {}
354
355 @Override
356 public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {}
357
358 @Override
359 public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {}
360
361 @Override
362 public void closeSystemDialogs(String reason) {}
363
364 @Override
365 public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
Lucas Dupin13f4b8a2020-02-19 13:41:52 -0800366 float zoom, boolean sync) {}
Evan Rosky22b6bbd2019-09-26 14:29:57 -0700367
368 @Override
369 public void dispatchWallpaperCommand(String action, int x, int y,
370 int z, Bundle extras, boolean sync) {}
371
372 /* Drag/drop */
373 @Override
374 public void dispatchDragEvent(DragEvent event) {}
375
376 @Override
377 public void updatePointerIcon(float x, float y) {}
378
379 @Override
380 public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
381 int localValue, int localChanges) {}
382
383 @Override
384 public void dispatchWindowShown() {}
385
386 @Override
387 public void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId) {}
388
389 @Override
390 public void dispatchPointerCaptureChanged(boolean hasCapture) {}
Mark Renoufa9279292020-04-17 12:22:50 -0400391
392 @Override
393 public void requestScrollCapture(IScrollCaptureController controller) {
394 try {
395 controller.onClientUnavailable();
396 } catch (RemoteException ex) {
397 // ignore
398 }
399 }
Evan Rosky22b6bbd2019-09-26 14:29:57 -0700400 }
401}