blob: b4779f4d91d62d08a211724f7bbdb88d3dfc51fc [file] [log] [blame]
Jeff Brown98365d72012-08-19 20:30:52 -07001/*
2 * Copyright (C) 2012 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 android.view;
18
19import android.animation.ValueAnimator;
20import android.app.ActivityManager;
21import android.content.ComponentCallbacks2;
22import android.content.res.Configuration;
23import android.opengl.ManagedEGLContext;
24import android.os.IBinder;
Jeff Brown98365d72012-08-19 20:30:52 -070025import android.os.RemoteException;
26import android.os.ServiceManager;
27import android.os.SystemProperties;
28import android.util.AndroidRuntimeException;
Craig Mautner8f303ad2013-06-14 11:32:22 -070029import android.util.ArraySet;
Jeff Brown98365d72012-08-19 20:30:52 -070030import android.util.Log;
31import android.view.inputmethod.InputMethodManager;
Dianne Hackborn8c841092013-06-24 13:46:13 -070032import com.android.internal.util.FastPrintWriter;
Jeff Brown98365d72012-08-19 20:30:52 -070033
34import java.io.FileDescriptor;
35import java.io.FileOutputStream;
36import java.io.PrintWriter;
Craig Mautner652fdfa2013-06-06 07:51:57 -070037import java.util.ArrayList;
Jeff Brown98365d72012-08-19 20:30:52 -070038
39/**
40 * Provides low-level communication with the system window manager for
41 * operations that are not associated with any particular context.
42 *
43 * This class is only used internally to implement global functions where
44 * the caller already knows the display and relevant compatibility information
45 * for the operation. For most purposes, you should use {@link WindowManager} instead
46 * since it is bound to a context.
47 *
48 * @see WindowManagerImpl
49 * @hide
50 */
51public final class WindowManagerGlobal {
52 private static final String TAG = "WindowManager";
53
54 /**
55 * The user is navigating with keys (not the touch screen), so
56 * navigational focus should be shown.
57 */
58 public static final int RELAYOUT_RES_IN_TOUCH_MODE = 0x1;
59
60 /**
61 * This is the first time the window is being drawn,
62 * so the client must call drawingFinished() when done
63 */
64 public static final int RELAYOUT_RES_FIRST_TIME = 0x2;
65
66 /**
67 * The window manager has changed the surface from the last call.
68 */
69 public static final int RELAYOUT_RES_SURFACE_CHANGED = 0x4;
70
71 /**
72 * The window manager is currently animating. It will call
73 * IWindow.doneAnimating() when done.
74 */
75 public static final int RELAYOUT_RES_ANIMATING = 0x8;
76
77 /**
78 * Flag for relayout: the client will be later giving
79 * internal insets; as a result, the window will not impact other window
80 * layouts until the insets are given.
81 */
82 public static final int RELAYOUT_INSETS_PENDING = 0x1;
83
84 /**
85 * Flag for relayout: the client may be currently using the current surface,
86 * so if it is to be destroyed as a part of the relayout the destroy must
87 * be deferred until later. The client will call performDeferredDestroy()
88 * when it is okay.
89 */
90 public static final int RELAYOUT_DEFER_SURFACE_DESTROY = 0x2;
91
92 public static final int ADD_FLAG_APP_VISIBLE = 0x2;
93 public static final int ADD_FLAG_IN_TOUCH_MODE = RELAYOUT_RES_IN_TOUCH_MODE;
94
95 public static final int ADD_OKAY = 0;
96 public static final int ADD_BAD_APP_TOKEN = -1;
97 public static final int ADD_BAD_SUBWINDOW_TOKEN = -2;
98 public static final int ADD_NOT_APP_TOKEN = -3;
99 public static final int ADD_APP_EXITING = -4;
100 public static final int ADD_DUPLICATE_ADD = -5;
101 public static final int ADD_STARTING_NOT_NEEDED = -6;
102 public static final int ADD_MULTIPLE_SINGLETON = -7;
103 public static final int ADD_PERMISSION_DENIED = -8;
Craig Mautner2d5618c2012-10-18 13:55:47 -0700104 public static final int ADD_INVALID_DISPLAY = -9;
Jeff Brown98365d72012-08-19 20:30:52 -0700105
106 private static WindowManagerGlobal sDefaultWindowManager;
107 private static IWindowManager sWindowManagerService;
108 private static IWindowSession sWindowSession;
109
110 private final Object mLock = new Object();
111
Craig Mautner652fdfa2013-06-06 07:51:57 -0700112 private final ArrayList<View> mViews = new ArrayList<View>();
113 private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
114 private final ArrayList<WindowManager.LayoutParams> mParams =
115 new ArrayList<WindowManager.LayoutParams>();
Craig Mautner8f303ad2013-06-14 11:32:22 -0700116 private final ArraySet<View> mDyingViews = new ArraySet<View>();
Jeff Brown98365d72012-08-19 20:30:52 -0700117 private boolean mNeedsEglTerminate;
118
119 private Runnable mSystemPropertyUpdater;
120
121 private WindowManagerGlobal() {
122 }
123
124 public static WindowManagerGlobal getInstance() {
125 synchronized (WindowManagerGlobal.class) {
126 if (sDefaultWindowManager == null) {
127 sDefaultWindowManager = new WindowManagerGlobal();
128 }
129 return sDefaultWindowManager;
130 }
131 }
132
133 public static IWindowManager getWindowManagerService() {
134 synchronized (WindowManagerGlobal.class) {
135 if (sWindowManagerService == null) {
136 sWindowManagerService = IWindowManager.Stub.asInterface(
137 ServiceManager.getService("window"));
138 }
139 return sWindowManagerService;
140 }
141 }
142
Jeff Brownf9e989d2013-04-04 23:04:03 -0700143 public static IWindowSession getWindowSession() {
Jeff Brown98365d72012-08-19 20:30:52 -0700144 synchronized (WindowManagerGlobal.class) {
145 if (sWindowSession == null) {
146 try {
Jeff Brownf9e989d2013-04-04 23:04:03 -0700147 InputMethodManager imm = InputMethodManager.getInstance();
Jeff Brown98365d72012-08-19 20:30:52 -0700148 IWindowManager windowManager = getWindowManagerService();
149 sWindowSession = windowManager.openSession(
150 imm.getClient(), imm.getInputContext());
151 float animatorScale = windowManager.getAnimationScale(2);
152 ValueAnimator.setDurationScale(animatorScale);
153 } catch (RemoteException e) {
154 Log.e(TAG, "Failed to open window session", e);
155 }
156 }
157 return sWindowSession;
158 }
159 }
160
161 public static IWindowSession peekWindowSession() {
162 synchronized (WindowManagerGlobal.class) {
163 return sWindowSession;
164 }
165 }
166
Siva Velusamy945bfb62013-01-06 16:03:12 -0800167 public String[] getViewRootNames() {
168 synchronized (mLock) {
Craig Mautner652fdfa2013-06-06 07:51:57 -0700169 final int numRoots = mRoots.size();
170 String[] mViewRoots = new String[numRoots];
171 for (int i = 0; i < numRoots; ++i) {
172 mViewRoots[i] = getWindowName(mRoots.get(i));
Siva Velusamy945bfb62013-01-06 16:03:12 -0800173 }
174 return mViewRoots;
175 }
176 }
177
178 public View getRootView(String name) {
179 synchronized (mLock) {
Craig Mautner652fdfa2013-06-06 07:51:57 -0700180 for (int i = mRoots.size() - 1; i >= 0; --i) {
181 final ViewRootImpl root = mRoots.get(i);
Siva Velusamy945bfb62013-01-06 16:03:12 -0800182 if (name.equals(getWindowName(root))) return root.getView();
183 }
184 }
185
186 return null;
187 }
188
Jeff Brown98365d72012-08-19 20:30:52 -0700189 public void addView(View view, ViewGroup.LayoutParams params,
190 Display display, Window parentWindow) {
191 if (view == null) {
192 throw new IllegalArgumentException("view must not be null");
193 }
194 if (display == null) {
195 throw new IllegalArgumentException("display must not be null");
196 }
197 if (!(params instanceof WindowManager.LayoutParams)) {
198 throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
199 }
200
201 final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
202 if (parentWindow != null) {
203 parentWindow.adjustLayoutParamsForSubWindow(wparams);
204 }
205
206 ViewRootImpl root;
207 View panelParentView = null;
208
209 synchronized (mLock) {
210 // Start watching for system property changes.
211 if (mSystemPropertyUpdater == null) {
212 mSystemPropertyUpdater = new Runnable() {
213 @Override public void run() {
214 synchronized (mLock) {
Craig Mautner652fdfa2013-06-06 07:51:57 -0700215 for (int i = mRoots.size() - 1; i >= 0; --i) {
216 mRoots.get(i).loadSystemProperties();
Jeff Brown98365d72012-08-19 20:30:52 -0700217 }
218 }
219 }
220 };
221 SystemProperties.addChangeCallback(mSystemPropertyUpdater);
222 }
223
224 int index = findViewLocked(view, false);
225 if (index >= 0) {
Craig Mautner8f303ad2013-06-14 11:32:22 -0700226 if (mDyingViews.contains(view)) {
227 // Don't wait for MSG_DIE to make it's way through root's queue.
228 mRoots.get(index).doDie();
229 } else {
230 throw new IllegalStateException("View " + view
231 + " has already been added to the window manager.");
232 }
233 // The previous removeView() had not completed executing. Now it has.
Jeff Brown98365d72012-08-19 20:30:52 -0700234 }
235
236 // If this is a panel window, then find the window it is being
237 // attached to for future reference.
238 if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
239 wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
Craig Mautner652fdfa2013-06-06 07:51:57 -0700240 final int count = mViews.size();
241 for (int i = 0; i < count; i++) {
242 if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
243 panelParentView = mViews.get(i);
Jeff Brown98365d72012-08-19 20:30:52 -0700244 }
245 }
246 }
247
248 root = new ViewRootImpl(view.getContext(), display);
249
250 view.setLayoutParams(wparams);
251
Craig Mautner652fdfa2013-06-06 07:51:57 -0700252 mViews.add(view);
253 mRoots.add(root);
254 mParams.add(wparams);
Jeff Brown98365d72012-08-19 20:30:52 -0700255 }
256
257 // do this last because it fires off messages to start doing things
Craig Mautner6018aee2012-10-23 14:27:49 -0700258 try {
259 root.setView(view, wparams, panelParentView);
260 } catch (RuntimeException e) {
261 // BadTokenException or InvalidDisplayException, clean up.
262 synchronized (mLock) {
263 final int index = findViewLocked(view, false);
264 if (index >= 0) {
265 removeViewLocked(index, true);
266 }
267 }
268 throw e;
269 }
Jeff Brown98365d72012-08-19 20:30:52 -0700270 }
271
272 public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
273 if (view == null) {
274 throw new IllegalArgumentException("view must not be null");
275 }
276 if (!(params instanceof WindowManager.LayoutParams)) {
277 throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
278 }
279
280 final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
281
282 view.setLayoutParams(wparams);
283
284 synchronized (mLock) {
285 int index = findViewLocked(view, true);
Craig Mautner652fdfa2013-06-06 07:51:57 -0700286 ViewRootImpl root = mRoots.get(index);
287 mParams.remove(index);
288 mParams.add(index, wparams);
Jeff Brown98365d72012-08-19 20:30:52 -0700289 root.setLayoutParams(wparams, false);
290 }
291 }
292
293 public void removeView(View view, boolean immediate) {
294 if (view == null) {
295 throw new IllegalArgumentException("view must not be null");
296 }
297
298 synchronized (mLock) {
299 int index = findViewLocked(view, true);
Craig Mautner652fdfa2013-06-06 07:51:57 -0700300 View curView = mRoots.get(index).getView();
Craig Mautner05eb7302013-06-03 17:24:21 -0700301 removeViewLocked(index, immediate);
Jeff Brown98365d72012-08-19 20:30:52 -0700302 if (curView == view) {
303 return;
304 }
305
306 throw new IllegalStateException("Calling with view " + view
307 + " but the ViewAncestor is attached to " + curView);
308 }
309 }
310
311 public void closeAll(IBinder token, String who, String what) {
312 synchronized (mLock) {
Craig Mautner652fdfa2013-06-06 07:51:57 -0700313 int count = mViews.size();
Jeff Brown98365d72012-08-19 20:30:52 -0700314 //Log.i("foo", "Closing all windows of " + token);
Craig Mautner05eb7302013-06-03 17:24:21 -0700315 for (int i = 0; i < count; i++) {
Jeff Brown98365d72012-08-19 20:30:52 -0700316 //Log.i("foo", "@ " + i + " token " + mParams[i].token
317 // + " view " + mRoots[i].getView());
Craig Mautner652fdfa2013-06-06 07:51:57 -0700318 if (token == null || mParams.get(i).token == token) {
319 ViewRootImpl root = mRoots.get(i);
Jeff Brown98365d72012-08-19 20:30:52 -0700320
321 //Log.i("foo", "Force closing " + root);
322 if (who != null) {
323 WindowLeaked leak = new WindowLeaked(
324 what + " " + who + " has leaked window "
325 + root.getView() + " that was originally added here");
326 leak.setStackTrace(root.getLocation().getStackTrace());
Craig Mautner05eb7302013-06-03 17:24:21 -0700327 Log.e(TAG, "", leak);
Jeff Brown98365d72012-08-19 20:30:52 -0700328 }
329
330 removeViewLocked(i, false);
Jeff Brown98365d72012-08-19 20:30:52 -0700331 }
332 }
333 }
334 }
335
Craig Mautner05eb7302013-06-03 17:24:21 -0700336 private void removeViewLocked(int index, boolean immediate) {
Craig Mautner652fdfa2013-06-06 07:51:57 -0700337 ViewRootImpl root = mRoots.get(index);
Jeff Brown98365d72012-08-19 20:30:52 -0700338 View view = root.getView();
339
340 if (view != null) {
Jeff Brownf9e989d2013-04-04 23:04:03 -0700341 InputMethodManager imm = InputMethodManager.getInstance();
Jeff Brown98365d72012-08-19 20:30:52 -0700342 if (imm != null) {
Craig Mautner652fdfa2013-06-06 07:51:57 -0700343 imm.windowDismissed(mViews.get(index).getWindowToken());
Jeff Brown98365d72012-08-19 20:30:52 -0700344 }
345 }
Craig Mautner8f303ad2013-06-14 11:32:22 -0700346 boolean deferred = root.die(immediate);
Craig Mautner92098c72013-06-10 11:27:26 -0700347 if (view != null) {
348 view.assignParent(null);
Craig Mautner8f303ad2013-06-14 11:32:22 -0700349 if (deferred) {
350 mDyingViews.add(view);
351 }
Craig Mautner92098c72013-06-10 11:27:26 -0700352 }
Craig Mautner05eb7302013-06-03 17:24:21 -0700353 }
Jeff Brown98365d72012-08-19 20:30:52 -0700354
Craig Mautner05eb7302013-06-03 17:24:21 -0700355 void doRemoveView(ViewRootImpl root) {
356 synchronized (mLock) {
Craig Mautner652fdfa2013-06-06 07:51:57 -0700357 final int index = mRoots.indexOf(root);
358 if (index >= 0) {
359 mRoots.remove(index);
Craig Mautner652fdfa2013-06-06 07:51:57 -0700360 mParams.remove(index);
Craig Mautner8f303ad2013-06-14 11:32:22 -0700361 final View view = mViews.remove(index);
362 mDyingViews.remove(view);
Jeff Brown98365d72012-08-19 20:30:52 -0700363 }
364 }
365 }
366
367 private int findViewLocked(View view, boolean required) {
Craig Mautner652fdfa2013-06-06 07:51:57 -0700368 final int index = mViews.indexOf(view);
369 if (required && index < 0) {
Craig Mautner05eb7302013-06-03 17:24:21 -0700370 throw new IllegalArgumentException("View=" + view + " not attached to window manager");
Craig Mautner6018aee2012-10-23 14:27:49 -0700371 }
Craig Mautner652fdfa2013-06-06 07:51:57 -0700372 return index;
Jeff Brown98365d72012-08-19 20:30:52 -0700373 }
374
375 public void startTrimMemory(int level) {
376 if (HardwareRenderer.isAvailable()) {
377 // On low-end gfx devices we trim when memory is moderate;
378 // on high-end devices we do this when low.
379 if (level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE
380 || (level >= ComponentCallbacks2.TRIM_MEMORY_MODERATE
381 && !ActivityManager.isHighEndGfx())) {
382 // Destroy all hardware surfaces and resources associated to
383 // known windows
384 synchronized (mLock) {
Craig Mautner652fdfa2013-06-06 07:51:57 -0700385 for (int i = mRoots.size() - 1; i >= 0; --i) {
Romain Guy46bfc482013-08-16 18:38:29 -0700386 mRoots.get(i).destroyHardwareResources();
Jeff Brown98365d72012-08-19 20:30:52 -0700387 }
388 }
389 // Force a full memory flush
390 mNeedsEglTerminate = true;
391 HardwareRenderer.startTrimMemory(ComponentCallbacks2.TRIM_MEMORY_COMPLETE);
392 return;
393 }
394
395 HardwareRenderer.startTrimMemory(level);
396 }
397 }
398
399 public void endTrimMemory() {
400 HardwareRenderer.endTrimMemory();
401
402 if (mNeedsEglTerminate) {
403 ManagedEGLContext.doTerminate();
404 mNeedsEglTerminate = false;
405 }
406 }
407
408 public void trimLocalMemory() {
409 synchronized (mLock) {
Craig Mautner652fdfa2013-06-06 07:51:57 -0700410 for (int i = mRoots.size() - 1; i >= 0; --i) {
411 mRoots.get(i).destroyHardwareLayers();
Jeff Brown98365d72012-08-19 20:30:52 -0700412 }
413 }
414 }
415
416 public void dumpGfxInfo(FileDescriptor fd) {
417 FileOutputStream fout = new FileOutputStream(fd);
Dianne Hackborn8c841092013-06-24 13:46:13 -0700418 PrintWriter pw = new FastPrintWriter(fout);
Jeff Brown98365d72012-08-19 20:30:52 -0700419 try {
420 synchronized (mLock) {
Craig Mautner652fdfa2013-06-06 07:51:57 -0700421 final int count = mViews.size();
Jeff Brown98365d72012-08-19 20:30:52 -0700422
Craig Mautner652fdfa2013-06-06 07:51:57 -0700423 pw.println("Profile data in ms:");
Jeff Brown98365d72012-08-19 20:30:52 -0700424
Craig Mautner652fdfa2013-06-06 07:51:57 -0700425 for (int i = 0; i < count; i++) {
426 ViewRootImpl root = mRoots.get(i);
427 String name = getWindowName(root);
428 pw.printf("\n\t%s", name);
Jeff Brown98365d72012-08-19 20:30:52 -0700429
Craig Mautner652fdfa2013-06-06 07:51:57 -0700430 HardwareRenderer renderer =
431 root.getView().mAttachInfo.mHardwareRenderer;
432 if (renderer != null) {
John Reckfe5e7b72014-05-23 17:42:28 -0700433 renderer.dumpGfxInfo(pw, fd);
Jeff Brown98365d72012-08-19 20:30:52 -0700434 }
Jeff Brown98365d72012-08-19 20:30:52 -0700435 }
Craig Mautner652fdfa2013-06-06 07:51:57 -0700436
437 pw.println("\nView hierarchy:\n");
438
439 int viewsCount = 0;
440 int displayListsSize = 0;
441 int[] info = new int[2];
442
443 for (int i = 0; i < count; i++) {
444 ViewRootImpl root = mRoots.get(i);
445 root.dumpGfxInfo(info);
446
447 String name = getWindowName(root);
448 pw.printf(" %s\n %d views, %.2f kB of display lists",
449 name, info[0], info[1] / 1024.0f);
Craig Mautner652fdfa2013-06-06 07:51:57 -0700450 pw.printf("\n\n");
451
452 viewsCount += info[0];
453 displayListsSize += info[1];
454 }
455
456 pw.printf("\nTotal ViewRootImpl: %d\n", count);
457 pw.printf("Total Views: %d\n", viewsCount);
458 pw.printf("Total DisplayList: %.2f kB\n\n", displayListsSize / 1024.0f);
Jeff Brown98365d72012-08-19 20:30:52 -0700459 }
460 } finally {
461 pw.flush();
462 }
463 }
464
465 private static String getWindowName(ViewRootImpl root) {
466 return root.mWindowAttributes.getTitle() + "/" +
467 root.getClass().getName() + '@' + Integer.toHexString(root.hashCode());
468 }
469
470 public void setStoppedState(IBinder token, boolean stopped) {
471 synchronized (mLock) {
Craig Mautner652fdfa2013-06-06 07:51:57 -0700472 int count = mViews.size();
473 for (int i = 0; i < count; i++) {
474 if (token == null || mParams.get(i).token == token) {
475 ViewRootImpl root = mRoots.get(i);
476 root.setStopped(stopped);
Jeff Brown98365d72012-08-19 20:30:52 -0700477 }
478 }
479 }
480 }
481
482 public void reportNewConfiguration(Configuration config) {
483 synchronized (mLock) {
Craig Mautner652fdfa2013-06-06 07:51:57 -0700484 int count = mViews.size();
485 config = new Configuration(config);
486 for (int i=0; i < count; i++) {
487 ViewRootImpl root = mRoots.get(i);
488 root.requestUpdateConfiguration(config);
Jeff Brown98365d72012-08-19 20:30:52 -0700489 }
490 }
491 }
Craig Mautnerbc57cd12013-08-19 15:47:42 -0700492
493 /** @hide */
494 public void changeCanvasOpacity(IBinder token, boolean opaque) {
495 if (token == null) {
496 return;
497 }
498 synchronized (mLock) {
499 for (int i = mParams.size() - 1; i >= 0; --i) {
500 if (mParams.get(i).token == token) {
501 mRoots.get(i).changeCanvasOpacity(opaque);
502 return;
503 }
504 }
505 }
506 }
Jeff Brown98365d72012-08-19 20:30:52 -0700507}
508
509final class WindowLeaked extends AndroidRuntimeException {
510 public WindowLeaked(String msg) {
511 super(msg);
512 }
513}