intindex=this.findViewLocked(view, false); if (index >= 0) { if (!this.mDyingViews.contains(view)) { //不允许重复添加窗口 thrownewIllegalStateException("View " + view + " has already been added to the window manager."); }
((ViewRootImpl)this.mRoots.get(index)).doDie(); }
if (wparams.type >= 1000 && wparams.type <= 1999) { index = this.mViews.size();
for(inti=0; i < index; ++i) { if (((ViewRootImpl)this.mRoots.get(i)).mWindow.asBinder() == wparams.token) { panelParentView = (View)this.mViews.get(i); } } }
//... if (res < 0) { //添加Window失败 this.mAttachInfo.mRootView = null; this.mAdded = false; this.mFallbackEventHandler.setView((View)null); this.unscheduleTraversals(); this.setAccessibilityFocus((View)null, (AccessibilityNodeInfo)null); switch(res) { case -10: thrownewInvalidDisplayException("Unable to add window " + this.mWindow + " -- the specified window type " + this.mWindowAttributes.type + " is not valid"); case -9: thrownewInvalidDisplayException("Unable to add window " + this.mWindow + " -- the specified display can not be found"); case -8: thrownewBadTokenException("Unable to add window " + this.mWindow + " -- permission denied for window type " + this.mWindowAttributes.type); case -7: thrownewBadTokenException("Unable to add window " + this.mWindow + " -- another window of type " + this.mWindowAttributes.type + " already exists"); case -6: return; case -5: thrownewBadTokenException("Unable to add window -- window " + this.mWindow + " has already been added"); case -4: thrownewBadTokenException("Unable to add window -- app for token " + attrs.token + " is exiting"); case -3: thrownewBadTokenException("Unable to add window -- token " + attrs.token + " is not for an application"); case -2: case -1: if (view.getContext().getPackageName().startsWith("com.google.android.gms")) { try { if (AppGlobals.getPackageManager().isFirstBoot()) { Log.d(this.mTag, "firstboot crash return"); return; } } catch (RemoteException var22) { var22.printStackTrace(); return; } }
thrownewBadTokenException("Unable to add window -- token " + attrs.token + " is not valid; is your activity running?"); default: thrownewRuntimeException("Unable to add window -- unknown error code " + res); } }
voidcheckThread() { if (this.mThread != Thread.currentThread()) { thrownewViewRootImpl.CalledFromWrongThreadException("Only the original thread that created a view hierarchy can touch its views."); } }
B:开始View的绘制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
voidscheduleTraversals() { if (!this.mTraversalScheduled) { this.mTraversalScheduled = true; this.mTraversalBarrier = this.mHandler.getLooper().getQueue().postSyncBarrier(); //回调mTraversalRunnable this.mChoreographer.postCallback(2, this.mTraversalRunnable, (Object)null); if (!this.mUnbufferedInputDispatch) { this.scheduleConsumeBatchedInput(); }
if (ENABLE_BLOCKED_TOASTS && !isSystemToast && (!areNotificationsEnabledForPackage(pkg, Binder.getCallingUid()) || isPackageSuspended)) { Slog.e(TAG, "Suppressing toast from package " + pkg + (isPackageSuspended ? " due to package suspended by administrator." : " by user request.")); return; }
synchronized (mToastQueue) { intcallingPid= Binder.getCallingPid(); longcallingId= Binder.clearCallingIdentity(); try { ToastRecord record; int index; // All packages aside from the android package can enqueue one toast at a time if (!isSystemToast) { index = indexOfToastPackageLocked(pkg); } else { index = indexOfToastLocked(pkg, callback); }
// If the package already has a toast, we update its toast // in the queue, we don't move it to the end of the queue. if (index >= 0) { record = mToastQueue.get(index); record.update(duration); record.update(callback); } else { Bindertoken=newBinder(); mWindowManagerInternal.addWindowToken(token, TYPE_TOAST, DEFAULT_DISPLAY); record = newToastRecord(callingPid, pkg, callback, duration, token); mToastQueue.add(record); index = mToastQueue.size() - 1; } keepProcessAliveIfNeededLocked(callingPid); // If it's at index 0, it's the current toast. It doesn't matter if it's // new or just been updated. Call back and tell it to show itself. // If the callback fails, this will remove it from the list, so don't // assume that it's valid after this. if (index == 0) { showNextToastLocked(); } } finally { Binder.restoreCallingIdentity(callingId); } } }
@GuardedBy("mToastQueue") voidshowNextToastLocked() { ToastRecordrecord= mToastQueue.get(0); while (record != null) { if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback); try { record.callback.show(record.token); scheduleTimeoutLocked(record); return; } catch (RemoteException e) { Slog.w(TAG, "Object died trying to show notification " + record.callback + " in package " + record.pkg); // remove it from the list and let the process die intindex= mToastQueue.indexOf(record); if (index >= 0) { mToastQueue.remove(index); } keepProcessAliveIfNeededLocked(record.pid); if (mToastQueue.size() > 0) { record = mToastQueue.get(0); } else { record = null; } } } }
publicvoidhandleShow(IBinder windowToken) { if (localLOGV) Log.v(TAG, "HANDLE SHOW: " + this + " mView=" + mView + " mNextView=" + mNextView); // If a cancel/hide is pending - no need to show - at this point // the window token is already invalid and no need to do any work. if (mHandler.hasMessages(CANCEL) || mHandler.hasMessages(HIDE)) { return; } if (mView != mNextView) { // remove the old view if necessary handleHide(); mView = mNextView; Contextcontext= mView.getContext().getApplicationContext(); StringpackageName= mView.getContext().getOpPackageName(); if (context == null) { context = mView.getContext(); } mWM = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); // We can resolve the Gravity here by using the Locale for getting // the layout direction finalConfigurationconfig= mView.getContext().getResources().getConfiguration(); finalintgravity= Gravity.getAbsoluteGravity(mGravity, config.getLayoutDirection()); mParams.gravity = gravity; if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) { mParams.horizontalWeight = 1.0f; } if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) { mParams.verticalWeight = 1.0f; } mParams.x = mX; mParams.y = mY; mParams.verticalMargin = mVerticalMargin; mParams.horizontalMargin = mHorizontalMargin; mParams.packageName = packageName; mParams.hideTimeoutMilliseconds = mDuration == Toast.LENGTH_LONG ? LONG_DURATION_TIMEOUT : SHORT_DURATION_TIMEOUT; mParams.token = windowToken; if (mView.getParent() != null) { if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this); mWM.removeView(mView); } if (localLOGV) Log.v(TAG, "ADD! " + mView + " in " + this); // Since the notification manager service cancels the token right // after it notifies us to cancel the toast there is an inherent // race and we may attempt to add a window after the token has been // invalidated. Let us hedge against that. try { mWM.addView(mView, mParams); trySendAccessibilityEvent(); } catch (WindowManager.BadTokenException e) { /* ignore */ } } }