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