1 /*
2  * Copyright (C) 2022 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.TypedArray;
21 import android.graphics.drawable.Drawable;
22 import android.util.AttributeSet;
23 import android.util.TypedValue;
24 import android.view.Gravity;
25 import android.view.View;
26 import android.widget.Button;
27 import android.widget.LinearLayout;
28 
29 import androidx.annotation.GravityInt;
30 import androidx.preference.Preference;
31 import androidx.preference.PreferenceViewHolder;
32 
33 /**
34  * A preference handled a button
35  */
36 public class ButtonPreference extends Preference {
37 
38     private static final int ICON_SIZE = 24;
39 
40     private View.OnClickListener mClickListener;
41     private Button mButton;
42     private CharSequence mTitle;
43     private Drawable mIcon;
44     @GravityInt
45     private int mGravity;
46 
47     /**
48      * Constructs a new LayoutPreference with the given context's theme, the supplied
49      * attribute set, and default style attribute.
50      *
51      * @param context      The Context the view is running in, through which it can
52      *                     access the current theme, resources, etc.
53      * @param attrs        The attributes of the XML tag that is inflating the view.
54      * @param defStyleAttr An attribute in the current theme that contains a
55      *                     reference to a style resource that supplies default
56      *                     values for the view. Can be 0 to not look for
57      *                     defaults.
58      */
ButtonPreference(Context context, AttributeSet attrs, int defStyleAttr)59     public ButtonPreference(Context context, AttributeSet attrs, int defStyleAttr) {
60         super(context, attrs, defStyleAttr);
61         init(context, attrs, defStyleAttr);
62     }
63 
64     /**
65      * Constructs a new LayoutPreference with the given context's theme and the supplied
66      * attribute set.
67      *
68      * @param context The Context the view is running in, through which it can
69      *                access the current theme, resources, etc.
70      * @param attrs   The attributes of the XML tag that is inflating the view.
71      */
ButtonPreference(Context context, AttributeSet attrs)72     public ButtonPreference(Context context, AttributeSet attrs) {
73         this(context, attrs, 0 /* defStyleAttr */);
74     }
75 
76     /**
77      * Constructs a new LayoutPreference with the given context's theme and a customized view.
78      *
79      * @param context The Context the view is running in, through which it can
80      *                access the current theme, resources, etc.
81      */
ButtonPreference(Context context)82     public ButtonPreference(Context context) {
83         this(context, null);
84     }
85 
init(Context context, AttributeSet attrs, int defStyleAttr)86     private void init(Context context, AttributeSet attrs, int defStyleAttr) {
87         setLayoutResource(R.layout.settingslib_button_layout);
88 
89         if (attrs != null) {
90             TypedArray a = context.obtainStyledAttributes(attrs,
91                     androidx.preference.R.styleable.Preference, defStyleAttr,
92                     0 /*defStyleRes*/);
93             mTitle = a.getText(
94                     androidx.preference.R.styleable.Preference_android_title);
95             mIcon = a.getDrawable(
96                     androidx.preference.R.styleable.Preference_android_icon);
97             a.recycle();
98 
99             a = context.obtainStyledAttributes(attrs,
100                     R.styleable.ButtonPreference, defStyleAttr,
101                     0 /*defStyleRes*/);
102             mGravity = a.getInt(R.styleable.ButtonPreference_android_gravity, Gravity.START);
103             a.recycle();
104         }
105     }
106 
107     @Override
onBindViewHolder(PreferenceViewHolder holder)108     public void onBindViewHolder(PreferenceViewHolder holder) {
109         mButton = (Button) holder.findViewById(R.id.settingslib_button);
110         setTitle(mTitle);
111         setIcon(mIcon);
112         setGravity(mGravity);
113         setOnClickListener(mClickListener);
114 
115         if (mButton != null) {
116             final boolean selectable = isSelectable();
117             mButton.setFocusable(selectable);
118             mButton.setClickable(selectable);
119 
120             mButton.setEnabled(isEnabled());
121         }
122 
123         holder.setDividerAllowedAbove(false);
124         holder.setDividerAllowedBelow(false);
125     }
126 
127     @Override
setTitle(CharSequence title)128     public void setTitle(CharSequence title) {
129         mTitle = title;
130         if (mButton != null) {
131             mButton.setText(title);
132         }
133     }
134 
getTitle()135     @Override public CharSequence getTitle() {
136         return mTitle;
137     }
138 
139     @Override
setIcon(Drawable icon)140     public void setIcon(Drawable icon) {
141         mIcon = icon;
142         if (mButton == null || icon == null) {
143             return;
144         }
145         //get pixel from dp
146         int size = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, ICON_SIZE,
147                 getContext().getResources().getDisplayMetrics());
148         icon.setBounds(0, 0, size, size);
149 
150         //set drawableStart
151         mButton.setCompoundDrawablesRelativeWithIntrinsicBounds(icon, null/* top */, null/* end */,
152                 null/* bottom */);
153     }
154 
155     @Override
setEnabled(boolean enabled)156     public void setEnabled(boolean enabled) {
157         super.setEnabled(enabled);
158         if (mButton != null) {
159             mButton.setEnabled(enabled);
160         }
161     }
162 
163     /**
164      * Return Button
165      */
getButton()166     public Button getButton() {
167         return mButton;
168     }
169 
170 
171     /**
172      * Set a listener for button click
173      */
setOnClickListener(View.OnClickListener listener)174     public void setOnClickListener(View.OnClickListener listener) {
175         mClickListener = listener;
176         if (mButton != null) {
177             mButton.setOnClickListener(listener);
178         }
179     }
180 
181     /**
182      * Set the gravity of button
183      *
184      * @param gravity The {@link Gravity} supported CENTER_HORIZONTAL
185      *                and the default value is START
186      */
setGravity(@ravityInt int gravity)187     public void setGravity(@GravityInt int gravity) {
188         if (gravity == Gravity.CENTER_HORIZONTAL || gravity == Gravity.CENTER_VERTICAL
189                 || gravity == Gravity.CENTER) {
190             mGravity = Gravity.CENTER_HORIZONTAL;
191         } else {
192             mGravity = Gravity.START;
193         }
194 
195         if (mButton != null) {
196             LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mButton.getLayoutParams();
197             lp.gravity = mGravity;
198             mButton.setLayoutParams(lp);
199         }
200     }
201 }
202