protected void onDraw(Canvas paramCanvas) { // today round if (mIsToday) { Paint painta = new Paint(); painta.setStyle(Paint.Style.STROKE); painta.setColor(Color.BLACK); painta.setAntiAlias(true); Rect rect = paramCanvas.getClipBounds(); RectF rt = new RectF(rect); rt.inset(getMeasuredWidth() / 12, getMeasuredHeight() / 12); paramCanvas.drawRoundRect(rt, getMeasuredWidth() / 5, getMeasuredHeight() / 5, painta); Paint paintb = new Paint(); paintb.setColor(Color.GRAY); paintb.setAntiAlias(true); paintb.setAlpha(50); paramCanvas.drawRoundRect(rt, getMeasuredWidth() / 6, getMeasuredWidth() / 6, paintb); } // solar text Paint paint1 = new Paint(); paint1.setAntiAlias(true); paint1.setFakeBoldText(true); paint1.setTextSize(getMeasuredWidth() / 2); if (mDay.mIsWeekEnd) { paint1.setColor(ECalendarActivity.mHolidayColor); } else { paint1.setColor(Color.BLACK); } Rect text = new Rect(); paint1.getTextBounds(mDay.mSolarDay, 0, mDay.mSolarDay.length(), text); int w = getMeasuredWidth(); int w1 = text.width(); float fw = (w - w1) / 2; float fh = getMeasuredHeight() / 2 + 1; paramCanvas.drawText(mDay.mSolarDay, fw, fh, paint1); // lunar text Paint paint2 = new Paint(); paint2.setAntiAlias(true); paint2.setTextSize(getMeasuredWidth() / 4); if (mDay.mIsFestival) { paint2.setColor(ECalendarActivity.mHolidayColor); } else { paint2.setColor(Color.BLACK); } paint2.getTextBounds(mDay.mLunarDay, 0, mDay.mLunarDay.length(), text); w1 = text.width(); fw = (w - w1) / 2; fh = getMeasuredHeight() / 2 + 2 + text.height(); paramCanvas.drawText(mDay.mLunarDay, fw, fh, paint2); if (mDay.mHasDiary) { Paint pd = new Paint(); pd.setStyle(Paint.Style.STROKE); pd.setColor(ECalendarActivity.mHolidayColor); pd.setStrokeWidth(2); Rect rect = paramCanvas.getClipBounds(); RectF rt = new RectF(rect); rt.inset(getMeasuredWidth() / 12, getMeasuredHeight() / 12); paramCanvas.drawLine(rt.left + rt.width() / 4, rt.top, rt.right - rt.width() / 4, rt.top, pd); } }
// Grows the cropping rectange by (dx, dy) in image space. void growBy(float dx, float dy) { if (mMaintainAspectRatio) { if (dx != 0) { dy = dx / mInitialAspectRatio; } else if (dy != 0) { dx = dy * mInitialAspectRatio; } } // Don't let the cropping rectangle grow too fast. // Grow at most half of the difference between the image rectangle and // the cropping rectangle. RectF r = new RectF(mCropRect); if (dx > 0F && r.width() + 2 * dx > mImageRect.width()) { float adjustment = (mImageRect.width() - r.width()) / 2F; dx = adjustment; if (mMaintainAspectRatio) { dy = dx / mInitialAspectRatio; } } if (dy > 0F && r.height() + 2 * dy > mImageRect.height()) { float adjustment = (mImageRect.height() - r.height()) / 2F; dy = adjustment; if (mMaintainAspectRatio) { dx = dy * mInitialAspectRatio; } } r.inset(-dx, -dy); // Don't let the cropping rectangle shrink too fast. final float widthCap = 25F; if (r.width() < widthCap) { r.inset(-(widthCap - r.width()) / 2F, 0F); } float heightCap = mMaintainAspectRatio ? (widthCap / mInitialAspectRatio) : widthCap; if (r.height() < heightCap) { r.inset(0F, -(heightCap - r.height()) / 2F); } // Put the cropping rectangle inside the image rectangle. if (r.left < mImageRect.left) { r.offset(mImageRect.left - r.left, 0F); } else if (r.right > mImageRect.right) { r.offset(-(r.right - mImageRect.right), 0); } if (r.top < mImageRect.top) { r.offset(0F, mImageRect.top - r.top); } else if (r.bottom > mImageRect.bottom) { r.offset(0F, -(r.bottom - mImageRect.bottom)); } mCropRect.set(r); mDrawRect = computeLayout(); mContext.invalidate(); }
// Grows the cropping rectangle by (dx, dy) in image space. void growBy(float dx, float dy) { if (maintainAspectRatio) { if (dx != 0) { dy = dx / initialAspectRatio; } else if (dy != 0) { dx = dy * initialAspectRatio; } } // Don't let the cropping rectangle grow too fast. // Grow at most half of the difference between the image rectangle and // the cropping rectangle. RectF r = new RectF(cropRect); if (dx > 0F && r.width() + 2 * dx > imageRect.width()) { dx = (imageRect.width() - r.width()) / 2F; if (maintainAspectRatio) { dy = dx / initialAspectRatio; } } if (dy > 0F && r.height() + 2 * dy > imageRect.height()) { dy = (imageRect.height() - r.height()) / 2F; if (maintainAspectRatio) { dx = dy * initialAspectRatio; } } r.inset(-dx, -dy); // Don't let the cropping rectangle shrink too fast final float widthCap = 25F; if (r.width() < widthCap) { r.inset(-(widthCap - r.width()) / 2F, 0F); } float heightCap = maintainAspectRatio ? (widthCap / initialAspectRatio) : widthCap; if (r.height() < heightCap) { r.inset(0F, -(heightCap - r.height()) / 2F); } // Put the cropping rectangle inside the image rectangle if (r.left < imageRect.left) { r.offset(imageRect.left - r.left, 0F); } else if (r.right > imageRect.right) { r.offset(-(r.right - imageRect.right), 0F); } if (r.top < imageRect.top) { r.offset(0F, imageRect.top - r.top); } else if (r.bottom > imageRect.bottom) { r.offset(0F, -(r.bottom - imageRect.bottom)); } cropRect.set(r); drawRect = computeLayout(); viewContext.invalidate(); }
@Override public void draw(Canvas canvas) { // Draw the bounding boxes drawBoundingBoxes(canvas); // Set the right values for the paint operatorPaint.setColor(getColor()); operatorPaint.setTextSize(findTextSize()); // Get our operator bounding boxes Rect[] operatorBounding = this.getOperatorBoundingBoxes(); // Draws the operator canvas.save(); Rect textBounding = new Rect(); operatorPaint.getTextBounds(type.getName(), 0, type.getName().length(), textBounding); canvas.translate( (operatorBounding[0].width() - textBounding.width()) / 2, (operatorBounding[0].height() - textBounding.height()) / 2); canvas.drawText( type.getName(), operatorBounding[0].left - textBounding.left, operatorBounding[0].top - textBounding.top, operatorPaint); canvas.restore(); // Use stroke style for the parentheses operatorPaint.setStyle(Paint.Style.STROKE); // Draw the left bracket canvas.save(); canvas.clipRect(operatorBounding[1], Region.Op.INTERSECT); RectF bracket = new RectF(operatorBounding[1]); bracket.inset(0, -operatorPaint.getStrokeWidth()); bracket.offset(bracket.width() / 4, 0); canvas.drawArc(bracket, 100.0f, 160.0f, false, operatorPaint); canvas.restore(); // Draw the right bracket canvas.save(); canvas.clipRect(operatorBounding[2], Region.Op.INTERSECT); bracket = new RectF(operatorBounding[2]); bracket.inset(0, -operatorPaint.getStrokeWidth()); bracket.offset(-bracket.width() / 4, 0); canvas.drawArc(bracket, -80.0f, 160.0f, false, operatorPaint); canvas.restore(); // Set the paint back to fill style operatorPaint.setStyle(Paint.Style.FILL); // Draw the children drawChildren(canvas); }
@Override public void draw(Canvas canvas, MapView mapView, boolean shadow) { // Get the map projection to convert lat/long to screen coordinates Projection projection = mapView.getProjection(); Point lPoint = new Point(); projection.toPixels(locationPoint, lPoint); // Draw the overlay if (shadow == false) { if (friendLocations.size() > 0) { Iterator<String> e = friendLocations.keySet().iterator(); do { // Get the name and location of each contact String name = e.next(); Location location = friendLocations.get(name); // Convert the lat / long to a Geopoint Double latitude = location.getLatitude() * 1E6; Double longitude = location.getLongitude() * 1E6; GeoPoint geopoint = new GeoPoint(latitude.intValue(), longitude.intValue()); // Ensure each contact is within 10km float dist = location.distanceTo(getLocation()); if (dist < 10000) { Point point = new Point(); projection.toPixels(geopoint, point); // Draw a line connecting the contact to your current location. canvas.drawLine(lPoint.x, lPoint.y, point.x, point.y, paint); // Draw a marker at the contact's location. RectF oval = new RectF( point.x - markerRadius, point.y - markerRadius, point.x + markerRadius, point.y + markerRadius); canvas.drawOval(oval, backPaint); oval.inset(2, 2); canvas.drawOval(oval, paint); // Draw the contact's name next to their position. float textWidth = paint.measureText(name); float textHeight = paint.getTextSize(); RectF textRect = new RectF( point.x + markerRadius, point.y - textHeight, point.x + markerRadius + 8 + textWidth, point.y + 4); canvas.drawRoundRect(textRect, 3, 3, backPaint); canvas.drawText(name, point.x + markerRadius + 4, point.y, paint); } } while (e.hasNext()); } } super.draw(canvas, mapView, shadow); }
private boolean findTextIntersection( Canvas cv, RenderingContext rc, QuadTree<TextDrawInfo> boundIntersections, TextDrawInfo text) { // for test purposes // drawTestBox(cv, text.bounds, text.pathRotate, text.text); boundIntersections.queryInBox(text.bounds, tempSearch); for (int i = 0; i < tempSearch.size(); i++) { TextDrawInfo t = tempSearch.get(i); if (intersects(text.bounds, text.pathRotate, t.bounds, t.pathRotate)) { return true; } } if (text.minDistance > 0) { RectF boundsSearch = new RectF(text.bounds); boundsSearch.inset( -rc.getDensityValue(Math.max(5.0f, text.minDistance)), -rc.getDensityValue(15)); boundIntersections.queryInBox(boundsSearch, tempSearch); // drawTestBox(cv, &boundsSearch, text.pathRotate, paintIcon, text.text, NULL/*paintText*/); for (int i = 0; i < tempSearch.size(); i++) { TextDrawInfo t = tempSearch.get(i); if (t.minDistance > 0 && t.text.equals(text.text) && intersects(boundsSearch, text.pathRotate, t.bounds, t.pathRotate)) { return true; } } } boundIntersections.insert(text, text.bounds); return false; }
protected void drawCenterText(Canvas c) { SpannableString centerText = mChart.getCenterText(); if (mChart.isDrawCenterTextEnabled() && centerText != null) { PointF center = mChart.getCenterCircleBox(); float innerRadius = mChart.isDrawHoleEnabled() && mChart.isHoleTransparent() ? mChart.getRadius() * (mChart.getHoleRadius() / 100f) : mChart.getRadius(); RectF holeRect = mRectBuffer[0]; holeRect.left = center.x - innerRadius; holeRect.top = center.y - innerRadius; holeRect.right = center.x + innerRadius; holeRect.bottom = center.y + innerRadius; RectF boundingRect = mRectBuffer[1]; boundingRect.set(holeRect); float radiusPercent = mChart.getCenterTextRadiusPercent(); if (radiusPercent > 0.0) { boundingRect.inset( (boundingRect.width() - boundingRect.width() * radiusPercent) / 2.f, (boundingRect.height() - boundingRect.height() * radiusPercent) / 2.f); } if (!centerText.equals(mCenterTextLastValue) || !boundingRect.equals(mCenterTextLastBounds)) { // Next time we won't recalculate StaticLayout... mCenterTextLastBounds.set(boundingRect); mCenterTextLastValue = centerText; float width = mCenterTextLastBounds.width(); // If width is 0, it will crash. Always have a minimum of 1 mCenterTextLayout = new StaticLayout( centerText, 0, centerText.length(), mCenterTextPaint, (int) Math.max(Math.ceil(width), 1.f), Layout.Alignment.ALIGN_CENTER, 1.f, 0.f, false); } float layoutHeight = mCenterTextLayout.getHeight(); c.save(); c.translate( boundingRect.left, boundingRect.top + (boundingRect.height() - layoutHeight) / 2.f); mCenterTextLayout.draw(c); c.restore(); } }
/** * Adjust left and right edges by current crop window height and the given aspect ratio, both * right and left edges adjusts equally relative to center to keep aspect ratio to the height. */ private void adjustLeftRightByAspectRatio(RectF rect, RectF bounds, float aspectRatio) { rect.inset((rect.width() - rect.height() * aspectRatio) / 2, 0); if (rect.left < bounds.left) { rect.offset(bounds.left - rect.left, 0); } if (rect.right > bounds.right) { rect.offset(bounds.right - rect.right, 0); } }
/** * Adjust top and bottom edges by current crop window width and the given aspect ratio, both top * and bottom edges adjusts equally relative to center to keep aspect ratio to the width. */ private void adjustTopBottomByAspectRatio(RectF rect, RectF bounds, float aspectRatio) { rect.inset(0, (rect.height() - rect.width() / aspectRatio) / 2); if (rect.top < bounds.top) { rect.offset(0, bounds.top - rect.top); } if (rect.bottom > bounds.bottom) { rect.offset(0, bounds.bottom - rect.bottom); } }
/** * Adjusts the gradient used for the chart series to set the shader used in the paint. This is * only done if the line contains two colors and the bounds of the line has changed since it was * last set. * * @param bounds The bounds used to draw the chart */ protected void processBoundsChange(final RectF bounds) { if (mBounds == null || !mBounds.equals(bounds)) { mBounds = new RectF(bounds); mBoundsInset = new RectF(bounds); if (mSeriesItem.getInset() != null) { mBoundsInset.inset(mSeriesItem.getInset().x, mSeriesItem.getInset().y); } applyGradientToPaint(); } }
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mInnerRectF.set(0, 0, canvas.getWidth(), canvas.getHeight()); final int halfBorder = (int) (mStrokePaint.getStrokeWidth() / 2f + 0.5f); mInnerRectF.inset(halfBorder, halfBorder); canvas.drawArc(mInnerRectF, 0, 360, true, mBackgroundPaint); switch (mProgressFillType) { case FILL_TYPE_RADIAL: float sweepAngle = 360 * mProgress / mMax; canvas.drawArc(mInnerRectF, mStartAngle, sweepAngle, true, mProgressPaint); break; case FILL_TYPE_CENTER: float centerX = canvas.getWidth() / 2; float centerY = canvas.getHeight() / 2; float radius = (canvas.getWidth() / 2) * ((float) mProgress / mMax); canvas.drawCircle( centerX, centerY, radius + 0.5f - mStrokePaint.getStrokeWidth(), mProgressPaint); break; default: throw new IllegalArgumentException("Invalid Progress Fill = " + mProgressFillType); } if (!TextUtils.isEmpty(mText) && mShowText) { if (!TextUtils.isEmpty(mTypeface)) { Typeface typeface = sTypefaceCache.get(mTypeface); if (null == typeface && null != getResources()) { AssetManager assets = getResources().getAssets(); if (null != assets) { typeface = Typeface.createFromAsset(assets, mTypeface); sTypefaceCache.put(mTypeface, typeface); } } mTextPaint.setTypeface(typeface); } int xPos = canvas.getWidth() / 2; int yPos = (int) ((canvas.getHeight() / 2) - ((mTextPaint.descent() + mTextPaint.ascent()) / 2)); canvas.drawText(mText, xPos, yPos, mTextPaint); } if (null != mImage && mShowImage) { int drawableSize = mImage.getIntrinsicWidth(); mImageRect.set(0, 0, drawableSize, drawableSize); mImageRect.offset((getWidth() - drawableSize) / 2, (getHeight() - drawableSize) / 2); mImage.setBounds(mImageRect); mImage.draw(canvas); } if (mShowStroke) { canvas.drawOval(mInnerRectF, mStrokePaint); } }
// For each face, we create a HightlightView for it. private void handleFace(FaceDetector.Face f) { PointF midPoint = new PointF(); int r = ((int) (f.eyesDistance() * mScale)) * 2; f.getMidPoint(midPoint); midPoint.x *= mScale; midPoint.y *= mScale; int midX = (int) midPoint.x; int midY = (int) midPoint.y; HighlightView hv = new HighlightView(mImageView); int width = mBitmap.getWidth(); int height = mBitmap.getHeight(); Rect imageRect = new Rect(0, 0, width, height); RectF faceRect = new RectF(midX, midY, midX, midY); faceRect.inset(-r, -r); if (faceRect.left < 0) { faceRect.inset(-faceRect.left, -faceRect.left); } if (faceRect.top < 0) { faceRect.inset(-faceRect.top, -faceRect.top); } if (faceRect.right > imageRect.right) { faceRect.inset(faceRect.right - imageRect.right, faceRect.right - imageRect.right); } if (faceRect.bottom > imageRect.bottom) { faceRect.inset(faceRect.bottom - imageRect.bottom, faceRect.bottom - imageRect.bottom); } hv.setup(mImageMatrix, imageRect, faceRect, mCircleCrop, mAspectX != 0 && mAspectY != 0); mImageView.add(hv); }
private void drawBorder(Canvas canvas) { RectF rect = new RectF(getBounds()); rect.inset(borderThickness / 2, borderThickness / 2); if (shape instanceof OvalShape) { canvas.drawOval(rect, borderPaint); } else if (shape instanceof RoundRectShape) { canvas.drawRoundRect(rect, radius, radius, borderPaint); } else { canvas.drawRect(rect, borderPaint); } }
public final void draw(Canvas paramCanvas) { Rect localRect = getBounds(); int i = paramCanvas.save(); paramCanvas.rotate(this.mRotation, localRect.exactCenterX(), localRect.exactCenterY()); Ring localRing = this.mRing; RectF localRectF = localRing.mTempBounds; localRectF.set(localRect); localRectF.inset(localRing.mStrokeInset, localRing.mStrokeInset); float f1 = 360.0F * (localRing.mStartTrim + localRing.mRotation); float f2 = 360.0F * (localRing.mEndTrim + localRing.mRotation) - f1; localRing.mPaint.setColor(localRing.mCurrentColor); paramCanvas.drawArc(localRectF, f1, f2, false, localRing.mPaint); if (localRing.mShowArrow) { if (localRing.mArrow != null) { break label427; } localRing.mArrow = new Path(); localRing.mArrow.setFillType(Path.FillType.EVEN_ODD); } for (; ; ) { float f3 = (int) localRing.mStrokeInset / 2 * localRing.mArrowScale; float f4 = (float) (localRing.mRingCenterRadius * Math.cos(0.0D) + localRect.exactCenterX()); float f5 = (float) (localRing.mRingCenterRadius * Math.sin(0.0D) + localRect.exactCenterY()); localRing.mArrow.moveTo(0.0F, 0.0F); localRing.mArrow.lineTo(localRing.mArrowWidth * localRing.mArrowScale, 0.0F); localRing.mArrow.lineTo( localRing.mArrowWidth * localRing.mArrowScale / 2.0F, localRing.mArrowHeight * localRing.mArrowScale); localRing.mArrow.offset(f4 - f3, f5); localRing.mArrow.close(); localRing.mArrowPaint.setColor(localRing.mCurrentColor); paramCanvas.rotate(f1 + f2 - 5.0F, localRect.exactCenterX(), localRect.exactCenterY()); paramCanvas.drawPath(localRing.mArrow, localRing.mArrowPaint); if (localRing.mAlpha < 255) { localRing.mCirclePaint.setColor(localRing.mBackgroundColor); localRing.mCirclePaint.setAlpha(255 - localRing.mAlpha); paramCanvas.drawCircle( localRect.exactCenterX(), localRect.exactCenterY(), localRect.width() / 2, localRing.mCirclePaint); } paramCanvas.restoreToCount(i); return; label427: localRing.mArrow.reset(); } }
private void setup() { if (!mReady) { mSetupPending = true; return; } if (getWidth() == 0 && getHeight() == 0) { return; } if (mBitmap == null) { invalidate(); return; } // 给图片设置bitmapShader,到时花园时,画的便是这张图片 mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); mBitmapPaint.setAntiAlias(true); mBitmapPaint.setShader(mBitmapShader); mBorderPaint.setStyle(Paint.Style.STROKE); mBorderPaint.setAntiAlias(true); mBorderPaint.setColor(mBorderColor); mBorderPaint.setStrokeWidth(mBorderWidth); mFillPaint.setStyle(Paint.Style.FILL); mFillPaint.setAntiAlias(true); mFillPaint.setColor(mFillColor); mBitmapHeight = mBitmap.getHeight(); mBitmapWidth = mBitmap.getWidth(); mBorderRect.set(calculateBounds()); mBorderRadius = Math.min( (mBorderRect.height() - mBorderWidth) / 2.0f, (mBorderRect.width() - mBorderWidth) / 2.0f); mDrawableRect.set(mBorderRect); if (!mBorderOverlay && mBorderWidth > 0) { mDrawableRect.inset(mBorderWidth - 1.0f, mBorderWidth - 1.0f); } mDrawableRadius = Math.min(mDrawableRect.height() / 2.0f, mDrawableRect.width() / 2.0f); applyColorFilter(); updateShaderMatrix(); invalidate(); }
private void setup() { if (!ready) { setupPending = true; return; } if (getWidth() == 0 && getHeight() == 0) { return; } if (bitmap == null) { invalidate(); return; } bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); bitmapPaint.setAntiAlias(true); bitmapPaint.setShader(bitmapShader); borderPaint.setStyle(Paint.Style.STROKE); borderPaint.setAntiAlias(true); borderPaint.setColor(borderColor); borderPaint.setStrokeWidth(borderWidth); fillPaint.setStyle(Paint.Style.FILL); fillPaint.setAntiAlias(true); fillPaint.setColor(fillColor); bitmapHeight = bitmap.getHeight(); bitmapWidth = bitmap.getWidth(); borderRect.set(0, 0, getWidth(), getHeight()); borderRadius = Math.min( (borderRect.height() - borderWidth) / 2.0f, (borderRect.width() - borderWidth) / 2.0f); drawableRect.set(borderRect); if (!borderOverlay) { drawableRect.inset(borderWidth, borderWidth); } drawableRadius = Math.min(drawableRect.height() / 2.0f, drawableRect.width() / 2.0f); updateShaderMatrix(); invalidate(); }
/** * The size of the indicator is same as the content region of the {@link #mBgDrawable} minus half * the stroke size to accommodate the indicator. */ private void initIndicatorRect() { Drawable d = mBgDrawable; Rect bounds = d.getBounds(); d.getPadding(sTempRect); // Amount by which padding has to be scaled float paddingScaleX = ((float) bounds.width()) / d.getIntrinsicWidth(); float paddingScaleY = ((float) bounds.height()) / d.getIntrinsicHeight(); mIndicatorRect.set( bounds.left + sTempRect.left * paddingScaleX, bounds.top + sTempRect.top * paddingScaleY, bounds.right - sTempRect.right * paddingScaleX, bounds.bottom - sTempRect.bottom * paddingScaleY); float inset = mPaint.getStrokeWidth() / 2; mIndicatorRect.inset(inset, inset); mIndicatorRectDirty = false; }
/** Draw the progress spinner */ public void draw(Canvas c, Rect bounds) { mCirclePaint.setColor(mBackgroundColor); mCirclePaint.setAlpha(mAlpha); c.drawCircle(bounds.exactCenterX(), bounds.exactCenterY(), bounds.width() / 2, mCirclePaint); final RectF arcBounds = mTempBounds; arcBounds.set(bounds); arcBounds.inset(mStrokeInset, mStrokeInset); final float startAngle = (mStartTrim + mRotation) * 360; final float endAngle = (mEndTrim + mRotation) * 360; float sweepAngle = endAngle - startAngle; mArcPaint.setColor(mColors[mColorIndex]); mArcPaint.setAlpha(mAlpha); c.drawArc(arcBounds, startAngle, sweepAngle, false, mArcPaint); drawTriangle(c, startAngle, sweepAngle, bounds); }
private void buildShadowCorners() { RectF innerBounds = new RectF(-mCornerRadius, -mCornerRadius, mCornerRadius, mCornerRadius); RectF outerBounds = new RectF(innerBounds); outerBounds.inset(-mShadowSize, -mShadowSize); if (mCornerShadowPath == null) { mCornerShadowPath = new Path(); } else { mCornerShadowPath.reset(); } mCornerShadowPath.setFillType(Path.FillType.EVEN_ODD); mCornerShadowPath.moveTo(-mCornerRadius, 0); mCornerShadowPath.rLineTo(-mShadowSize, 0); // outer arc mCornerShadowPath.arcTo(outerBounds, 180f, 90f, false); // inner arc mCornerShadowPath.arcTo(innerBounds, 270f, -90f, false); mCornerShadowPath.close(); float startRatio = mCornerRadius / (mCornerRadius + mShadowSize); mCornerShadowPaint.setShader( new RadialGradient( 0, 0, mCornerRadius + mShadowSize, new int[] {mShadowStartColor, mShadowStartColor, mShadowEndColor}, new float[] {0f, startRatio, 1f}, Shader.TileMode.CLAMP)); // we offset the content shadowSize/2 pixels up to make it more realistic. // this is why edge shadow shader has some extra space // When drawing bottom edge shadow, we use that extra space. mEdgeShadowPaint.setShader( new LinearGradient( 0, -mCornerRadius + mShadowSize, 0, -mCornerRadius - mShadowSize, new int[] {mShadowStartColor, mShadowStartColor, mShadowEndColor}, new float[] {0f, .5f, 1f}, Shader.TileMode.CLAMP)); }
private Path createRiverPath(RectF arcBounds) { if (mRiverPath != null) { return mRiverPath; } mRiverPath = new Path(); RectF rectF = new RectF( arcBounds.centerX() - mRiverWidth / 2.0f, arcBounds.centerY() - mRiverHeight / 2.0f, arcBounds.centerX() + mRiverWidth / 2.0f, arcBounds.centerY() + mRiverHeight / 2.0f); rectF.inset(mStrokeWidth / 2.0f, mStrokeWidth / 2.0f); mRiverPath.addRect(rectF, Path.Direction.CW); return mRiverPath; }
private void drawArcs(Canvas c, int width, int height) { mPaint.setStrokeWidth(STROKE_WIDTH); // firstCircleDrawPoint is circle diameter + circle width float firstCircleDrawPoint = THICK_STROKE_WIDTH - STROKE_WIDTH / 2; RectF rect = new RectF( firstCircleDrawPoint, firstCircleDrawPoint, width - firstCircleDrawPoint, height - firstCircleDrawPoint); float degree = mPercentage * 360f; if (mInDrag) { mPaint.setStrokeWidth(THICK_STROKE_WIDTH); float sizeChange = -(THICK_STROKE_WIDTH - STROKE_WIDTH) / 2; rect.inset(sizeChange, sizeChange); } mPaint.setStyle(Paint.Style.STROKE); mPaint.setColor(mPrimaryColor); c.drawArc(rect, -90f, degree, false, mPaint); }
private void setup() { if (!mReady) { mSetupPending = true; return; } if (mBitmap == null) { return; } mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); mBitmapPaint.setAntiAlias(true); mBitmapPaint.setShader(mBitmapShader); mBorderPaint.setStyle(Paint.Style.STROKE); mBorderPaint.setAntiAlias(true); mBorderPaint.setColor(mBorderColor); mBorderPaint.setStrokeWidth(mBorderWidth); mBitmapHeight = mBitmap.getHeight(); mBitmapWidth = mBitmap.getWidth(); mBorderRect.set(0, 0, getWidth(), getHeight()); mBorderRadius = Math.min( (mBorderRect.height() - mBorderWidth) / 2, (mBorderRect.width() - mBorderWidth) / 2); mDrawableRect.set(mBorderRect); if (!mBorderOverlay) { mDrawableRect.inset(mBorderWidth, mBorderWidth); } mDrawableRadius = Math.min(mDrawableRect.height() / 2, mDrawableRect.width() / 2); updateShaderMatrix(); invalidate(); }
private void updatePath() { if (!mNeedUpdatePathForBorderRadius) { return; } mNeedUpdatePathForBorderRadius = false; if (mPathForBorderRadius == null) { mPathForBorderRadius = new Path(); mTempRectForBorderRadius = new RectF(); mPathForBorderRadiusOutline = new Path(); mTempRectForBorderRadiusOutline = new RectF(); } mPathForBorderRadius.reset(); mPathForBorderRadiusOutline.reset(); mTempRectForBorderRadius.set(getBounds()); mTempRectForBorderRadiusOutline.set(getBounds()); float fullBorderWidth = getFullBorderWidth(); if (fullBorderWidth > 0) { mTempRectForBorderRadius.inset(fullBorderWidth * 0.5f, fullBorderWidth * 0.5f); } float defaultBorderRadius = !CSSConstants.isUndefined(mBorderRadius) ? mBorderRadius : 0; float topLeftRadius = mBorderCornerRadii != null && !CSSConstants.isUndefined(mBorderCornerRadii[0]) ? mBorderCornerRadii[0] : defaultBorderRadius; float topRightRadius = mBorderCornerRadii != null && !CSSConstants.isUndefined(mBorderCornerRadii[1]) ? mBorderCornerRadii[1] : defaultBorderRadius; float bottomRightRadius = mBorderCornerRadii != null && !CSSConstants.isUndefined(mBorderCornerRadii[2]) ? mBorderCornerRadii[2] : defaultBorderRadius; float bottomLeftRadius = mBorderCornerRadii != null && !CSSConstants.isUndefined(mBorderCornerRadii[3]) ? mBorderCornerRadii[3] : defaultBorderRadius; mPathForBorderRadius.addRoundRect( mTempRectForBorderRadius, new float[] { topLeftRadius, topLeftRadius, topRightRadius, topRightRadius, bottomRightRadius, bottomRightRadius, bottomLeftRadius, bottomLeftRadius }, Path.Direction.CW); float extraRadiusForOutline = 0; if (mBorderWidth != null) { extraRadiusForOutline = mBorderWidth.get(Spacing.ALL) / 2f; } mPathForBorderRadiusOutline.addRoundRect( mTempRectForBorderRadiusOutline, new float[] { topLeftRadius + extraRadiusForOutline, topLeftRadius + extraRadiusForOutline, topRightRadius + extraRadiusForOutline, topRightRadius + extraRadiusForOutline, bottomRightRadius + extraRadiusForOutline, bottomRightRadius + extraRadiusForOutline, bottomLeftRadius + extraRadiusForOutline, bottomLeftRadius + extraRadiusForOutline }, Path.Direction.CW); }
void c(float paramFloat1, float paramFloat2) { boolean bool = ImageViewTouchBase.a; if (this.h) if (paramFloat1 != 0.0F) { paramFloat2 = paramFloat1 / this.i; if (bool) App.wc = 1 + App.wc; } else if (paramFloat2 != 0.0F) { paramFloat1 = paramFloat2 * this.i; } RectF localRectF = new RectF(this.f); float f1; if ((paramFloat1 > 0.0F) && (localRectF.width() + 2.0F * paramFloat1 > this.e.width())) { paramFloat1 = (this.e.width() - localRectF.width()) / 2.0F; if (this.h) f1 = paramFloat1 / this.i; } for (float f2 = paramFloat1; ; f2 = paramFloat1) { if ((f1 > 0.0F) && (localRectF.height() + 2.0F * f1 > this.e.height())) { f1 = (this.e.height() - localRectF.height()) / 2.0F; if (this.h) f2 = f1 * this.i; } if (this.k > 0) { if (localRectF.width() + 2.0F * f2 < this.k) f2 = (this.k - localRectF.width()) / 2.0F; if (this.h) f1 = f2 / this.i; if (localRectF.height() + 2.0F * f1 < this.k) f1 = (this.k - localRectF.height()) / 2.0F; if (this.h) f2 = f1 * this.i; } localRectF.inset(-f2, -f1); if (localRectF.width() < 25.0F) localRectF.inset(-(25.0F - localRectF.width()) / 2.0F, 0.0F); if (this.h); for (float f3 = 25.0F / this.i; ; f3 = 25.0F) { if (localRectF.height() < f3) localRectF.inset(0.0F, -(f3 - localRectF.height()) / 2.0F); if (localRectF.left < this.e.left) { localRectF.offset(this.e.left - localRectF.left, 0.0F); if (!bool); } else if (localRectF.right > this.e.right) { localRectF.offset(-(localRectF.right - this.e.right), 0.0F); } if (localRectF.top < this.e.top) { localRectF.offset(0.0F, this.e.top - localRectF.top); if (!bool); } else if (localRectF.bottom > this.e.bottom) { localRectF.offset(0.0F, -(localRectF.bottom - this.e.bottom)); } this.f.set(localRectF); this.d = d(); this.a.invalidate(); return; } f1 = paramFloat2; } }
@Override protected void onDraw(Canvas canvas) { int selectedIndex = getSelectedIndicatorIndex(); // Draw the highlight arc if an indicator is selected or being pressed. // And skip the zoom control which index is zero. if (selectedIndex >= 1) { int degree = (int) Math.toDegrees(mChildRadians[selectedIndex]); float innerR = (float) mShutterButtonRadius; float outerR = (float) (mShutterButtonRadius + mStrokeWidth + EDGE_STROKE_WIDTH * 0.5); // Construct the path of the fan-shaped semi-transparent area. Path fanPath = new Path(); mBackgroundRect.set( mCenterX - innerR, mCenterY - innerR, mCenterX + innerR, mCenterY + innerR); fanPath.arcTo(mBackgroundRect, -degree + HIGHLIGHT_DEGREES / 2, -HIGHLIGHT_DEGREES); mBackgroundRect.set( mCenterX - outerR, mCenterY - outerR, mCenterX + outerR, mCenterY + outerR); fanPath.arcTo(mBackgroundRect, -degree - HIGHLIGHT_DEGREES / 2, HIGHLIGHT_DEGREES); fanPath.close(); mBackgroundPaint.setStrokeWidth(HIGHLIGHT_WIDTH); mBackgroundPaint.setStrokeCap(Paint.Cap.SQUARE); mBackgroundPaint.setStyle(Paint.Style.FILL_AND_STROKE); mBackgroundPaint.setColor(HIGHLIGHT_FAN_COLOR); if (FeatureOption.MTK_THEMEMANAGER_APP) { int bgColor = res.getThemeMainColor(); if (bgColor != 0) { bgColor &= 0x3FFFFFFF; mBackgroundPaint.setColor(bgColor); } } canvas.drawPath(fanPath, mBackgroundPaint); // Draw the highlight edge mBackgroundPaint.setStyle(Paint.Style.STROKE); mBackgroundPaint.setColor(HIGHLIGHT_COLOR); if (FeatureOption.MTK_THEMEMANAGER_APP) { int bgColor = res.getThemeMainColor(); if (bgColor != 0) { mBackgroundPaint.setColor(bgColor); } } canvas.drawArc( mBackgroundRect, -degree - HIGHLIGHT_DEGREES / 2, HIGHLIGHT_DEGREES, false, mBackgroundPaint); } // Draw arc shaped indicator in time lapse recording. if (mTimeLapseInterval != 0) { // Setup rectangle and paint. mBackgroundRect.set( (float) (mCenterX - mShutterButtonRadius), (float) (mCenterY - mShutterButtonRadius), (float) (mCenterX + mShutterButtonRadius), (float) (mCenterY + mShutterButtonRadius)); mBackgroundRect.inset(3f, 3f); mBackgroundPaint.setStrokeWidth(TIME_LAPSE_ARC_WIDTH); mBackgroundPaint.setStrokeCap(Paint.Cap.ROUND); mBackgroundPaint.setColor(TIME_LAPSE_ARC_COLOR); // Compute the start angle and sweep angle. long timeDelta = SystemClock.uptimeMillis() - mRecordingStartTime; long numberOfFrames = timeDelta / mTimeLapseInterval; float sweepAngle; if (numberOfFrames > mNumberOfFrames) { // The arc just acrosses 0 degree. Draw a full circle so it // looks better. sweepAngle = 360; mNumberOfFrames = numberOfFrames; } else { sweepAngle = timeDelta % mTimeLapseInterval * 360f / mTimeLapseInterval; } canvas.drawArc(mBackgroundRect, 0, sweepAngle, false, mBackgroundPaint); invalidate(); } super.onDraw(canvas); }
void c(float paramFloat1, float paramFloat2) { RectF localRectF; float f1; float f2; if (this.j) { if (paramFloat1 != 0.0F) paramFloat2 = paramFloat1 / this.k; } else { localRectF = new RectF(this.e); if ((paramFloat1 <= 0.0F) || (localRectF.width() + 2.0F * paramFloat1 <= this.i.width())) break label412; paramFloat1 = (this.i.width() - localRectF.width()) / 2.0F; if (!this.j) break label412; f1 = paramFloat1 / this.k; f2 = paramFloat1; } while (true) { if ((f1 > 0.0F) && (localRectF.height() + 2.0F * f1 > this.i.height())) { f1 = (this.i.height() - localRectF.height()) / 2.0F; if (this.j) f2 = f1 * this.k; } localRectF.inset(-f2, -f1); if (localRectF.width() < 25.0F) localRectF.inset(-(25.0F - localRectF.width()) / 2.0F, 0.0F); float f3; if (this.j) { f3 = 25.0F / this.k; label203: if (localRectF.height() < f3) localRectF.inset(0.0F, -(f3 - localRectF.height()) / 2.0F); if (localRectF.left >= this.i.left) break label340; localRectF.offset(this.i.left - localRectF.left, 0.0F); label260: if (localRectF.top >= this.i.top) break label376; localRectF.offset(0.0F, this.i.top - localRectF.top); } while (true) { this.e.set(localRectF); this.d = e(); this.a.invalidate(); return; if (paramFloat2 == 0.0F) break; paramFloat1 = paramFloat2 * this.k; break; f3 = 25.0F; break label203; label340: if (localRectF.right <= this.i.right) break label260; localRectF.offset(-(localRectF.right - this.i.right), 0.0F); break label260; label376: if (localRectF.bottom <= this.i.bottom) continue; localRectF.offset(0.0F, -(localRectF.bottom - this.i.bottom)); } label412: f1 = paramFloat2; f2 = paramFloat1; } }
/** * draws the description text in the center of the pie chart makes most sense when center-hole is * enabled */ protected void drawCenterText(Canvas c) { CharSequence centerText = mChart.getCenterText(); if (mChart.isDrawCenterTextEnabled() && centerText != null) { PointF center = mChart.getCenterCircleBox(); float innerRadius = mChart.isDrawHoleEnabled() ? mChart.getRadius() * (mChart.getHoleRadius() / 100f) : mChart.getRadius(); RectF holeRect = mRectBuffer[0]; holeRect.left = center.x - innerRadius; holeRect.top = center.y - innerRadius; holeRect.right = center.x + innerRadius; holeRect.bottom = center.y + innerRadius; RectF boundingRect = mRectBuffer[1]; boundingRect.set(holeRect); float radiusPercent = mChart.getCenterTextRadiusPercent() / 100f; if (radiusPercent > 0.0) { boundingRect.inset( (boundingRect.width() - boundingRect.width() * radiusPercent) / 2.f, (boundingRect.height() - boundingRect.height() * radiusPercent) / 2.f); } if (!centerText.equals(mCenterTextLastValue) || !boundingRect.equals(mCenterTextLastBounds)) { // Next time we won't recalculate StaticLayout... mCenterTextLastBounds.set(boundingRect); mCenterTextLastValue = centerText; float width = mCenterTextLastBounds.width(); // If width is 0, it will crash. Always have a minimum of 1 mCenterTextLayout = new StaticLayout( centerText, 0, centerText.length(), mCenterTextPaint, (int) Math.max(Math.ceil(width), 1.f), Layout.Alignment.ALIGN_CENTER, 1.f, 0.f, false); } // I wish we could make an ellipse clipping path on Android to clip to the hole... // If we ever find out how, this is the place to add it, based on holeRect // float layoutWidth = Utils.getStaticLayoutMaxWidth(mCenterTextLayout); float layoutHeight = mCenterTextLayout.getHeight(); c.save(); c.translate( boundingRect.left, boundingRect.top + (boundingRect.height() - layoutHeight) / 2.f); mCenterTextLayout.draw(c); c.restore(); // } // // else { // // // // get all lines from the text // String[] lines = centerText.toString().split("\n"); // // float maxlineheight = 0f; // // // calc the maximum line height // for (String line : lines) { // float curHeight = Utils.calcTextHeight(mCenterTextPaint, line); // if (curHeight > maxlineheight) // maxlineheight = curHeight; // } // // float linespacing = maxlineheight * 0.25f; // // float totalheight = maxlineheight * lines.length - linespacing * // (lines.length - 1); // // int cnt = lines.length; // // float y = center.y; // // for (int i = 0; i < lines.length; i++) { // // String line = lines[lines.length - i - 1]; // // // // c.drawText(line, center.x, y // + maxlineheight * cnt - totalheight / 2f, // mCenterTextPaint); // cnt--; // y -= linespacing; // } // } } }
public void drawTextOverCanvas(RenderingContext rc, Canvas cv, boolean useEnglishNames) { int size = rc.textToDraw.size(); // 1. Sort text using text order Collections.sort( rc.textToDraw, new Comparator<TextDrawInfo>() { @Override public int compare(TextDrawInfo object1, TextDrawInfo object2) { return object1.textOrder - object2.textOrder; } }); RectF r = new RectF(0, 0, rc.width, rc.height); r.inset(-100, -100); QuadTree<TextDrawInfo> nonIntersectedBounds = new QuadTree<TextDrawInfo>(r, 4, 0.6f); for (int i = 0; i < size; i++) { TextDrawInfo text = rc.textToDraw.get(i); if (text.text != null && text.text.length() > 0) { if (useEnglishNames) { text.text = Junidecode.unidecode(text.text); } // sest text size before finding intersection (it is used there) float textSize = rc.getDensityValue(text.textSize); paintText.setTextSize(textSize); paintText.setFakeBoldText(text.bold); paintText.setColor(text.textColor); // align center y text.centerY += (-paintText.ascent()); // calculate if there is intersection boolean intersects = findTextIntersection(cv, rc, nonIntersectedBounds, text); if (!intersects) { if (text.drawOnPath != null) { if (text.textShadow > 0) { paintText.setColor(Color.WHITE); paintText.setStyle(Style.STROKE); paintText.setStrokeWidth(2 + text.textShadow); cv.drawTextOnPath(text.text, text.drawOnPath, 0, text.vOffset, paintText); // reset paintText.setStyle(Style.FILL); paintText.setStrokeWidth(2); paintText.setColor(text.textColor); } cv.drawTextOnPath(text.text, text.drawOnPath, 0, text.vOffset, paintText); } else { if (text.shieldRes != null) { Bitmap ico = RenderingIcons.getIcon(context, text.shieldRes); if (ico != null) { if (rc.highResMode) { float left = text.centerX - rc.getDensityValue(ico.getWidth() / 2) - 0.5f; float top = text.centerY - rc.getDensityValue(ico.getHeight() / 2) - rc.getDensityValue(4.5f); Rect rec = new Rect(0, 0, ico.getWidth(), ico.getHeight()); cv.drawBitmap( ico, rec, new RectF( left, top, left + rc.getDensityValue(ico.getWidth()), top + rc.getDensityValue(ico.getHeight())), paintIcon); } else { float left = text.centerX - ico.getWidth() / 2 - 0.5f; float top = text.centerY - ico.getHeight() / 2 - rc.getDensityValue(4.5f); cv.drawBitmap(ico, left, top, paintIcon); } } } drawWrappedText(cv, text, textSize); } } } } }
private void updateShaderMatrix() { float scale; float dx; float dy; switch (mScaleType) { case CENTER: mBorderRect.set(mBounds); mBorderRect.inset((mBorderWidth) / 2, (mBorderWidth) / 2); mShaderMatrix.set(null); mShaderMatrix.setTranslate( (int) ((mBorderRect.width() - mBitmapWidth) * 0.5f + 0.5f), (int) ((mBorderRect.height() - mBitmapHeight) * 0.5f + 0.5f)); break; case CENTER_CROP: mBorderRect.set(mBounds); mBorderRect.inset((mBorderWidth) / 2, (mBorderWidth) / 2); mShaderMatrix.set(null); dx = 0; dy = 0; if (mBitmapWidth * mBorderRect.height() > mBorderRect.width() * mBitmapHeight) { scale = mBorderRect.height() / (float) mBitmapHeight; dx = (mBorderRect.width() - mBitmapWidth * scale) * 0.5f; } else { scale = mBorderRect.width() / (float) mBitmapWidth; dy = (mBorderRect.height() - mBitmapHeight * scale) * 0.5f; } mShaderMatrix.setScale(scale, scale); mShaderMatrix.postTranslate( (int) (dx + 0.5f) + mBorderWidth, (int) (dy + 0.5f) + mBorderWidth); break; case CENTER_INSIDE: mShaderMatrix.set(null); if (mBitmapWidth <= mBounds.width() && mBitmapHeight <= mBounds.height()) { scale = 1.0f; } else { scale = Math.min( mBounds.width() / (float) mBitmapWidth, mBounds.height() / (float) mBitmapHeight); } dx = (int) ((mBounds.width() - mBitmapWidth * scale) * 0.5f + 0.5f); dy = (int) ((mBounds.height() - mBitmapHeight * scale) * 0.5f + 0.5f); mShaderMatrix.setScale(scale, scale); mShaderMatrix.postTranslate(dx, dy); mBorderRect.set(mBitmapRect); mShaderMatrix.mapRect(mBorderRect); mBorderRect.inset((mBorderWidth) / 2, (mBorderWidth) / 2); mShaderMatrix.setRectToRect(mBitmapRect, mBorderRect, Matrix.ScaleToFit.FILL); break; default: case FIT_CENTER: mBorderRect.set(mBitmapRect); mShaderMatrix.setRectToRect(mBitmapRect, mBounds, Matrix.ScaleToFit.CENTER); mShaderMatrix.mapRect(mBorderRect); mBorderRect.inset((mBorderWidth) / 2, (mBorderWidth) / 2); mShaderMatrix.setRectToRect(mBitmapRect, mBorderRect, Matrix.ScaleToFit.FILL); break; case FIT_END: mBorderRect.set(mBitmapRect); mShaderMatrix.setRectToRect(mBitmapRect, mBounds, Matrix.ScaleToFit.END); mShaderMatrix.mapRect(mBorderRect); mBorderRect.inset((mBorderWidth) / 2, (mBorderWidth) / 2); mShaderMatrix.setRectToRect(mBitmapRect, mBorderRect, Matrix.ScaleToFit.FILL); break; case FIT_START: mBorderRect.set(mBitmapRect); mShaderMatrix.setRectToRect(mBitmapRect, mBounds, Matrix.ScaleToFit.START); mShaderMatrix.mapRect(mBorderRect); mBorderRect.inset((mBorderWidth) / 2, (mBorderWidth) / 2); mShaderMatrix.setRectToRect(mBitmapRect, mBorderRect, Matrix.ScaleToFit.FILL); break; case FIT_XY: mBorderRect.set(mBounds); mBorderRect.inset((mBorderWidth) / 2, (mBorderWidth) / 2); mShaderMatrix.set(null); mShaderMatrix.setRectToRect(mBitmapRect, mBorderRect, Matrix.ScaleToFit.FILL); break; } mDrawableRect.set(mBorderRect); mBitmapShader.setLocalMatrix(mShaderMatrix); }
private Intent createShortcutIntent(int position) { String url = getUrl(position); String title = getBookmarkTitle(position); Bitmap touchIcon = getTouchIcon(position); final Intent i = new Intent(); final Intent shortcutIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); long urlHash = url.hashCode(); long uniqueId = (urlHash << 32) | shortcutIntent.hashCode(); shortcutIntent.putExtra(Browser.EXTRA_APPLICATION_ID, Long.toString(uniqueId)); i.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent); i.putExtra(Intent.EXTRA_SHORTCUT_NAME, title); // Use the apple-touch-icon if available if (touchIcon != null) { // Make a copy so we can modify the pixels. We can't use // createScaledBitmap or copy since they will preserve the config // and lose the ability to add alpha. Bitmap bm = Bitmap.createBitmap(mIconSize, mIconSize, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bm); Rect src = new Rect(0, 0, touchIcon.getWidth(), touchIcon.getHeight()); Rect dest = new Rect(0, 0, bm.getWidth(), bm.getHeight()); // Paint used for scaling the bitmap and drawing the rounded rect. Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setFilterBitmap(true); canvas.drawBitmap(touchIcon, src, dest, paint); // Construct a path from a round rect. This will allow drawing with // an inverse fill so we can punch a hole using the round rect. Path path = new Path(); path.setFillType(Path.FillType.INVERSE_WINDING); RectF rect = new RectF(0, 0, bm.getWidth(), bm.getHeight()); rect.inset(1, 1); path.addRoundRect(rect, 8f, 8f, Path.Direction.CW); // Reuse the paint and clear the outside of the rectangle. paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); canvas.drawPath(path, paint); i.putExtra(Intent.EXTRA_SHORTCUT_ICON, bm); } else { Bitmap favicon = getFavicon(position); if (favicon == null) { i.putExtra( Intent.EXTRA_SHORTCUT_ICON_RESOURCE, Intent.ShortcutIconResource.fromContext( BrowserBookmarksPage.this, R.drawable.ic_launcher_shortcut_browser_bookmark)); } else { Bitmap icon = BitmapFactory.decodeResource( getResources(), R.drawable.ic_launcher_shortcut_browser_bookmark_icon); // Make a copy of the regular icon so we can modify the pixels. Bitmap copy = icon.copy(Bitmap.Config.ARGB_8888, true); Canvas canvas = new Canvas(copy); // Make a Paint for the white background rectangle and for // filtering the favicon. Paint p = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); p.setStyle(Paint.Style.FILL_AND_STROKE); p.setColor(Color.WHITE); final float density = getResources().getDisplayMetrics().density; // Create a rectangle that is slightly wider than the favicon final float iconSize = 16 * density; // 16x16 favicon final float padding = 2 * density; // white padding around icon final float rectSize = iconSize + 2 * padding; final Rect iconBounds = new Rect(0, 0, icon.getWidth(), icon.getHeight()); final float x = iconBounds.exactCenterX() - (rectSize / 2); // Note: Subtract 2 dip from the y position since the box is // slightly higher than center. Use padding since it is already // 2 * density. final float y = iconBounds.exactCenterY() - (rectSize / 2) - padding; RectF r = new RectF(x, y, x + rectSize, y + rectSize); // Draw a white rounded rectangle behind the favicon canvas.drawRoundRect(r, 2, 2, p); // Draw the favicon in the same rectangle as the rounded // rectangle but inset by the padding // (results in a 16x16 favicon). r.inset(padding, padding); canvas.drawBitmap(favicon, null, r, p); i.putExtra(Intent.EXTRA_SHORTCUT_ICON, copy); } } // Do not allow duplicate items i.putExtra("duplicate", false); return i; }