• 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.content.res.CompatibilityInfo;
20 import android.content.res.Configuration;
21 import android.graphics.PixelFormat;
22 import android.os.IBinder;
23 import android.util.AndroidRuntimeException;
24 import android.util.Log;
25 import android.view.inputmethod.InputMethodManager;
26 
27 import java.io.FileDescriptor;
28 import java.io.FileOutputStream;
29 import java.io.PrintWriter;
30 import java.util.HashMap;
31 
32 final class WindowLeaked extends AndroidRuntimeException {
WindowLeaked(String msg)33     public WindowLeaked(String msg) {
34         super(msg);
35     }
36 }
37 
38 /**
39  * Low-level communication with the global system window manager.  It implements
40  * the ViewManager interface, allowing you to add any View subclass as a
41  * top-level window on the screen. Additional window manager specific layout
42  * parameters are defined for control over how windows are displayed.
43  * It also implemens the WindowManager interface, allowing you to control the
44  * displays attached to the device.
45  *
46  * <p>Applications will not normally use WindowManager directly, instead relying
47  * on the higher-level facilities in {@link android.app.Activity} and
48  * {@link android.app.Dialog}.
49  *
50  * <p>Even for low-level window manager access, it is almost never correct to use
51  * this class.  For example, {@link android.app.Activity#getWindowManager}
52  * provides a ViewManager for adding windows that are associated with that
53  * activity -- the window manager will not normally allow you to add arbitrary
54  * windows that are not associated with an activity.
55  *
56  * @hide
57  */
58 public class WindowManagerImpl implements WindowManager {
59     /**
60      * The user is navigating with keys (not the touch screen), so
61      * navigational focus should be shown.
62      */
63     public static final int RELAYOUT_IN_TOUCH_MODE = 0x1;
64     /**
65      * This is the first time the window is being drawn,
66      * so the client must call drawingFinished() when done
67      */
68     public static final int RELAYOUT_FIRST_TIME = 0x2;
69 
70     public static final int ADD_FLAG_APP_VISIBLE = 0x2;
71     public static final int ADD_FLAG_IN_TOUCH_MODE = RELAYOUT_IN_TOUCH_MODE;
72 
73     public static final int ADD_OKAY = 0;
74     public static final int ADD_BAD_APP_TOKEN = -1;
75     public static final int ADD_BAD_SUBWINDOW_TOKEN = -2;
76     public static final int ADD_NOT_APP_TOKEN = -3;
77     public static final int ADD_APP_EXITING = -4;
78     public static final int ADD_DUPLICATE_ADD = -5;
79     public static final int ADD_STARTING_NOT_NEEDED = -6;
80     public static final int ADD_MULTIPLE_SINGLETON = -7;
81     public static final int ADD_PERMISSION_DENIED = -8;
82 
83     private View[] mViews;
84     private ViewRootImpl[] mRoots;
85     private WindowManager.LayoutParams[] mParams;
86 
87     private final static Object sLock = new Object();
88     private final static WindowManagerImpl sWindowManager = new WindowManagerImpl();
89     private final static HashMap<CompatibilityInfo, WindowManager> sCompatWindowManagers
90             = new HashMap<CompatibilityInfo, WindowManager>();
91 
92     static class CompatModeWrapper implements WindowManager {
93         private final WindowManagerImpl mWindowManager;
94         private final Display mDefaultDisplay;
95         private final CompatibilityInfoHolder mCompatibilityInfo;
96 
CompatModeWrapper(WindowManager wm, CompatibilityInfoHolder ci)97         CompatModeWrapper(WindowManager wm, CompatibilityInfoHolder ci) {
98             mWindowManager = wm instanceof CompatModeWrapper
99                     ? ((CompatModeWrapper)wm).mWindowManager : (WindowManagerImpl)wm;
100 
101             // Use the original display if there is no compatibility mode
102             // to apply, or the underlying window manager is already a
103             // compatibility mode wrapper.  (We assume that if it is a
104             // wrapper, it is applying the same compatibility mode.)
105             if (ci == null) {
106                 mDefaultDisplay = mWindowManager.getDefaultDisplay();
107             } else {
108                 //mDefaultDisplay = mWindowManager.getDefaultDisplay();
109                 mDefaultDisplay = Display.createCompatibleDisplay(
110                         mWindowManager.getDefaultDisplay().getDisplayId(), ci);
111             }
112 
113             mCompatibilityInfo = ci;
114         }
115 
116         @Override
addView(View view, android.view.ViewGroup.LayoutParams params)117         public void addView(View view, android.view.ViewGroup.LayoutParams params) {
118             mWindowManager.addView(view, params, mCompatibilityInfo);
119         }
120 
121         @Override
updateViewLayout(View view, android.view.ViewGroup.LayoutParams params)122         public void updateViewLayout(View view, android.view.ViewGroup.LayoutParams params) {
123             mWindowManager.updateViewLayout(view, params);
124 
125         }
126 
127         @Override
removeView(View view)128         public void removeView(View view) {
129             mWindowManager.removeView(view);
130         }
131 
132         @Override
getDefaultDisplay()133         public Display getDefaultDisplay() {
134             return mDefaultDisplay;
135         }
136 
137         @Override
removeViewImmediate(View view)138         public void removeViewImmediate(View view) {
139             mWindowManager.removeViewImmediate(view);
140         }
141 
142         @Override
isHardwareAccelerated()143         public boolean isHardwareAccelerated() {
144             return mWindowManager.isHardwareAccelerated();
145         }
146 
147     }
148 
getDefault()149     public static WindowManagerImpl getDefault() {
150         return sWindowManager;
151     }
152 
getDefault(CompatibilityInfo compatInfo)153     public static WindowManager getDefault(CompatibilityInfo compatInfo) {
154         CompatibilityInfoHolder cih = new CompatibilityInfoHolder();
155         cih.set(compatInfo);
156         if (cih.getIfNeeded() == null) {
157             return sWindowManager;
158         }
159 
160         synchronized (sLock) {
161             // NOTE: It would be cleaner to move the implementation of
162             // WindowManagerImpl into a static inner class, and have this
163             // public impl just call into that.  Then we can make multiple
164             // instances of WindowManagerImpl for compat mode rather than
165             // having to make wrappers.
166             WindowManager wm = sCompatWindowManagers.get(compatInfo);
167             if (wm == null) {
168                 wm = new CompatModeWrapper(sWindowManager, cih);
169                 sCompatWindowManagers.put(compatInfo, wm);
170             }
171             return wm;
172         }
173     }
174 
getDefault(CompatibilityInfoHolder compatInfo)175     public static WindowManager getDefault(CompatibilityInfoHolder compatInfo) {
176         return new CompatModeWrapper(sWindowManager, compatInfo);
177     }
178 
isHardwareAccelerated()179     public boolean isHardwareAccelerated() {
180         return false;
181     }
182 
addView(View view)183     public void addView(View view) {
184         addView(view, new WindowManager.LayoutParams(
185             WindowManager.LayoutParams.TYPE_APPLICATION, 0, PixelFormat.OPAQUE));
186     }
187 
addView(View view, ViewGroup.LayoutParams params)188     public void addView(View view, ViewGroup.LayoutParams params) {
189         addView(view, params, null, false);
190     }
191 
addView(View view, ViewGroup.LayoutParams params, CompatibilityInfoHolder cih)192     public void addView(View view, ViewGroup.LayoutParams params, CompatibilityInfoHolder cih) {
193         addView(view, params, cih, false);
194     }
195 
addView(View view, ViewGroup.LayoutParams params, CompatibilityInfoHolder cih, boolean nest)196     private void addView(View view, ViewGroup.LayoutParams params,
197             CompatibilityInfoHolder cih, boolean nest) {
198         if (false) Log.v("WindowManager", "addView view=" + view);
199 
200         if (!(params instanceof WindowManager.LayoutParams)) {
201             throw new IllegalArgumentException(
202                     "Params must be WindowManager.LayoutParams");
203         }
204 
205         final WindowManager.LayoutParams wparams
206                 = (WindowManager.LayoutParams)params;
207 
208         ViewRootImpl root;
209         View panelParentView = null;
210 
211         synchronized (this) {
212             // Here's an odd/questionable case: if someone tries to add a
213             // view multiple times, then we simply bump up a nesting count
214             // and they need to remove the view the corresponding number of
215             // times to have it actually removed from the window manager.
216             // This is useful specifically for the notification manager,
217             // which can continually add/remove the same view as a
218             // notification gets updated.
219             int index = findViewLocked(view, false);
220             if (index >= 0) {
221                 if (!nest) {
222                     throw new IllegalStateException("View " + view
223                             + " has already been added to the window manager.");
224                 }
225                 root = mRoots[index];
226                 root.mAddNesting++;
227                 // Update layout parameters.
228                 view.setLayoutParams(wparams);
229                 root.setLayoutParams(wparams, true);
230                 return;
231             }
232 
233             // If this is a panel window, then find the window it is being
234             // attached to for future reference.
235             if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
236                     wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
237                 final int count = mViews != null ? mViews.length : 0;
238                 for (int i=0; i<count; i++) {
239                     if (mRoots[i].mWindow.asBinder() == wparams.token) {
240                         panelParentView = mViews[i];
241                     }
242                 }
243             }
244 
245             root = new ViewRootImpl(view.getContext());
246             root.mAddNesting = 1;
247             if (cih == null) {
248                 root.mCompatibilityInfo = new CompatibilityInfoHolder();
249             } else {
250                 root.mCompatibilityInfo = cih;
251             }
252 
253             view.setLayoutParams(wparams);
254 
255             if (mViews == null) {
256                 index = 1;
257                 mViews = new View[1];
258                 mRoots = new ViewRootImpl[1];
259                 mParams = new WindowManager.LayoutParams[1];
260             } else {
261                 index = mViews.length + 1;
262                 Object[] old = mViews;
263                 mViews = new View[index];
264                 System.arraycopy(old, 0, mViews, 0, index-1);
265                 old = mRoots;
266                 mRoots = new ViewRootImpl[index];
267                 System.arraycopy(old, 0, mRoots, 0, index-1);
268                 old = mParams;
269                 mParams = new WindowManager.LayoutParams[index];
270                 System.arraycopy(old, 0, mParams, 0, index-1);
271             }
272             index--;
273 
274             mViews[index] = view;
275             mRoots[index] = root;
276             mParams[index] = wparams;
277         }
278         // do this last because it fires off messages to start doing things
279         root.setView(view, wparams, panelParentView);
280     }
281 
updateViewLayout(View view, ViewGroup.LayoutParams params)282     public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
283         if (!(params instanceof WindowManager.LayoutParams)) {
284             throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
285         }
286 
287         final WindowManager.LayoutParams wparams
288                 = (WindowManager.LayoutParams)params;
289 
290         view.setLayoutParams(wparams);
291 
292         synchronized (this) {
293             int index = findViewLocked(view, true);
294             ViewRootImpl root = mRoots[index];
295             mParams[index] = wparams;
296             root.setLayoutParams(wparams, false);
297         }
298     }
299 
removeView(View view)300     public void removeView(View view) {
301         synchronized (this) {
302             int index = findViewLocked(view, true);
303             View curView = removeViewLocked(index);
304             if (curView == view) {
305                 return;
306             }
307 
308             throw new IllegalStateException("Calling with view " + view
309                     + " but the ViewAncestor is attached to " + curView);
310         }
311     }
312 
removeViewImmediate(View view)313     public void removeViewImmediate(View view) {
314         synchronized (this) {
315             int index = findViewLocked(view, true);
316             ViewRootImpl root = mRoots[index];
317             View curView = root.getView();
318 
319             root.mAddNesting = 0;
320             root.die(true);
321             finishRemoveViewLocked(curView, index);
322             if (curView == view) {
323                 return;
324             }
325 
326             throw new IllegalStateException("Calling with view " + view
327                     + " but the ViewAncestor is attached to " + curView);
328         }
329     }
330 
removeViewLocked(int index)331     View removeViewLocked(int index) {
332         ViewRootImpl root = mRoots[index];
333         View view = root.getView();
334 
335         // Don't really remove until we have matched all calls to add().
336         root.mAddNesting--;
337         if (root.mAddNesting > 0) {
338             return view;
339         }
340 
341         if (view != null) {
342             InputMethodManager imm = InputMethodManager.getInstance(view.getContext());
343             if (imm != null) {
344                 imm.windowDismissed(mViews[index].getWindowToken());
345             }
346         }
347         root.die(false);
348         finishRemoveViewLocked(view, index);
349         return view;
350     }
351 
finishRemoveViewLocked(View view, int index)352     void finishRemoveViewLocked(View view, int index) {
353         final int count = mViews.length;
354 
355         // remove it from the list
356         View[] tmpViews = new View[count-1];
357         removeItem(tmpViews, mViews, index);
358         mViews = tmpViews;
359 
360         ViewRootImpl[] tmpRoots = new ViewRootImpl[count-1];
361         removeItem(tmpRoots, mRoots, index);
362         mRoots = tmpRoots;
363 
364         WindowManager.LayoutParams[] tmpParams
365                 = new WindowManager.LayoutParams[count-1];
366         removeItem(tmpParams, mParams, index);
367         mParams = tmpParams;
368 
369         if (view != null) {
370             view.assignParent(null);
371             // func doesn't allow null...  does it matter if we clear them?
372             //view.setLayoutParams(null);
373         }
374     }
375 
closeAll(IBinder token, String who, String what)376     public void closeAll(IBinder token, String who, String what) {
377         synchronized (this) {
378             if (mViews == null)
379                 return;
380 
381             int count = mViews.length;
382             //Log.i("foo", "Closing all windows of " + token);
383             for (int i=0; i<count; i++) {
384                 //Log.i("foo", "@ " + i + " token " + mParams[i].token
385                 //        + " view " + mRoots[i].getView());
386                 if (token == null || mParams[i].token == token) {
387                     ViewRootImpl root = mRoots[i];
388                     root.mAddNesting = 1;
389 
390                     //Log.i("foo", "Force closing " + root);
391                     if (who != null) {
392                         WindowLeaked leak = new WindowLeaked(
393                                 what + " " + who + " has leaked window "
394                                 + root.getView() + " that was originally added here");
395                         leak.setStackTrace(root.getLocation().getStackTrace());
396                         Log.e("WindowManager", leak.getMessage(), leak);
397                     }
398 
399                     removeViewLocked(i);
400                     i--;
401                     count--;
402                 }
403             }
404         }
405     }
406 
407     /**
408      * @param level See {@link android.content.ComponentCallbacks}
409      */
trimMemory(int level)410     public void trimMemory(int level) {
411         if (HardwareRenderer.isAvailable()) {
412             HardwareRenderer.trimMemory(level);
413         }
414     }
415 
416     /**
417      * @hide
418      */
trimLocalMemory()419     public void trimLocalMemory() {
420         synchronized (this) {
421             if (mViews == null) return;
422             int count = mViews.length;
423             for (int i = 0; i < count; i++) {
424                 mRoots[i].destroyHardwareLayers();
425             }
426         }
427     }
428 
429     /**
430      * @hide
431      */
dumpGfxInfo(FileDescriptor fd)432     public void dumpGfxInfo(FileDescriptor fd) {
433         FileOutputStream fout = new FileOutputStream(fd);
434         PrintWriter pw = new PrintWriter(fout);
435         try {
436             synchronized (this) {
437                 if (mViews != null) {
438                     pw.println("View hierarchy:");
439 
440                     final int count = mViews.length;
441 
442                     int viewsCount = 0;
443                     int displayListsSize = 0;
444                     int[] info = new int[2];
445 
446                     for (int i = 0; i < count; i++) {
447                         ViewRootImpl root = mRoots[i];
448                         root.dumpGfxInfo(pw, info);
449 
450                         String name = root.getClass().getName() + '@' +
451                                 Integer.toHexString(hashCode());
452                         pw.printf("  %s: %d views, %.2f kB (display lists)\n",
453                                 name, info[0], info[1] / 1024.0f);
454 
455                         viewsCount += info[0];
456                         displayListsSize += info[1];
457                     }
458 
459                     pw.printf("\nTotal ViewRootImpl: %d\n", count);
460                     pw.printf("Total Views:        %d\n", viewsCount);
461                     pw.printf("Total DisplayList:  %.2f kB\n\n", displayListsSize / 1024.0f);
462                 }
463             }
464         } finally {
465             pw.flush();
466         }
467     }
468 
setStoppedState(IBinder token, boolean stopped)469     public void setStoppedState(IBinder token, boolean stopped) {
470         synchronized (this) {
471             if (mViews == null)
472                 return;
473             int count = mViews.length;
474             for (int i=0; i<count; i++) {
475                 if (token == null || mParams[i].token == token) {
476                     ViewRootImpl root = mRoots[i];
477                     root.setStopped(stopped);
478                 }
479             }
480         }
481     }
482 
reportNewConfiguration(Configuration config)483     public void reportNewConfiguration(Configuration config) {
484         synchronized (this) {
485             int count = mViews.length;
486             config = new Configuration(config);
487             for (int i=0; i<count; i++) {
488                 ViewRootImpl root = mRoots[i];
489                 root.requestUpdateConfiguration(config);
490             }
491         }
492     }
493 
getRootViewLayoutParameter(View view)494     public WindowManager.LayoutParams getRootViewLayoutParameter(View view) {
495         ViewParent vp = view.getParent();
496         while (vp != null && !(vp instanceof ViewRootImpl)) {
497             vp = vp.getParent();
498         }
499 
500         if (vp == null) return null;
501 
502         ViewRootImpl vr = (ViewRootImpl)vp;
503 
504         int N = mRoots.length;
505         for (int i = 0; i < N; ++i) {
506             if (mRoots[i] == vr) {
507                 return mParams[i];
508             }
509         }
510 
511         return null;
512     }
513 
closeAll()514     public void closeAll() {
515         closeAll(null, null, null);
516     }
517 
getDefaultDisplay()518     public Display getDefaultDisplay() {
519         return new Display(Display.DEFAULT_DISPLAY, null);
520     }
521 
removeItem(Object[] dst, Object[] src, int index)522     private static void removeItem(Object[] dst, Object[] src, int index) {
523         if (dst.length > 0) {
524             if (index > 0) {
525                 System.arraycopy(src, 0, dst, 0, index);
526             }
527             if (index < dst.length) {
528                 System.arraycopy(src, index+1, dst, index, src.length-index-1);
529             }
530         }
531     }
532 
findViewLocked(View view, boolean required)533     private int findViewLocked(View view, boolean required) {
534         synchronized (this) {
535             final int count = mViews != null ? mViews.length : 0;
536             for (int i=0; i<count; i++) {
537                 if (mViews[i] == view) {
538                     return i;
539                 }
540             }
541             if (required) {
542                 throw new IllegalArgumentException(
543                         "View not attached to window manager");
544             }
545             return -1;
546         }
547     }
548 }
549