WindowManagerImpl.java revision 7eec10e6c99c30d5ee061fec08ac89ad4254ac32
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.Config; 23import android.util.Log; 24import android.view.WindowManager; 25import android.view.inputmethod.InputMethodManager; 26 27final class WindowLeaked extends AndroidRuntimeException { 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 */ 53public 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 78 public static WindowManagerImpl getDefault() 79 { 80 return mWindowManager; 81 } 82 83 public boolean isHardwareAccelerated() { 84 return false; 85 } 86 87 public void addView(View view) 88 { 89 addView(view, new WindowManager.LayoutParams( 90 WindowManager.LayoutParams.TYPE_APPLICATION, 0, PixelFormat.OPAQUE)); 91 } 92 93 public void addView(View view, ViewGroup.LayoutParams params) 94 { 95 addView(view, params, false); 96 } 97 98 public void addViewNesting(View view, ViewGroup.LayoutParams params) 99 { 100 addView(view, params, false); 101 } 102 103 private void addView(View view, ViewGroup.LayoutParams params, boolean nest) 104 { 105 if (Config.LOGV) Log.v("WindowManager", "addView view=" + view); 106 107 if (!(params instanceof WindowManager.LayoutParams)) { 108 throw new IllegalArgumentException( 109 "Params must be WindowManager.LayoutParams"); 110 } 111 112 final WindowManager.LayoutParams wparams 113 = (WindowManager.LayoutParams)params; 114 115 ViewRoot root; 116 View panelParentView = null; 117 118 synchronized (this) { 119 // Here's an odd/questionable case: if someone tries to add a 120 // view multiple times, then we simply bump up a nesting count 121 // and they need to remove the view the corresponding number of 122 // times to have it actually removed from the window manager. 123 // This is useful specifically for the notification manager, 124 // which can continually add/remove the same view as a 125 // notification gets updated. 126 int index = findViewLocked(view, false); 127 if (index >= 0) { 128 if (!nest) { 129 throw new IllegalStateException("View " + view 130 + " has already been added to the window manager."); 131 } 132 root = mRoots[index]; 133 root.mAddNesting++; 134 // Update layout parameters. 135 view.setLayoutParams(wparams); 136 root.setLayoutParams(wparams, true); 137 return; 138 } 139 140 // If this is a panel window, then find the window it is being 141 // attached to for future reference. 142 if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW && 143 wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) { 144 final int count = mViews != null ? mViews.length : 0; 145 for (int i=0; i<count; i++) { 146 if (mRoots[i].mWindow.asBinder() == wparams.token) { 147 panelParentView = mViews[i]; 148 } 149 } 150 } 151 152 root = new ViewRoot(view.getContext()); 153 root.mAddNesting = 1; 154 155 view.setLayoutParams(wparams); 156 157 if (mViews == null) { 158 index = 1; 159 mViews = new View[1]; 160 mRoots = new ViewRoot[1]; 161 mParams = new WindowManager.LayoutParams[1]; 162 } else { 163 index = mViews.length + 1; 164 Object[] old = mViews; 165 mViews = new View[index]; 166 System.arraycopy(old, 0, mViews, 0, index-1); 167 old = mRoots; 168 mRoots = new ViewRoot[index]; 169 System.arraycopy(old, 0, mRoots, 0, index-1); 170 old = mParams; 171 mParams = new WindowManager.LayoutParams[index]; 172 System.arraycopy(old, 0, mParams, 0, index-1); 173 } 174 index--; 175 176 mViews[index] = view; 177 mRoots[index] = root; 178 mParams[index] = wparams; 179 } 180 // do this last because it fires off messages to start doing things 181 root.setView(view, wparams, panelParentView); 182 } 183 184 public void updateViewLayout(View view, ViewGroup.LayoutParams params) { 185 if (!(params instanceof WindowManager.LayoutParams)) { 186 throw new IllegalArgumentException("Params must be WindowManager.LayoutParams"); 187 } 188 189 final WindowManager.LayoutParams wparams 190 = (WindowManager.LayoutParams)params; 191 192 view.setLayoutParams(wparams); 193 194 synchronized (this) { 195 int index = findViewLocked(view, true); 196 ViewRoot root = mRoots[index]; 197 mParams[index] = wparams; 198 root.setLayoutParams(wparams, false); 199 } 200 } 201 202 public void removeView(View view) { 203 synchronized (this) { 204 int index = findViewLocked(view, true); 205 View curView = removeViewLocked(index); 206 if (curView == view) { 207 return; 208 } 209 210 throw new IllegalStateException("Calling with view " + view 211 + " but the ViewRoot is attached to " + curView); 212 } 213 } 214 215 public void removeViewImmediate(View view) { 216 synchronized (this) { 217 int index = findViewLocked(view, true); 218 ViewRoot root = mRoots[index]; 219 View curView = root.getView(); 220 221 root.mAddNesting = 0; 222 root.die(true); 223 finishRemoveViewLocked(curView, index); 224 if (curView == view) { 225 return; 226 } 227 228 throw new IllegalStateException("Calling with view " + view 229 + " but the ViewRoot is attached to " + curView); 230 } 231 } 232 233 View removeViewLocked(int index) { 234 ViewRoot root = mRoots[index]; 235 View view = root.getView(); 236 237 // Don't really remove until we have matched all calls to add(). 238 root.mAddNesting--; 239 if (root.mAddNesting > 0) { 240 return view; 241 } 242 243 InputMethodManager imm = InputMethodManager.getInstance(view.getContext()); 244 if (imm != null) { 245 imm.windowDismissed(mViews[index].getWindowToken()); 246 } 247 root.die(false); 248 finishRemoveViewLocked(view, index); 249 return view; 250 } 251 252 void finishRemoveViewLocked(View view, int index) { 253 final int count = mViews.length; 254 255 // remove it from the list 256 View[] tmpViews = new View[count-1]; 257 removeItem(tmpViews, mViews, index); 258 mViews = tmpViews; 259 260 ViewRoot[] tmpRoots = new ViewRoot[count-1]; 261 removeItem(tmpRoots, mRoots, index); 262 mRoots = tmpRoots; 263 264 WindowManager.LayoutParams[] tmpParams 265 = new WindowManager.LayoutParams[count-1]; 266 removeItem(tmpParams, mParams, index); 267 mParams = tmpParams; 268 269 view.assignParent(null); 270 // func doesn't allow null... does it matter if we clear them? 271 //view.setLayoutParams(null); 272 } 273 274 public void closeAll(IBinder token, String who, String what) { 275 synchronized (this) { 276 if (mViews == null) 277 return; 278 279 int count = mViews.length; 280 //Log.i("foo", "Closing all windows of " + token); 281 for (int i=0; i<count; i++) { 282 //Log.i("foo", "@ " + i + " token " + mParams[i].token 283 // + " view " + mRoots[i].getView()); 284 if (token == null || mParams[i].token == token) { 285 ViewRoot root = mRoots[i]; 286 root.mAddNesting = 1; 287 288 //Log.i("foo", "Force closing " + root); 289 if (who != null) { 290 WindowLeaked leak = new WindowLeaked( 291 what + " " + who + " has leaked window " 292 + root.getView() + " that was originally added here"); 293 leak.setStackTrace(root.getLocation().getStackTrace()); 294 Log.e("WindowManager", leak.getMessage(), leak); 295 } 296 297 removeViewLocked(i); 298 i--; 299 count--; 300 } 301 } 302 } 303 } 304 305 public WindowManager.LayoutParams getRootViewLayoutParameter(View view) { 306 ViewParent vp = view.getParent(); 307 while (vp != null && !(vp instanceof ViewRoot)) { 308 vp = vp.getParent(); 309 } 310 311 if (vp == null) return null; 312 313 ViewRoot vr = (ViewRoot)vp; 314 315 int N = mRoots.length; 316 for (int i = 0; i < N; ++i) { 317 if (mRoots[i] == vr) { 318 return mParams[i]; 319 } 320 } 321 322 return null; 323 } 324 325 public void closeAll() { 326 closeAll(null, null, null); 327 } 328 329 public Display getDefaultDisplay() { 330 return new Display(Display.DEFAULT_DISPLAY); 331 } 332 333 private View[] mViews; 334 private ViewRoot[] mRoots; 335 private WindowManager.LayoutParams[] mParams; 336 337 private static void removeItem(Object[] dst, Object[] src, int index) 338 { 339 if (dst.length > 0) { 340 if (index > 0) { 341 System.arraycopy(src, 0, dst, 0, index); 342 } 343 if (index < dst.length) { 344 System.arraycopy(src, index+1, dst, index, src.length-index-1); 345 } 346 } 347 } 348 349 private int findViewLocked(View view, boolean required) 350 { 351 synchronized (this) { 352 final int count = mViews != null ? mViews.length : 0; 353 for (int i=0; i<count; i++) { 354 if (mViews[i] == view) { 355 return i; 356 } 357 } 358 if (required) { 359 throw new IllegalArgumentException( 360 "View not attached to window manager"); 361 } 362 return -1; 363 } 364 } 365 366 private static WindowManagerImpl mWindowManager = new WindowManagerImpl(); 367} 368