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 com.android.setupwizardlib.view; 18 19import android.annotation.SuppressLint; 20import android.content.Context; 21import android.content.res.ColorStateList; 22import android.graphics.PorterDuff; 23import android.graphics.drawable.Drawable; 24import android.graphics.drawable.LayerDrawable; 25import android.os.Build; 26import android.support.annotation.NonNull; 27import android.util.AttributeSet; 28import android.widget.Button; 29 30/** 31 * Button for navigation bar, which includes tinting of its compound drawables to be used for dark 32 * and light themes. 33 */ 34@SuppressLint("AppCompatCustomView") 35public class NavigationBarButton extends Button { 36 37 public NavigationBarButton(Context context) { 38 super(context); 39 init(); 40 } 41 42 public NavigationBarButton(Context context, AttributeSet attrs) { 43 super(context, attrs); 44 init(); 45 } 46 47 private void init() { 48 // Unfortunately, drawableStart and drawableEnd set through XML does not call the setter, 49 // so manually getting it and wrapping it in the compat drawable. 50 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 51 Drawable[] drawables = getCompoundDrawablesRelative(); 52 for (int i = 0; i < drawables.length; i++) { 53 if (drawables[i] != null) { 54 drawables[i] = TintedDrawable.wrap(drawables[i]); 55 } 56 } 57 setCompoundDrawablesRelativeWithIntrinsicBounds(drawables[0], drawables[1], 58 drawables[2], drawables[3]); 59 } 60 } 61 62 @Override 63 public void setCompoundDrawables(Drawable left, Drawable top, Drawable right, Drawable bottom) { 64 if (left != null) left = TintedDrawable.wrap(left); 65 if (top != null) top = TintedDrawable.wrap(top); 66 if (right != null) right = TintedDrawable.wrap(right); 67 if (bottom != null) bottom = TintedDrawable.wrap(bottom); 68 super.setCompoundDrawables(left, top, right, bottom); 69 tintDrawables(); 70 } 71 72 @Override 73 public void setCompoundDrawablesRelative(Drawable start, Drawable top, Drawable end, 74 Drawable bottom) { 75 if (start != null) start = TintedDrawable.wrap(start); 76 if (top != null) top = TintedDrawable.wrap(top); 77 if (end != null) end = TintedDrawable.wrap(end); 78 if (bottom != null) bottom = TintedDrawable.wrap(bottom); 79 super.setCompoundDrawablesRelative(start, top, end, bottom); 80 tintDrawables(); 81 } 82 83 @Override 84 public void setTextColor(ColorStateList colors) { 85 super.setTextColor(colors); 86 tintDrawables(); 87 } 88 89 private void tintDrawables() { 90 final ColorStateList textColors = getTextColors(); 91 if (textColors != null) { 92 for (Drawable drawable : getAllCompoundDrawables()) { 93 if (drawable instanceof TintedDrawable) { 94 ((TintedDrawable) drawable).setTintListCompat(textColors); 95 } 96 } 97 invalidate(); 98 } 99 } 100 101 private Drawable[] getAllCompoundDrawables() { 102 Drawable[] drawables = new Drawable[6]; 103 Drawable[] compoundDrawables = getCompoundDrawables(); 104 drawables[0] = compoundDrawables[0]; // left 105 drawables[1] = compoundDrawables[1]; // top 106 drawables[2] = compoundDrawables[2]; // right 107 drawables[3] = compoundDrawables[3]; // bottom 108 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 109 Drawable[] compoundDrawablesRelative = getCompoundDrawablesRelative(); 110 drawables[4] = compoundDrawablesRelative[0]; // start 111 drawables[5] = compoundDrawablesRelative[2]; // end 112 } 113 return drawables; 114 } 115 116 // TODO: Remove this class and use DrawableCompat.wrap() once we can use support library 22.1.0 117 // or above 118 private static class TintedDrawable extends LayerDrawable { 119 120 public static TintedDrawable wrap(Drawable drawable) { 121 if (drawable instanceof TintedDrawable) { 122 return (TintedDrawable) drawable; 123 } 124 return new TintedDrawable(drawable.mutate()); 125 } 126 127 private ColorStateList mTintList = null; 128 129 TintedDrawable(Drawable wrapped) { 130 super(new Drawable[] { wrapped }); 131 } 132 133 @Override 134 public boolean isStateful() { 135 return true; 136 } 137 138 @Override 139 public boolean setState(@NonNull int[] stateSet) { 140 boolean needsInvalidate = super.setState(stateSet); 141 boolean needsInvalidateForState = updateState(); 142 return needsInvalidate || needsInvalidateForState; 143 } 144 145 public void setTintListCompat(ColorStateList colors) { 146 mTintList = colors; 147 if (updateState()) { 148 invalidateSelf(); 149 } 150 } 151 152 private boolean updateState() { 153 if (mTintList != null) { 154 final int color = mTintList.getColorForState(getState(), 0); 155 setColorFilter(color, PorterDuff.Mode.SRC_IN); 156 return true; // Needs invalidate 157 } 158 return false; 159 } 160 } 161} 162