1ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei/* 2ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * Copyright (C) 2014 The Android Open Source Project 3ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * 4ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * Licensed under the Apache License, Version 2.0 (the "License"); 5ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * you may not use this file except in compliance with the License. 6ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * You may obtain a copy of the License at 7ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * 8ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * http://www.apache.org/licenses/LICENSE-2.0 9ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * 10ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * Unless required by applicable law or agreed to in writing, software 11ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * distributed under the License is distributed on an "AS IS" BASIS, 12ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * See the License for the specific language governing permissions and 14ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * limitations under the License. 15ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei */ 16ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 17ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Weipackage com.android.bitmap.drawable; 18ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 19ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Weiimport android.content.res.Resources; 20ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Weiimport android.graphics.Canvas; 21ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Weiimport android.graphics.Color; 22ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Weiimport android.graphics.Paint; 23ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Weiimport android.graphics.Paint.Style; 24ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Weiimport android.graphics.Path; 25ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Weiimport android.graphics.Rect; 26ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Weiimport android.graphics.RectF; 27c5644927c0e7e121049b063046296ee8a59a4b37Mark Weiimport android.util.Log; 28856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Weiimport android.view.View; 29ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 30ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Weiimport com.android.bitmap.BitmapCache; 31ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 32ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei/** 33ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * A custom ExtendedBitmapDrawable that styles the corners in configurable ways. 34ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * 35ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * All four corners can be configured as {@link #CORNER_STYLE_SHARP}, 36ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * {@link #CORNER_STYLE_ROUND}, or {@link #CORNER_STYLE_FLAP}. 37ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * This is accomplished applying a non-rectangular clip applied to the canvas. 38ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * 39ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * A border is draw that conforms to the styled corners. 40ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * 41ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * {@link #CORNER_STYLE_FLAP} corners have a colored flap drawn within the bounds. 42ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei */ 43ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Weipublic class StyledCornersBitmapDrawable extends ExtendedBitmapDrawable { 44c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei private static final String TAG = StyledCornersBitmapDrawable.class.getSimpleName(); 45ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 46ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei public static final int CORNER_STYLE_SHARP = 0; 47ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei public static final int CORNER_STYLE_ROUND = 1; 48ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei public static final int CORNER_STYLE_FLAP = 2; 49ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 50ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei private static final int START_RIGHT = 0; 51ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei private static final int START_BOTTOM = 90; 52ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei private static final int START_LEFT = 180; 53ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei private static final int START_TOP = 270; 54ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei private static final int QUARTER_CIRCLE = 90; 55ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei private static final RectF sRectF = new RectF(); 56ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 57ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei private final Paint mFlapPaint = new Paint(); 58ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei private final Paint mBorderPaint = new Paint(); 59df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei private final Paint mCompatibilityModeBackgroundPaint = new Paint(); 60ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei private final Path mClipPath = new Path(); 61df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei private final Path mCompatibilityModePath = new Path(); 62ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei private final float mCornerRoundRadius; 63ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei private final float mCornerFlapSide; 64ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 65ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei private int mTopLeftCornerStyle = CORNER_STYLE_SHARP; 66ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei private int mTopRightCornerStyle = CORNER_STYLE_SHARP; 67ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei private int mBottomRightCornerStyle = CORNER_STYLE_SHARP; 68ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei private int mBottomLeftCornerStyle = CORNER_STYLE_SHARP; 69856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei 70856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei private int mTopStartCornerStyle = CORNER_STYLE_SHARP; 71856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei private int mTopEndCornerStyle = CORNER_STYLE_SHARP; 72856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei private int mBottomEndCornerStyle = CORNER_STYLE_SHARP; 73856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei private int mBottomStartCornerStyle = CORNER_STYLE_SHARP; 74856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei 75ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei private int mScrimColor; 76ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei private float mBorderWidth; 77df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei private boolean mIsCompatibilityMode; 78c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei private boolean mEatInvalidates; 79ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 80ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei /** 81ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * Create a new StyledCornersBitmapDrawable. 82ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei */ 83ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei public StyledCornersBitmapDrawable(Resources res, BitmapCache cache, 84ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei boolean limitDensity, ExtendedOptions opts, float cornerRoundRadius, 85ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei float cornerFlapSide) { 86ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei super(res, cache, limitDensity, opts); 87ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 88ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mCornerRoundRadius = cornerRoundRadius; 89ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mCornerFlapSide = cornerFlapSide; 90ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 91ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mFlapPaint.setColor(Color.TRANSPARENT); 92ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mFlapPaint.setStyle(Style.FILL); 93df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mFlapPaint.setAntiAlias(true); 94ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 95ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBorderPaint.setColor(Color.TRANSPARENT); 96ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBorderPaint.setStyle(Style.STROKE); 97ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBorderPaint.setStrokeWidth(mBorderWidth); 98ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBorderPaint.setAntiAlias(true); 99ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 100df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModeBackgroundPaint.setColor(Color.TRANSPARENT); 101df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModeBackgroundPaint.setStyle(Style.FILL); 102df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModeBackgroundPaint.setAntiAlias(true); 103df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei 104ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mScrimColor = Color.TRANSPARENT; 105ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 106ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 107ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei /** 108ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * Set the border stroke width of this drawable. 109ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei */ 110ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei public void setBorderWidth(final float borderWidth) { 111ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei final boolean changed = mBorderPaint.getStrokeWidth() != borderWidth; 112ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBorderPaint.setStrokeWidth(borderWidth); 113ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBorderWidth = borderWidth; 114ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 115ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei if (changed) { 116ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei invalidateSelf(); 117ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 118ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 119ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 120ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei /** 121ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * Set the border stroke color of this drawable. Set to {@link Color#TRANSPARENT} to disable. 122ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei */ 123ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei public void setBorderColor(final int color) { 124ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei final boolean changed = mBorderPaint.getColor() != color; 125ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBorderPaint.setColor(color); 126ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 127ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei if (changed) { 128ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei invalidateSelf(); 129ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 130ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 131ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 132856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei /** Set the corner styles for all four corners specified in RTL friendly ways */ 133856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei public void setCornerStylesRelative(int topStart, int topEnd, int bottomEnd, int bottomStart) { 134856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei mTopStartCornerStyle = topStart; 135856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei mTopEndCornerStyle = topEnd; 136856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei mBottomEndCornerStyle = bottomEnd; 137856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei mBottomStartCornerStyle = bottomStart; 138856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei resolveCornerStyles(); 139856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei } 140ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 141856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei @Override 142856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei public void onLayoutDirectionChangeLocal(int layoutDirection) { 143856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei resolveCornerStyles(); 144ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 145ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 146ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei /** 147df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei * Get the flap color for all corners that have style {@link #CORNER_STYLE_SHARP}. 148df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei */ 149df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei public int getFlapColor() { 150df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei return mFlapPaint.getColor(); 151df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei } 152df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei 153df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei /** 154ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * Set the flap color for all corners that have style {@link #CORNER_STYLE_SHARP}. 155ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * 156ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * Use {@link android.graphics.Color#TRANSPARENT} to disable flap colors. 157ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei */ 158ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei public void setFlapColor(int flapColor) { 159ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei boolean changed = mFlapPaint.getColor() != flapColor; 160ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mFlapPaint.setColor(flapColor); 161ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 162ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei if (changed) { 163ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei invalidateSelf(); 164ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 165ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 166ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 167ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei /** 168ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * Get the color of the scrim that is drawn over the contents, but under the flaps and borders. 169ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei */ 170ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei public int getScrimColor() { 171ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei return mScrimColor; 172ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 173ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 174ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei /** 175ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * Set the color of the scrim that is drawn over the contents, but under the flaps and borders. 176ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * 177ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * Use {@link android.graphics.Color#TRANSPARENT} to disable the scrim. 178ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei */ 179ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei public void setScrimColor(int color) { 180ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei boolean changed = mScrimColor != color; 181ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mScrimColor = color; 182ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 183ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei if (changed) { 184ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei invalidateSelf(); 185ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 186ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 187ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 188df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei /** 189df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei * Sets whether we should work around an issue introduced in Android 4.4.3, 190df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei * where a WebView can corrupt the stencil buffer of the canvas when the canvas is clipped 191df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei * using a non-rectangular Path. 192df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei */ 193df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei public void setCompatibilityMode(boolean isCompatibilityMode) { 194df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei boolean changed = mIsCompatibilityMode != isCompatibilityMode; 195df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mIsCompatibilityMode = isCompatibilityMode; 196df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei 197df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei if (changed) { 198df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei invalidateSelf(); 199df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei } 200df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei } 201df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei 202df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei /** 203df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei * Sets the color of the container that this drawable is in. The given color will be used in 204df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei * {@link #setCompatibilityMode compatibility mode} to draw fake corners to emulate clipped 205df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei * corners. 206df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei */ 207df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei public void setCompatibilityModeBackgroundColor(int color) { 208df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei boolean changed = mCompatibilityModeBackgroundPaint.getColor() != color; 209df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModeBackgroundPaint.setColor(color); 210df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei 211df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei if (changed) { 212df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei invalidateSelf(); 213df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei } 214df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei } 215df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei 216ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei @Override 217ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei protected void onBoundsChange(Rect bounds) { 218ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei super.onBoundsChange(bounds); 219ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 220ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei recalculatePath(); 221ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 222ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 223ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei /** 224ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * Override draw(android.graphics.Canvas) instead of 225ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * {@link #onDraw(android.graphics.Canvas)} to clip all the drawable layers. 226ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei */ 227ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei @Override 228ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei public void draw(Canvas canvas) { 229ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei final Rect bounds = getBounds(); 230ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei if (bounds.isEmpty()) { 231ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei return; 232ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 233ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 234c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei pauseInvalidate(); 235c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei 236ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei // Clip to path. 237df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei if (!mIsCompatibilityMode) { 238df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei canvas.save(); 239df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei canvas.clipPath(mClipPath); 240df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei } 241ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 242ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei // Draw parent within path. 243ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei super.draw(canvas); 244ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 245ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei // Draw scrim on top of parent. 246ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei canvas.drawColor(mScrimColor); 247ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 248df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei // Draw flaps. 249ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei float left = bounds.left + mBorderWidth / 2; 250ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei float top = bounds.top + mBorderWidth / 2; 251ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei float right = bounds.right - mBorderWidth / 2; 252ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei float bottom = bounds.bottom - mBorderWidth / 2; 253ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei RectF flapCornerRectF = sRectF; 254ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei flapCornerRectF.set(0, 0, mCornerFlapSide + mCornerRoundRadius, 255ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mCornerFlapSide + mCornerRoundRadius); 256ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 257ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei if (mTopLeftCornerStyle == CORNER_STYLE_FLAP) { 258ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei flapCornerRectF.offsetTo(left, top); 259ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei canvas.drawRoundRect(flapCornerRectF, mCornerRoundRadius, 260ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mCornerRoundRadius, mFlapPaint); 261ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 262ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei if (mTopRightCornerStyle == CORNER_STYLE_FLAP) { 263ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei flapCornerRectF.offsetTo(right - mCornerFlapSide, top); 264ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei canvas.drawRoundRect(flapCornerRectF, mCornerRoundRadius, 265ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mCornerRoundRadius, mFlapPaint); 266ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 267ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei if (mBottomRightCornerStyle == CORNER_STYLE_FLAP) { 268ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei flapCornerRectF.offsetTo(right - mCornerFlapSide, bottom - mCornerFlapSide); 269ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei canvas.drawRoundRect(flapCornerRectF, mCornerRoundRadius, 270ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mCornerRoundRadius, mFlapPaint); 271ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 272ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei if (mBottomLeftCornerStyle == CORNER_STYLE_FLAP) { 273ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei flapCornerRectF.offsetTo(left, bottom - mCornerFlapSide); 274ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei canvas.drawRoundRect(flapCornerRectF, mCornerRoundRadius, 275ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mCornerRoundRadius, mFlapPaint); 276ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 277ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 278df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei if (!mIsCompatibilityMode) { 279df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei canvas.restore(); 280df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei } 281df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei 282df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei if (mIsCompatibilityMode) { 283df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei drawFakeCornersForCompatibilityMode(canvas); 284df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei } 285ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 286ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei // Draw border around path. 287ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei canvas.drawPath(mClipPath, mBorderPaint); 288c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei 289c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei resumeInvalidate(); 290c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei } 291c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei 292c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei @Override 293c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei public void invalidateSelf() { 294c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei if (!mEatInvalidates) { 295c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei super.invalidateSelf(); 296c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei } else { 297c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei Log.d(TAG, "Skipping invalidate."); 298c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei } 299ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 300ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 301df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei protected void drawFakeCornersForCompatibilityMode(final Canvas canvas) { 302df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei final Rect bounds = getBounds(); 303df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei 304df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei float left = bounds.left; 305df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei float top = bounds.top; 306df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei float right = bounds.right; 307df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei float bottom = bounds.bottom; 308df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei 309df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei // Draw fake round corners. 310df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei RectF fakeCornerRectF = sRectF; 311df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei fakeCornerRectF.set(0, 0, mCornerRoundRadius * 2, mCornerRoundRadius * 2); 312df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei if (mTopLeftCornerStyle == CORNER_STYLE_ROUND) { 313df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei fakeCornerRectF.offsetTo(left, top); 314df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModePath.rewind(); 315df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModePath.moveTo(left, top); 316df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModePath.lineTo(left + mCornerRoundRadius, top); 317df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModePath.arcTo(fakeCornerRectF, START_TOP, -QUARTER_CIRCLE); 318df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModePath.close(); 319df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei canvas.drawPath(mCompatibilityModePath, mCompatibilityModeBackgroundPaint); 320df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei } 321df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei if (mTopRightCornerStyle == CORNER_STYLE_ROUND) { 322df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei fakeCornerRectF.offsetTo(right - fakeCornerRectF.width(), top); 323df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModePath.rewind(); 324df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModePath.moveTo(right, top); 325df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModePath.lineTo(right, top + mCornerRoundRadius); 326df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModePath.arcTo(fakeCornerRectF, START_RIGHT, -QUARTER_CIRCLE); 327df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModePath.close(); 328df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei canvas.drawPath(mCompatibilityModePath, mCompatibilityModeBackgroundPaint); 329df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei } 330df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei if (mBottomRightCornerStyle == CORNER_STYLE_ROUND) { 331df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei fakeCornerRectF 332df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei .offsetTo(right - fakeCornerRectF.width(), bottom - fakeCornerRectF.height()); 333df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModePath.rewind(); 334df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModePath.moveTo(right, bottom); 335df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModePath.lineTo(right - mCornerRoundRadius, bottom); 336df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModePath.arcTo(fakeCornerRectF, START_BOTTOM, -QUARTER_CIRCLE); 337df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModePath.close(); 338df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei canvas.drawPath(mCompatibilityModePath, mCompatibilityModeBackgroundPaint); 339df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei } 340df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei if (mBottomLeftCornerStyle == CORNER_STYLE_ROUND) { 341df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei fakeCornerRectF.offsetTo(left, bottom - fakeCornerRectF.height()); 342df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModePath.rewind(); 343df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModePath.moveTo(left, bottom); 344df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModePath.lineTo(left, bottom - mCornerRoundRadius); 345df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModePath.arcTo(fakeCornerRectF, START_LEFT, -QUARTER_CIRCLE); 346df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModePath.close(); 347df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei canvas.drawPath(mCompatibilityModePath, mCompatibilityModeBackgroundPaint); 348df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei } 349df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei 350df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei // Draw fake flap corners. 351df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei if (mTopLeftCornerStyle == CORNER_STYLE_FLAP) { 352df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModePath.rewind(); 353df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModePath.moveTo(left, top); 354df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModePath.lineTo(left + mCornerFlapSide, top); 355df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModePath.lineTo(left, top + mCornerFlapSide); 356df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModePath.close(); 357df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei canvas.drawPath(mCompatibilityModePath, mCompatibilityModeBackgroundPaint); 358df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei } 359df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei if (mTopRightCornerStyle == CORNER_STYLE_FLAP) { 360df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModePath.rewind(); 361df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModePath.moveTo(right, top); 362df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModePath.lineTo(right, top + mCornerFlapSide); 363df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModePath.lineTo(right - mCornerFlapSide, top); 364df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModePath.close(); 365df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei canvas.drawPath(mCompatibilityModePath, mCompatibilityModeBackgroundPaint); 366df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei } 367df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei if (mBottomRightCornerStyle == CORNER_STYLE_FLAP) { 368df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModePath.rewind(); 369df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModePath.moveTo(right, bottom); 370df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModePath.lineTo(right - mCornerFlapSide, bottom); 371df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModePath.lineTo(right, bottom - mCornerFlapSide); 372df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModePath.close(); 373df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei canvas.drawPath(mCompatibilityModePath, mCompatibilityModeBackgroundPaint); 374df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei } 375df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei if (mBottomLeftCornerStyle == CORNER_STYLE_FLAP) { 376df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModePath.rewind(); 377df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModePath.moveTo(left, bottom); 378df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModePath.lineTo(left, bottom - mCornerFlapSide); 379df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModePath.lineTo(left + mCornerFlapSide, bottom); 380df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mCompatibilityModePath.close(); 381df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei canvas.drawPath(mCompatibilityModePath, mCompatibilityModeBackgroundPaint); 382df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei } 383ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 384ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 385c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei private void pauseInvalidate() { 386c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei mEatInvalidates = true; 387c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei } 388c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei 389c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei private void resumeInvalidate() { 390c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei mEatInvalidates = false; 391c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei } 392c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei 393ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei private void recalculatePath() { 394ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei Rect bounds = getBounds(); 395ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 396ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei if (bounds.isEmpty()) { 397ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei return; 398ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 399ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 400ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei // Setup. 401ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei float left = bounds.left + mBorderWidth / 2; 402ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei float top = bounds.top + mBorderWidth / 2; 403ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei float right = bounds.right - mBorderWidth / 2; 404ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei float bottom = bounds.bottom - mBorderWidth / 2; 405ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei RectF roundedCornerRectF = sRectF; 406ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei roundedCornerRectF.set(0, 0, 2 * mCornerRoundRadius, 2 * mCornerRoundRadius); 407ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mClipPath.rewind(); 408ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 409ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei switch (mTopLeftCornerStyle) { 410ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei case CORNER_STYLE_SHARP: 411ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mClipPath.moveTo(left, top); 412ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei break; 413ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei case CORNER_STYLE_ROUND: 414ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei roundedCornerRectF.offsetTo(left, top); 415ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mClipPath.arcTo(roundedCornerRectF, START_LEFT, QUARTER_CIRCLE); 416ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei break; 417ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei case CORNER_STYLE_FLAP: 418ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mClipPath.moveTo(left, top - mCornerFlapSide); 419ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mClipPath.lineTo(left + mCornerFlapSide, top); 420ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei break; 421ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 422ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 423ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei switch (mTopRightCornerStyle) { 424ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei case CORNER_STYLE_SHARP: 425ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mClipPath.lineTo(right, top); 426ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei break; 427ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei case CORNER_STYLE_ROUND: 428ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei roundedCornerRectF.offsetTo(right - roundedCornerRectF.width(), top); 429ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mClipPath.arcTo(roundedCornerRectF, START_TOP, QUARTER_CIRCLE); 430ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei break; 431ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei case CORNER_STYLE_FLAP: 432ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mClipPath.lineTo(right - mCornerFlapSide, top); 433ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mClipPath.lineTo(right, top + mCornerFlapSide); 434ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei break; 435ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 436ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 437ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei switch (mBottomRightCornerStyle) { 438ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei case CORNER_STYLE_SHARP: 439ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mClipPath.lineTo(right, bottom); 440ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei break; 441ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei case CORNER_STYLE_ROUND: 442ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei roundedCornerRectF.offsetTo(right - roundedCornerRectF.width(), 443ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei bottom - roundedCornerRectF.height()); 444ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mClipPath.arcTo(roundedCornerRectF, START_RIGHT, QUARTER_CIRCLE); 445ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei break; 446ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei case CORNER_STYLE_FLAP: 447ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mClipPath.lineTo(right, bottom - mCornerFlapSide); 448ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mClipPath.lineTo(right - mCornerFlapSide, bottom); 449ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei break; 450ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 451ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 452ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei switch (mBottomLeftCornerStyle) { 453ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei case CORNER_STYLE_SHARP: 454ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mClipPath.lineTo(left, bottom); 455ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei break; 456ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei case CORNER_STYLE_ROUND: 457ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei roundedCornerRectF.offsetTo(left, bottom - roundedCornerRectF.height()); 458ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mClipPath.arcTo(roundedCornerRectF, START_BOTTOM, QUARTER_CIRCLE); 459ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei break; 460ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei case CORNER_STYLE_FLAP: 461ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mClipPath.lineTo(left + mCornerFlapSide, bottom); 462ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mClipPath.lineTo(left, bottom - mCornerFlapSide); 463ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei break; 464ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 465ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 466ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei // Finish. 467ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mClipPath.close(); 468ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 469856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei 470856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei private void resolveCornerStyles() { 471856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei boolean isLtr = getLayoutDirectionLocal() == View.LAYOUT_DIRECTION_LTR; 472856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei setCornerStyles( 473856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei isLtr ? mTopStartCornerStyle : mTopEndCornerStyle, 474856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei isLtr ? mTopEndCornerStyle : mTopStartCornerStyle, 475856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei isLtr ? mBottomEndCornerStyle : mBottomStartCornerStyle, 476856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei isLtr ? mBottomStartCornerStyle : mBottomEndCornerStyle); 477856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei } 478856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei 479856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei /** Set the corner styles for all four corners */ 480856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei private void setCornerStyles(int topLeft, int topRight, int bottomRight, int bottomLeft) { 481856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei boolean changed = mTopLeftCornerStyle != topLeft 482856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei || mTopRightCornerStyle != topRight 483856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei || mBottomRightCornerStyle != bottomRight 484856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei || mBottomLeftCornerStyle != bottomLeft; 485856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei 486856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei mTopLeftCornerStyle = topLeft; 487856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei mTopRightCornerStyle = topRight; 488856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei mBottomRightCornerStyle = bottomRight; 489856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei mBottomLeftCornerStyle = bottomLeft; 490856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei 491856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei if (changed) { 492856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei recalculatePath(); 493856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei } 494856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei } 495ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei} 496