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