• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.util.AttributeSet;
23 import android.widget.CompoundButton;
24 import android.widget.CompoundButton.OnCheckedChangeListener;
25 
26 import androidx.annotation.NonNull;
27 import androidx.preference.PreferenceViewHolder;
28 import androidx.preference.TwoStatePreference;
29 
30 import com.android.settings.R;
31 import com.android.settings.widget.SettingsMainSwitchBar.OnBeforeCheckedChangeListener;
32 import com.android.settingslib.RestrictedPreferenceHelper;
33 import com.android.settingslib.RestrictedPreferenceHelperProvider;
34 import com.android.settingslib.core.instrumentation.SettingsJankMonitor;
35 import com.android.settingslib.widget.GroupSectionDividerMixin;
36 
37 import java.util.ArrayList;
38 import java.util.List;
39 
40 /**
41  * SettingsMainSwitchPreference is a Preference with a customized Switch.
42  * This component is used as the main switch of the page
43  * to enable or disable the preferences on the page.
44  */
45 public class SettingsMainSwitchPreference extends TwoStatePreference implements
46         OnCheckedChangeListener, RestrictedPreferenceHelperProvider, GroupSectionDividerMixin {
47 
48     private final List<OnBeforeCheckedChangeListener> mBeforeCheckedChangeListeners =
49             new ArrayList<>();
50     private final List<OnCheckedChangeListener> mSwitchChangeListeners = new ArrayList<>();
51 
52     private SettingsMainSwitchBar mMainSwitchBar;
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
getRestrictedPreferenceHelper()78     public @NonNull RestrictedPreferenceHelper getRestrictedPreferenceHelper() {
79         return mRestrictedHelper;
80     }
81 
82     @Override
onBindViewHolder(PreferenceViewHolder holder)83     public void onBindViewHolder(PreferenceViewHolder holder) {
84         super.onBindViewHolder(holder);
85 
86         holder.setDividerAllowedAbove(false);
87         holder.setDividerAllowedBelow(false);
88 
89         if (mEnforcedAdmin == null && mRestrictedHelper != null) {
90             mEnforcedAdmin = mRestrictedHelper.checkRestrictionEnforced();
91         }
92         mMainSwitchBar = (SettingsMainSwitchBar) holder.findViewById(R.id.main_switch_bar);
93         initMainSwitchBar();
94         if (isVisible()) {
95             mMainSwitchBar.show();
96             if (mMainSwitchBar.isChecked() != isChecked()) {
97                 setChecked(isChecked());
98             }
99             registerListenerToSwitchBar();
100         } else {
101             mMainSwitchBar.hide();
102         }
103     }
104 
init(Context context, AttributeSet attrs)105     private void init(Context context, AttributeSet attrs) {
106         setLayoutResource(R.layout.preference_widget_main_switch);
107         mSwitchChangeListeners.add(this);
108 
109         if (attrs != null) {
110             mRestrictedHelper = new RestrictedPreferenceHelper(context, this, attrs);
111         }
112     }
113 
114     @Override
setChecked(boolean checked)115     public void setChecked(boolean checked) {
116         super.setChecked(checked);
117         if (mMainSwitchBar != null) {
118             mMainSwitchBar.setChecked(checked);
119         }
120     }
121 
122     /**
123      * Return the SettingsMainSwitchBar
124      */
getSwitchBar()125     public final SettingsMainSwitchBar getSwitchBar() {
126         return mMainSwitchBar;
127     }
128 
129     @Override
setTitle(CharSequence title)130     public void setTitle(CharSequence title) {
131         super.setTitle(title);
132         if (mMainSwitchBar != null) {
133             mMainSwitchBar.setTitle(title);
134         }
135     }
136 
137     @Override
onCheckedChanged(CompoundButton buttonView, boolean isChecked)138     public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
139         super.setChecked(isChecked);
140         SettingsJankMonitor.detectToggleJank(getKey(), buttonView);
141     }
142 
143     /**
144      * Show the MainSwitchBar
145      */
show()146     public void show() {
147         setVisible(true);
148         if (mMainSwitchBar != null) {
149             mMainSwitchBar.show();
150         }
151     }
152 
153     /**
154      * Hide the MainSwitchBar
155      */
hide()156     public void hide() {
157         setVisible(false);
158         if (mMainSwitchBar != null) {
159             mMainSwitchBar.hide();
160         }
161     }
162 
163     /**
164      * Returns if the MainSwitchBar is visible.
165      */
isShowing()166     public boolean isShowing() {
167         if (mMainSwitchBar != null) {
168             return mMainSwitchBar.isShowing();
169         }
170         return false;
171     }
172 
173     /**
174      * Update the status of switch but doesn't notify the mOnBeforeListener.
175      */
setCheckedInternal(boolean checked)176     public void setCheckedInternal(boolean checked) {
177         super.setChecked(checked);
178         if (mMainSwitchBar != null) {
179             mMainSwitchBar.setCheckedInternal(checked);
180         }
181     }
182 
183     /**
184      * Enable or disable the text and switch.
185      */
setSwitchBarEnabled(boolean enabled)186     public void setSwitchBarEnabled(boolean enabled) {
187         setEnabled(enabled);
188         if (mMainSwitchBar != null) {
189             mMainSwitchBar.setEnabled(enabled);
190         }
191     }
192 
193     /**
194      * Set the OnBeforeCheckedChangeListener.
195      */
setOnBeforeCheckedChangeListener(OnBeforeCheckedChangeListener listener)196     public void setOnBeforeCheckedChangeListener(OnBeforeCheckedChangeListener listener) {
197         if (!mBeforeCheckedChangeListeners.contains(listener)) {
198             mBeforeCheckedChangeListeners.add(listener);
199         }
200         if (mMainSwitchBar != null) {
201             mMainSwitchBar.setOnBeforeCheckedChangeListener(listener);
202         }
203     }
204 
205     /**
206      * Adds a listener for switch changes
207      */
addOnSwitchChangeListener(OnCheckedChangeListener listener)208     public void addOnSwitchChangeListener(OnCheckedChangeListener listener) {
209         if (!mSwitchChangeListeners.contains(listener)) {
210             mSwitchChangeListeners.add(listener);
211         }
212         if (mMainSwitchBar != null) {
213             mMainSwitchBar.addOnSwitchChangeListener(listener);
214         }
215     }
216 
217     /**
218      * Remove a listener for switch changes
219      */
removeOnSwitchChangeListener(OnCheckedChangeListener listener)220     public void removeOnSwitchChangeListener(OnCheckedChangeListener listener) {
221         mSwitchChangeListeners.remove(listener);
222         if (mMainSwitchBar != null) {
223             mMainSwitchBar.removeOnSwitchChangeListener(listener);
224         }
225     }
226 
227     /**
228      * If admin is not null, disables the text and switch but keeps the view clickable.
229      * Otherwise, calls setEnabled which will enables the entire view including
230      * the text and switch.
231      */
setDisabledByAdmin(EnforcedAdmin admin)232     public void setDisabledByAdmin(EnforcedAdmin admin) {
233         mEnforcedAdmin = admin;
234         if (mMainSwitchBar != null) {
235             mMainSwitchBar.setDisabledByAdmin(mEnforcedAdmin);
236         }
237     }
238 
initMainSwitchBar()239     private void initMainSwitchBar() {
240         if (mMainSwitchBar != null) {
241             mMainSwitchBar.setTitle(getTitle());
242             mMainSwitchBar.setDisabledByAdmin(mEnforcedAdmin);
243 
244             // Disable the focusability of the switch bar. The parent FrameLayout
245             // will be the only focusable view for the Main Switch Bar to avoid
246             // duplicate a11y focus.
247             mMainSwitchBar.setFocusable(false);
248         }
249     }
250 
registerListenerToSwitchBar()251     private void registerListenerToSwitchBar() {
252         for (OnBeforeCheckedChangeListener listener : mBeforeCheckedChangeListeners) {
253             mMainSwitchBar.setOnBeforeCheckedChangeListener(listener);
254         }
255         for (OnCheckedChangeListener listener : mSwitchChangeListeners) {
256             mMainSwitchBar.addOnSwitchChangeListener(listener);
257         }
258     }
259 }
260