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