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.settings.widget;
18 
19 import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
20 
21 import android.content.Context;
22 import android.content.res.TypedArray;
23 import android.text.TextUtils;
24 import android.util.AttributeSet;
25 import android.widget.Switch;
26 
27 import androidx.core.content.res.TypedArrayUtils;
28 import androidx.preference.PreferenceViewHolder;
29 import androidx.preference.TwoStatePreference;
30 
31 import com.android.settings.R;
32 import com.android.settings.widget.SettingsMainSwitchBar.OnBeforeCheckedChangeListener;
33 import com.android.settingslib.RestrictedPreferenceHelper;
34 import com.android.settingslib.widget.OnMainSwitchChangeListener;
35 
36 import java.util.ArrayList;
37 import java.util.List;
38 
39 /**
40  * SettingsMainSwitchPreference is a Preference with a customized Switch.
41  * This component is used as the main switch of the page
42  * to enable or disable the prefereces on the page.
43  */
44 public class SettingsMainSwitchPreference extends TwoStatePreference implements
45         OnMainSwitchChangeListener {
46 
47     private final List<OnBeforeCheckedChangeListener> mBeforeCheckedChangeListeners =
48             new ArrayList<>();
49     private final List<OnMainSwitchChangeListener> mSwitchChangeListeners = new ArrayList<>();
50 
51     private SettingsMainSwitchBar mMainSwitchBar;
52     private CharSequence mTitle;
53     private EnforcedAdmin mEnforcedAdmin;
54     private RestrictedPreferenceHelper mRestrictedHelper;
55 
SettingsMainSwitchPreference(Context context)56     public SettingsMainSwitchPreference(Context context) {
57         super(context);
58         init(context, null);
59     }
60 
SettingsMainSwitchPreference(Context context, AttributeSet attrs)61     public SettingsMainSwitchPreference(Context context, AttributeSet attrs) {
62         super(context, attrs);
63         init(context, attrs);
64     }
65 
SettingsMainSwitchPreference(Context context, AttributeSet attrs, int defStyleAttr)66     public SettingsMainSwitchPreference(Context context, AttributeSet attrs, int defStyleAttr) {
67         super(context, attrs, defStyleAttr);
68         init(context, attrs);
69     }
70 
SettingsMainSwitchPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)71     public SettingsMainSwitchPreference(Context context, AttributeSet attrs, int defStyleAttr,
72             int defStyleRes) {
73         super(context, attrs, defStyleAttr, defStyleRes);
74         init(context, attrs);
75     }
76 
77     @Override
onBindViewHolder(PreferenceViewHolder holder)78     public void onBindViewHolder(PreferenceViewHolder holder) {
79         super.onBindViewHolder(holder);
80 
81         holder.setDividerAllowedAbove(false);
82         holder.setDividerAllowedBelow(false);
83 
84         if (mRestrictedHelper != null) {
85             mEnforcedAdmin = mRestrictedHelper.checkRestrictionEnforced();
86         }
87         mMainSwitchBar = (SettingsMainSwitchBar) holder.findViewById(R.id.main_switch_bar);
88         initMainSwitchBar();
89         if (isVisible()) {
90             mMainSwitchBar.show();
91             if (mMainSwitchBar.isChecked() != isChecked()) {
92                 setChecked(isChecked());
93             }
94             registerListenerToSwitchBar();
95         } else {
96             mMainSwitchBar.hide();
97         }
98     }
99 
init(Context context, AttributeSet attrs)100     private void init(Context context, AttributeSet attrs) {
101         setLayoutResource(R.layout.preference_widget_main_switch);
102         mSwitchChangeListeners.add(this);
103 
104         if (attrs != null) {
105             final TypedArray a = context.obtainStyledAttributes(attrs,
106                     androidx.preference.R.styleable.Preference, 0/*defStyleAttr*/,
107                     0/*defStyleRes*/);
108             final CharSequence title = TypedArrayUtils.getText(a,
109                     androidx.preference.R.styleable.Preference_title,
110                     androidx.preference.R.styleable.Preference_android_title);
111             if (!TextUtils.isEmpty(title)) {
112                 setTitle(title.toString());
113             }
114             a.recycle();
115 
116             mRestrictedHelper = new RestrictedPreferenceHelper(context, this, attrs);
117         }
118     }
119 
120     @Override
setChecked(boolean checked)121     public void setChecked(boolean checked) {
122         super.setChecked(checked);
123         if (mMainSwitchBar != null) {
124             mMainSwitchBar.setChecked(checked);
125         }
126     }
127 
128     /**
129      * Return the SettingsMainSwitchBar
130      */
getSwitchBar()131     public final SettingsMainSwitchBar getSwitchBar() {
132         return mMainSwitchBar;
133     }
134 
135     @Override
setTitle(CharSequence title)136     public void setTitle(CharSequence title) {
137         mTitle = title;
138         if (mMainSwitchBar != null) {
139             mMainSwitchBar.setTitle(mTitle);
140         }
141     }
142 
143     @Override
onSwitchChanged(Switch switchView, boolean isChecked)144     public void onSwitchChanged(Switch switchView, boolean isChecked) {
145         super.setChecked(isChecked);
146     }
147 
148     /**
149      * Show the MainSwitchBar
150      */
show()151     public void show() {
152         setVisible(true);
153         if (mMainSwitchBar != null) {
154             mMainSwitchBar.show();
155         }
156     }
157 
158     /**
159      * Hide the MainSwitchBar
160      */
hide()161     public void hide() {
162         setVisible(false);
163         if (mMainSwitchBar != null) {
164             mMainSwitchBar.hide();
165         }
166     }
167 
168     /**
169      * Returns if the MainSwitchBar is visible.
170      */
isShowing()171     public boolean isShowing() {
172         if (mMainSwitchBar != null) {
173             return mMainSwitchBar.isShowing();
174         }
175         return false;
176     }
177 
178     /**
179      * Update the status of switch but doesn't notify the mOnBeforeListener.
180      */
setCheckedInternal(boolean checked)181     public void setCheckedInternal(boolean checked) {
182         super.setChecked(checked);
183         if (mMainSwitchBar != null) {
184             mMainSwitchBar.setCheckedInternal(checked);
185         }
186     }
187 
188     /**
189      * Enable or disable the text and switch.
190      */
setSwitchBarEnabled(boolean enabled)191     public void setSwitchBarEnabled(boolean enabled) {
192         setEnabled(enabled);
193         if (mMainSwitchBar != null) {
194             mMainSwitchBar.setEnabled(enabled);
195         }
196     }
197 
198     /**
199      * Set the OnBeforeCheckedChangeListener.
200      */
setOnBeforeCheckedChangeListener(OnBeforeCheckedChangeListener listener)201     public void setOnBeforeCheckedChangeListener(OnBeforeCheckedChangeListener listener) {
202         if (mMainSwitchBar == null) {
203             mBeforeCheckedChangeListeners.add(listener);
204         } else {
205             mMainSwitchBar.setOnBeforeCheckedChangeListener(listener);
206         }
207     }
208 
209     /**
210      * Adds a listener for switch changes
211      */
addOnSwitchChangeListener(OnMainSwitchChangeListener listener)212     public void addOnSwitchChangeListener(OnMainSwitchChangeListener listener) {
213         if (mMainSwitchBar == null) {
214             mSwitchChangeListeners.add(listener);
215         } else {
216             mMainSwitchBar.addOnSwitchChangeListener(listener);
217         }
218     }
219 
220     /**
221      * Remove a listener for switch changes
222      */
removeOnSwitchChangeListener(OnMainSwitchChangeListener listener)223     public void removeOnSwitchChangeListener(OnMainSwitchChangeListener listener) {
224         if (mMainSwitchBar == null) {
225             mSwitchChangeListeners.remove(listener);
226         } else {
227             mMainSwitchBar.removeOnSwitchChangeListener(listener);
228         }
229     }
230 
231     /**
232      * If admin is not null, disables the text and switch but keeps the view clickable.
233      * Otherwise, calls setEnabled which will enables the entire view including
234      * the text and switch.
235      */
setDisabledByAdmin(EnforcedAdmin admin)236     public void setDisabledByAdmin(EnforcedAdmin admin) {
237         mEnforcedAdmin = admin;
238         if (mMainSwitchBar != null) {
239             mMainSwitchBar.setDisabledByAdmin(mEnforcedAdmin);
240         }
241     }
242 
initMainSwitchBar()243     private void initMainSwitchBar() {
244         if (mMainSwitchBar != null) {
245             mMainSwitchBar.setTitle(mTitle);
246             mMainSwitchBar.setDisabledByAdmin(mEnforcedAdmin);
247         }
248     }
249 
registerListenerToSwitchBar()250     private void registerListenerToSwitchBar() {
251         for (OnBeforeCheckedChangeListener listener : mBeforeCheckedChangeListeners) {
252             mMainSwitchBar.setOnBeforeCheckedChangeListener(listener);
253         }
254         for (OnMainSwitchChangeListener listener : mSwitchChangeListeners) {
255             mMainSwitchBar.addOnSwitchChangeListener(listener);
256         }
257         mBeforeCheckedChangeListeners.clear();
258         mSwitchChangeListeners.clear();
259     }
260 }
261