/** * @return true if drawing was successful, false if an error occurred */ privatebooleandrawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff, boolean scalingRequired, Rect dirty, Rect surfaceInsets){
// Draw with software renderer. final Canvas canvas;
try { dirty.offset(-dirtyXOffset, -dirtyYOffset); finalint left = dirty.left; finalint top = dirty.top; finalint right = dirty.right; finalint bottom = dirty.bottom;
canvas = mSurface.lockCanvas(dirty);
// TODO: Do this in native canvas.setDensity(mDensity); } catch (Surface.OutOfResourcesException e) { handleOutOfResourcesException(e); returnfalse; } catch (IllegalArgumentException e) { Log.e(mTag, "Could not lock surface", e); // Don't assume this is due to out of memory, it could be // something else, and if it is something else then we could // kill stuff (or ourself) for no reason. mLayoutRequested = true; // ask wm for a new surface next time. returnfalse; } finally { dirty.offset(dirtyXOffset, dirtyYOffset); // Reset to the original value. }
// If this bitmap's format includes an alpha channel, we // need to clear it before drawing so that the child will // properly re-composite its drawing on a transparent // background. This automatically respects the clip/dirty region // or // If we are applying an offset, we need to clear the area // where the offset doesn't appear to avoid having garbage // left in the blank areas. if (!canvas.isOpaque() || yoff != 0 || xoff != 0) { canvas.drawColor(0, PorterDuff.Mode.CLEAR); }
/* * Draw traversal performs several drawing steps which must be executed * in the appropriate order: * * 1. Draw the background * 2. If necessary, save the canvas' layers to prepare for fading * 3. Draw view's content * 4. Draw children * 5. If necessary, draw the fading edges and restore layers * 6. Draw decorations (scrollbars for instance) * 7. If necessary, draw the default focus highlight */
// Step 1, draw the background, if needed int saveCount;
// Step 4, draw the children dispatchDraw(canvas);
drawAutofilledHighlight(canvas);
// Overlay is part of the content and draws beneath Foreground if (mOverlay != null && !mOverlay.isEmpty()) { mOverlay.getOverlayView().dispatchDraw(canvas); }
* 1. Draw the background * 2. If necessary, save the canvas' layers to prepare for fading * 3. Draw view's content * 4. Draw children * 5. If necessary, draw the fading edges and restore layers * 6.Draw decorations(scrollbars for instance) * 7. If necessary, draw the default focus highlight
privatevoiddrawBackground(Canvas canvas){ final Drawable background = mBackground; if (background == null) { return; }
setBackgroundBounds();
// Attempt to use a display list if requested. if (canvas.isHardwareAccelerated() && mAttachInfo != null && mAttachInfo.mThreadedRenderer != null) { mBackgroundRenderNode = getDrawableRenderNode(background, mBackgroundRenderNode);
final RenderNode renderNode = mBackgroundRenderNode; if (renderNode != null && renderNode.hasDisplayList()) { setBackgroundRenderNodeProperties(renderNode); ((RecordingCanvas) canvas).drawRenderNode(renderNode); return; } }
@Override protectedvoiddispatchDraw(Canvas canvas){ boolean usingRenderNodeProperties = canvas.isRecordingFor(mRenderNode); finalint childrenCount = mChildrenCount; final View[] children = mChildren;
if (usingRenderNodeProperties) canvas.insertReorderBarrier(); finalint transientCount = mTransientIndices == null ? 0 : mTransientIndices.size(); int transientIndex = transientCount != 0 ? 0 : -1; // Only use the preordered list if not HW accelerated, since the HW pipeline will do the // draw reordering internally final ArrayList<View> preorderedList = usingRenderNodeProperties ? null : buildOrderedChildList(); finalboolean customOrder = preorderedList == null && isChildrenDrawingOrderEnabled(); for (int i = 0; i < childrenCount; i++) { while (transientIndex >= 0 && mTransientIndices.get(transientIndex) == i) { final View transientChild = mTransientViews.get(transientIndex); if ((transientChild.mViewFlags & VISIBILITY_MASK) == VISIBLE || transientChild.getAnimation() != null) { more |= drawChild(canvas, transientChild, drawingTime); } transientIndex++; if (transientIndex >= transientCount) { transientIndex = -1; } }
finalint childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder); final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex); if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) { more |= drawChild(canvas, child, drawingTime); } } while (transientIndex >= 0) { // there may be additional transient views after the normal views final View transientChild = mTransientViews.get(transientIndex); if ((transientChild.mViewFlags & VISIBILITY_MASK) == VISIBLE || transientChild.getAnimation() != null) { more |= drawChild(canvas, transientChild, drawingTime); } transientIndex++; if (transientIndex >= transientCount) { break; } } if (preorderedList != null) preorderedList.clear();
// Draw any disappearing views that have animations if (mDisappearingChildren != null) { final ArrayList<View> disappearingChildren = mDisappearingChildren; finalint disappearingCount = disappearingChildren.size() - 1; // Go backwards -- we may delete as animations finish for (int i = disappearingCount; i >= 0; i--) { final View child = disappearingChildren.get(i); more |= drawChild(canvas, child, drawingTime); } }