1 /* 2 * Copyright (C) 2024 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.settingslib.widget 18 19 import android.content.Context 20 import android.content.res.ColorStateList 21 import android.graphics.drawable.Drawable 22 import android.util.AttributeSet 23 import android.view.View 24 import android.widget.ImageView 25 import androidx.annotation.StringRes 26 import androidx.core.content.ContextCompat 27 import androidx.preference.Preference 28 import androidx.preference.PreferenceViewHolder 29 import com.android.settingslib.widget.preference.statusbanner.R 30 import com.google.android.material.button.MaterialButton 31 32 class StatusBannerPreference @JvmOverloads constructor( 33 context: Context, 34 attrs: AttributeSet? = null, 35 defStyleAttr: Int = 0, 36 defStyleRes: Int = 0 37 ) : Preference(context, attrs, defStyleAttr, defStyleRes), GroupSectionDividerMixin { 38 39 enum class BannerStatus { 40 GENERIC, 41 LOW, 42 MEDIUM, 43 HIGH 44 } 45 var iconLevel: BannerStatus = BannerStatus.GENERIC 46 set(value) { 47 field = value 48 notifyChanged() 49 } 50 var buttonLevel: BannerStatus = BannerStatus.GENERIC 51 set(value) { 52 field = value 53 notifyChanged() 54 } 55 private var buttonText: String = "" 56 set(value) { 57 field = value 58 notifyChanged() 59 } 60 private var listener: View.OnClickListener? = null 61 62 init { 63 layoutResource = R.layout.settingslib_expressive_preference_statusbanner 64 isSelectable = false 65 66 initAttributes(context, attrs, defStyleAttr) 67 } 68 initAttributesnull69 private fun initAttributes(context: Context, attrs: AttributeSet?, defStyleAttr: Int) { 70 context.obtainStyledAttributes( 71 attrs, 72 R.styleable.StatusBanner, defStyleAttr, 0 73 ).apply { 74 iconLevel = getInteger(R.styleable.StatusBanner_iconLevel, 0).toBannerStatus() 75 if (icon == null) { 76 icon = getIconDrawable(iconLevel) 77 } else { 78 icon!!.setTintList(ColorStateList.valueOf(getBackgroundColor(iconLevel))) 79 } 80 buttonLevel = getInteger(R.styleable.StatusBanner_buttonLevel, 0).toBannerStatus() 81 buttonText = getString(R.styleable.StatusBanner_buttonText) ?: "" 82 recycle() 83 } 84 } 85 toBannerStatusnull86 private fun Int.toBannerStatus(): BannerStatus = when (this) { 87 1 -> BannerStatus.LOW 88 2 -> BannerStatus.MEDIUM 89 3 -> BannerStatus.HIGH 90 else -> BannerStatus.GENERIC 91 } 92 onBindViewHoldernull93 override fun onBindViewHolder(holder: PreferenceViewHolder) { 94 super.onBindViewHolder(holder) 95 holder.isDividerAllowedBelow = false 96 holder.isDividerAllowedAbove = false 97 98 (holder.findViewById(R.id.icon_background) as? ImageView)?.apply { 99 setImageDrawable(getBackgroundDrawable(iconLevel)) 100 } 101 102 holder.findViewById(android.R.id.icon_frame)?.apply { 103 visibility = if (icon != null) View.VISIBLE else View.GONE 104 } 105 106 (holder.findViewById(R.id.status_banner_button) as? MaterialButton)?.apply { 107 setBackgroundColor(getBackgroundColor(buttonLevel)) 108 text = buttonText 109 setOnClickListener(listener) 110 visibility = if (listener != null) View.VISIBLE else View.GONE 111 } 112 } 113 114 /** 115 * Sets the text to be displayed in button. 116 */ setButtonTextnull117 fun setButtonText(@StringRes textResId: Int) { 118 buttonText = context.getString(textResId) 119 } 120 121 /** 122 * Register a callback to be invoked when positive button is clicked. 123 */ setButtonOnClickListenernull124 fun setButtonOnClickListener(listener: View.OnClickListener) { 125 this.listener = listener 126 notifyChanged() 127 } 128 getBackgroundColornull129 private fun getBackgroundColor(level: BannerStatus): Int { 130 return when (level) { 131 BannerStatus.LOW -> ContextCompat.getColor( 132 context, 133 R.color.settingslib_expressive_color_status_level_low 134 ) 135 136 BannerStatus.MEDIUM -> ContextCompat.getColor( 137 context, 138 R.color.settingslib_expressive_color_status_level_medium 139 ) 140 141 BannerStatus.HIGH -> ContextCompat.getColor( 142 context, 143 R.color.settingslib_expressive_color_status_level_high 144 ) 145 146 else -> ContextCompat.getColor( 147 context, 148 com.android.settingslib.widget.theme.R.color.settingslib_materialColorPrimary 149 ) 150 } 151 } 152 getIconDrawablenull153 private fun getIconDrawable(level: BannerStatus): Drawable? { 154 return when (level) { 155 BannerStatus.LOW -> ContextCompat.getDrawable( 156 context, 157 R.drawable.settingslib_expressive_icon_status_level_low 158 ) 159 160 BannerStatus.MEDIUM -> ContextCompat.getDrawable( 161 context, 162 R.drawable.settingslib_expressive_icon_status_level_medium 163 ) 164 165 BannerStatus.HIGH -> ContextCompat.getDrawable( 166 context, 167 R.drawable.settingslib_expressive_icon_status_level_high 168 ) 169 170 else -> null 171 } 172 } 173 getBackgroundDrawablenull174 private fun getBackgroundDrawable(level: BannerStatus): Drawable? { 175 return when (level) { 176 BannerStatus.LOW -> ContextCompat.getDrawable( 177 context, 178 R.drawable.settingslib_expressive_background_level_low 179 ) 180 181 BannerStatus.MEDIUM -> ContextCompat.getDrawable( 182 context, 183 R.drawable.settingslib_expressive_background_level_medium 184 ) 185 186 BannerStatus.HIGH -> ContextCompat.getDrawable( 187 context, 188 R.drawable.settingslib_expressive_background_level_high 189 ) 190 191 else -> ContextCompat.getDrawable( 192 context, 193 R.drawable.settingslib_expressive_background_generic 194 ) 195 } 196 } 197 }