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