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