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