本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处!
PopupWindow上套PopupWindow,报错:unable to add window ,is your activity running ?
经查在windowManager执行addView操作时出错
- @Override
- public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
- applyDefaultToken(params);
- mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
- }
- public void addView(View view, ViewGroup.LayoutParams params,
- Display display, Window parentWindow) {
- if (view == null) {
- throw new IllegalArgumentException("view must not be null");
- }
- if (display == null) {
- throw new IllegalArgumentException("display must not be null");
- }
- if (!(params instanceof WindowManager.LayoutParams)) {
- throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
- }
- // do this last because it fires off messages to start doing things
- try {
- root.setView(view, wparams, panelParentView);
- } catch (RuntimeException e) {
- // BadTokenException or InvalidDisplayException, clean up.
- synchronized (mLock) {
- final int index = findViewLocked(view, false);
- if (index >= 0) {
- removeViewLocked(index, true);
- }
- }
- throw e;
- }
- }
- /**
- * We have one child
- */
- public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
- synchronized (this) {
- if (mView == null) {
- mView = view;
- int res; /* = WindowManagerImpl.ADD_OKAY; */
- // Schedule the first layout -before- adding to the window
- // manager, to make sure we do the relayout before receiving
- // any other events from the system.
- requestLayout();
- if ((mWindowAttributes.inputFeatures
- & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
- mInputChannel = new InputChannel();
- }
- mForceDecorViewVisibility = (mWindowAttributes.privateFlags
- & PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0;
- try {
- mOrigWindowType = mWindowAttributes.type;
- mAttachInfo.mRecomputeGlobalAttributes = true;
- collectViewAttributes();
- res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
- getHostVisibility(), mDisplay.getDisplayId(),
- mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
- mAttachInfo.mOutsets, mInputChannel);
- } catch (RemoteException e) {
- mAdded = false;
- mView = null;
- mAttachInfo.mRootView = null;
- mInputChannel = null;
- mFallbackEventHandler.setView(null);
- unscheduleTraversals();
- setAccessibilityFocus(null, null);
- throw new RuntimeException("Adding window failed", e);
- } finally {
- if (restore) {
- attrs.restore();
- }
- }
- if (mTranslator != null) {
- mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets);
- }
- mPendingOverscanInsets.set(0, 0, 0, 0);
- mPendingContentInsets.set(mAttachInfo.mContentInsets);
- mPendingStableInsets.set(mAttachInfo.mStableInsets);
- mPendingVisibleInsets.set(0, 0, 0, 0);
- mAttachInfo.mAlwaysConsumeNavBar =
- (res & WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_NAV_BAR) != 0;
- mPendingAlwaysConsumeNavBar = mAttachInfo.mAlwaysConsumeNavBar;
- if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow);
- if (res < WindowManagerGlobal.ADD_OKAY) {
- mAttachInfo.mRootView = null;
- mAdded = false;
- mFallbackEventHandler.setView(null);
- unscheduleTraversals();
- setAccessibilityFocus(null, null);
- switch (res) {
- case WindowManagerGlobal.ADD_BAD_APP_TOKEN:
- case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN:
- throw new WindowManager.BadTokenException(
- "Unable to add window -- token " + attrs.token
- + " is not valid; is your activity running?");
- case WindowManagerGlobal.ADD_NOT_APP_TOKEN:
- throw new WindowManager.BadTokenException(
- "Unable to add window -- token " + attrs.token
- + " is not for an application");
- case WindowManagerGlobal.ADD_APP_EXITING:
- throw new WindowManager.BadTokenException(
- "Unable to add window -- app for token " + attrs.token
- + " is exiting");
- case WindowManagerGlobal.ADD_DUPLICATE_ADD:
- throw new WindowManager.BadTokenException(
- "Unable to add window -- window " + mWindow
- + " has already been added");
- case WindowManagerGlobal.ADD_STARTING_NOT_NEEDED:
- // Silently ignore -- we would have just removed it
- // right away, anyway.
- return;
- case WindowManagerGlobal.ADD_MULTIPLE_SINGLETON:
- throw new WindowManager.BadTokenException("Unable to add window "
- + mWindow + " -- another window of type "
- + mWindowAttributes.type + " already exists");
- case WindowManagerGlobal.ADD_PERMISSION_DENIED:
- throw new WindowManager.BadTokenException("Unable to add window "
- + mWindow + " -- permission denied for window type "
- + mWindowAttributes.type);
- case WindowManagerGlobal.ADD_INVALID_DISPLAY:
- throw new WindowManager.InvalidDisplayException("Unable to add window "
- + mWindow + " -- the specified display can not be found");
- case WindowManagerGlobal.ADD_INVALID_TYPE:
- throw new WindowManager.InvalidDisplayException("Unable to add window "
- + mWindow + " -- the specified window type "
- + mWindowAttributes.type + " is not valid");
- }
- throw new RuntimeException(
- "Unable to add window -- unknown error code " + res);
- }
- }
- }
WindowSession
- @Override
- public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
- int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
- InputChannel outInputChannel) {
- return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
- outContentInsets, outStableInsets, outInputChannel);
- }
WindowManagerService
- public int addWindow(Session session, IWindow client, int seq,
- WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
- Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
- InputChannel outInputChannel) {
- int[] appOp = new int[1];
- int res = mPolicy.checkAddPermission(attrs, appOp);
- if (res != WindowManagerGlobal.ADD_OKAY) {
- return res;
- }
- boolean reportNewConfig = false;
- WindowState attachedWindow = null;
- long origId;
- final int type = attrs.type;
- synchronized(mWindowMap) {
- if (!mDisplayReady) {
- throw new IllegalStateException("Display has not been initialialized");
- }
- final DisplayContent displayContent = getDisplayContentLocked(displayId);
- if (displayContent == null) {
- Slog.w(TAG_WM, "Attempted to add window to a display that does not exist: "
- + displayId + ". Aborting.");
- return WindowManagerGlobal.ADD_INVALID_DISPLAY;
- }
- if (!displayContent.hasAccess(session.mUid)) {
- Slog.w(TAG_WM, "Attempted to add window to a display for which the application "
- + "does not have access: " + displayId + ". Aborting.");
- return WindowManagerGlobal.ADD_INVALID_DISPLAY;
- }
- if (mWindowMap.containsKey(client.asBinder())) {
- Slog.w(TAG_WM, "Window " + client + " is already added");
- return WindowManagerGlobal.ADD_DUPLICATE_ADD;
- }
- if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {
- attachedWindow = windowForClientLocked(null, attrs.token, false);
- if (attachedWindow == null) {
- Slog.w(TAG_WM, "Attempted to add window with token that is not a window: "
- + attrs.token + ". Aborting.");
- return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
- }
- if (attachedWindow.mAttrs.type >= FIRST_SUB_WINDOW
- && attachedWindow.mAttrs.type <= LAST_SUB_WINDOW) {
- Slog.w(TAG_WM, "Attempted to add window with token that is a sub-window: "
- + attrs.token + ". Aborting.");
- return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
- }
- }
- if (type == TYPE_PRIVATE_PRESENTATION && !displayContent.isPrivate()) {
- Slog.w(TAG_WM, "Attempted to add private presentation window to a non-private display. Aborting.");
- return WindowManagerGlobal.ADD_PERMISSION_DENIED;
- }
- boolean addToken = false;
- WindowToken token = mTokenMap.get(attrs.token);
- AppWindowToken atoken = null;
- if (token == null) {
- if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
- Slog.w(TAG_WM, "Attempted to add application window with unknown token "
- + attrs.token + ". Aborting.");
- return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
- }
- if (type == TYPE_INPUT_METHOD) {
- Slog.w(TAG_WM, "Attempted to add input method window with unknown token "
- + attrs.token + ". Aborting.");
- return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
- }
- if (type == TYPE_VOICE_INTERACTION) {
- Slog.w(TAG_WM, "Attempted to add voice interaction window with unknown token "
- + attrs.token + ". Aborting.");
- return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
- }
- if (type == TYPE_WALLPAPER) {
- Slog.w(TAG_WM, "Attempted to add wallpaper window with unknown token "
- + attrs.token + ". Aborting.");
- return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
- }
- if (type == TYPE_DREAM) {
- Slog.w(TAG_WM, "Attempted to add Dream window with unknown token "
- + attrs.token + ". Aborting.");
- return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
- }
- if (type == TYPE_QS_DIALOG) {
- Slog.w(TAG_WM, "Attempted to add QS dialog window with unknown token "
- + attrs.token + ". Aborting.");
- return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
- }
- if (type == TYPE_ACCESSIBILITY_OVERLAY) {
- Slog.w(TAG_WM, "Attempted to add Accessibility overlay window with unknown token "
- + attrs.token + ". Aborting.");
- return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
- }
- token = new WindowToken(this, attrs.token, -1, false);
- addToken = true;
- } else if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
- atoken = token.appWindowToken;
- if (atoken == null) {
- Slog.w(TAG_WM, "Attempted to add window with non-application token "
- + token + ". Aborting.");
- return WindowManagerGlobal.ADD_NOT_APP_TOKEN;
- } else if (atoken.removed) {
- Slog.w(TAG_WM, "Attempted to add window with exiting application token "
- + token + ". Aborting.");
- return WindowManagerGlobal.ADD_APP_EXITING;
- }
- if (type == TYPE_APPLICATION_STARTING && atoken.firstWindowDrawn) {
- // No need for this guy!
- if (DEBUG_STARTING_WINDOW || localLOGV) Slog.v(
- TAG_WM, "**** NO NEED TO START: " + attrs.getTitle());
- return WindowManagerGlobal.ADD_STARTING_NOT_NEEDED;
- }
- } else if (type == TYPE_INPUT_METHOD) {
- if (token.windowType != TYPE_INPUT_METHOD) {
- Slog.w(TAG_WM, "Attempted to add input method window with bad token "
- + attrs.token + ". Aborting.");
- return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
- }
- } else if (type == TYPE_VOICE_INTERACTION) {
- if (token.windowType != TYPE_VOICE_INTERACTION) {
- Slog.w(TAG_WM, "Attempted to add voice interaction window with bad token "
- + attrs.token + ". Aborting.");
- return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
- }
- } else if (type == TYPE_WALLPAPER) {
- if (token.windowType != TYPE_WALLPAPER) {
- Slog.w(TAG_WM, "Attempted to add wallpaper window with bad token "
- + attrs.token + ". Aborting.");
- return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
- }
- } else if (type == TYPE_DREAM) {
- if (token.windowType != TYPE_DREAM) {
- Slog.w(TAG_WM, "Attempted to add Dream window with bad token "
- + attrs.token + ". Aborting.");
- return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
- }
- } else if (type == TYPE_ACCESSIBILITY_OVERLAY) {
- if (token.windowType != TYPE_ACCESSIBILITY_OVERLAY) {
- Slog.w(TAG_WM, "Attempted to add Accessibility overlay window with bad token "
- + attrs.token + ". Aborting.");
- return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
- }
- } else if (type == TYPE_QS_DIALOG) {
- if (token.windowType != TYPE_QS_DIALOG) {
- Slog.w(TAG_WM, "Attempted to add QS dialog window with bad token "
- + attrs.token + ". Aborting.");
- return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
- }
- } else if (token.appWindowToken != null) {
- Slog.w(TAG_WM, "Non-null appWindowToken for system window of type=" + type);
- // It is not valid to use an app token with other system types; we will
- // instead make a new token for it (as if null had been passed in for the token).
- attrs.token = null;
- token = new WindowToken(this, null, -1, false);
- addToken = true;
- }
- if (addToken) {
- mTokenMap.put(attrs.token, token);
- }
- win.attach();
- mWindowMap.put(client.asBinder(), win);
- if (win.mAppOp != AppOpsManager.OP_NONE) {
- int startOpResult = mAppOps.startOpNoThrow(win.mAppOp, win.getOwningUid(),
- win.getOwningPackage());
- if ((startOpResult != AppOpsManager.MODE_ALLOWED) &&
- (startOpResult != AppOpsManager.MODE_DEFAULT)) {
- win.setAppOpVisibilityLw(false);
- }
- }
- Binder.restoreCallingIdentity(origId);
- return res;
- }
查到mTokenMap.get(attr.token)为null,同时又是子窗口,因此报错。
至于为什么是null,继续
回到PopupWindow
- public void showAsDropDown(View anchor, int xoff, int yoff, int gravity) {
- if (isShowing() || mContentView == null) {
- return;
- }
- TransitionManager.endTransitions(mDecorView);
- attachToAnchor(anchor, xoff, yoff, gravity);
- mIsShowing = true;
- mIsDropdown = true;
- final WindowManager.LayoutParams p = createPopupLayoutParams(anchor.getWindowToken());
- preparePopup(p);
- final boolean aboveAnchor = findDropDownPosition(anchor, p, xoff, yoff,
- p.width, p.height, gravity);
- updateAboveAnchor(aboveAnchor);
- p.accessibilityIdOfAnchor = (anchor != null) ? anchor.getAccessibilityViewId() : -1;
- invokePopup(p);
- }
可以看到,二次添加的PopupWidow,使用一次添加的PopupWindow对象的token,而此token为
- private int mWindowLayoutType = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
- private WindowManager.LayoutParams createPopupLayoutParams(IBinder token) {
- final WindowManager.LayoutParams p = new WindowManager.LayoutParams();
- // These gravity settings put the view at the top left corner of the
- // screen. The view is then positioned to the appropriate location by
- // setting the x and y offsets to match the anchor's bottom-left
- // corner.
- p.gravity = computeGravity();
- p.flags = computeFlags(p.flags);
- p.type = mWindowLayoutType;
- p.token = token;
- p.softInputMode = mSoftInputMode;
- p.windowAnimations = computeAnimationResource();
- return p;
- }
但在WindowManagerService里,PopupWindow依赖show的控件是传过来的,而一次PopupWindow的type刚好等于
- /**
- * Window type: a panel on top of an application window. These windows
- * appear on top of their attached window.
- */
- public static final int TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW;
- if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {
- attachedWindow = windowForClientLocked(null, attrs.token, false);
- if (attachedWindow == null) {
- Slog.w(TAG_WM, "Attempted to add window with token that is not a window: "
- + attrs.token + ". Aborting.");
- return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
- }
- if (attachedWindow.mAttrs.type >= FIRST_SUB_WINDOW
- && attachedWindow.mAttrs.type <= LAST_SUB_WINDOW) {
- Slog.w(TAG_WM, "Attempted to add window with token that is a sub-window: "
- + attrs.token + ". Aborting.");
- return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
- }
- }
完。
补充:Dialog则无此限制
- public void show() {
- if (mShowing) {
- if (mDecor != null) {
- if (mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
- mWindow.invalidatePanelMenu(Window.FEATURE_ACTION_BAR);
- }
- mDecor.setVisibility(View.VISIBLE);
- }
- return;
- }
- WindowManager.LayoutParams l = mWindow.getAttributes();
- if ((l.softInputMode
- & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) == 0) {
- WindowManager.LayoutParams nl = new WindowManager.LayoutParams();
- nl.copyFrom(l);
- nl.softInputMode |=
- WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
- l = nl;
- }
- mWindowManager.addView(mDecor, l);
- mShowing = true;
- sendShowMessage();
- }
- Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
- final Window w = new PhoneWindow(mContext);
- mWindow = w;
- }
PhoneWindow
- public final WindowManager.LayoutParams getAttributes() {
- return mWindowAttributes;
- }
- private final WindowManager.LayoutParams mWindowAttributes =
- new WindowManager.LayoutParams();
- public LayoutParams() {
- super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
- type = TYPE_APPLICATION;
- format = PixelFormat.OPAQUE;
- }
- public static final int TYPE_APPLICATION = 2;
WindowManagerService要求大于等1000,小于等于1999才报ADD_BAD_SUB_WINDOW。
因此Dialog无此限制,所以PopupWindow上弹Dialog即可解决此问题。