diff options
| author | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
|---|---|---|
| committer | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
| commit | 54b6cfa9a9e5b861a9930af873580d6dc20f773c (patch) | |
| tree | 35051494d2af230dce54d6b31c6af8fc24091316 /core/java/android/view/WindowManagerImpl.java | |
Initial Contribution
Diffstat (limited to 'core/java/android/view/WindowManagerImpl.java')
| -rw-r--r-- | core/java/android/view/WindowManagerImpl.java | 339 |
1 files changed, 339 insertions, 0 deletions
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java new file mode 100644 index 000000000000..fbecf4668ca2 --- /dev/null +++ b/core/java/android/view/WindowManagerImpl.java @@ -0,0 +1,339 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view; + +import android.graphics.PixelFormat; +import android.os.IBinder; +import android.util.AndroidRuntimeException; +import android.util.Config; +import android.util.Log; +import android.view.WindowManager; + +final class WindowLeaked extends AndroidRuntimeException { + public WindowLeaked(String msg) { + super(msg); + } +} + +/** + * Low-level communication with the global system window manager. It implements + * the ViewManager interface, allowing you to add any View subclass as a + * top-level window on the screen. Additional window manager specific layout + * parameters are defined for control over how windows are displayed. + * It also implemens the WindowManager interface, allowing you to control the + * displays attached to the device. + * + * <p>Applications will not normally use WindowManager directly, instead relying + * on the higher-level facilities in {@link android.app.Activity} and + * {@link android.app.Dialog}. + * + * <p>Even for low-level window manager access, it is almost never correct to use + * this class. For example, {@link android.app.Activity#getWindowManager} + * provides a ViewManager for adding windows that are associated with that + * activity -- the window manager will not normally allow you to add arbitrary + * windows that are not associated with an activity. + * + * @hide + */ +public class WindowManagerImpl implements WindowManager { + /** + * The user is navigating with keys (not the touch screen), so + * navigational focus should be shown. + */ + public static final int RELAYOUT_IN_TOUCH_MODE = 0x1; + /** + * This is the first time the window is being drawn, + * so the client must call drawingFinished() when done + */ + public static final int RELAYOUT_FIRST_TIME = 0x2; + + public static final int ADD_FLAG_APP_VISIBLE = 0x2; + public static final int ADD_FLAG_IN_TOUCH_MODE = RELAYOUT_IN_TOUCH_MODE; + + public static final int ADD_OKAY = 0; + public static final int ADD_BAD_APP_TOKEN = -1; + public static final int ADD_BAD_SUBWINDOW_TOKEN = -2; + public static final int ADD_NOT_APP_TOKEN = -3; + public static final int ADD_APP_EXITING = -4; + public static final int ADD_DUPLICATE_ADD = -5; + public static final int ADD_STARTING_NOT_NEEDED = -6; + public static final int ADD_MULTIPLE_SINGLETON = -7; + public static final int ADD_PERMISSION_DENIED = -8; + + public static WindowManagerImpl getDefault() + { + return mWindowManager; + } + + public void addView(View view) + { + addView(view, new WindowManager.LayoutParams( + WindowManager.LayoutParams.TYPE_APPLICATION, 0, PixelFormat.OPAQUE)); + } + + public void addView(View view, ViewGroup.LayoutParams params) + { + addView(view, params, false); + } + + public void addViewNesting(View view, ViewGroup.LayoutParams params) + { + addView(view, params, false); + } + + private void addView(View view, ViewGroup.LayoutParams params, boolean nest) + { + if (Config.LOGV) Log.v("WindowManager", "addView view=" + view); + + if (!(params instanceof WindowManager.LayoutParams)) { + throw new IllegalArgumentException( + "Params must be WindowManager.LayoutParams"); + } + + final WindowManager.LayoutParams wparams + = (WindowManager.LayoutParams)params; + + ViewRoot root; + View panelParentView = null; + + synchronized (this) { + // Here's an odd/questionable case: if someone tries to add a + // view multiple times, then we simply bump up a nesting count + // and they need to remove the view the corresponding number of + // times to have it actually removed from the window manager. + // This is useful specifically for the notification manager, + // which can continually add/remove the same view as a + // notification gets updated. + int index = findViewLocked(view, false); + if (index >= 0) { + if (!nest) { + throw new IllegalStateException("View " + view + + " has already been added to the window manager."); + } + root = mRoots[index]; + root.mAddNesting++; + // Update layout parameters. + view.setLayoutParams(wparams); + root.setLayoutParams(wparams); + return; + } + + // If this is a panel window, then find the window it is being + // attached to for future reference. + if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW && + wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) { + final int count = mViews != null ? mViews.length : 0; + for (int i=0; i<count; i++) { + if (mRoots[i].mWindow.asBinder() == wparams.token) { + panelParentView = mViews[i]; + } + } + } + + root = new ViewRoot(); + root.mAddNesting = 1; + + view.setLayoutParams(wparams); + + if (mViews == null) { + index = 1; + mViews = new View[1]; + mRoots = new ViewRoot[1]; + mParams = new WindowManager.LayoutParams[1]; + } else { + index = mViews.length + 1; + Object[] old = mViews; + mViews = new View[index]; + System.arraycopy(old, 0, mViews, 0, index-1); + old = mRoots; + mRoots = new ViewRoot[index]; + System.arraycopy(old, 0, mRoots, 0, index-1); + old = mParams; + mParams = new WindowManager.LayoutParams[index]; + System.arraycopy(old, 0, mParams, 0, index-1); + } + index--; + + mViews[index] = view; + mRoots[index] = root; + mParams[index] = wparams; + } + + // do this last because it fires off messages to start doing things + root.setView(view, wparams, panelParentView); + } + + public void updateViewLayout(View view, ViewGroup.LayoutParams params) { + if (!(params instanceof WindowManager.LayoutParams)) { + throw new IllegalArgumentException("Params must be WindowManager.LayoutParams"); + } + + final WindowManager.LayoutParams wparams + = (WindowManager.LayoutParams)params; + + view.setLayoutParams(wparams); + + synchronized (this) { + int index = findViewLocked(view, true); + ViewRoot root = mRoots[index]; + mParams[index] = wparams; + root.setLayoutParams(wparams); + } + } + + public void removeView(View view) { + synchronized (this) { + int index = findViewLocked(view, true); + View curView = removeViewLocked(index); + if (curView == view) { + return; + } + + throw new IllegalStateException("Calling with view " + view + + " but the ViewRoot is attached to " + curView); + } + } + + public void removeViewImmediate(View view) { + synchronized (this) { + int index = findViewLocked(view, true); + ViewRoot root = mRoots[index]; + View curView = root.getView(); + + root.mAddNesting = 0; + root.die(true); + finishRemoveViewLocked(curView, index); + if (curView == view) { + return; + } + + throw new IllegalStateException("Calling with view " + view + + " but the ViewRoot is attached to " + curView); + } + } + + View removeViewLocked(int index) { + ViewRoot root = mRoots[index]; + View view = root.getView(); + + // Don't really remove until we have matched all calls to add(). + root.mAddNesting--; + if (root.mAddNesting > 0) { + return view; + } + + root.die(false); + finishRemoveViewLocked(view, index); + return view; + } + + void finishRemoveViewLocked(View view, int index) { + final int count = mViews.length; + + // remove it from the list + View[] tmpViews = new View[count-1]; + removeItem(tmpViews, mViews, index); + mViews = tmpViews; + + ViewRoot[] tmpRoots = new ViewRoot[count-1]; + removeItem(tmpRoots, mRoots, index); + mRoots = tmpRoots; + + WindowManager.LayoutParams[] tmpParams + = new WindowManager.LayoutParams[count-1]; + removeItem(tmpParams, mParams, index); + mParams = tmpParams; + + view.assignParent(null); + // func doesn't allow null... does it matter if we clear them? + //view.setLayoutParams(null); + } + + public void closeAll(IBinder token, String who, String what) { + synchronized (this) { + if (mViews == null) + return; + + int count = mViews.length; + //Log.i("foo", "Closing all windows of " + token); + for (int i=0; i<count; i++) { + //Log.i("foo", "@ " + i + " token " + mParams[i].token + // + " view " + mRoots[i].getView()); + if (token == null || mParams[i].token == token) { + ViewRoot root = mRoots[i]; + root.mAddNesting = 1; + + //Log.i("foo", "Force closing " + root); + if (who != null) { + WindowLeaked leak = new WindowLeaked( + what + " " + who + " has leaked window " + + root.getView() + " that was originally added here"); + leak.setStackTrace(root.getLocation().getStackTrace()); + Log.e("WindowManager", leak.getMessage(), leak); + } + + removeViewLocked(i); + i--; + count--; + } + } + } + } + + public void closeAll() { + closeAll(null, null, null); + } + + public Display getDefaultDisplay() { + return new Display(Display.DEFAULT_DISPLAY); + } + + private View[] mViews; + private ViewRoot[] mRoots; + private WindowManager.LayoutParams[] mParams; + + private static void removeItem(Object[] dst, Object[] src, int index) + { + if (dst.length > 0) { + if (index > 0) { + System.arraycopy(src, 0, dst, 0, index); + } + if (index < dst.length) { + System.arraycopy(src, index+1, dst, index, src.length-index-1); + } + } + } + + private int findViewLocked(View view, boolean required) + { + synchronized (this) { + final int count = mViews != null ? mViews.length : 0; + for (int i=0; i<count; i++) { + if (mViews[i] == view) { + return i; + } + } + if (required) { + throw new IllegalArgumentException( + "View not attached to window manager"); + } + return -1; + } + } + + private static WindowManagerImpl mWindowManager = new WindowManagerImpl(); +} |
