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.support.v7.widget;
18
19import android.content.res.ColorStateList;
20import android.content.res.TypedArray;
21import android.graphics.PorterDuff;
22import android.graphics.drawable.Drawable;
23import android.os.Build;
24import android.support.annotation.Nullable;
25import android.support.v4.graphics.drawable.DrawableCompat;
26import android.support.v4.widget.CompoundButtonCompat;
27import android.support.v7.appcompat.R;
28import android.support.v7.content.res.AppCompatResources;
29import android.util.AttributeSet;
30import android.widget.CompoundButton;
31
32class AppCompatCompoundButtonHelper {
33
34    private final CompoundButton mView;
35
36    private ColorStateList mButtonTintList = null;
37    private PorterDuff.Mode mButtonTintMode = null;
38    private boolean mHasButtonTint = false;
39    private boolean mHasButtonTintMode = false;
40
41    private boolean mSkipNextApply;
42
43    /**
44     * Interface which allows us to directly set a button, bypass any calls back to ourselves.
45     */
46    interface DirectSetButtonDrawableInterface {
47        void setButtonDrawable(Drawable buttonDrawable);
48    }
49
50    AppCompatCompoundButtonHelper(CompoundButton view) {
51        mView = view;
52    }
53
54    void loadFromAttributes(AttributeSet attrs, int defStyleAttr) {
55        TypedArray a = mView.getContext().obtainStyledAttributes(attrs, R.styleable.CompoundButton,
56                defStyleAttr, 0);
57        try {
58            if (a.hasValue(R.styleable.CompoundButton_android_button)) {
59                final int resourceId = a.getResourceId(
60                        R.styleable.CompoundButton_android_button, 0);
61                if (resourceId != 0) {
62                    mView.setButtonDrawable(
63                            AppCompatResources.getDrawable(mView.getContext(), resourceId));
64                }
65            }
66            if (a.hasValue(R.styleable.CompoundButton_buttonTint)) {
67                CompoundButtonCompat.setButtonTintList(mView,
68                        a.getColorStateList(R.styleable.CompoundButton_buttonTint));
69            }
70            if (a.hasValue(R.styleable.CompoundButton_buttonTintMode)) {
71                CompoundButtonCompat.setButtonTintMode(mView,
72                        DrawableUtils.parseTintMode(
73                                a.getInt(R.styleable.CompoundButton_buttonTintMode, -1),
74                                null));
75            }
76        } finally {
77            a.recycle();
78        }
79    }
80
81    void setSupportButtonTintList(ColorStateList tint) {
82        mButtonTintList = tint;
83        mHasButtonTint = true;
84
85        applyButtonTint();
86    }
87
88    ColorStateList getSupportButtonTintList() {
89        return mButtonTintList;
90    }
91
92    void setSupportButtonTintMode(@Nullable PorterDuff.Mode tintMode) {
93        mButtonTintMode = tintMode;
94        mHasButtonTintMode = true;
95
96        applyButtonTint();
97    }
98
99    PorterDuff.Mode getSupportButtonTintMode() {
100        return mButtonTintMode;
101    }
102
103    void onSetButtonDrawable() {
104        if (mSkipNextApply) {
105            mSkipNextApply = false;
106            return;
107        }
108
109        mSkipNextApply = true;
110        applyButtonTint();
111    }
112
113    void applyButtonTint() {
114        Drawable buttonDrawable = CompoundButtonCompat.getButtonDrawable(mView);
115
116        if (buttonDrawable != null && (mHasButtonTint || mHasButtonTintMode)) {
117            buttonDrawable = DrawableCompat.wrap(buttonDrawable);
118            buttonDrawable = buttonDrawable.mutate();
119            if (mHasButtonTint) {
120                DrawableCompat.setTintList(buttonDrawable, mButtonTintList);
121            }
122            if (mHasButtonTintMode) {
123                DrawableCompat.setTintMode(buttonDrawable, mButtonTintMode);
124            }
125            // The drawable (or one of its children) may not have been
126            // stateful before applying the tint, so let's try again.
127            if (buttonDrawable.isStateful()) {
128                buttonDrawable.setState(mView.getDrawableState());
129            }
130            mView.setButtonDrawable(buttonDrawable);
131        }
132    }
133
134    int getCompoundPaddingLeft(int superValue) {
135        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
136            // Before JB-MR1 the button drawable wasn't taken into account for padding. We'll
137            // workaround that here
138            Drawable buttonDrawable = CompoundButtonCompat.getButtonDrawable(mView);
139            if (buttonDrawable != null) {
140                superValue += buttonDrawable.getIntrinsicWidth();
141            }
142        }
143        return superValue;
144    }
145}
146