• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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 android.content.Context;
20 import android.content.res.TypedArray;
21 import android.os.Parcel;
22 import android.os.Parcelable;
23 import android.text.SpannableStringBuilder;
24 import android.text.TextUtils;
25 import android.text.style.TextAppearanceSpan;
26 import android.util.AttributeSet;
27 import android.view.LayoutInflater;
28 import android.view.View;
29 import android.view.ViewGroup;
30 import android.widget.CompoundButton;
31 import android.widget.LinearLayout;
32 import android.widget.Switch;
33 import android.widget.TextView;
34 
35 import com.android.settings.R;
36 
37 import java.util.ArrayList;
38 
39 public class SwitchBar extends LinearLayout implements CompoundButton.OnCheckedChangeListener,
40         View.OnClickListener {
41 
42     public static interface OnSwitchChangeListener {
43         /**
44          * Called when the checked state of the Switch has changed.
45          *
46          * @param switchView The Switch view whose state has changed.
47          * @param isChecked  The new checked state of switchView.
48          */
onSwitchChanged(Switch switchView, boolean isChecked)49         void onSwitchChanged(Switch switchView, boolean isChecked);
50     }
51 
52     private final TextAppearanceSpan mSummarySpan;
53 
54     private ToggleSwitch mSwitch;
55     private TextView mTextView;
56     private String mLabel;
57     private String mSummary;
58 
59     private ArrayList<OnSwitchChangeListener> mSwitchChangeListeners =
60             new ArrayList<OnSwitchChangeListener>();
61 
62     private static int[] MARGIN_ATTRIBUTES = {
63             R.attr.switchBarMarginStart, R.attr.switchBarMarginEnd};
64 
SwitchBar(Context context)65     public SwitchBar(Context context) {
66         this(context, null);
67     }
68 
SwitchBar(Context context, AttributeSet attrs)69     public SwitchBar(Context context, AttributeSet attrs) {
70         this(context, attrs, 0);
71     }
72 
SwitchBar(Context context, AttributeSet attrs, int defStyleAttr)73     public SwitchBar(Context context, AttributeSet attrs, int defStyleAttr) {
74         this(context, attrs, defStyleAttr, 0);
75     }
76 
SwitchBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)77     public SwitchBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
78         super(context, attrs, defStyleAttr, defStyleRes);
79 
80         LayoutInflater.from(context).inflate(R.layout.switch_bar, this);
81 
82         final TypedArray a = context.obtainStyledAttributes(attrs, MARGIN_ATTRIBUTES);
83         int switchBarMarginStart = (int) a.getDimension(0, 0);
84         int switchBarMarginEnd = (int) a.getDimension(1, 0);
85         a.recycle();
86 
87         mTextView = (TextView) findViewById(R.id.switch_text);
88         mLabel = getResources().getString(R.string.switch_off_text);
89         mSummarySpan = new TextAppearanceSpan(mContext, R.style.TextAppearance_Small_SwitchBar);
90         updateText();
91         ViewGroup.MarginLayoutParams lp = (MarginLayoutParams) mTextView.getLayoutParams();
92         lp.setMarginStart(switchBarMarginStart);
93 
94         mSwitch = (ToggleSwitch) findViewById(R.id.switch_widget);
95         // Prevent onSaveInstanceState() to be called as we are managing the state of the Switch
96         // on our own
97         mSwitch.setSaveEnabled(false);
98         lp = (MarginLayoutParams) mSwitch.getLayoutParams();
99         lp.setMarginEnd(switchBarMarginEnd);
100 
101         addOnSwitchChangeListener(new OnSwitchChangeListener() {
102             @Override
103             public void onSwitchChanged(Switch switchView, boolean isChecked) {
104                 setTextViewLabel(isChecked);
105             }
106         });
107 
108         setOnClickListener(this);
109 
110         // Default is hide
111         setVisibility(View.GONE);
112     }
113 
setTextViewLabel(boolean isChecked)114     public void setTextViewLabel(boolean isChecked) {
115         mLabel = getResources()
116                 .getString(isChecked ? R.string.switch_on_text : R.string.switch_off_text);
117         updateText();
118     }
119 
setSummary(String summary)120     public void setSummary(String summary) {
121         mSummary = summary;
122         updateText();
123     }
124 
updateText()125     private void updateText() {
126         if (TextUtils.isEmpty(mSummary)) {
127             mTextView.setText(mLabel);
128             return;
129         }
130         final SpannableStringBuilder ssb = new SpannableStringBuilder(mLabel).append('\n');
131         final int start = ssb.length();
132         ssb.append(mSummary);
133         ssb.setSpan(mSummarySpan, start, ssb.length(), 0);
134         mTextView.setText(ssb);
135     }
136 
setChecked(boolean checked)137     public void setChecked(boolean checked) {
138         setTextViewLabel(checked);
139         mSwitch.setChecked(checked);
140     }
141 
setCheckedInternal(boolean checked)142     public void setCheckedInternal(boolean checked) {
143         setTextViewLabel(checked);
144         mSwitch.setCheckedInternal(checked);
145     }
146 
isChecked()147     public boolean isChecked() {
148         return mSwitch.isChecked();
149     }
150 
setEnabled(boolean enabled)151     public void setEnabled(boolean enabled) {
152         super.setEnabled(enabled);
153         mTextView.setEnabled(enabled);
154         mSwitch.setEnabled(enabled);
155     }
156 
getSwitch()157     public final ToggleSwitch getSwitch() {
158         return mSwitch;
159     }
160 
show()161     public void show() {
162         if (!isShowing()) {
163             setVisibility(View.VISIBLE);
164             mSwitch.setOnCheckedChangeListener(this);
165         }
166     }
167 
hide()168     public void hide() {
169         if (isShowing()) {
170             setVisibility(View.GONE);
171             mSwitch.setOnCheckedChangeListener(null);
172         }
173     }
174 
isShowing()175     public boolean isShowing() {
176         return (getVisibility() == View.VISIBLE);
177     }
178 
179     @Override
onClick(View v)180     public void onClick(View v) {
181         final boolean isChecked = !mSwitch.isChecked();
182         setChecked(isChecked);
183     }
184 
propagateChecked(boolean isChecked)185     public void propagateChecked(boolean isChecked) {
186         final int count = mSwitchChangeListeners.size();
187         for (int n = 0; n < count; n++) {
188             mSwitchChangeListeners.get(n).onSwitchChanged(mSwitch, isChecked);
189         }
190     }
191 
192     @Override
onCheckedChanged(CompoundButton buttonView, boolean isChecked)193     public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
194         propagateChecked(isChecked);
195     }
196 
addOnSwitchChangeListener(OnSwitchChangeListener listener)197     public void addOnSwitchChangeListener(OnSwitchChangeListener listener) {
198         if (mSwitchChangeListeners.contains(listener)) {
199             throw new IllegalStateException("Cannot add twice the same OnSwitchChangeListener");
200         }
201         mSwitchChangeListeners.add(listener);
202     }
203 
removeOnSwitchChangeListener(OnSwitchChangeListener listener)204     public void removeOnSwitchChangeListener(OnSwitchChangeListener listener) {
205         if (!mSwitchChangeListeners.contains(listener)) {
206             throw new IllegalStateException("Cannot remove OnSwitchChangeListener");
207         }
208         mSwitchChangeListeners.remove(listener);
209     }
210 
211     static class SavedState extends BaseSavedState {
212         boolean checked;
213         boolean visible;
214 
SavedState(Parcelable superState)215         SavedState(Parcelable superState) {
216             super(superState);
217         }
218 
219         /**
220          * Constructor called from {@link #CREATOR}
221          */
SavedState(Parcel in)222         private SavedState(Parcel in) {
223             super(in);
224             checked = (Boolean)in.readValue(null);
225             visible = (Boolean)in.readValue(null);
226         }
227 
228         @Override
writeToParcel(Parcel out, int flags)229         public void writeToParcel(Parcel out, int flags) {
230             super.writeToParcel(out, flags);
231             out.writeValue(checked);
232             out.writeValue(visible);
233         }
234 
235         @Override
toString()236         public String toString() {
237             return "SwitchBar.SavedState{"
238                     + Integer.toHexString(System.identityHashCode(this))
239                     + " checked=" + checked
240                     + " visible=" + visible + "}";
241         }
242 
243         public static final Parcelable.Creator<SavedState> CREATOR
244                 = new Parcelable.Creator<SavedState>() {
245             public SavedState createFromParcel(Parcel in) {
246                 return new SavedState(in);
247             }
248 
249             public SavedState[] newArray(int size) {
250                 return new SavedState[size];
251             }
252         };
253     }
254 
255     @Override
onSaveInstanceState()256     public Parcelable onSaveInstanceState() {
257         Parcelable superState = super.onSaveInstanceState();
258 
259         SavedState ss = new SavedState(superState);
260         ss.checked = mSwitch.isChecked();
261         ss.visible = isShowing();
262         return ss;
263     }
264 
265     @Override
onRestoreInstanceState(Parcelable state)266     public void onRestoreInstanceState(Parcelable state) {
267         SavedState ss = (SavedState) state;
268 
269         super.onRestoreInstanceState(ss.getSuperState());
270 
271         mSwitch.setCheckedInternal(ss.checked);
272         setTextViewLabel(ss.checked);
273         setVisibility(ss.visible ? View.VISIBLE : View.GONE);
274         mSwitch.setOnCheckedChangeListener(ss.visible ? this : null);
275 
276         requestLayout();
277     }
278 }
279