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