Home | History | Annotate | Download | only in widget
      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          */
     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 
     65     public SwitchBar(Context context) {
     66         this(context, null);
     67     }
     68 
     69     public SwitchBar(Context context, AttributeSet attrs) {
     70         this(context, attrs, 0);
     71     }
     72 
     73     public SwitchBar(Context context, AttributeSet attrs, int defStyleAttr) {
     74         this(context, attrs, defStyleAttr, 0);
     75     }
     76 
     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 
    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 
    120     public void setSummary(String summary) {
    121         mSummary = summary;
    122         updateText();
    123     }
    124 
    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 
    137     public void setChecked(boolean checked) {
    138         setTextViewLabel(checked);
    139         mSwitch.setChecked(checked);
    140     }
    141 
    142     public void setCheckedInternal(boolean checked) {
    143         setTextViewLabel(checked);
    144         mSwitch.setCheckedInternal(checked);
    145     }
    146 
    147     public boolean isChecked() {
    148         return mSwitch.isChecked();
    149     }
    150 
    151     public void setEnabled(boolean enabled) {
    152         super.setEnabled(enabled);
    153         mTextView.setEnabled(enabled);
    154         mSwitch.setEnabled(enabled);
    155     }
    156 
    157     public final ToggleSwitch getSwitch() {
    158         return mSwitch;
    159     }
    160 
    161     public void show() {
    162         if (!isShowing()) {
    163             setVisibility(View.VISIBLE);
    164             mSwitch.setOnCheckedChangeListener(this);
    165         }
    166     }
    167 
    168     public void hide() {
    169         if (isShowing()) {
    170             setVisibility(View.GONE);
    171             mSwitch.setOnCheckedChangeListener(null);
    172         }
    173     }
    174 
    175     public boolean isShowing() {
    176         return (getVisibility() == View.VISIBLE);
    177     }
    178 
    179     @Override
    180     public void onClick(View v) {
    181         final boolean isChecked = !mSwitch.isChecked();
    182         setChecked(isChecked);
    183     }
    184 
    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
    193     public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
    194         propagateChecked(isChecked);
    195     }
    196 
    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 
    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 
    215         SavedState(Parcelable superState) {
    216             super(superState);
    217         }
    218 
    219         /**
    220          * Constructor called from {@link #CREATOR}
    221          */
    222         private SavedState(Parcel in) {
    223             super(in);
    224             checked = (Boolean)in.readValue(null);
    225             visible = (Boolean)in.readValue(null);
    226         }
    227 
    228         @Override
    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
    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
    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
    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