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