1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.graphics.drawable;
18
19import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
20
21import android.graphics.Path;
22import android.graphics.drawable.GradientDrawable.GradientState;
23
24import java.lang.reflect.Field;
25
26/**
27 * Delegate implementing the native methods of {@link GradientDrawable}
28 *
29 * Through the layoutlib_create tool, the original native methods of GradientDrawable have been
30 * replaced by calls to methods of the same name in this delegate class.
31 */
32public class GradientDrawable_Delegate {
33
34    /**
35     * The ring can be built either by drawing full circles, or by drawing arcs in case the
36     * circle isn't complete. LayoutLib cannot handle drawing full circles (requires path
37     * subtraction). So, if we need to draw full circles, we switch to drawing 99% circle.
38     */
39    @LayoutlibDelegate
40    /*package*/ static Path buildRing(GradientDrawable thisDrawable, GradientState st) {
41        boolean useLevel = st.mUseLevelForShape;
42        int level = thisDrawable.getLevel();
43        // 10000 is the max level. See android.graphics.drawable.Drawable#getLevel()
44        float sweep = useLevel ? (360.0f * level / 10000.0f) : 360f;
45        Field mLevel = null;
46        if (sweep >= 360 || sweep <= -360) {
47            st.mUseLevelForShape = true;
48            // Use reflection to set the value of the field to prevent setting the drawable to
49            // dirty again.
50            try {
51                mLevel = Drawable.class.getDeclaredField("mLevel");
52                mLevel.setAccessible(true);
53                mLevel.setInt(thisDrawable, 9999);  // set to one less than max.
54            } catch (NoSuchFieldException e) {
55                // The field has been removed in a recent framework change. Fall back to old
56                // buggy behaviour.
57            } catch (IllegalAccessException e) {
58                // We've already set the field to be accessible.
59                assert false;
60            }
61        }
62        Path path = thisDrawable.buildRing_Original(st);
63        st.mUseLevelForShape = useLevel;
64        if (mLevel != null) {
65            try {
66                mLevel.setInt(thisDrawable, level);
67            } catch (IllegalAccessException e) {
68                assert false;
69            }
70        }
71        return path;
72    }
73}
74