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.car.settings.common; 18 19 20 import static com.android.car.ui.utils.CarUiUtils.requireViewByRefId; 21 22 import android.content.Context; 23 import android.content.res.ColorStateList; 24 import android.content.res.TypedArray; 25 import android.text.TextUtils; 26 import android.util.AttributeSet; 27 import android.view.View; 28 import android.widget.Switch; 29 import android.widget.TextView; 30 31 import androidx.annotation.Nullable; 32 import androidx.annotation.VisibleForTesting; 33 import androidx.preference.Preference; 34 import androidx.preference.PreferenceViewHolder; 35 36 import com.android.car.ui.R; 37 import com.android.car.ui.preference.CarUiTwoActionBasePreference; 38 import com.android.settingslib.Utils; 39 40 import java.util.function.Consumer; 41 42 /** 43 * Extends {@link CarUiTwoActionBasePreference} to add in a colored action text. 44 */ 45 public class ColoredTwoActionSwitchPreference extends CarUiTwoActionBasePreference { 46 @Nullable 47 protected Consumer<Boolean> mSecondaryActionOnClickListener; 48 private boolean mSecondaryActionChecked; 49 private ColorStateList mWarningTextColor; 50 private ColorStateList mNormalTextColor; 51 private boolean mIsWarning; 52 private CharSequence mActionText; 53 ColoredTwoActionSwitchPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)54 public ColoredTwoActionSwitchPreference(Context context, 55 AttributeSet attrs, 56 int defStyleAttr, int defStyleRes) { 57 super(context, attrs, defStyleAttr, defStyleRes); 58 } 59 ColoredTwoActionSwitchPreference(Context context, AttributeSet attrs, int defStyleAttr)60 public ColoredTwoActionSwitchPreference(Context context, AttributeSet attrs, int defStyleAttr) { 61 super(context, attrs, defStyleAttr); 62 } 63 ColoredTwoActionSwitchPreference(Context context, AttributeSet attrs)64 public ColoredTwoActionSwitchPreference(Context context, AttributeSet attrs) { 65 super(context, attrs); 66 } 67 ColoredTwoActionSwitchPreference(Context context)68 public ColoredTwoActionSwitchPreference(Context context) { 69 super(context); 70 } 71 72 @Override init(@ullable AttributeSet attrs)73 protected void init(@Nullable AttributeSet attrs) { 74 super.init(attrs); 75 76 setLayoutResourceInternal(R.layout.colored_two_action_switch_preference); 77 TypedArray a = getContext().obtainStyledAttributes(attrs, 78 R.styleable.ColoredTwoActionSwitchPreference); 79 mWarningTextColor = a.getColorStateList( 80 R.styleable.ColoredTwoActionSwitchPreference_warningTextColor); 81 if (mWarningTextColor == null) { 82 mWarningTextColor = Utils.getColorAttr(getContext(), android.R.attr.textColorPrimary); 83 } 84 85 mNormalTextColor = a.getColorStateList( 86 R.styleable.ColoredTwoActionSwitchPreference_normalTextColor); 87 if (mNormalTextColor == null) { 88 mNormalTextColor = Utils.getColorAttr(getContext(), android.R.attr.textColorPrimary); 89 } 90 } 91 92 @Override performSecondaryActionClickInternal()93 protected void performSecondaryActionClickInternal() { 94 if (isSecondaryActionEnabled()) { 95 if (isUxRestricted()) { 96 Consumer<Preference> restrictedListener = getOnClickWhileRestrictedListener(); 97 if (restrictedListener != null) { 98 restrictedListener.accept(this); 99 } 100 } else { 101 mSecondaryActionChecked = !mSecondaryActionChecked; 102 notifyChanged(); 103 if (mSecondaryActionOnClickListener != null) { 104 mSecondaryActionOnClickListener.accept(mSecondaryActionChecked); 105 } 106 } 107 } 108 } 109 110 @Override onBindViewHolder(PreferenceViewHolder holder)111 public void onBindViewHolder(PreferenceViewHolder holder) { 112 super.onBindViewHolder(holder); 113 114 View firstActionContainer = requireViewByRefId(holder.itemView, 115 R.id.colored_preference_first_action_container); 116 View secondActionContainer = requireViewByRefId(holder.itemView, 117 R.id.colored_preference_second_action_container); 118 View secondaryAction = requireViewByRefId(holder.itemView, 119 R.id.colored_preference_secondary_action); 120 Switch s = requireViewByRefId(holder.itemView, 121 R.id.colored_preference_secondary_action_concrete); 122 123 holder.itemView.setFocusable(false); 124 holder.itemView.setClickable(false); 125 firstActionContainer.setOnClickListener(this::performClick); 126 firstActionContainer.setEnabled(isEnabled() || isUxRestricted()); 127 firstActionContainer.setFocusable(isEnabled() || isUxRestricted()); 128 129 secondActionContainer.setVisibility(mSecondaryActionVisible ? View.VISIBLE : View.GONE); 130 s.setChecked(mSecondaryActionChecked); 131 s.setEnabled(isSecondaryActionEnabled()); 132 133 secondaryAction.setOnClickListener(v -> performSecondaryActionClickInternal()); 134 secondaryAction.setEnabled(isSecondaryActionEnabled() || isUxRestricted()); 135 secondaryAction.setFocusable(isSecondaryActionEnabled() || isUxRestricted()); 136 137 138 TextView actionTextView = holder.itemView.findViewById(R.id.action_text); 139 if (actionTextView != null) { 140 if (!TextUtils.isEmpty(mActionText)) { 141 actionTextView.setText(mActionText); 142 actionTextView.setVisibility(View.VISIBLE); 143 if (getIsWarning()) { 144 actionTextView.setTextColor(mWarningTextColor); 145 } else { 146 actionTextView.setTextColor(mNormalTextColor); 147 } 148 } else { 149 actionTextView.setVisibility(View.GONE); 150 } 151 } 152 } 153 154 /** 155 * Sets the checked state of the switch in the secondary action space. 156 * @param checked Whether the switch should be checked or not. 157 */ 158 @VisibleForTesting setSecondaryActionChecked(boolean checked)159 public void setSecondaryActionChecked(boolean checked) { 160 mSecondaryActionChecked = checked; 161 notifyChanged(); 162 } 163 164 /** 165 * Sets the on-click listener of the secondary action button. 166 * 167 * The listener is called with the current checked state of the switch. 168 */ setOnSecondaryActionClickListener(@ullable Consumer<Boolean> onClickListener)169 public void setOnSecondaryActionClickListener(@Nullable Consumer<Boolean> onClickListener) { 170 mSecondaryActionOnClickListener = onClickListener; 171 notifyChanged(); 172 } 173 174 /** 175 * Get the category of the action text 176 */ getIsWarning()177 public boolean getIsWarning() { 178 return mIsWarning; 179 } 180 181 /** 182 * Set whether action text is a warning text 183 */ setIsWarning(boolean isWarning)184 public void setIsWarning(boolean isWarning) { 185 mIsWarning = isWarning; 186 notifyChanged(); 187 } 188 189 /** 190 * Set the action text 191 */ 192 @VisibleForTesting setActionText(CharSequence actionText)193 public void setActionText(CharSequence actionText) { 194 mActionText = actionText; 195 notifyChanged(); 196 } 197 198 @VisibleForTesting getWarningTextColor()199 public ColorStateList getWarningTextColor() { 200 return mWarningTextColor; 201 } 202 } 203