1091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes/*
2091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes * Copyright (C) 2015 The Android Open Source Project
3091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes *
4091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes * Licensed under the Apache License, Version 2.0 (the "License");
5091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes * you may not use this file except in compliance with the License.
6091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes * You may obtain a copy of the License at
7091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes *
8091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes *      http://www.apache.org/licenses/LICENSE-2.0
9091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes *
10091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes * Unless required by applicable law or agreed to in writing, software
11091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes * distributed under the License is distributed on an "AS IS" BASIS,
12091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes * See the License for the specific language governing permissions and
14091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes * limitations under the License.
15091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes */
16091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes
17091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banespackage android.support.v7.widget;
18091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes
19091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banesimport android.content.res.ColorStateList;
20091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banesimport android.content.res.TypedArray;
21091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banesimport android.graphics.PorterDuff;
22091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banesimport android.graphics.drawable.Drawable;
23091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banesimport android.os.Build;
24091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banesimport android.support.annotation.Nullable;
25091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banesimport android.support.v4.graphics.drawable.DrawableCompat;
26091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banesimport android.support.v4.widget.CompoundButtonCompat;
27091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banesimport android.support.v7.appcompat.R;
284c99f0e29b0926d8e5de44b7e3980d47f052f04cChris Banesimport android.support.v7.content.res.AppCompatResources;
29091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banesimport android.util.AttributeSet;
30091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banesimport android.widget.CompoundButton;
31091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes
32091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banesclass AppCompatCompoundButtonHelper {
33091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes
34091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes    private final CompoundButton mView;
35091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes
36091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes    private ColorStateList mButtonTintList = null;
37091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes    private PorterDuff.Mode mButtonTintMode = null;
38091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes    private boolean mHasButtonTint = false;
39091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes    private boolean mHasButtonTintMode = false;
40091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes
41091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes    private boolean mSkipNextApply;
42091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes
43091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes    /**
44091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes     * Interface which allows us to directly set a button, bypass any calls back to ourselves.
45091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes     */
46091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes    interface DirectSetButtonDrawableInterface {
47091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes        void setButtonDrawable(Drawable buttonDrawable);
48091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes    }
49091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes
504c99f0e29b0926d8e5de44b7e3980d47f052f04cChris Banes    AppCompatCompoundButtonHelper(CompoundButton view) {
51091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes        mView = view;
52091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes    }
53091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes
54091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes    void loadFromAttributes(AttributeSet attrs, int defStyleAttr) {
55091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes        TypedArray a = mView.getContext().obtainStyledAttributes(attrs, R.styleable.CompoundButton,
56091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes                defStyleAttr, 0);
57091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes        try {
58091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes            if (a.hasValue(R.styleable.CompoundButton_android_button)) {
59091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes                final int resourceId = a.getResourceId(
60091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes                        R.styleable.CompoundButton_android_button, 0);
61091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes                if (resourceId != 0) {
627e4e8b664820f773bc96e37ee1d2bbf500d64e69Chris Banes                    mView.setButtonDrawable(
634c99f0e29b0926d8e5de44b7e3980d47f052f04cChris Banes                            AppCompatResources.getDrawable(mView.getContext(), resourceId));
64091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes                }
65091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes            }
66091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes            if (a.hasValue(R.styleable.CompoundButton_buttonTint)) {
67091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes                CompoundButtonCompat.setButtonTintList(mView,
68091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes                        a.getColorStateList(R.styleable.CompoundButton_buttonTint));
69091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes            }
70091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes            if (a.hasValue(R.styleable.CompoundButton_buttonTintMode)) {
71091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes                CompoundButtonCompat.setButtonTintMode(mView,
72091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes                        DrawableUtils.parseTintMode(
73091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes                                a.getInt(R.styleable.CompoundButton_buttonTintMode, -1),
74091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes                                null));
75091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes            }
76091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes        } finally {
77091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes            a.recycle();
78091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes        }
79091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes    }
80091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes
81091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes    void setSupportButtonTintList(ColorStateList tint) {
82091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes        mButtonTintList = tint;
83091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes        mHasButtonTint = true;
84091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes
85091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes        applyButtonTint();
86091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes    }
87091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes
88091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes    ColorStateList getSupportButtonTintList() {
89091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes        return mButtonTintList;
90091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes    }
91091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes
92091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes    void setSupportButtonTintMode(@Nullable PorterDuff.Mode tintMode) {
93091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes        mButtonTintMode = tintMode;
94091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes        mHasButtonTintMode = true;
95091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes
96091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes        applyButtonTint();
97091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes    }
98091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes
99091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes    PorterDuff.Mode getSupportButtonTintMode() {
100091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes        return mButtonTintMode;
101091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes    }
102091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes
103091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes    void onSetButtonDrawable() {
104091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes        if (mSkipNextApply) {
105091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes            mSkipNextApply = false;
106091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes            return;
107091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes        }
108091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes
109091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes        mSkipNextApply = true;
110091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes        applyButtonTint();
111091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes    }
112091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes
113091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes    void applyButtonTint() {
114091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes        Drawable buttonDrawable = CompoundButtonCompat.getButtonDrawable(mView);
115091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes
116091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes        if (buttonDrawable != null && (mHasButtonTint || mHasButtonTintMode)) {
117091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes            buttonDrawable = DrawableCompat.wrap(buttonDrawable);
118091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes            buttonDrawable = buttonDrawable.mutate();
119091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes            if (mHasButtonTint) {
120091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes                DrawableCompat.setTintList(buttonDrawable, mButtonTintList);
121091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes            }
122091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes            if (mHasButtonTintMode) {
123091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes                DrawableCompat.setTintMode(buttonDrawable, mButtonTintMode);
124091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes            }
125091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes            // The drawable (or one of its children) may not have been
126091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes            // stateful before applying the tint, so let's try again.
127091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes            if (buttonDrawable.isStateful()) {
128091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes                buttonDrawable.setState(mView.getDrawableState());
129091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes            }
130091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes            mView.setButtonDrawable(buttonDrawable);
131091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes        }
132091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes    }
133091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes
134091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes    int getCompoundPaddingLeft(int superValue) {
135091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
136091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes            // Before JB-MR1 the button drawable wasn't taken into account for padding. We'll
137091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes            // workaround that here
138091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes            Drawable buttonDrawable = CompoundButtonCompat.getButtonDrawable(mView);
139091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes            if (buttonDrawable != null) {
140091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes                superValue += buttonDrawable.getIntrinsicWidth();
141091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes            }
142091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes        }
143091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes        return superValue;
144091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes    }
145091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes}
146