blob: d7a309686d4d4da5a3e62a821e55c7b620296f39 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 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.graphics.PixelFormat;
20import android.os.IBinder;
21import android.util.AndroidRuntimeException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022import android.util.Log;
23import android.view.WindowManager;
24import android.view.inputmethod.InputMethodManager;
25
26final class WindowLeaked extends AndroidRuntimeException {
27 public WindowLeaked(String msg) {
28 super(msg);
29 }
30}
31
32/**
33 * Low-level communication with the global system window manager. It implements
34 * the ViewManager interface, allowing you to add any View subclass as a
35 * top-level window on the screen. Additional window manager specific layout
36 * parameters are defined for control over how windows are displayed.
37 * It also implemens the WindowManager interface, allowing you to control the
38 * displays attached to the device.
39 *
40 * <p>Applications will not normally use WindowManager directly, instead relying
41 * on the higher-level facilities in {@link android.app.Activity} and
42 * {@link android.app.Dialog}.
43 *
44 * <p>Even for low-level window manager access, it is almost never correct to use
45 * this class. For example, {@link android.app.Activity#getWindowManager}
46 * provides a ViewManager for adding windows that are associated with that
47 * activity -- the window manager will not normally allow you to add arbitrary
48 * windows that are not associated with an activity.
49 *
50 * @hide
51 */
52public class WindowManagerImpl implements WindowManager {
53 /**
54 * The user is navigating with keys (not the touch screen), so
55 * navigational focus should be shown.
56 */
57 public static final int RELAYOUT_IN_TOUCH_MODE = 0x1;
58 /**
59 * This is the first time the window is being drawn,
60 * so the client must call drawingFinished() when done
61 */
62 public static final int RELAYOUT_FIRST_TIME = 0x2;
63
64 public static final int ADD_FLAG_APP_VISIBLE = 0x2;
65 public static final int ADD_FLAG_IN_TOUCH_MODE = RELAYOUT_IN_TOUCH_MODE;
66
67 public static final int ADD_OKAY = 0;
68 public static final int ADD_BAD_APP_TOKEN = -1;
69 public static final int ADD_BAD_SUBWINDOW_TOKEN = -2;
70 public static final int ADD_NOT_APP_TOKEN = -3;
71 public static final int ADD_APP_EXITING = -4;
72 public static final int ADD_DUPLICATE_ADD = -5;
73 public static final int ADD_STARTING_NOT_NEEDED = -6;
74 public static final int ADD_MULTIPLE_SINGLETON = -7;
75 public static final int ADD_PERMISSION_DENIED = -8;
76
77 public static WindowManagerImpl getDefault()
78 {
79 return mWindowManager;
80 }
81
Dianne Hackborn7eec10e2010-11-12 18:03:47 -080082 public boolean isHardwareAccelerated() {
83 return false;
84 }
85
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086 public void addView(View view)
87 {
88 addView(view, new WindowManager.LayoutParams(
89 WindowManager.LayoutParams.TYPE_APPLICATION, 0, PixelFormat.OPAQUE));
90 }
91
92 public void addView(View view, ViewGroup.LayoutParams params)
93 {
94 addView(view, params, false);
95 }
96
97 public void addViewNesting(View view, ViewGroup.LayoutParams params)
98 {
99 addView(view, params, false);
100 }
101
102 private void addView(View view, ViewGroup.LayoutParams params, boolean nest)
103 {
Joe Onorato43a17652011-04-06 19:22:23 -0700104 if (false) Log.v("WindowManager", "addView view=" + view);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105
106 if (!(params instanceof WindowManager.LayoutParams)) {
107 throw new IllegalArgumentException(
108 "Params must be WindowManager.LayoutParams");
109 }
110
111 final WindowManager.LayoutParams wparams
112 = (WindowManager.LayoutParams)params;
113
Joe Onoratoc6cc0f82011-04-12 11:53:13 -0700114 ViewAncestor root;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115 View panelParentView = null;
116
117 synchronized (this) {
118 // Here's an odd/questionable case: if someone tries to add a
119 // view multiple times, then we simply bump up a nesting count
120 // and they need to remove the view the corresponding number of
121 // times to have it actually removed from the window manager.
122 // This is useful specifically for the notification manager,
123 // which can continually add/remove the same view as a
124 // notification gets updated.
125 int index = findViewLocked(view, false);
126 if (index >= 0) {
127 if (!nest) {
128 throw new IllegalStateException("View " + view
129 + " has already been added to the window manager.");
130 }
131 root = mRoots[index];
132 root.mAddNesting++;
133 // Update layout parameters.
134 view.setLayoutParams(wparams);
135 root.setLayoutParams(wparams, true);
136 return;
137 }
138
139 // If this is a panel window, then find the window it is being
140 // attached to for future reference.
141 if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
142 wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
143 final int count = mViews != null ? mViews.length : 0;
144 for (int i=0; i<count; i++) {
145 if (mRoots[i].mWindow.asBinder() == wparams.token) {
146 panelParentView = mViews[i];
147 }
148 }
149 }
150
Joe Onoratoc6cc0f82011-04-12 11:53:13 -0700151 root = new ViewAncestor(view.getContext());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152 root.mAddNesting = 1;
153
154 view.setLayoutParams(wparams);
155
156 if (mViews == null) {
157 index = 1;
158 mViews = new View[1];
Joe Onoratoc6cc0f82011-04-12 11:53:13 -0700159 mRoots = new ViewAncestor[1];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160 mParams = new WindowManager.LayoutParams[1];
161 } else {
162 index = mViews.length + 1;
163 Object[] old = mViews;
164 mViews = new View[index];
165 System.arraycopy(old, 0, mViews, 0, index-1);
166 old = mRoots;
Joe Onoratoc6cc0f82011-04-12 11:53:13 -0700167 mRoots = new ViewAncestor[index];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800168 System.arraycopy(old, 0, mRoots, 0, index-1);
169 old = mParams;
170 mParams = new WindowManager.LayoutParams[index];
171 System.arraycopy(old, 0, mParams, 0, index-1);
172 }
173 index--;
174
175 mViews[index] = view;
176 mRoots[index] = root;
177 mParams[index] = wparams;
178 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800179 // do this last because it fires off messages to start doing things
180 root.setView(view, wparams, panelParentView);
181 }
182
183 public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
184 if (!(params instanceof WindowManager.LayoutParams)) {
185 throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
186 }
187
188 final WindowManager.LayoutParams wparams
189 = (WindowManager.LayoutParams)params;
190
191 view.setLayoutParams(wparams);
192
193 synchronized (this) {
194 int index = findViewLocked(view, true);
Joe Onoratoc6cc0f82011-04-12 11:53:13 -0700195 ViewAncestor root = mRoots[index];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800196 mParams[index] = wparams;
197 root.setLayoutParams(wparams, false);
198 }
199 }
200
201 public void removeView(View view) {
202 synchronized (this) {
203 int index = findViewLocked(view, true);
204 View curView = removeViewLocked(index);
205 if (curView == view) {
206 return;
207 }
208
209 throw new IllegalStateException("Calling with view " + view
Joe Onoratoc6cc0f82011-04-12 11:53:13 -0700210 + " but the ViewAncestor is attached to " + curView);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800211 }
212 }
213
214 public void removeViewImmediate(View view) {
215 synchronized (this) {
216 int index = findViewLocked(view, true);
Joe Onoratoc6cc0f82011-04-12 11:53:13 -0700217 ViewAncestor root = mRoots[index];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800218 View curView = root.getView();
219
220 root.mAddNesting = 0;
221 root.die(true);
222 finishRemoveViewLocked(curView, index);
223 if (curView == view) {
224 return;
225 }
226
227 throw new IllegalStateException("Calling with view " + view
Joe Onoratoc6cc0f82011-04-12 11:53:13 -0700228 + " but the ViewAncestor is attached to " + curView);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800229 }
230 }
231
232 View removeViewLocked(int index) {
Joe Onoratoc6cc0f82011-04-12 11:53:13 -0700233 ViewAncestor root = mRoots[index];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800234 View view = root.getView();
235
236 // Don't really remove until we have matched all calls to add().
237 root.mAddNesting--;
238 if (root.mAddNesting > 0) {
239 return view;
240 }
241
242 InputMethodManager imm = InputMethodManager.getInstance(view.getContext());
243 if (imm != null) {
244 imm.windowDismissed(mViews[index].getWindowToken());
245 }
246 root.die(false);
247 finishRemoveViewLocked(view, index);
248 return view;
249 }
250
251 void finishRemoveViewLocked(View view, int index) {
252 final int count = mViews.length;
253
254 // remove it from the list
255 View[] tmpViews = new View[count-1];
256 removeItem(tmpViews, mViews, index);
257 mViews = tmpViews;
258
Joe Onoratoc6cc0f82011-04-12 11:53:13 -0700259 ViewAncestor[] tmpRoots = new ViewAncestor[count-1];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800260 removeItem(tmpRoots, mRoots, index);
261 mRoots = tmpRoots;
262
263 WindowManager.LayoutParams[] tmpParams
264 = new WindowManager.LayoutParams[count-1];
265 removeItem(tmpParams, mParams, index);
266 mParams = tmpParams;
267
268 view.assignParent(null);
269 // func doesn't allow null... does it matter if we clear them?
270 //view.setLayoutParams(null);
271 }
272
273 public void closeAll(IBinder token, String who, String what) {
274 synchronized (this) {
275 if (mViews == null)
276 return;
277
278 int count = mViews.length;
279 //Log.i("foo", "Closing all windows of " + token);
280 for (int i=0; i<count; i++) {
281 //Log.i("foo", "@ " + i + " token " + mParams[i].token
282 // + " view " + mRoots[i].getView());
283 if (token == null || mParams[i].token == token) {
Joe Onoratoc6cc0f82011-04-12 11:53:13 -0700284 ViewAncestor root = mRoots[i];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800285 root.mAddNesting = 1;
286
287 //Log.i("foo", "Force closing " + root);
288 if (who != null) {
289 WindowLeaked leak = new WindowLeaked(
290 what + " " + who + " has leaked window "
291 + root.getView() + " that was originally added here");
292 leak.setStackTrace(root.getLocation().getStackTrace());
293 Log.e("WindowManager", leak.getMessage(), leak);
294 }
295
296 removeViewLocked(i);
297 i--;
298 count--;
299 }
300 }
301 }
302 }
303
Dianne Hackbornce418e62011-03-01 14:31:38 -0800304 public void setStoppedState(IBinder token, boolean stopped) {
305 synchronized (this) {
306 if (mViews == null)
307 return;
308 int count = mViews.length;
309 for (int i=0; i<count; i++) {
310 if (token == null || mParams[i].token == token) {
Joe Onoratoc6cc0f82011-04-12 11:53:13 -0700311 ViewAncestor root = mRoots[i];
Dianne Hackbornce418e62011-03-01 14:31:38 -0800312 root.setStopped(stopped);
313 }
314 }
315 }
316 }
317
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800318 public WindowManager.LayoutParams getRootViewLayoutParameter(View view) {
319 ViewParent vp = view.getParent();
Joe Onoratoc6cc0f82011-04-12 11:53:13 -0700320 while (vp != null && !(vp instanceof ViewAncestor)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800321 vp = vp.getParent();
322 }
323
324 if (vp == null) return null;
325
Joe Onoratoc6cc0f82011-04-12 11:53:13 -0700326 ViewAncestor vr = (ViewAncestor)vp;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800327
328 int N = mRoots.length;
329 for (int i = 0; i < N; ++i) {
330 if (mRoots[i] == vr) {
331 return mParams[i];
332 }
333 }
334
335 return null;
336 }
337
338 public void closeAll() {
339 closeAll(null, null, null);
340 }
341
342 public Display getDefaultDisplay() {
343 return new Display(Display.DEFAULT_DISPLAY);
344 }
345
346 private View[] mViews;
Joe Onoratoc6cc0f82011-04-12 11:53:13 -0700347 private ViewAncestor[] mRoots;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800348 private WindowManager.LayoutParams[] mParams;
349
350 private static void removeItem(Object[] dst, Object[] src, int index)
351 {
352 if (dst.length > 0) {
353 if (index > 0) {
354 System.arraycopy(src, 0, dst, 0, index);
355 }
356 if (index < dst.length) {
357 System.arraycopy(src, index+1, dst, index, src.length-index-1);
358 }
359 }
360 }
361
362 private int findViewLocked(View view, boolean required)
363 {
364 synchronized (this) {
365 final int count = mViews != null ? mViews.length : 0;
366 for (int i=0; i<count; i++) {
367 if (mViews[i] == view) {
368 return i;
369 }
370 }
371 if (required) {
372 throw new IllegalArgumentException(
373 "View not attached to window manager");
374 }
375 return -1;
376 }
377 }
378
379 private static WindowManagerImpl mWindowManager = new WindowManagerImpl();
380}