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 android.content.Context; 20 import android.graphics.drawable.Drawable; 21 import android.view.LayoutInflater; 22 import android.view.ViewGroup; 23 import android.widget.FrameLayout; 24 25 import androidx.annotation.DrawableRes; 26 import androidx.annotation.NonNull; 27 import androidx.annotation.Nullable; 28 import androidx.annotation.StringRes; 29 import androidx.preference.Preference; 30 31 import com.android.car.settings.R; 32 import com.android.car.ui.uxr.DrawableStateToggleButton; 33 34 import java.util.function.Consumer; 35 36 /** 37 * Handles ToggleButton action item logic 38 */ 39 public final class ToggleButtonActionItem extends BaseActionItem { 40 private boolean mIsChecked = true; 41 @Nullable 42 private Consumer<Boolean> mOnClickListener; 43 @Nullable 44 private Consumer<Preference> mOnClickWhileDisabledListener; 45 46 @Nullable 47 private Drawable mDrawable; 48 49 @Nullable 50 private String mContentDescription; 51 ToggleButtonActionItem(ActionItemInfoChangeListener actionItemInfoChangeListener)52 public ToggleButtonActionItem(ActionItemInfoChangeListener actionItemInfoChangeListener) { 53 super(actionItemInfoChangeListener); 54 } 55 56 /** 57 * Create and setup views. 58 * 59 * @param frameLayout ViewGroup to attach views to 60 */ 61 @Override bindViewHolder(FrameLayout frameLayout)62 public void bindViewHolder(FrameLayout frameLayout) { 63 // Required to be effectively final for inner class access 64 final DrawableStateToggleButton toggleButton = getOptionalToggleButton(frameLayout); 65 toggleButton.setOnClickListener(null); 66 // Prevent "double calls" when checked status is changed 67 toggleButton.setOnCheckedChangeListener(null); 68 toggleButton.setButtonDrawable(mDrawable); 69 toggleButton.setChecked(mIsChecked); 70 toggleButton.setEnabled(isEnabled()); 71 toggleButton.setAllowClickWhenDisabled(true); 72 toggleButton.setContentDescription(mContentDescription); 73 toggleButton.setOnCheckedChangeListener((view, isChecked) -> { 74 onClick(); 75 toggleButton.setChecked(mIsChecked); 76 }); 77 } 78 getOptionalToggleButton(FrameLayout frameLayout)79 private DrawableStateToggleButton getOptionalToggleButton(FrameLayout frameLayout) { 80 DrawableStateToggleButton toggleButton = 81 frameLayout.findViewById(R.id.multi_action_preference_toggle_button); 82 83 if (toggleButton == null) { 84 toggleButton = createView(frameLayout.getContext(), frameLayout); 85 // Ensure the default "On" and "Off" text don't show 86 toggleButton.setText(null); 87 toggleButton.setTextOn(null); 88 toggleButton.setTextOff(null); 89 frameLayout.addView(toggleButton); 90 } 91 return toggleButton; 92 } 93 94 @Override getLayoutResource()95 public int getLayoutResource() { 96 return R.layout.multi_action_preference_toggle_button; 97 } 98 99 /** 100 * Set the checked state. 101 */ isChecked()102 public boolean isChecked() { 103 return mIsChecked; 104 } 105 106 /** 107 * Get the checked state. 108 */ setChecked(boolean checked)109 public void setChecked(boolean checked) { 110 if (checked != mIsChecked) { 111 mIsChecked = checked; 112 update(); 113 } 114 } 115 116 /** 117 * Get the Consumer that should run when toggle button is clicked. 118 */ getOnClickListener()119 public Consumer<Boolean> getOnClickListener() { 120 return mOnClickListener; 121 } 122 123 /** 124 * Set the Consumer that should run when toggle button is clicked. 125 */ setOnClickListener(Consumer<Boolean> onClickListener)126 public void setOnClickListener(Consumer<Boolean> onClickListener) { 127 if (onClickListener != mOnClickListener) { 128 mOnClickListener = onClickListener; 129 update(); 130 } 131 } 132 133 /** 134 * Set the Consumer that should run when toggle button is clicked even when disabled. 135 */ setOnClickWhileDisabledListener(Consumer<Preference> listener)136 public void setOnClickWhileDisabledListener(Consumer<Preference> listener) { 137 if (listener != mOnClickWhileDisabledListener) { 138 mOnClickWhileDisabledListener = listener; 139 update(); 140 } 141 } 142 143 /** 144 * Get the ToggleButton drawable. 145 */ getDrawable()146 public Drawable getDrawable() { 147 return mDrawable; 148 } 149 150 /** 151 * Set the ToggleButton drawable. 152 */ setDrawable(Drawable drawable)153 public void setDrawable(Drawable drawable) { 154 if (drawable != mDrawable) { 155 mDrawable = drawable; 156 update(); 157 } 158 } 159 160 /** 161 * Set the ToggleButton drawable. 162 */ setDrawable(Context context, @DrawableRes int iconResId)163 public void setDrawable(Context context, @DrawableRes int iconResId) { 164 Drawable drawable = context.getDrawable(iconResId); 165 166 if (drawable != mDrawable) { 167 mDrawable = drawable; 168 update(); 169 } 170 } 171 172 /** 173 * Get the ToggleButton content description. 174 */ 175 @Nullable getContentDescription()176 public String getContentDescription() { 177 return mContentDescription; 178 } 179 180 /** 181 * Set the ToggleButton content description. 182 */ setContentDescription(@ullable String contentDescription)183 public void setContentDescription(@Nullable String contentDescription) { 184 mContentDescription = contentDescription; 185 } 186 187 /** 188 * Set the ToggleButton content description. 189 */ setContentDescription(@onNull Context context, @StringRes int contentDescriptionResId)190 public void setContentDescription(@NonNull Context context, 191 @StringRes int contentDescriptionResId) { 192 mContentDescription = context.getString(contentDescriptionResId); 193 } 194 195 /** 196 * Executes when ToggleButton is clicked. 197 */ onClick()198 public void onClick() { 199 if (mIsRestricted && mPreference != null 200 && mRestrictedOnClickListener != null) { 201 mRestrictedOnClickListener.accept(mPreference); 202 } else if (isEnabled() && !mIsRestricted && mOnClickListener != null) { 203 mIsChecked = !mIsChecked; 204 mOnClickListener.accept(mIsChecked); 205 } else if (!isEnabled() && mOnClickWhileDisabledListener != null) { 206 mOnClickWhileDisabledListener.accept(mPreference); 207 } 208 } 209 createView(Context context, ViewGroup viewGroup)210 private DrawableStateToggleButton createView(Context context, ViewGroup viewGroup) { 211 LayoutInflater layoutInflater = LayoutInflater.from(context); 212 213 return (DrawableStateToggleButton) layoutInflater 214 .inflate(getLayoutResource(), viewGroup, false); 215 } 216 } 217