summaryrefslogtreecommitdiffstats
path: root/tools/layoutlib/bridge/src/android/graphics/drawable/GradientDrawable_Delegate.java
blob: a3ad2aac7d3df0b58acac02c4e280407da4a86b5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.graphics.drawable;

import com.android.tools.layoutlib.annotations.LayoutlibDelegate;

import android.graphics.Path;
import android.graphics.drawable.GradientDrawable.GradientState;

import java.lang.reflect.Field;

/**
 * Delegate implementing the native methods of {@link GradientDrawable}
 *
 * Through the layoutlib_create tool, the original native methods of GradientDrawable have been
 * replaced by calls to methods of the same name in this delegate class.
 */
public class GradientDrawable_Delegate {

    /**
     * The ring can be built either by drawing full circles, or by drawing arcs in case the
     * circle isn't complete. LayoutLib cannot handle drawing full circles (requires path
     * subtraction). So, if we need to draw full circles, we switch to drawing 99% circle.
     */
    @LayoutlibDelegate
    /*package*/ static Path buildRing(GradientDrawable thisDrawable, GradientState st) {
        boolean useLevel = st.mUseLevelForShape;
        int level = thisDrawable.getLevel();
        // 10000 is the max level. See android.graphics.drawable.Drawable#getLevel()
        float sweep = useLevel ? (360.0f * level / 10000.0f) : 360f;
        Field mLevel = null;
        if (sweep >= 360 || sweep <= -360) {
            st.mUseLevelForShape = true;
            // Use reflection to set the value of the field to prevent setting the drawable to
            // dirty again.
            try {
                mLevel = Drawable.class.getDeclaredField("mLevel");
                mLevel.setAccessible(true);
                mLevel.setInt(thisDrawable, 9999);  // set to one less than max.
            } catch (NoSuchFieldException e) {
                // The field has been removed in a recent framework change. Fall back to old
                // buggy behaviour.
            } catch (IllegalAccessException e) {
                // We've already set the field to be accessible.
                assert false;
            }
        }
        Path path = thisDrawable.buildRing_Original(st);
        st.mUseLevelForShape = useLevel;
        if (mLevel != null) {
            try {
                mLevel.setInt(thisDrawable, level);
            } catch (IllegalAccessException e) {
                assert false;
            }
        }
        return path;
    }
}