WindowManagerImpl.java revision c6cc0f8c19d9eccf408a443fa2bf668af261dcd0
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 17package android.view; 18 19import android.graphics.PixelFormat; 20import android.os.IBinder; 21import android.util.AndroidRuntimeException; 22import 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 82 public boolean isHardwareAccelerated() { 83 return false; 84 } 85 86 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 { 104 if (false) Log.v("WindowManager", "addView view=" + view); 105 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 114 ViewAncestor root; 115 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 151 root = new ViewAncestor(view.getContext()); 152 root.mAddNesting = 1; 153 154 view.setLayoutParams(wparams); 155 156 if (mViews == null) { 157 index = 1; 158 mViews = new View[1]; 159 mRoots = new ViewAncestor[1]; 160 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; 167 mRoots = new ViewAncestor[index]; 168 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 } 179 // 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); 195 ViewAncestor root = mRoots[index]; 196 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 210 + " but the ViewAncestor is attached to " + curView); 211 } 212 } 213 214 public void removeViewImmediate(View view) { 215 synchronized (this) { 216 int index = findViewLocked(view, true); 217 ViewAncestor root = mRoots[index]; 218 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 228 + " but the ViewAncestor is attached to " + curView); 229 } 230 } 231 232 View removeViewLocked(int index) { 233 ViewAncestor root = mRoots[index]; 234 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 259 ViewAncestor[] tmpRoots = new ViewAncestor[count-1]; 260 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) { 284 ViewAncestor root = mRoots[i]; 285 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 304 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) { 311 ViewAncestor root = mRoots[i]; 312 root.setStopped(stopped); 313 } 314 } 315 } 316 } 317 318 public WindowManager.LayoutParams getRootViewLayoutParameter(View view) { 319 ViewParent vp = view.getParent(); 320 while (vp != null && !(vp instanceof ViewAncestor)) { 321 vp = vp.getParent(); 322 } 323 324 if (vp == null) return null; 325 326 ViewAncestor vr = (ViewAncestor)vp; 327 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; 347 private ViewAncestor[] mRoots; 348 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} 381