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