1 /* 2 * Copyright (C) 2021 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.car.settings.common; 18 19 import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON_BACKGROUND_ARGB; 20 import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON_BACKGROUND_HINT; 21 22 import android.content.Context; 23 import android.content.pm.PackageManager; 24 import android.content.res.ColorStateList; 25 import android.graphics.drawable.Drawable; 26 import android.graphics.drawable.LayerDrawable; 27 import android.os.Bundle; 28 29 import androidx.annotation.ColorInt; 30 import androidx.annotation.VisibleForTesting; 31 32 import com.android.car.settings.R; 33 import com.android.internal.graphics.ColorUtils; 34 import com.android.settingslib.utils.ColorUtil; 35 36 /** 37 * Top-level icon that can set background color. 38 * 39 * Adapted from {@link com.android.settingslib.widget.AdaptiveIcon} 40 */ 41 public class TopLevelIcon extends LayerDrawable { 42 private static final Logger LOG = new Logger("TopLevelIcon"); 43 44 private static final int BACKGROUND_INDEX = 0; 45 private static final int FOREGROUND_INDEX = 1; 46 47 private Context mContext; 48 private AdaptiveConstantState mAdaptiveConstantState; 49 private boolean mAlwaysDefaultColor; 50 @VisibleForTesting 51 ColorStateList mBackgroundColorStateList; 52 TopLevelIcon(Context context, Drawable foreground)53 public TopLevelIcon(Context context, Drawable foreground) { 54 this(context, foreground, R.dimen.top_level_foreground_icon_inset); 55 } 56 TopLevelIcon(Context context, Drawable foreground, int insetResId)57 public TopLevelIcon(Context context, Drawable foreground, int insetResId) { 58 super(new Drawable[]{ 59 new TopLevelIconShapeDrawable(context.getResources()), 60 foreground 61 }); 62 mContext = context; 63 int insetPx = context.getResources().getDimensionPixelSize(insetResId); 64 setLayerInset(FOREGROUND_INDEX , insetPx, insetPx, insetPx, insetPx); 65 mAdaptiveConstantState = new AdaptiveConstantState(context, foreground); 66 mAlwaysDefaultColor = context.getResources().getBoolean( 67 R.bool.config_top_level_injection_background_always_use_default); 68 } 69 70 /** 71 * Sets background color based on injected metaData. 72 */ setBackgroundColor(Context context, Bundle metaData, String packageName)73 public void setBackgroundColor(Context context, Bundle metaData, String packageName) { 74 try { 75 if (metaData != null && packageName != null && !mAlwaysDefaultColor) { 76 // Load from bg.argb first 77 int bgColor = metaData.getInt(META_DATA_PREFERENCE_ICON_BACKGROUND_ARGB, 78 /* defaultValue= */ 0); 79 // If not found, load from bg.hint 80 if (bgColor == 0) { 81 int colorRes = metaData.getInt(META_DATA_PREFERENCE_ICON_BACKGROUND_HINT, 82 /* defaultValue= */ 0); 83 if (colorRes != 0) { 84 bgColor = context.getPackageManager() 85 .getResourcesForApplication(packageName) 86 .getColor(colorRes, /* theme= */ null); 87 } 88 } 89 // If a color was found, use it. 90 if (bgColor != 0) { 91 setBackgroundColor(bgColor); 92 return; 93 } 94 } 95 } catch (PackageManager.NameNotFoundException e) { 96 LOG.e("Failed to set background color for " + packageName); 97 } 98 setBackgroundColor(context.getColor(R.color.top_level_injected_default_background)); 99 } 100 101 /** 102 * Sets background color by {@code color}. 103 */ setBackgroundColor(@olorInt int color)104 public void setBackgroundColor(@ColorInt int color) { 105 mBackgroundColorStateList = createBackgroundColorStateList(color); 106 getDrawable(BACKGROUND_INDEX).setTintList(mBackgroundColorStateList); 107 mAdaptiveConstantState.mColor = color; 108 } 109 110 @Override getConstantState()111 public ConstantState getConstantState() { 112 return mAdaptiveConstantState; 113 } 114 createBackgroundColorStateList(@olorInt int color)115 private ColorStateList createBackgroundColorStateList(@ColorInt int color) { 116 return new ColorStateList( 117 new int[][]{ 118 new int[]{-android.R.attr.state_enabled}, // disabled state 119 new int[]{R.attr.state_ux_restricted}, // ux restricted state 120 new int[]{} // default state 121 }, 122 new int[]{ 123 getDisabledAlphaColor(color), 124 getDisabledAlphaColor(color), 125 color 126 } 127 ); 128 } 129 130 @ColorInt getDisabledAlphaColor(@olorInt int color)131 private int getDisabledAlphaColor(@ColorInt int color) { 132 return ColorUtils.setAlphaComponent(color, 133 (int) (ColorUtil.getDisabledAlpha(mContext) * 255)); 134 } 135 136 @VisibleForTesting 137 static class AdaptiveConstantState extends ConstantState { 138 Context mContext; 139 Drawable mDrawable; 140 int mColor; 141 AdaptiveConstantState(Context context, Drawable drawable)142 AdaptiveConstantState(Context context, Drawable drawable) { 143 this.mContext = context; 144 this.mDrawable = drawable; 145 } 146 147 @Override newDrawable()148 public Drawable newDrawable() { 149 TopLevelIcon icon = new TopLevelIcon(mContext, mDrawable); 150 icon.setBackgroundColor(mColor); 151 152 return icon; 153 } 154 155 @Override getChangingConfigurations()156 public int getChangingConfigurations() { 157 return 0; 158 } 159 } 160 } 161