364 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			364 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
| /*
 | |
|  * 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;
 | |
| import android.view.inputmethod.InputMethodManager;
 | |
| 
 | |
| 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, true);
 | |
|                 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(view.getContext());
 | |
|             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, false);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     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;
 | |
|         }
 | |
| 
 | |
|         InputMethodManager imm = InputMethodManager.getInstance(view.getContext());
 | |
|         if (imm != null) {
 | |
|             imm.windowDismissed(mViews[index].getWindowToken());
 | |
|         }
 | |
|         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 WindowManager.LayoutParams getRootViewLayoutParameter(View view) {
 | |
|         ViewParent vp = view.getParent();
 | |
|         while (vp != null && !(vp instanceof ViewRoot)) {
 | |
|             vp = vp.getParent();
 | |
|         }
 | |
|         
 | |
|         if (vp == null) return null;
 | |
|         
 | |
|         ViewRoot vr = (ViewRoot)vp;
 | |
|         
 | |
|         int N = mRoots.length;
 | |
|         for (int i = 0; i < N; ++i) {
 | |
|             if (mRoots[i] == vr) {
 | |
|                 return mParams[i];
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         return null;
 | |
|     }
 | |
|     
 | |
|     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();
 | |
| }
 | 
