publicvoidaddView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) { if (view == null) { thrownewIllegalArgumentException("view must not be null"); } if (display == null) { thrownewIllegalArgumentException("display must not be null"); } if (!(params instanceof WindowManager.LayoutParams)) { thrownewIllegalArgumentException("Params must be WindowManager.LayoutParams"); }
final WindowManager.LayoutParamswparams= (WindowManager.LayoutParams) params; if (parentWindow != null) { parentWindow.adjustLayoutParamsForSubWindow(wparams); } else { // If there's no parent, then hardware acceleration for this view is // set from the application's hardware acceleration setting. finalContextcontext= view.getContext(); if (context != null && (context.getApplicationInfo().flags & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) { wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; } }
ViewRootImpl root; ViewpanelParentView=null;
synchronized (mLock) { // Start watching for system property changes. if (mSystemPropertyUpdater == null) { mSystemPropertyUpdater = newRunnable() { @Overridepublicvoidrun() { synchronized (mLock) { for (inti= mRoots.size() - 1; i >= 0; --i) { mRoots.get(i).loadSystemProperties(); } } } }; SystemProperties.addChangeCallback(mSystemPropertyUpdater); }
intindex= findViewLocked(view, false); if (index >= 0) { if (mDyingViews.contains(view)) { // Don't wait for MSG_DIE to make it's way through root's queue. mRoots.get(index).doDie(); } else { thrownewIllegalStateException("View " + view + " has already been added to the window manager."); } // The previous removeView() had not completed executing. Now it has. }
// 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) { finalintcount= mViews.size(); for (inti=0; i < count; i++) { if (mRoots.get(i).mWindow.asBinder() == wparams.token) { panelParentView = mViews.get(i); } } }
// 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) { finalintindex= findViewLocked(view, false); if (index >= 0) { removeViewLocked(index, true); } } throw e; } }
// Ask host how big it wants to be performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); privatestaticintgetRootMeasureSpec(int windowSize, int rootDimension) { int measureSpec; switch (rootDimension) {
case ViewGroup.LayoutParams.MATCH_PARENT: // Window can't resize. Force root view to be windowSize. measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY); break; case ViewGroup.LayoutParams.WRAP_CONTENT: // Window can resize. Set max size for root view. measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST); break; default: // Window wants to be an exact size. Force root view to be that size. measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY); break; } return measureSpec; }
mInLayout = false; intnumViewsRequestingLayout= mLayoutRequesters.size(); if (numViewsRequestingLayout > 0) { // requestLayout() was called during layout. // If no layout-request flags are set on the requesting views, there is no problem. // If some requests are still pending, then we need to clear those flags and do // a full request/measure/layout pass to handle this situation. ArrayList<View> validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, false); if (validLayoutRequesters != null) { // Set this flag to indicate that any further requests are happening during // the second pass, which may result in posting those requests to the next // frame instead mHandlingLayoutInLayoutRequest = true;
// Process fresh layout requests, then measure and layout intnumValidRequests= validLayoutRequesters.size(); for (inti=0; i < numValidRequests; ++i) { finalViewview= validLayoutRequesters.get(i); Log.w("View", "requestLayout() improperly called by " + view + " during layout: running second layout pass"); view.requestLayout(); } measureHierarchy(host, lp, mView.getContext().getResources(), desiredWindowWidth, desiredWindowHeight); mInLayout = true; host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
mHandlingLayoutInLayoutRequest = false;
// Check the valid requests again, this time without checking/clearing the // layout flags, since requests happening during the second pass get noop'd validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, true); if (validLayoutRequesters != null) { final ArrayList<View> finalRequesters = validLayoutRequesters; // Post second-pass requests to the next frame getRunQueue().post(newRunnable() { @Override publicvoidrun() { intnumValidRequests= finalRequesters.size(); for (inti=0; i < numValidRequests; ++i) { finalViewview= finalRequesters.get(i); Log.w("View", "requestLayout() improperly called by " + view + " during second layout pass: posting in next frame"); view.requestLayout(); } } }); } }
// For whatever reason we didn't create a HardwareRenderer, end any // hardware animations that are now dangling if (mAttachInfo.mPendingAnimatingRenderNodes != null) { finalintcount= mAttachInfo.mPendingAnimatingRenderNodes.size(); for (inti=0; i < count; i++) { mAttachInfo.mPendingAnimatingRenderNodes.get(i).endAllAnimators(); } mAttachInfo.mPendingAnimatingRenderNodes.clear(); }
if (mReportNextDraw) { mReportNextDraw = false; if (mAttachInfo.mHardwareRenderer != null) { mAttachInfo.mHardwareRenderer.fence(); }
if (LOCAL_LOGV) { Log.v(TAG, "FINISHED DRAWING: " + mWindowAttributes.getTitle()); } if (mSurfaceHolder != null && mSurface.isValid()) { mSurfaceHolderCallback.surfaceRedrawNeeded(mSurfaceHolder); SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks(); if (callbacks != null) { for (SurfaceHolder.Callback c : callbacks) { if (c instanceof SurfaceHolder.Callback2) { ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded( mSurfaceHolder); } } } } try { mWindowSession.finishDrawing(mWindow); } catch (RemoteException e) { } } } 调用draw()方法 如果开启了硬件加速,使用ThreadedRender.draw绘制,否则采用传统canvas绘制
// Grab a copy of everything we need CanvasContext* context = mContext;
// From this point on anything in "this" is *UNSAFE TO ACCESS* if (canUnblockUiThread) { unblockUiThread(); }
if (CC_LIKELY(canDrawThisFrame)) { context->draw(); }
if (!canUnblockUiThread) { unblockUiThread(); } }
CanvasContext
voidCanvasContext::draw() { LOG_ALWAYS_FATAL_IF(!mCanvas || mEglSurface == EGL_NO_SURFACE, "drawRenderNode called on a context with no canvas or surface!");
SkRect dirty; mDamageAccumulator.finish(&dirty);
// TODO: Re-enable after figuring out cause of b/22592975 // if (dirty.isEmpty() && Properties::skipEmptyFrames) { // mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame); // return; // }
Rect outBounds; mCanvas->drawRenderNode(mRootRenderNode.get(), outBounds);
profiler().draw(mCanvas);
bool drew = mCanvas->finish();
// Even if we decided to cancel the frame, from the perspective of jank // metrics the frame was swapped at this point mCurrentFrameInfo->markSwapBuffers();
if (drew) { swapBuffers(dirty, width, height); }
// TODO: Use a fence for real completion? mCurrentFrameInfo->markFrameCompleted(); mJankTracker.addFrame(*mCurrentFrameInfo); mRenderThread.jankTracker().addFrame(*mCurrentFrameInfo); }