1 /*
2  * Copyright (C) 2019 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.text.TextUtils;
21 import android.util.AttributeSet;
22 import android.view.View;
23 import android.widget.ImageView;
24 
25 import androidx.preference.CheckBoxPreference;
26 import androidx.preference.PreferenceViewHolder;
27 
28 /**
29  * Check box preference with check box replaced by radio button.
30  *
31  * Functionally speaking, it's actually a CheckBoxPreference. We only modified
32  * the widget to RadioButton to make it "look like" a RadioButtonPreference.
33  *
34  * In other words, there's no "RadioButtonPreferenceGroup" in this
35  * implementation. When you check one RadioButtonPreference, if you want to
36  * uncheck all the other preferences, you should do that by code yourself.
37  *
38  * RadioButtonPreference can assign a extraWidgetListener to show a gear icon
39  * on the right side that can open another page.
40  */
41 public class RadioButtonPreference extends CheckBoxPreference {
42 
43     /**
44      * Interface definition for a callback to be invoked when the preference is clicked.
45      */
46     public interface OnClickListener {
47         /**
48          * Called when a preference has been clicked.
49          *
50          * @param emiter The clicked preference
51          */
onRadioButtonClicked(RadioButtonPreference emiter)52         void onRadioButtonClicked(RadioButtonPreference emiter);
53     }
54 
55     private OnClickListener mListener = null;
56     private View mAppendix;
57     private int mAppendixVisibility = -1;
58 
59     private View mExtraWidgetContainer;
60     private ImageView mExtraWidget;
61 
62     private View.OnClickListener mExtraWidgetOnClickListener;
63 
64     /**
65      * Perform inflation from XML and apply a class-specific base style.
66      *
67      * @param context  The {@link Context} this is associated with, through which it can
68      *                 access the current theme, resources, {@link SharedPreferences}, etc.
69      * @param attrs    The attributes of the XML tag that is inflating the preference
70      * @param defStyle An attribute in the current theme that contains a reference to a style
71      *                 resource that supplies default values for the view. Can be 0 to not
72      *                 look for defaults.
73      */
RadioButtonPreference(Context context, AttributeSet attrs, int defStyle)74     public RadioButtonPreference(Context context, AttributeSet attrs, int defStyle) {
75         super(context, attrs, defStyle);
76         init();
77     }
78 
79     /**
80      * Perform inflation from XML and apply a class-specific base style.
81      *
82      * @param context The {@link Context} this is associated with, through which it can
83      *                access the current theme, resources, {@link SharedPreferences}, etc.
84      * @param attrs   The attributes of the XML tag that is inflating the preference
85      */
RadioButtonPreference(Context context, AttributeSet attrs)86     public RadioButtonPreference(Context context, AttributeSet attrs) {
87         super(context, attrs);
88         init();
89     }
90 
91     /**
92      * Constructor to create a preference.
93      *
94      * @param context The Context this is associated with.
95      */
RadioButtonPreference(Context context)96     public RadioButtonPreference(Context context) {
97         this(context, null);
98     }
99 
100     /**
101      * Sets the callback to be invoked when this preference is clicked by the user.
102      *
103      * @param listener The callback to be invoked
104      */
setOnClickListener(OnClickListener listener)105     public void setOnClickListener(OnClickListener listener) {
106         mListener = listener;
107     }
108 
109     /**
110      * Processes a click on the preference.
111      */
112     @Override
onClick()113     public void onClick() {
114         if (mListener != null) {
115             mListener.onRadioButtonClicked(this);
116         }
117     }
118 
119     /**
120      * Binds the created View to the data for this preference.
121      *
122      * <p>This is a good place to grab references to custom Views in the layout and set
123      * properties on them.
124      *
125      * <p>Make sure to call through to the superclass's implementation.
126      *
127      * @param holder The ViewHolder that provides references to the views to fill in. These views
128      *               will be recycled, so you should not hold a reference to them after this method
129      *               returns.
130      */
131     @Override
onBindViewHolder(PreferenceViewHolder holder)132     public void onBindViewHolder(PreferenceViewHolder holder) {
133         super.onBindViewHolder(holder);
134 
135         View summaryContainer = holder.findViewById(R.id.summary_container);
136         if (summaryContainer != null) {
137             summaryContainer.setVisibility(
138                     TextUtils.isEmpty(getSummary()) ? View.GONE : View.VISIBLE);
139             mAppendix = holder.findViewById(R.id.appendix);
140             if (mAppendix != null && mAppendixVisibility != -1) {
141                 mAppendix.setVisibility(mAppendixVisibility);
142             }
143         }
144 
145         mExtraWidget = (ImageView) holder.findViewById(R.id.radio_extra_widget);
146         mExtraWidgetContainer = holder.findViewById(R.id.radio_extra_widget_container);
147 
148         setExtraWidgetOnClickListener(mExtraWidgetOnClickListener);
149     }
150 
151     /**
152      * Set the visibility state of appendix view.
153      *
154      * @param visibility One of {@link View#VISIBLE}, {@link View#INVISIBLE}, or {@link View#GONE}.
155      */
setAppendixVisibility(int visibility)156     public void setAppendixVisibility(int visibility) {
157         if (mAppendix != null) {
158             mAppendix.setVisibility(visibility);
159         }
160         mAppendixVisibility = visibility;
161     }
162 
163     /**
164      * Sets the callback to be invoked when extra widget is clicked by the user.
165      *
166      * @param listener The callback to be invoked
167      */
setExtraWidgetOnClickListener(View.OnClickListener listener)168     public void setExtraWidgetOnClickListener(View.OnClickListener listener) {
169         mExtraWidgetOnClickListener = listener;
170 
171         if (mExtraWidget == null || mExtraWidgetContainer == null) {
172             return;
173         }
174 
175         mExtraWidget.setOnClickListener(mExtraWidgetOnClickListener);
176 
177         mExtraWidgetContainer.setVisibility((mExtraWidgetOnClickListener != null)
178                 ? View.VISIBLE : View.GONE);
179     }
180 
init()181     private void init() {
182         setWidgetLayoutResource(R.layout.preference_widget_radiobutton);
183         setLayoutResource(R.layout.preference_radio);
184         setIconSpaceReserved(false);
185     }
186 }
187