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