1 /*
2  * Copyright (C) 2007 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 android.widget;
18 
19 import android.annotation.FloatRange;
20 import android.annotation.NonNull;
21 import android.content.Context;
22 import android.content.res.TypedArray;
23 import android.graphics.drawable.Drawable;
24 import android.graphics.drawable.LayerDrawable;
25 import android.util.AttributeSet;
26 import android.view.inspector.InspectableProperty;
27 
28 import com.android.internal.R;
29 
30 /**
31  * Displays checked/unchecked states as a button
32  * with a "light" indicator and by default accompanied with the text "ON" or "OFF".
33  *
34  * <p>See the <a href="{@docRoot}guide/topics/ui/controls/togglebutton.html">Toggle Buttons</a>
35  * guide.</p>
36  *
37  * @attr ref android.R.styleable#ToggleButton_textOn
38  * @attr ref android.R.styleable#ToggleButton_textOff
39  * @attr ref android.R.styleable#ToggleButton_disabledAlpha
40  */
41 public class ToggleButton extends CompoundButton {
42     private CharSequence mTextOn;
43     private CharSequence mTextOff;
44 
45     private Drawable mIndicatorDrawable;
46 
47     private static final int NO_ALPHA = 0xFF;
48     private float mDisabledAlpha;
49 
ToggleButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)50     public ToggleButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
51         super(context, attrs, defStyleAttr, defStyleRes);
52 
53         final TypedArray a = context.obtainStyledAttributes(
54                 attrs, com.android.internal.R.styleable.ToggleButton, defStyleAttr, defStyleRes);
55         saveAttributeDataForStyleable(context, com.android.internal.R.styleable.ToggleButton,
56                 attrs, a, defStyleAttr, defStyleRes);
57         mTextOn = a.getText(com.android.internal.R.styleable.ToggleButton_textOn);
58         mTextOff = a.getText(com.android.internal.R.styleable.ToggleButton_textOff);
59         mDisabledAlpha = a.getFloat(com.android.internal.R.styleable.ToggleButton_disabledAlpha, 0.5f);
60         syncTextState();
61         // Default state is derived from on/off-text, so state has to be updated when on/off-text
62         // are updated.
63         setDefaultStateDescription();
64         a.recycle();
65     }
66 
ToggleButton(Context context, AttributeSet attrs, int defStyleAttr)67     public ToggleButton(Context context, AttributeSet attrs, int defStyleAttr) {
68         this(context, attrs, defStyleAttr, 0);
69     }
70 
ToggleButton(Context context, AttributeSet attrs)71     public ToggleButton(Context context, AttributeSet attrs) {
72         this(context, attrs, com.android.internal.R.attr.buttonStyleToggle);
73     }
74 
ToggleButton(Context context)75     public ToggleButton(Context context) {
76         this(context, null);
77     }
78 
79     @Override
setChecked(boolean checked)80     public void setChecked(boolean checked) {
81         super.setChecked(checked);
82 
83         syncTextState();
84     }
85 
syncTextState()86     private void syncTextState() {
87         boolean checked = isChecked();
88         if (checked && mTextOn != null) {
89             setText(mTextOn);
90         } else if (!checked && mTextOff != null) {
91             setText(mTextOff);
92         }
93     }
94 
95     /**
96      * Returns the text for when the button is in the checked state.
97      *
98      * @return The text.
99      */
100     @InspectableProperty
getTextOn()101     public CharSequence getTextOn() {
102         return mTextOn;
103     }
104 
105     /**
106      * Sets the text for when the button is in the checked state.
107      *
108      * @param textOn The text.
109      */
setTextOn(CharSequence textOn)110     public void setTextOn(CharSequence textOn) {
111         mTextOn = textOn;
112         // Default state is derived from on/off-text, so state has to be updated when on/off-text
113         // are updated.
114         setDefaultStateDescription();
115     }
116 
117     /**
118      * Returns the text for when the button is not in the checked state.
119      *
120      * @return The text.
121      */
122     @InspectableProperty
getTextOff()123     public CharSequence getTextOff() {
124         return mTextOff;
125     }
126 
127     /**
128      * Sets the text for when the button is not in the checked state.
129      *
130      * @param textOff The text.
131      */
setTextOff(CharSequence textOff)132     public void setTextOff(CharSequence textOff) {
133         mTextOff = textOff;
134         // Default state is derived from on/off-text, so state has to be updated when on/off-text
135         // are updated.
136         setDefaultStateDescription();
137     }
138 
139     /**
140      * Returns the alpha value of the button when it is disabled
141      *
142      * @return the alpha value, 0.0-1.0
143      */
144     @InspectableProperty
145     @FloatRange(from = 0.0, to = 1.0)
getDisabledAlpha()146     public float getDisabledAlpha() {
147         return mDisabledAlpha;
148     }
149 
150     @Override
onFinishInflate()151     protected void onFinishInflate() {
152         super.onFinishInflate();
153 
154         updateReferenceToIndicatorDrawable(getBackground());
155     }
156 
157     @Override
setBackgroundDrawable(Drawable d)158     public void setBackgroundDrawable(Drawable d) {
159         super.setBackgroundDrawable(d);
160 
161         updateReferenceToIndicatorDrawable(d);
162     }
163 
updateReferenceToIndicatorDrawable(Drawable backgroundDrawable)164     private void updateReferenceToIndicatorDrawable(Drawable backgroundDrawable) {
165         if (backgroundDrawable instanceof LayerDrawable) {
166             LayerDrawable layerDrawable = (LayerDrawable) backgroundDrawable;
167             mIndicatorDrawable =
168                     layerDrawable.findDrawableByLayerId(com.android.internal.R.id.toggle);
169         } else {
170             mIndicatorDrawable = null;
171         }
172     }
173 
174     @Override
drawableStateChanged()175     protected void drawableStateChanged() {
176         super.drawableStateChanged();
177 
178         if (mIndicatorDrawable != null) {
179             mIndicatorDrawable.setAlpha(isEnabled() ? NO_ALPHA : (int) (NO_ALPHA * mDisabledAlpha));
180         }
181     }
182 
183     @Override
getAccessibilityClassName()184     public CharSequence getAccessibilityClassName() {
185         return ToggleButton.class.getName();
186     }
187 
188     /** @hide **/
189     @Override
190     @NonNull
getButtonStateDescription()191     protected CharSequence getButtonStateDescription() {
192         if (isChecked()) {
193             return mTextOn == null ? getResources().getString(R.string.capital_on) : mTextOn;
194         } else {
195             return mTextOff == null ? getResources().getString(R.string.capital_off) : mTextOff;
196         }
197     }
198 }
199