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 17 package com.android.messaging.util; 18 19 import android.content.Context; 20 import android.content.res.ColorStateList; 21 import android.graphics.Color; 22 import android.graphics.PorterDuff; 23 import android.graphics.drawable.Drawable; 24 import androidx.appcompat.graphics.drawable.DrawableWrapper; 25 import androidx.appcompat.widget.SwitchCompat; 26 import android.util.TypedValue; 27 28 /* Most methods in this file are copied from 29 * v7/appcompat/src/androidx.appcompat.internal/widget/TintManager.java. It would be better if 30 * we could have just extended the TintManager but this is a final class that we do not have 31 * access to. */ 32 33 /** 34 * Util methods for the SwitchCompat widget 35 */ 36 public class SwitchCompatUtils { 37 /** 38 * Given a color and a SwitchCompat view, updates the SwitchCompat to appear with the appropiate 39 * color when enabled and checked 40 */ updateSwitchCompatColor(SwitchCompat switchCompat, final int color)41 public static void updateSwitchCompatColor(SwitchCompat switchCompat, final int color) { 42 final Context context = switchCompat.getContext(); 43 final TypedValue typedValue = new TypedValue(); 44 45 switchCompat.setThumbDrawable(getColorTintedDrawable(switchCompat.getThumbDrawable(), 46 getSwitchThumbColorStateList(context, color, typedValue), 47 PorterDuff.Mode.MULTIPLY)); 48 49 switchCompat.setTrackDrawable(getColorTintedDrawable(switchCompat.getTrackDrawable(), 50 getSwitchTrackColorStateList(context, color, typedValue), PorterDuff.Mode.SRC_IN)); 51 } 52 getColorTintedDrawable(Drawable oldDrawable, final ColorStateList colorStateList, final PorterDuff.Mode mode)53 private static Drawable getColorTintedDrawable(Drawable oldDrawable, 54 final ColorStateList colorStateList, final PorterDuff.Mode mode) { 55 final int[] thumbState = oldDrawable.isStateful() ? oldDrawable.getState() : null; 56 if (oldDrawable instanceof DrawableWrapper) { 57 oldDrawable = ((DrawableWrapper) oldDrawable).getWrappedDrawable(); 58 } 59 final Drawable newDrawable = new TintDrawableWrapper(oldDrawable, colorStateList, mode); 60 if (thumbState != null) { 61 newDrawable.setState(thumbState); 62 } 63 return newDrawable; 64 } 65 getSwitchThumbColorStateList(final Context context, final int color, final TypedValue typedValue)66 private static ColorStateList getSwitchThumbColorStateList(final Context context, 67 final int color, final TypedValue typedValue) { 68 final int[][] states = new int[3][]; 69 final int[] colors = new int[3]; 70 int i = 0; 71 // Disabled state 72 states[i] = new int[] { -android.R.attr.state_enabled }; 73 colors[i] = getColor(Color.parseColor("#ffbdbdbd"), 1f); 74 i++; 75 states[i] = new int[] { android.R.attr.state_checked }; 76 colors[i] = color; 77 i++; 78 // Default enabled state 79 states[i] = new int[0]; 80 colors[i] = getThemeAttrColor(context, typedValue, 81 androidx.appcompat.R.attr.colorSwitchThumbNormal); 82 i++; 83 return new ColorStateList(states, colors); 84 } 85 getSwitchTrackColorStateList(final Context context, final int color, final TypedValue typedValue)86 private static ColorStateList getSwitchTrackColorStateList(final Context context, 87 final int color, final TypedValue typedValue) { 88 final int[][] states = new int[3][]; 89 final int[] colors = new int[3]; 90 int i = 0; 91 // Disabled state 92 states[i] = new int[] { -android.R.attr.state_enabled }; 93 colors[i] = getThemeAttrColor(context, typedValue, android.R.attr.colorForeground, 0.1f); 94 i++; 95 states[i] = new int[] { android.R.attr.state_checked }; 96 colors[i] = getColor(color, 0.3f); 97 i++; 98 // Default enabled state 99 states[i] = new int[0]; 100 colors[i] = getThemeAttrColor(context, typedValue, android.R.attr.colorForeground, 0.3f); 101 i++; 102 return new ColorStateList(states, colors); 103 } 104 getThemeAttrColor(final Context context, final TypedValue typedValue, final int attr)105 private static int getThemeAttrColor(final Context context, final TypedValue typedValue, 106 final int attr) { 107 if (context.getTheme().resolveAttribute(attr, typedValue, true)) { 108 if (typedValue.type >= TypedValue.TYPE_FIRST_INT 109 && typedValue.type <= TypedValue.TYPE_LAST_INT) { 110 return typedValue.data; 111 } else if (typedValue.type == TypedValue.TYPE_STRING) { 112 return context.getResources().getColor(typedValue.resourceId); 113 } 114 } 115 return 0; 116 } 117 getThemeAttrColor(final Context context, final TypedValue typedValue, final int attr, final float alpha)118 private static int getThemeAttrColor(final Context context, final TypedValue typedValue, 119 final int attr, final float alpha) { 120 final int color = getThemeAttrColor(context, typedValue, attr); 121 return getColor(color, alpha); 122 } 123 getColor(int color, float alpha)124 private static int getColor(int color, float alpha) { 125 final int originalAlpha = Color.alpha(color); 126 // Return the color, multiplying the original alpha by the disabled value 127 return (color & 0x00ffffff) | (Math.round(originalAlpha * alpha) << 24); 128 } 129 } 130