112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell/*
212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell * Copyright (C) 2010 The Android Open Source Project
312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell *
412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell * Licensed under the Apache License, Version 2.0 (the "License");
512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell * you may not use this file except in compliance with the License.
612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell * You may obtain a copy of the License at
712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell *
812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell *      http://www.apache.org/licenses/LICENSE-2.0
912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell *
1012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell * Unless required by applicable law or agreed to in writing, software
1112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell * distributed under the License is distributed on an "AS IS" BASIS,
1212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell * See the License for the specific language governing permissions and
1412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell * limitations under the License.
1512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell */
1612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
1712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellpackage android.widget;
1812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
19cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viveretteimport android.animation.ObjectAnimator;
207b9c912f536925ac6ec43935d6e97506851b33d6Tor Norbyeimport android.annotation.DrawableRes;
21f6d87ec193f17e8dad82c9994ba7a58e975d364bAlan Viveretteimport android.annotation.NonNull;
22e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viveretteimport android.annotation.Nullable;
237b9c912f536925ac6ec43935d6e97506851b33d6Tor Norbyeimport android.annotation.StyleRes;
2412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.content.Context;
2512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.content.res.ColorStateList;
2612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.content.res.Resources;
2712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.content.res.TypedArray;
2812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.graphics.Canvas;
29661e63658da39cccfe49a129e4860455716ff3c9Alan Viveretteimport android.graphics.Insets;
306a49ddef62865c1b245ad60a13c334f0ffaf1a5fChris Craikimport android.graphics.Paint;
31e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viveretteimport android.graphics.PorterDuff;
3212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.graphics.Rect;
33661e63658da39cccfe49a129e4860455716ff3c9Alan Viveretteimport android.graphics.Region.Op;
3499441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikasimport android.graphics.Typeface;
3512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.graphics.drawable.Drawable;
3612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.text.Layout;
3712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.text.StaticLayout;
3812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.text.TextPaint;
3912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.text.TextUtils;
404c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandlerimport android.text.method.AllCapsTransformationMethod;
414c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandlerimport android.text.method.TransformationMethod2;
4212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.util.AttributeSet;
43cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viveretteimport android.util.FloatProperty;
44cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viveretteimport android.util.MathUtils;
4512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.view.Gravity;
4612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.view.MotionEvent;
47d4e7790fee10e21b41a1c387c2734722bda56a0bAlan Viveretteimport android.view.SoundEffectConstants;
4812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.view.VelocityTracker;
4912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.view.ViewConfiguration;
5099441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikasimport android.view.ViewStructure;
5163bce03cc69be4a45230aa8bbd89dbde60681067Svetoslav Ganovimport android.view.accessibility.AccessibilityEvent;
528a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganovimport android.view.accessibility.AccessibilityNodeInfo;
5312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
54be0a4535053bbfdebd215e244b154ac810fd8edcAdam Powellimport com.android.internal.R;
55be0a4535053bbfdebd215e244b154ac810fd8edcAdam Powell
5612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell/**
5712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell * A Switch is a two-state toggle switch widget that can select between two
5812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell * options. The user may drag the "thumb" back and forth to choose the selected option,
59150176d83023e3c486dba10edebb72af36b4099aChet Haase * or simply tap to toggle as if it were a checkbox. The {@link #setText(CharSequence) text}
60150176d83023e3c486dba10edebb72af36b4099aChet Haase * property controls the text displayed in the label for the switch, whereas the
61150176d83023e3c486dba10edebb72af36b4099aChet Haase * {@link #setTextOff(CharSequence) off} and {@link #setTextOn(CharSequence) on} text
62150176d83023e3c486dba10edebb72af36b4099aChet Haase * controls the text on the thumb. Similarly, the
63150176d83023e3c486dba10edebb72af36b4099aChet Haase * {@link #setTextAppearance(android.content.Context, int) textAppearance} and the related
64150176d83023e3c486dba10edebb72af36b4099aChet Haase * setTypeface() methods control the typeface and style of label text, whereas the
65150176d83023e3c486dba10edebb72af36b4099aChet Haase * {@link #setSwitchTextAppearance(android.content.Context, int) switchTextAppearance} and
6607e7021e062dd3579f662502b15c0682c4672cfeAndrew Solovay * the related setSwitchTypeface() methods control that of the thumb.
6712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell *
683404032dfc3ef9130806de62289da27b3de0be46Mark Lu * <p>{@link android.support.v7.widget.SwitchCompat} is a version of
693404032dfc3ef9130806de62289da27b3de0be46Mark Lu * the Switch widget which runs on devices back to API 7.</p>
703404032dfc3ef9130806de62289da27b3de0be46Mark Lu *
714c359b76f9a030f92a302ba74a528faa170bad4eScott Main * <p>See the <a href="{@docRoot}guide/topics/ui/controls/togglebutton.html">Toggle Buttons</a>
724c359b76f9a030f92a302ba74a528faa170bad4eScott Main * guide.</p>
734c359b76f9a030f92a302ba74a528faa170bad4eScott Main *
744c359b76f9a030f92a302ba74a528faa170bad4eScott Main * @attr ref android.R.styleable#Switch_textOn
754c359b76f9a030f92a302ba74a528faa170bad4eScott Main * @attr ref android.R.styleable#Switch_textOff
764c359b76f9a030f92a302ba74a528faa170bad4eScott Main * @attr ref android.R.styleable#Switch_switchMinWidth
774c359b76f9a030f92a302ba74a528faa170bad4eScott Main * @attr ref android.R.styleable#Switch_switchPadding
784c359b76f9a030f92a302ba74a528faa170bad4eScott Main * @attr ref android.R.styleable#Switch_switchTextAppearance
794c359b76f9a030f92a302ba74a528faa170bad4eScott Main * @attr ref android.R.styleable#Switch_thumb
804c359b76f9a030f92a302ba74a528faa170bad4eScott Main * @attr ref android.R.styleable#Switch_thumbTextPadding
814c359b76f9a030f92a302ba74a528faa170bad4eScott Main * @attr ref android.R.styleable#Switch_track
8212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell */
8312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellpublic class Switch extends CompoundButton {
84cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    private static final int THUMB_ANIMATION_DURATION = 250;
85cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette
8612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int TOUCH_MODE_IDLE = 0;
8712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int TOUCH_MODE_DOWN = 1;
8812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int TOUCH_MODE_DRAGGING = 2;
8912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
9012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    // Enum for the "typeface" XML parameter.
9112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int SANS = 1;
9212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int SERIF = 2;
9312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int MONOSPACE = 3;
9412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
9512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private Drawable mThumbDrawable;
96e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette    private ColorStateList mThumbTintList = null;
97e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette    private PorterDuff.Mode mThumbTintMode = null;
98e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette    private boolean mHasThumbTint = false;
99e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette    private boolean mHasThumbTintMode = false;
100e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette
10112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private Drawable mTrackDrawable;
102e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette    private ColorStateList mTrackTintList = null;
103e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette    private PorterDuff.Mode mTrackTintMode = null;
104e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette    private boolean mHasTrackTint = false;
105e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette    private boolean mHasTrackTintMode = false;
106e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette
10712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mThumbTextPadding;
10812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchMinWidth;
10912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchPadding;
110661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    private boolean mSplitTrack;
11112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private CharSequence mTextOn;
11212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private CharSequence mTextOff;
1132a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette    private boolean mShowText;
11412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
11512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mTouchMode;
11612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mTouchSlop;
11712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private float mTouchX;
11812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private float mTouchY;
11912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private VelocityTracker mVelocityTracker = VelocityTracker.obtain();
12012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mMinFlingVelocity;
12112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
12212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private float mThumbPosition;
1230c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
1240c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette    /**
1250c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     * Width required to draw the switch track and thumb. Includes padding and
1260c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     * optical bounds for both the track and thumb.
1270c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     */
12812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchWidth;
1290c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
1300c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette    /**
1310c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     * Height required to draw the switch track and thumb. Includes padding and
1320c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     * optical bounds for both the track and thumb.
1330c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     */
13412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchHeight;
13512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
1360c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette    /**
1370c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     * Width of the thumb's content region. Does not include padding or
1380c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     * optical bounds.
1390c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     */
1400c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette    private int mThumbWidth;
1410c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
1420c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette    /** Left bound for drawing the switch track and thumb. */
14312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchLeft;
1440c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
1450c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette    /** Top bound for drawing the switch track and thumb. */
14612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchTop;
1470c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
1480c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette    /** Right bound for drawing the switch track and thumb. */
14912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchRight;
1500c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
1510c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette    /** Bottom bound for drawing the switch track and thumb. */
15212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchBottom;
15312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
15412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private TextPaint mTextPaint;
15512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private ColorStateList mTextColors;
15612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private Layout mOnLayout;
15712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private Layout mOffLayout;
1584c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler    private TransformationMethod2 mSwitchTransformationMethod;
159cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    private ObjectAnimator mPositionAnimator;
16012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
161be0a4535053bbfdebd215e244b154ac810fd8edcAdam Powell    @SuppressWarnings("hiding")
16212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private final Rect mTempRect = new Rect();
16312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
16412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int[] CHECKED_STATE_SET = {
16512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        R.attr.state_checked
16612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    };
16712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
16812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
16912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Construct a new Switch with default styling.
17012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     *
17112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param context The Context that will determine this widget's theming.
17212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
17312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public Switch(Context context) {
17412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        this(context, null);
17512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
17612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
17712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
17812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Construct a new Switch with default styling, overriding specific style
17912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * attributes as requested.
18012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     *
18112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param context The Context that will determine this widget's theming.
18212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param attrs Specification of attributes that should deviate from default styling.
18312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
18412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public Switch(Context context, AttributeSet attrs) {
18512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        this(context, attrs, com.android.internal.R.attr.switchStyle);
18612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
18712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
18812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
18912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Construct a new Switch with a default style determined by the given theme attribute,
19012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * overriding specific style attributes as requested.
19112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     *
19212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param context The Context that will determine this widget's theming.
19312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param attrs Specification of attributes that should deviate from the default styling.
194617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     * @param defStyleAttr An attribute in the current theme that contains a
195617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        reference to a style resource that supplies default values for
196617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        the view. Can be 0 to not look for defaults.
19712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
198617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    public Switch(Context context, AttributeSet attrs, int defStyleAttr) {
199617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette        this(context, attrs, defStyleAttr, 0);
200617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    }
201617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette
202617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette
203617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    /**
204617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     * Construct a new Switch with a default style determined by the given theme
205617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     * attribute or style resource, overriding specific style attributes as
206617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     * requested.
207617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *
208617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     * @param context The Context that will determine this widget's theming.
209617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     * @param attrs Specification of attributes that should deviate from the
210617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        default styling.
211617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     * @param defStyleAttr An attribute in the current theme that contains a
212617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        reference to a style resource that supplies default values for
213617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        the view. Can be 0 to not look for defaults.
214617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     * @param defStyleRes A resource identifier of a style resource that
215617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        supplies default values for the view, used only if
216617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        defStyleAttr is 0 or can not be found in the theme. Can be 0
217617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        to not look for defaults.
218617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     */
219617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    public Switch(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
220617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette        super(context, attrs, defStyleAttr, defStyleRes);
22112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
2226a49ddef62865c1b245ad60a13c334f0ffaf1a5fChris Craik        mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
223661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
224661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        final Resources res = getResources();
22512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextPaint.density = res.getDisplayMetrics().density;
22612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextPaint.setCompatibilityScaling(res.getCompatibilityInfo().applicationScale);
22712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
228617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette        final TypedArray a = context.obtainStyledAttributes(
229617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette                attrs, com.android.internal.R.styleable.Switch, defStyleAttr, defStyleRes);
230150176d83023e3c486dba10edebb72af36b4099aChet Haase        mThumbDrawable = a.getDrawable(com.android.internal.R.styleable.Switch_thumb);
231b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette        if (mThumbDrawable != null) {
232b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette            mThumbDrawable.setCallback(this);
233b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette        }
234150176d83023e3c486dba10edebb72af36b4099aChet Haase        mTrackDrawable = a.getDrawable(com.android.internal.R.styleable.Switch_track);
235b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette        if (mTrackDrawable != null) {
236b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette            mTrackDrawable.setCallback(this);
237b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette        }
23812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextOn = a.getText(com.android.internal.R.styleable.Switch_textOn);
23912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextOff = a.getText(com.android.internal.R.styleable.Switch_textOff);
2402a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette        mShowText = a.getBoolean(com.android.internal.R.styleable.Switch_showText, true);
24112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mThumbTextPadding = a.getDimensionPixelSize(
24212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                com.android.internal.R.styleable.Switch_thumbTextPadding, 0);
24312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchMinWidth = a.getDimensionPixelSize(
24412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                com.android.internal.R.styleable.Switch_switchMinWidth, 0);
24512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchPadding = a.getDimensionPixelSize(
24612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                com.android.internal.R.styleable.Switch_switchPadding, 0);
247661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        mSplitTrack = a.getBoolean(com.android.internal.R.styleable.Switch_splitTrack, false);
24812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
2499fb302cfbca57270250a33503791a85f2f5122f1Jun Mukai        ColorStateList thumbTintList = a.getColorStateList(
2509fb302cfbca57270250a33503791a85f2f5122f1Jun Mukai                com.android.internal.R.styleable.Switch_thumbTint);
2519fb302cfbca57270250a33503791a85f2f5122f1Jun Mukai        if (thumbTintList != null) {
2529fb302cfbca57270250a33503791a85f2f5122f1Jun Mukai            mThumbTintList = thumbTintList;
2539fb302cfbca57270250a33503791a85f2f5122f1Jun Mukai            mHasThumbTint = true;
2549fb302cfbca57270250a33503791a85f2f5122f1Jun Mukai        }
2559fb302cfbca57270250a33503791a85f2f5122f1Jun Mukai        PorterDuff.Mode thumbTintMode = Drawable.parseTintMode(
2569fb302cfbca57270250a33503791a85f2f5122f1Jun Mukai                a.getInt(com.android.internal.R.styleable.Switch_thumbTintMode, -1), null);
2579fb302cfbca57270250a33503791a85f2f5122f1Jun Mukai        if (mThumbTintMode != thumbTintMode) {
2589fb302cfbca57270250a33503791a85f2f5122f1Jun Mukai            mThumbTintMode = thumbTintMode;
2599fb302cfbca57270250a33503791a85f2f5122f1Jun Mukai            mHasThumbTintMode = true;
2609fb302cfbca57270250a33503791a85f2f5122f1Jun Mukai        }
2619fb302cfbca57270250a33503791a85f2f5122f1Jun Mukai        if (mHasThumbTint || mHasThumbTintMode) {
2629fb302cfbca57270250a33503791a85f2f5122f1Jun Mukai            applyThumbTint();
2639fb302cfbca57270250a33503791a85f2f5122f1Jun Mukai        }
2649fb302cfbca57270250a33503791a85f2f5122f1Jun Mukai
2659fb302cfbca57270250a33503791a85f2f5122f1Jun Mukai        ColorStateList trackTintList = a.getColorStateList(
2669fb302cfbca57270250a33503791a85f2f5122f1Jun Mukai                com.android.internal.R.styleable.Switch_trackTint);
2679fb302cfbca57270250a33503791a85f2f5122f1Jun Mukai        if (trackTintList != null) {
2689fb302cfbca57270250a33503791a85f2f5122f1Jun Mukai            mTrackTintList = trackTintList;
2699fb302cfbca57270250a33503791a85f2f5122f1Jun Mukai            mHasTrackTint = true;
2709fb302cfbca57270250a33503791a85f2f5122f1Jun Mukai        }
2719fb302cfbca57270250a33503791a85f2f5122f1Jun Mukai        PorterDuff.Mode trackTintMode = Drawable.parseTintMode(
2729fb302cfbca57270250a33503791a85f2f5122f1Jun Mukai                a.getInt(com.android.internal.R.styleable.Switch_trackTintMode, -1), null);
2739fb302cfbca57270250a33503791a85f2f5122f1Jun Mukai        if (mTrackTintMode != trackTintMode) {
2749fb302cfbca57270250a33503791a85f2f5122f1Jun Mukai            mTrackTintMode = trackTintMode;
2759fb302cfbca57270250a33503791a85f2f5122f1Jun Mukai            mHasTrackTintMode = true;
2769fb302cfbca57270250a33503791a85f2f5122f1Jun Mukai        }
2779fb302cfbca57270250a33503791a85f2f5122f1Jun Mukai        if (mHasTrackTint || mHasTrackTintMode) {
2789fb302cfbca57270250a33503791a85f2f5122f1Jun Mukai            applyTrackTint();
2799fb302cfbca57270250a33503791a85f2f5122f1Jun Mukai        }
2809fb302cfbca57270250a33503791a85f2f5122f1Jun Mukai
281661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        final int appearance = a.getResourceId(
28212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                com.android.internal.R.styleable.Switch_switchTextAppearance, 0);
28312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (appearance != 0) {
284150176d83023e3c486dba10edebb72af36b4099aChet Haase            setSwitchTextAppearance(context, appearance);
28512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
28612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        a.recycle();
28712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
288661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        final ViewConfiguration config = ViewConfiguration.get(context);
28912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTouchSlop = config.getScaledTouchSlop();
29012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mMinFlingVelocity = config.getScaledMinimumFlingVelocity();
29112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
29212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        // Refresh display with current params
293e724ee4b04d121556e9764f72f9b921a0e16392aGilles Debunne        refreshDrawableState();
29412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        setChecked(isChecked());
29512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
29612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
29712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
29812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Sets the switch text color, size, style, hint color, and highlight color
29912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * from the specified TextAppearance resource.
3006c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3016c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_switchTextAppearance
30212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
3037b9c912f536925ac6ec43935d6e97506851b33d6Tor Norbye    public void setSwitchTextAppearance(Context context, @StyleRes int resid) {
30412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        TypedArray appearance =
305150176d83023e3c486dba10edebb72af36b4099aChet Haase                context.obtainStyledAttributes(resid,
30612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        com.android.internal.R.styleable.TextAppearance);
30712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
30812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        ColorStateList colors;
30912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int ts;
31012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
31112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        colors = appearance.getColorStateList(com.android.internal.R.styleable.
31212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                TextAppearance_textColor);
31312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (colors != null) {
31412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mTextColors = colors;
315150176d83023e3c486dba10edebb72af36b4099aChet Haase        } else {
316150176d83023e3c486dba10edebb72af36b4099aChet Haase            // If no color set in TextAppearance, default to the view's textColor
317150176d83023e3c486dba10edebb72af36b4099aChet Haase            mTextColors = getTextColors();
31812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
31912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
32012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        ts = appearance.getDimensionPixelSize(com.android.internal.R.styleable.
32112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                TextAppearance_textSize, 0);
32212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (ts != 0) {
32312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            if (ts != mTextPaint.getTextSize()) {
32412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                mTextPaint.setTextSize(ts);
32512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                requestLayout();
32612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
32712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
32812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
32912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int typefaceIndex, styleIndex;
33012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
33112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        typefaceIndex = appearance.getInt(com.android.internal.R.styleable.
33212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                TextAppearance_typeface, -1);
33312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        styleIndex = appearance.getInt(com.android.internal.R.styleable.
33412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                TextAppearance_textStyle, -1);
33512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
33612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        setSwitchTypefaceByIndex(typefaceIndex, styleIndex);
33712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
3384c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler        boolean allCaps = appearance.getBoolean(com.android.internal.R.styleable.
3394c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler                TextAppearance_textAllCaps, false);
3404c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler        if (allCaps) {
3414c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler            mSwitchTransformationMethod = new AllCapsTransformationMethod(getContext());
3424c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler            mSwitchTransformationMethod.setLengthChangesAllowed(true);
3434c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler        } else {
3444c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler            mSwitchTransformationMethod = null;
3454c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler        }
3464c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler
34712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        appearance.recycle();
34812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
34912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
35012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private void setSwitchTypefaceByIndex(int typefaceIndex, int styleIndex) {
35112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        Typeface tf = null;
35212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        switch (typefaceIndex) {
35312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case SANS:
35412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                tf = Typeface.SANS_SERIF;
35512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
35612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
35712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case SERIF:
35812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                tf = Typeface.SERIF;
35912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
36012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
36112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MONOSPACE:
36212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                tf = Typeface.MONOSPACE;
36312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
36412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
36512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
36612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        setSwitchTypeface(tf, styleIndex);
36712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
36812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
36912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
37012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Sets the typeface and style in which the text should be displayed on the
37112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * switch, and turns on the fake bold and italic bits in the Paint if the
37212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Typeface that you provided does not have all the bits in the
37312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * style that you specified.
37412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
37512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void setSwitchTypeface(Typeface tf, int style) {
37612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (style > 0) {
37712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            if (tf == null) {
37812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                tf = Typeface.defaultFromStyle(style);
37912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            } else {
38012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                tf = Typeface.create(tf, style);
38112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
38212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
38312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            setSwitchTypeface(tf);
38412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            // now compute what (if any) algorithmic styling is needed
38512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            int typefaceStyle = tf != null ? tf.getStyle() : 0;
38612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            int need = style & ~typefaceStyle;
38712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mTextPaint.setFakeBoldText((need & Typeface.BOLD) != 0);
38812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mTextPaint.setTextSkewX((need & Typeface.ITALIC) != 0 ? -0.25f : 0);
38912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        } else {
390aa0980afab57a6aebb06e70f60e92511708fa5afVictoria Lease            mTextPaint.setFakeBoldText(false);
39112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mTextPaint.setTextSkewX(0);
39212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            setSwitchTypeface(tf);
39312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
39412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
39512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
39612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
397150176d83023e3c486dba10edebb72af36b4099aChet Haase     * Sets the typeface in which the text should be displayed on the switch.
39812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Note that not all Typeface families actually have bold and italic
39912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * variants, so you may need to use
40012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * {@link #setSwitchTypeface(Typeface, int)} to get the appearance
40112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * that you actually want.
40212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     *
40312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @attr ref android.R.styleable#TextView_typeface
40412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @attr ref android.R.styleable#TextView_textStyle
40512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
40612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void setSwitchTypeface(Typeface tf) {
40712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (mTextPaint.getTypeface() != tf) {
40812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mTextPaint.setTypeface(tf);
40912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
41012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            requestLayout();
41112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            invalidate();
41212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
41312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
41412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
41512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
4166c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Set the amount of horizontal padding between the switch and the associated text.
4176c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4186c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @param pixels Amount of padding in pixels
4196c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4206c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_switchPadding
4216c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
4226c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public void setSwitchPadding(int pixels) {
4236c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        mSwitchPadding = pixels;
4246c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        requestLayout();
4256c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
4266c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
4276c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
4286c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Get the amount of horizontal padding between the switch and the associated text.
4296c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4306c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @return Amount of padding in pixels
4316c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4326c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_switchPadding
4336c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
4346c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public int getSwitchPadding() {
4356c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        return mSwitchPadding;
4366c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
4376c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
4386c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
4396c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Set the minimum width of the switch in pixels. The switch's width will be the maximum
4406c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * of this value and its measured width as determined by the switch drawables and text used.
4416c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4426c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @param pixels Minimum width of the switch in pixels
4436c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4446c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_switchMinWidth
4456c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
4466c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public void setSwitchMinWidth(int pixels) {
4476c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        mSwitchMinWidth = pixels;
4486c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        requestLayout();
4496c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
4506c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
4516c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
4526c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Get the minimum width of the switch in pixels. The switch's width will be the maximum
4536c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * of this value and its measured width as determined by the switch drawables and text used.
4546c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4556c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @return Minimum width of the switch in pixels
4566c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4576c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_switchMinWidth
4586c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
4596c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public int getSwitchMinWidth() {
4606c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        return mSwitchMinWidth;
4616c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
4626c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
4636c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
4646c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Set the horizontal padding around the text drawn on the switch itself.
4656c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4666c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @param pixels Horizontal padding for switch thumb text in pixels
4676c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4686c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_thumbTextPadding
4696c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
4706c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public void setThumbTextPadding(int pixels) {
4716c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        mThumbTextPadding = pixels;
4726c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        requestLayout();
4736c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
4746c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
4756c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
4766c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Get the horizontal padding around the text drawn on the switch itself.
4776c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4786c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @return Horizontal padding for switch thumb text in pixels
4796c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4806c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_thumbTextPadding
4816c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
4826c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public int getThumbTextPadding() {
4836c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        return mThumbTextPadding;
4846c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
4856c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
4866c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
4876c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Set the drawable used for the track that the switch slides within.
4886c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4896c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @param track Track drawable
4906c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4916c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_track
4926c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
4936c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public void setTrackDrawable(Drawable track) {
494b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette        if (mTrackDrawable != null) {
495b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette            mTrackDrawable.setCallback(null);
496b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette        }
4976c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        mTrackDrawable = track;
498b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette        if (track != null) {
499b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette            track.setCallback(this);
500b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette        }
5016c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        requestLayout();
5026c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
5036c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
5046c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
505d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     * Set the drawable used for the track that the switch slides within.
506d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     *
507dca510e026e3e75759bac84c3860dc84b83a608fAdam Powell     * @param resId Resource ID of a track drawable
508d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     *
509d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     * @attr ref android.R.styleable#Switch_track
510d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     */
5117b9c912f536925ac6ec43935d6e97506851b33d6Tor Norbye    public void setTrackResource(@DrawableRes int resId) {
5128eea3ea5591e59f55cbb4f6b2b7e9363a285ced3Alan Viverette        setTrackDrawable(getContext().getDrawable(resId));
513d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell    }
514d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell
515d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell    /**
5166c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Get the drawable used for the track that the switch slides within.
5176c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
5186c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @return Track drawable
5196c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
5206c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_track
5216c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
5226c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public Drawable getTrackDrawable() {
5236c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        return mTrackDrawable;
5246c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
5256c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
5266c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
527e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * Applies a tint to the track drawable. Does not modify the current
528e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * tint mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
529e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * <p>
530e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * Subsequent calls to {@link #setTrackDrawable(Drawable)} will
531e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * automatically mutate the drawable and apply the specified tint and tint
532e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * mode using {@link Drawable#setTintList(ColorStateList)}.
533e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     *
534e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * @param tint the tint to apply, may be {@code null} to clear tint
535e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     *
536e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * @attr ref android.R.styleable#Switch_trackTint
537e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * @see #getTrackTintList()
538e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * @see Drawable#setTintList(ColorStateList)
539e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     */
540e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette    public void setTrackTintList(@Nullable ColorStateList tint) {
541e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette        mTrackTintList = tint;
542e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette        mHasTrackTint = true;
543e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette
544e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette        applyTrackTint();
545e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette    }
546e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette
547e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette    /**
548e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * @return the tint applied to the track drawable
549e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * @attr ref android.R.styleable#Switch_trackTint
550e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * @see #setTrackTintList(ColorStateList)
551e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     */
552e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette    @Nullable
553e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette    public ColorStateList getTrackTintList() {
554e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette        return mTrackTintList;
555e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette    }
556e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette
557e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette    /**
558e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * Specifies the blending mode used to apply the tint specified by
559e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * {@link #setTrackTintList(ColorStateList)}} to the track drawable.
560e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * The default mode is {@link PorterDuff.Mode#SRC_IN}.
561e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     *
562e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * @param tintMode the blending mode used to apply the tint, may be
563e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     *                 {@code null} to clear tint
564e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * @attr ref android.R.styleable#Switch_trackTintMode
565e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * @see #getTrackTintMode()
566e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * @see Drawable#setTintMode(PorterDuff.Mode)
567e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     */
568e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette    public void setTrackTintMode(@Nullable PorterDuff.Mode tintMode) {
569e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette        mTrackTintMode = tintMode;
570e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette        mHasTrackTintMode = true;
571e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette
572e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette        applyTrackTint();
573e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette    }
574e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette
575e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette    /**
576e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * @return the blending mode used to apply the tint to the track
577e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     *         drawable
578e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * @attr ref android.R.styleable#Switch_trackTintMode
579e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * @see #setTrackTintMode(PorterDuff.Mode)
580e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     */
581e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette    @Nullable
582e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette    public PorterDuff.Mode getTrackTintMode() {
583e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette        return mTrackTintMode;
584e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette    }
585e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette
586e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette    private void applyTrackTint() {
587e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette        if (mTrackDrawable != null && (mHasTrackTint || mHasTrackTintMode)) {
588e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette            mTrackDrawable = mTrackDrawable.mutate();
589e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette
590e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette            if (mHasTrackTint) {
591e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette                mTrackDrawable.setTintList(mTrackTintList);
592e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette            }
593e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette
594e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette            if (mHasTrackTintMode) {
595e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette                mTrackDrawable.setTintMode(mTrackTintMode);
596e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette            }
597e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette
598e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette            // The drawable (or one of its children) may not have been
599e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette            // stateful before applying the tint, so let's try again.
600e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette            if (mTrackDrawable.isStateful()) {
601e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette                mTrackDrawable.setState(getDrawableState());
602e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette            }
603e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette        }
604e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette    }
605e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette
606e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette    /**
6076c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Set the drawable used for the switch "thumb" - the piece that the user
6086c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * can physically touch and drag along the track.
6096c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
6106c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @param thumb Thumb drawable
6116c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
6126c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_thumb
6136c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
6146c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public void setThumbDrawable(Drawable thumb) {
615b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette        if (mThumbDrawable != null) {
616b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette            mThumbDrawable.setCallback(null);
617b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette        }
6186c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        mThumbDrawable = thumb;
619b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette        if (thumb != null) {
620b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette            thumb.setCallback(this);
621b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette        }
6226c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        requestLayout();
6236c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
6246c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
6256c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
626d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     * Set the drawable used for the switch "thumb" - the piece that the user
627d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     * can physically touch and drag along the track.
628d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     *
629dca510e026e3e75759bac84c3860dc84b83a608fAdam Powell     * @param resId Resource ID of a thumb drawable
630d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     *
631d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     * @attr ref android.R.styleable#Switch_thumb
632d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     */
6337b9c912f536925ac6ec43935d6e97506851b33d6Tor Norbye    public void setThumbResource(@DrawableRes int resId) {
6348eea3ea5591e59f55cbb4f6b2b7e9363a285ced3Alan Viverette        setThumbDrawable(getContext().getDrawable(resId));
635d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell    }
636d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell
637d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell    /**
6386c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Get the drawable used for the switch "thumb" - the piece that the user
6396c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * can physically touch and drag along the track.
6406c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
6416c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @return Thumb drawable
6426c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
6436c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_thumb
6446c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
6456c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public Drawable getThumbDrawable() {
6466c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        return mThumbDrawable;
6476c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
6486c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
6496c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
650e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * Applies a tint to the thumb drawable. Does not modify the current
651e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * tint mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
652e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * <p>
653e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * Subsequent calls to {@link #setThumbDrawable(Drawable)} will
654e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * automatically mutate the drawable and apply the specified tint and tint
655e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * mode using {@link Drawable#setTintList(ColorStateList)}.
656e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     *
657e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * @param tint the tint to apply, may be {@code null} to clear tint
658e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     *
659e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * @attr ref android.R.styleable#Switch_thumbTint
660e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * @see #getThumbTintList()
661e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * @see Drawable#setTintList(ColorStateList)
662e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     */
663e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette    public void setThumbTintList(@Nullable ColorStateList tint) {
664e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette        mThumbTintList = tint;
665e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette        mHasThumbTint = true;
666e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette
667e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette        applyThumbTint();
668e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette    }
669e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette
670e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette    /**
671e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * @return the tint applied to the thumb drawable
672e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * @attr ref android.R.styleable#Switch_thumbTint
673e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * @see #setThumbTintList(ColorStateList)
674e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     */
675e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette    @Nullable
676e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette    public ColorStateList getThumbTintList() {
677e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette        return mThumbTintList;
678e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette    }
679e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette
680e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette    /**
681e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * Specifies the blending mode used to apply the tint specified by
682e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * {@link #setThumbTintList(ColorStateList)}} to the thumb drawable.
683e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * The default mode is {@link PorterDuff.Mode#SRC_IN}.
684e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     *
685e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * @param tintMode the blending mode used to apply the tint, may be
686e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     *                 {@code null} to clear tint
687e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * @attr ref android.R.styleable#Switch_thumbTintMode
688e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * @see #getThumbTintMode()
689e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * @see Drawable#setTintMode(PorterDuff.Mode)
690e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     */
691e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette    public void setThumbTintMode(@Nullable PorterDuff.Mode tintMode) {
692e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette        mThumbTintMode = tintMode;
693e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette        mHasThumbTintMode = true;
694e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette
695e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette        applyThumbTint();
696e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette    }
697e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette
698e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette    /**
699e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * @return the blending mode used to apply the tint to the thumb
700e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     *         drawable
701e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * @attr ref android.R.styleable#Switch_thumbTintMode
702e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     * @see #setThumbTintMode(PorterDuff.Mode)
703e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette     */
704e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette    @Nullable
705e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette    public PorterDuff.Mode getThumbTintMode() {
706e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette        return mThumbTintMode;
707e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette    }
708e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette
709e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette    private void applyThumbTint() {
710e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette        if (mThumbDrawable != null && (mHasThumbTint || mHasThumbTintMode)) {
711e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette            mThumbDrawable = mThumbDrawable.mutate();
712e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette
713e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette            if (mHasThumbTint) {
714e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette                mThumbDrawable.setTintList(mThumbTintList);
715e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette            }
716e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette
717e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette            if (mHasThumbTintMode) {
718e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette                mThumbDrawable.setTintMode(mThumbTintMode);
719e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette            }
720e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette
721e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette            // The drawable (or one of its children) may not have been
722e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette            // stateful before applying the tint, so let's try again.
723e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette            if (mThumbDrawable.isStateful()) {
724e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette                mThumbDrawable.setState(getDrawableState());
725e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette            }
726e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette        }
727e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette    }
728e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette
729e7eee640f83b0cffef63ef1f196efa4dcac64095Alan Viverette    /**
730661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     * Specifies whether the track should be split by the thumb. When true,
731661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     * the thumb's optical bounds will be clipped out of the track drawable,
732661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     * then the thumb will be drawn into the resulting gap.
733661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     *
734661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     * @param splitTrack Whether the track should be split by the thumb
735661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     *
736661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     * @attr ref android.R.styleable#Switch_splitTrack
737661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     */
738661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    public void setSplitTrack(boolean splitTrack) {
739661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        mSplitTrack = splitTrack;
740661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        invalidate();
741661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    }
742661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
743661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    /**
744661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     * Returns whether the track should be split by the thumb.
745661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     *
746661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     * @attr ref android.R.styleable#Switch_splitTrack
747661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     */
748661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    public boolean getSplitTrack() {
749661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        return mSplitTrack;
750661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    }
751661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
752661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    /**
753150176d83023e3c486dba10edebb72af36b4099aChet Haase     * Returns the text displayed when the button is in the checked state.
7546c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
7556c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_textOn
75612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
75712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public CharSequence getTextOn() {
75812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return mTextOn;
75912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
76012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
76112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
762150176d83023e3c486dba10edebb72af36b4099aChet Haase     * Sets the text displayed when the button is in the checked state.
7636c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
7646c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_textOn
76512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
76612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void setTextOn(CharSequence textOn) {
76712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextOn = textOn;
76812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        requestLayout();
76912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
77012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
77112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
772150176d83023e3c486dba10edebb72af36b4099aChet Haase     * Returns the text displayed when the button is not in the checked state.
7736c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
7746c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_textOff
77512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
77612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public CharSequence getTextOff() {
77712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return mTextOff;
77812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
77912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
78012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
781150176d83023e3c486dba10edebb72af36b4099aChet Haase     * Sets the text displayed when the button is not in the checked state.
7826c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
7836c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_textOff
78412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
78512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void setTextOff(CharSequence textOff) {
78612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextOff = textOff;
78712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        requestLayout();
78812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
78912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
7902a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette    /**
7912a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette     * Sets whether the on/off text should be displayed.
7922a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette     *
7932a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette     * @param showText {@code true} to display on/off text
7940c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     * @attr ref android.R.styleable#Switch_showText
7952a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette     */
7962a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette    public void setShowText(boolean showText) {
7972a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette        if (mShowText != showText) {
7982a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette            mShowText = showText;
7992a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette            requestLayout();
8002a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette        }
8012a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette    }
8022a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette
8032a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette    /**
8042a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette     * @return whether the on/off text should be displayed
8050c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     * @attr ref android.R.styleable#Switch_showText
8062a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette     */
8072a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette    public boolean getShowText() {
8082a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette        return mShowText;
8092a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette    }
8102a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette
81112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
81212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
8132a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette        if (mShowText) {
8142a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette            if (mOnLayout == null) {
8152a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette                mOnLayout = makeLayout(mTextOn);
8162a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette            }
8175876ff4a0ac938297bfd114da6b5d8c9dcb4cef6Alan Viverette
8182a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette            if (mOffLayout == null) {
8192a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette                mOffLayout = makeLayout(mTextOff);
8202a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette            }
82112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
82212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
8239b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette        final Rect padding = mTempRect;
8249b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette        final int thumbWidth;
8259b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette        final int thumbHeight;
8268bb399069da4e46b231333cff6880a0cf35b9417Alan Viverette        if (mThumbDrawable != null) {
8270c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            // Cached thumb width does not include padding.
8280c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            mThumbDrawable.getPadding(padding);
8290c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            thumbWidth = mThumbDrawable.getIntrinsicWidth() - padding.left - padding.right;
8309b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette            thumbHeight = mThumbDrawable.getIntrinsicHeight();
8319b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette        } else {
8329b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette            thumbWidth = 0;
8339b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette            thumbHeight = 0;
8348bb399069da4e46b231333cff6880a0cf35b9417Alan Viverette        }
8358bb399069da4e46b231333cff6880a0cf35b9417Alan Viverette
8360c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        final int maxTextWidth;
8370c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        if (mShowText) {
8380c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            maxTextWidth = Math.max(mOnLayout.getWidth(), mOffLayout.getWidth())
8390c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                    + mThumbTextPadding * 2;
8400c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        } else {
8410c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            maxTextWidth = 0;
8420c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        }
8430c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
8449b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette        mThumbWidth = Math.max(maxTextWidth, thumbWidth);
8459b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette
8460c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        final int trackHeight;
8470c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        if (mTrackDrawable != null) {
8480c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            mTrackDrawable.getPadding(padding);
8490c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            trackHeight = mTrackDrawable.getIntrinsicHeight();
8500c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        } else {
8510c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            padding.setEmpty();
8520c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            trackHeight = 0;
8530c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        }
8540c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
8550c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        // Adjust left and right padding to ensure there's enough room for the
8560c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        // thumb's padding (when present).
8570c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        int paddingLeft = padding.left;
8580c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        int paddingRight = padding.right;
8590c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        if (mThumbDrawable != null) {
8600c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            final Insets inset = mThumbDrawable.getOpticalInsets();
8610c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            paddingLeft = Math.max(paddingLeft, inset.left);
8620c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            paddingRight = Math.max(paddingRight, inset.right);
8630c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        }
8640c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
86512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int switchWidth = Math.max(mSwitchMinWidth,
8660c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                2 * mThumbWidth + paddingLeft + paddingRight);
8674d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        final int switchHeight = Math.max(trackHeight, thumbHeight);
86812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchWidth = switchWidth;
86912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchHeight = switchHeight;
87012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
87112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
8724d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette
87312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int measuredHeight = getMeasuredHeight();
87412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (measuredHeight < switchHeight) {
875189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn            setMeasuredDimension(getMeasuredWidthAndState(), switchHeight);
87612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
87712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
87812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
879a54956a0bc611b1e9b3914edc7a604b59688f6b7Alan Viverette    /** @hide */
88063bce03cc69be4a45230aa8bbd89dbde60681067Svetoslav Ganov    @Override
881a54956a0bc611b1e9b3914edc7a604b59688f6b7Alan Viverette    public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) {
882a54956a0bc611b1e9b3914edc7a604b59688f6b7Alan Viverette        super.onPopulateAccessibilityEventInternal(event);
8832a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette
8842a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette        final CharSequence text = isChecked() ? mTextOn : mTextOff;
8852a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette        if (text != null) {
8862a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette            event.getText().add(text);
8877650259a597dd24137420d32acc35efc44db381eSvetoslav Ganov        }
88863bce03cc69be4a45230aa8bbd89dbde60681067Svetoslav Ganov    }
88963bce03cc69be4a45230aa8bbd89dbde60681067Svetoslav Ganov
89012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private Layout makeLayout(CharSequence text) {
8914c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler        final CharSequence transformed = (mSwitchTransformationMethod != null)
8924c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler                    ? mSwitchTransformationMethod.getTransformation(text, this)
8934c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler                    : text;
8944c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler
89579bf9d19f2f76cbfbd6659c9323e519deaa887c7Siyamed Sinir        int width = (int) Math.ceil(Layout.getDesiredWidth(transformed, 0,
89679bf9d19f2f76cbfbd6659c9323e519deaa887c7Siyamed Sinir                transformed.length(), mTextPaint, getTextDirectionHeuristic()));
89779bf9d19f2f76cbfbd6659c9323e519deaa887c7Siyamed Sinir        return new StaticLayout(transformed, mTextPaint, width,
89812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                Layout.Alignment.ALIGN_NORMAL, 1.f, 0, true);
89912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
90012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
90112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
90212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @return true if (x, y) is within the target area of the switch thumb
90312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
90412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private boolean hitThumb(float x, float y) {
90501a09630060eccc471ba3d8d83b34a602871d5c1Alan Viverette        if (mThumbDrawable == null) {
90601a09630060eccc471ba3d8d83b34a602871d5c1Alan Viverette            return false;
90701a09630060eccc471ba3d8d83b34a602871d5c1Alan Viverette        }
90801a09630060eccc471ba3d8d83b34a602871d5c1Alan Viverette
909cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        // Relies on mTempRect, MUST be called first!
910cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        final int thumbOffset = getThumbOffset();
911cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette
91212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mThumbDrawable.getPadding(mTempRect);
91312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int thumbTop = mSwitchTop - mTouchSlop;
914cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        final int thumbLeft = mSwitchLeft + thumbOffset - mTouchSlop;
91512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int thumbRight = thumbLeft + mThumbWidth +
91612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                mTempRect.left + mTempRect.right + mTouchSlop;
91712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int thumbBottom = mSwitchBottom + mTouchSlop;
91812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return x > thumbLeft && x < thumbRight && y > thumbTop && y < thumbBottom;
91912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
92012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
92112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
92212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public boolean onTouchEvent(MotionEvent ev) {
92312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mVelocityTracker.addMovement(ev);
92412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int action = ev.getActionMasked();
92512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        switch (action) {
92612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MotionEvent.ACTION_DOWN: {
92712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                final float x = ev.getX();
92812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                final float y = ev.getY();
929c2ab0d665c9d1c332fbd726abf582a27cf7a6701Gilles Debunne                if (isEnabled() && hitThumb(x, y)) {
93012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    mTouchMode = TOUCH_MODE_DOWN;
93112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    mTouchX = x;
93212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    mTouchY = y;
93312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                }
93412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
93512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
93612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
93712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MotionEvent.ACTION_MOVE: {
93812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switch (mTouchMode) {
93912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    case TOUCH_MODE_IDLE:
94012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        // Didn't target the thumb, treat normally.
94112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        break;
94212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
94312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    case TOUCH_MODE_DOWN: {
94412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        final float x = ev.getX();
94512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        final float y = ev.getY();
94612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        if (Math.abs(x - mTouchX) > mTouchSlop ||
94712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                                Math.abs(y - mTouchY) > mTouchSlop) {
94812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            mTouchMode = TOUCH_MODE_DRAGGING;
94912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            getParent().requestDisallowInterceptTouchEvent(true);
95012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            mTouchX = x;
95112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            mTouchY = y;
95212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            return true;
95312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        }
95412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        break;
95512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    }
95612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
95712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    case TOUCH_MODE_DRAGGING: {
95812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        final float x = ev.getX();
959cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                        final int thumbScrollRange = getThumbScrollRange();
960cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                        final float thumbScrollOffset = x - mTouchX;
961cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                        float dPos;
962cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                        if (thumbScrollRange != 0) {
963cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                            dPos = thumbScrollOffset / thumbScrollRange;
964cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                        } else {
965cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                            // If the thumb scroll range is empty, just use the
966cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                            // movement direction to snap on or off.
967cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                            dPos = thumbScrollOffset > 0 ? 1 : -1;
968cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                        }
969cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                        if (isLayoutRtl()) {
970cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                            dPos = -dPos;
971cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                        }
972cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                        final float newPos = MathUtils.constrain(mThumbPosition + dPos, 0, 1);
97312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        if (newPos != mThumbPosition) {
97412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            mTouchX = x;
975cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                            setThumbPosition(newPos);
97612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        }
97712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        return true;
97812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    }
97912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                }
98012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
98112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
98212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
98312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MotionEvent.ACTION_UP:
98412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MotionEvent.ACTION_CANCEL: {
98512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                if (mTouchMode == TOUCH_MODE_DRAGGING) {
98612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    stopDrag(ev);
987ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette                    // Allow super class to handle pressed state, etc.
988ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette                    super.onTouchEvent(ev);
98912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    return true;
99012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                }
99112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                mTouchMode = TOUCH_MODE_IDLE;
99212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                mVelocityTracker.clear();
99312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
99412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
99512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
99612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
99712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return super.onTouchEvent(ev);
99812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
99912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
100012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private void cancelSuperTouch(MotionEvent ev) {
100112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        MotionEvent cancel = MotionEvent.obtain(ev);
100212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        cancel.setAction(MotionEvent.ACTION_CANCEL);
100312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.onTouchEvent(cancel);
100412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        cancel.recycle();
100512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
100612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
100712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
100812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Called from onTouchEvent to end a drag operation.
100912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     *
101012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param ev Event that triggered the end of drag mode - ACTION_UP or ACTION_CANCEL
101112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
101212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private void stopDrag(MotionEvent ev) {
101312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTouchMode = TOUCH_MODE_IDLE;
101412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
101586453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette        // Commit the change if the event is up and not canceled and the switch
101686453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette        // has not been disabled during the drag.
101786453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette        final boolean commitChange = ev.getAction() == MotionEvent.ACTION_UP && isEnabled();
1018d4e7790fee10e21b41a1c387c2734722bda56a0bAlan Viverette        final boolean oldState = isChecked();
101986453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette        final boolean newState;
102012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (commitChange) {
102112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mVelocityTracker.computeCurrentVelocity(1000);
102286453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette            final float xvel = mVelocityTracker.getXVelocity();
102312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            if (Math.abs(xvel) > mMinFlingVelocity) {
102428efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio                newState = isLayoutRtl() ? (xvel < 0) : (xvel > 0);
102512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            } else {
102612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                newState = getTargetCheckedState();
102712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
102812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        } else {
1029d4e7790fee10e21b41a1c387c2734722bda56a0bAlan Viverette            newState = oldState;
1030d4e7790fee10e21b41a1c387c2734722bda56a0bAlan Viverette        }
1031d4e7790fee10e21b41a1c387c2734722bda56a0bAlan Viverette
1032d4e7790fee10e21b41a1c387c2734722bda56a0bAlan Viverette        if (newState != oldState) {
1033d4e7790fee10e21b41a1c387c2734722bda56a0bAlan Viverette            playSoundEffect(SoundEffectConstants.CLICK);
103412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
103503306a0b275c24e9c4681bee53e5dd98c0654e01Alan Viverette        // Always call setChecked so that the thumb is moved back to the correct edge
103603306a0b275c24e9c4681bee53e5dd98c0654e01Alan Viverette        setChecked(newState);
103786453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette        cancelSuperTouch(ev);
103812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
103912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
104012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private void animateThumbToCheckedState(boolean newCheckedState) {
1041cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        final float targetPosition = newCheckedState ? 1 : 0;
1042cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        mPositionAnimator = ObjectAnimator.ofFloat(this, THUMB_POS, targetPosition);
1043cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        mPositionAnimator.setDuration(THUMB_ANIMATION_DURATION);
1044cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        mPositionAnimator.setAutoCancel(true);
1045cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        mPositionAnimator.start();
104612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
104712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
1048cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    private void cancelPositionAnimator() {
1049cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        if (mPositionAnimator != null) {
1050cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette            mPositionAnimator.cancel();
105128efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        }
105228efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio    }
105328efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio
1054cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    private boolean getTargetCheckedState() {
1055cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        return mThumbPosition > 0.5f;
1056cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    }
1057cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette
1058cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    /**
1059cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette     * Sets the thumb position as a decimal value between 0 (off) and 1 (on).
1060cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette     *
1061cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette     * @param position new position between [0,1]
1062cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette     */
1063cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    private void setThumbPosition(float position) {
1064cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        mThumbPosition = position;
1065cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        invalidate();
1066cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    }
1067cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette
1068cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    @Override
1069cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    public void toggle() {
107086453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette        setChecked(!isChecked());
107112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
107212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
107312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
107412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void setChecked(boolean checked) {
107512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.setChecked(checked);
1076cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette
1077467d629ca714cd74658043c1ddfec36c60d898c1Alan Viverette        // Calling the super method may result in setChecked() getting called
1078467d629ca714cd74658043c1ddfec36c60d898c1Alan Viverette        // recursively with a different value, so load the REAL value...
1079467d629ca714cd74658043c1ddfec36c60d898c1Alan Viverette        checked = isChecked();
1080467d629ca714cd74658043c1ddfec36c60d898c1Alan Viverette
108186453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette        if (isAttachedToWindow() && isLaidOut()) {
108286453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette            animateThumbToCheckedState(checked);
108386453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette        } else {
108486453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette            // Immediately move the thumb to the new position.
108586453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette            cancelPositionAnimator();
108686453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette            setThumbPosition(checked ? 1 : 0);
108786453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette        }
108812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
108912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
109012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
109112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
109212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.onLayout(changed, left, top, right, bottom);
109312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
10940c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        int opticalInsetLeft = 0;
10950c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        int opticalInsetRight = 0;
10960c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        if (mThumbDrawable != null) {
10970c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            final Rect trackPadding = mTempRect;
10980c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            if (mTrackDrawable != null) {
10990c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                mTrackDrawable.getPadding(trackPadding);
11000c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            } else {
11010c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                trackPadding.setEmpty();
11020c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            }
11030c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
11040c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            final Insets insets = mThumbDrawable.getOpticalInsets();
11050c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            opticalInsetLeft = Math.max(0, insets.left - trackPadding.left);
11060c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            opticalInsetRight = Math.max(0, insets.right - trackPadding.right);
11070c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        }
110828efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio
11090c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        final int switchRight;
11100c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        final int switchLeft;
111128efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        if (isLayoutRtl()) {
11120c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            switchLeft = getPaddingLeft() + opticalInsetLeft;
11130c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            switchRight = switchLeft + mSwitchWidth - opticalInsetLeft - opticalInsetRight;
111428efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        } else {
11150c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            switchRight = getWidth() - getPaddingRight() - opticalInsetRight;
11160c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            switchLeft = switchRight - mSwitchWidth + opticalInsetLeft + opticalInsetRight;
111728efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        }
1118c3eabb9b6ce7f556313c8e3870d76c5b443f1c51Joe Onorato
11190c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        final int switchTop;
11200c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        final int switchBottom;
112112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        switch (getGravity() & Gravity.VERTICAL_GRAVITY_MASK) {
112212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            default:
112312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case Gravity.TOP:
112412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchTop = getPaddingTop();
112512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchBottom = switchTop + mSwitchHeight;
112612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
112712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
112812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case Gravity.CENTER_VERTICAL:
112912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchTop = (getPaddingTop() + getHeight() - getPaddingBottom()) / 2 -
113012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        mSwitchHeight / 2;
113112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchBottom = switchTop + mSwitchHeight;
113212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
113312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
113412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case Gravity.BOTTOM:
113512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchBottom = getHeight() - getPaddingBottom();
113612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchTop = switchBottom - mSwitchHeight;
113712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
113812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
113912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
114012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchLeft = switchLeft;
114112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchTop = switchTop;
114212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchBottom = switchBottom;
114312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchRight = switchRight;
114412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
114512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
114612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
1147ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    public void draw(Canvas c) {
11484d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        final Rect padding = mTempRect;
11495876ff4a0ac938297bfd114da6b5d8c9dcb4cef6Alan Viverette        final int switchLeft = mSwitchLeft;
11505876ff4a0ac938297bfd114da6b5d8c9dcb4cef6Alan Viverette        final int switchTop = mSwitchTop;
11515876ff4a0ac938297bfd114da6b5d8c9dcb4cef6Alan Viverette        final int switchRight = mSwitchRight;
11525876ff4a0ac938297bfd114da6b5d8c9dcb4cef6Alan Viverette        final int switchBottom = mSwitchBottom;
11530c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
11540c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        int thumbInitialLeft = switchLeft + getThumbOffset();
11550c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
11560c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        final Insets thumbInsets;
11570c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        if (mThumbDrawable != null) {
11580c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            thumbInsets = mThumbDrawable.getOpticalInsets();
11590c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        } else {
11600c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            thumbInsets = Insets.NONE;
11618bb399069da4e46b231333cff6880a0cf35b9417Alan Viverette        }
1162cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette
11630c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        // Layout the track.
11640c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        if (mTrackDrawable != null) {
11650c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            mTrackDrawable.getPadding(padding);
11669b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette
11670c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            // Adjust thumb position for track padding.
11680c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            thumbInitialLeft += padding.left;
11690c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
11700c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            // If necessary, offset by the optical insets of the thumb asset.
11710c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            int trackLeft = switchLeft;
11720c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            int trackTop = switchTop;
11730c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            int trackRight = switchRight;
11740c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            int trackBottom = switchBottom;
11750c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            if (thumbInsets != Insets.NONE) {
11760c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                if (thumbInsets.left > padding.left) {
11770c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                    trackLeft += thumbInsets.left - padding.left;
11780c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                }
11790c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                if (thumbInsets.top > padding.top) {
11800c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                    trackTop += thumbInsets.top - padding.top;
11810c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                }
11820c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                if (thumbInsets.right > padding.right) {
11830c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                    trackRight -= thumbInsets.right - padding.right;
11840c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                }
11850c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                if (thumbInsets.bottom > padding.bottom) {
11860c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                    trackBottom -= thumbInsets.bottom - padding.bottom;
11870c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                }
11880c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            }
11890c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            mTrackDrawable.setBounds(trackLeft, trackTop, trackRight, trackBottom);
11900c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        }
11919b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette
1192661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        // Layout the thumb.
11934d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        if (mThumbDrawable != null) {
11944d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            mThumbDrawable.getPadding(padding);
11950c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
11960c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            final int thumbLeft = thumbInitialLeft - padding.left;
11970c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            final int thumbRight = thumbInitialLeft + mThumbWidth + padding.right;
11984d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            mThumbDrawable.setBounds(thumbLeft, switchTop, thumbRight, switchBottom);
11994d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette
12004d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            final Drawable background = getBackground();
12014d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            if (background != null) {
12024d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                background.setHotspotBounds(thumbLeft, switchTop, thumbRight, switchBottom);
12034d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            }
120461956606818918194a38e045a8e35e7108480e5eAlan Viverette        }
120561956606818918194a38e045a8e35e7108480e5eAlan Viverette
1206ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette        // Draw the background.
1207ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette        super.draw(c);
1208ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    }
1209ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette
1210ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    @Override
1211ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    protected void onDraw(Canvas canvas) {
121261956606818918194a38e045a8e35e7108480e5eAlan Viverette        super.onDraw(canvas);
121361956606818918194a38e045a8e35e7108480e5eAlan Viverette
12144d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        final Rect padding = mTempRect;
1215ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette        final Drawable trackDrawable = mTrackDrawable;
12164d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        if (trackDrawable != null) {
12174d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            trackDrawable.getPadding(padding);
12184d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        } else {
12194d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            padding.setEmpty();
12204d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        }
1221ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette
1222ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette        final int switchTop = mSwitchTop;
1223ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette        final int switchBottom = mSwitchBottom;
12244d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        final int switchInnerTop = switchTop + padding.top;
12254d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        final int switchInnerBottom = switchBottom - padding.bottom;
12264d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette
12274d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        final Drawable thumbDrawable = mThumbDrawable;
12284d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        if (trackDrawable != null) {
12294d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            if (mSplitTrack && thumbDrawable != null) {
12304d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                final Insets insets = thumbDrawable.getOpticalInsets();
12314d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                thumbDrawable.copyBounds(padding);
12324d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                padding.left += insets.left;
12334d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                padding.right -= insets.right;
12344d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette
12354d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                final int saveCount = canvas.save();
12364d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                canvas.clipRect(padding, Op.DIFFERENCE);
12374d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                trackDrawable.draw(canvas);
12384d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                canvas.restoreToCount(saveCount);
12394d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            } else {
12404d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                trackDrawable.draw(canvas);
12414d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            }
1242661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        }
124361956606818918194a38e045a8e35e7108480e5eAlan Viverette
124461956606818918194a38e045a8e35e7108480e5eAlan Viverette        final int saveCount = canvas.save();
12454d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette
12464d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        if (thumbDrawable != null) {
12474d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            thumbDrawable.draw(canvas);
12484d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        }
124912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
12505876ff4a0ac938297bfd114da6b5d8c9dcb4cef6Alan Viverette        final Layout switchText = getTargetCheckedState() ? mOnLayout : mOffLayout;
1251be06e3292b295324b3b47d13f9a40787b666309fFabrice Di Meglio        if (switchText != null) {
1252661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            final int drawableState[] = getDrawableState();
1253661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            if (mTextColors != null) {
1254661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette                mTextPaint.setColor(mTextColors.getColorForState(drawableState, 0));
1255661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            }
1256661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            mTextPaint.drawableState = drawableState;
1257661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
12584d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            final int cX;
12594d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            if (thumbDrawable != null) {
12604d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                final Rect bounds = thumbDrawable.getBounds();
12614d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                cX = bounds.left + bounds.right;
12624d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            } else {
1263dec17299fef93f673d8e8cab0ec0f734bf6b8539Alan Viverette                cX = getWidth();
12644d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            }
12654d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette
12664d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            final int left = cX / 2 - switchText.getWidth() / 2;
12675876ff4a0ac938297bfd114da6b5d8c9dcb4cef6Alan Viverette            final int top = (switchInnerTop + switchInnerBottom) / 2 - switchText.getHeight() / 2;
12685876ff4a0ac938297bfd114da6b5d8c9dcb4cef6Alan Viverette            canvas.translate(left, top);
1269be06e3292b295324b3b47d13f9a40787b666309fFabrice Di Meglio            switchText.draw(canvas);
1270be06e3292b295324b3b47d13f9a40787b666309fFabrice Di Meglio        }
127112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
12725876ff4a0ac938297bfd114da6b5d8c9dcb4cef6Alan Viverette        canvas.restoreToCount(saveCount);
127312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
127412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
127512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
127628efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio    public int getCompoundPaddingLeft() {
127728efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        if (!isLayoutRtl()) {
127828efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio            return super.getCompoundPaddingLeft();
127928efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        }
128028efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        int padding = super.getCompoundPaddingLeft() + mSwitchWidth;
128128efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        if (!TextUtils.isEmpty(getText())) {
128228efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio            padding += mSwitchPadding;
128328efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        }
128428efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        return padding;
128528efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio    }
128628efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio
128728efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio    @Override
128812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public int getCompoundPaddingRight() {
128928efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        if (isLayoutRtl()) {
129028efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio            return super.getCompoundPaddingRight();
129128efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        }
129212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int padding = super.getCompoundPaddingRight() + mSwitchWidth;
129312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (!TextUtils.isEmpty(getText())) {
129412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            padding += mSwitchPadding;
129512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
129612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return padding;
129712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
129812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
1299cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    /**
1300cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette     * Translates thumb position to offset according to current RTL setting and
13010c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     * thumb scroll range. Accounts for both track and thumb padding.
1302cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette     *
1303cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette     * @return thumb offset
1304cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette     */
1305cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    private int getThumbOffset() {
1306cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        final float thumbPosition;
1307cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        if (isLayoutRtl()) {
1308cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette            thumbPosition = 1 - mThumbPosition;
1309cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        } else {
1310cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette            thumbPosition = mThumbPosition;
1311cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        }
1312cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        return (int) (thumbPosition * getThumbScrollRange() + 0.5f);
1313cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    }
1314cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette
131512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int getThumbScrollRange() {
13164d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        if (mTrackDrawable != null) {
13170c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            final Rect padding = mTempRect;
13180c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            mTrackDrawable.getPadding(padding);
13190c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
13200c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            final Insets insets;
13210c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            if (mThumbDrawable != null) {
13220c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                insets = mThumbDrawable.getOpticalInsets();
13230c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            } else {
13240c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                insets = Insets.NONE;
13250c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            }
13260c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
13270c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            return mSwitchWidth - mThumbWidth - padding.left - padding.right
13280c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                    - insets.left - insets.right;
13294d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        } else {
133012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            return 0;
133112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
133212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
133312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
133412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
133512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    protected int[] onCreateDrawableState(int extraSpace) {
133612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
133712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (isChecked()) {
133812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mergeDrawableStates(drawableState, CHECKED_STATE_SET);
133912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
134012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return drawableState;
134112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
134212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
134312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
134412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    protected void drawableStateChanged() {
134512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.drawableStateChanged();
134612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
1347ad0020f8075ecf768cb610d60dbb167d41f0fbe5Alan Viverette        final int[] state = getDrawableState();
1348ad0020f8075ecf768cb610d60dbb167d41f0fbe5Alan Viverette        boolean changed = false;
1349661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
1350ad0020f8075ecf768cb610d60dbb167d41f0fbe5Alan Viverette        final Drawable thumbDrawable = mThumbDrawable;
1351ad0020f8075ecf768cb610d60dbb167d41f0fbe5Alan Viverette        if (thumbDrawable != null && thumbDrawable.isStateful()) {
1352ad0020f8075ecf768cb610d60dbb167d41f0fbe5Alan Viverette            changed |= thumbDrawable.setState(state);
1353661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        }
135412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
1355ad0020f8075ecf768cb610d60dbb167d41f0fbe5Alan Viverette        final Drawable trackDrawable = mTrackDrawable;
1356ad0020f8075ecf768cb610d60dbb167d41f0fbe5Alan Viverette        if (trackDrawable != null && trackDrawable.isStateful()) {
1357ad0020f8075ecf768cb610d60dbb167d41f0fbe5Alan Viverette            changed |= trackDrawable.setState(state);
1358661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        }
135912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
1360ad0020f8075ecf768cb610d60dbb167d41f0fbe5Alan Viverette        if (changed) {
1361ad0020f8075ecf768cb610d60dbb167d41f0fbe5Alan Viverette            invalidate();
1362ad0020f8075ecf768cb610d60dbb167d41f0fbe5Alan Viverette        }
136312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
136412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
1365cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette    @Override
13668de1494557cf1d00c1c3fce439138a28de7fbd61Alan Viverette    public void drawableHotspotChanged(float x, float y) {
13678de1494557cf1d00c1c3fce439138a28de7fbd61Alan Viverette        super.drawableHotspotChanged(x, y);
1368cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette
1369cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette        if (mThumbDrawable != null) {
1370cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette            mThumbDrawable.setHotspot(x, y);
1371cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette        }
1372cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette
1373cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette        if (mTrackDrawable != null) {
1374cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette            mTrackDrawable.setHotspot(x, y);
1375cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette        }
1376cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette    }
1377cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette
137812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
1379f6d87ec193f17e8dad82c9994ba7a58e975d364bAlan Viverette    protected boolean verifyDrawable(@NonNull Drawable who) {
138012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return super.verifyDrawable(who) || who == mThumbDrawable || who == mTrackDrawable;
138112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
138212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
138312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
138412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void jumpDrawablesToCurrentState() {
138512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.jumpDrawablesToCurrentState();
13864d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette
13874d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        if (mThumbDrawable != null) {
13884d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            mThumbDrawable.jumpToCurrentState();
13894d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        }
13904d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette
13914d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        if (mTrackDrawable != null) {
13924d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            mTrackDrawable.jumpToCurrentState();
13934d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        }
13944d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette
1395ee20d7799f25eba9881344473190077bf1d5a4c4Alan Viverette        if (mPositionAnimator != null && mPositionAnimator.isStarted()) {
13964d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            mPositionAnimator.end();
13974d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            mPositionAnimator = null;
13984d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        }
139912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
14008a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov
14018a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    @Override
1402a7bb6fbeab933326d58aa806d8194b7b13239d34Dianne Hackborn    public CharSequence getAccessibilityClassName() {
1403a7bb6fbeab933326d58aa806d8194b7b13239d34Dianne Hackborn        return Switch.class.getName();
1404a7bb6fbeab933326d58aa806d8194b7b13239d34Dianne Hackborn    }
1405a7bb6fbeab933326d58aa806d8194b7b13239d34Dianne Hackborn
1406a7bb6fbeab933326d58aa806d8194b7b13239d34Dianne Hackborn    @Override
14076d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme    public void onProvideStructure(ViewStructure structure) {
14086d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme        super.onProvideStructure(structure);
1409640f30a7763b0a4b80c767acb84c740aac04768bFelipe Leme        onProvideAutoFillStructureForAssistOrAutofill(structure);
14106d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme    }
14116d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme
14126d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme    @Override
1413640f30a7763b0a4b80c767acb84c740aac04768bFelipe Leme    public void onProvideAutofillStructure(ViewStructure structure, int flags) {
1414640f30a7763b0a4b80c767acb84c740aac04768bFelipe Leme        super.onProvideAutofillStructure(structure, flags);
1415640f30a7763b0a4b80c767acb84c740aac04768bFelipe Leme        onProvideAutoFillStructureForAssistOrAutofill(structure);
14166d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme    }
14171ca634a544a47193dd9e57f9b3eb3e42ab0dbbf1Felipe Leme
14186d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme    // NOTE: currently there is no difference for Assist or AutoFill, so it doesn't take flags
1419640f30a7763b0a4b80c767acb84c740aac04768bFelipe Leme    private void onProvideAutoFillStructureForAssistOrAutofill(ViewStructure structure) {
1420a7bb6fbeab933326d58aa806d8194b7b13239d34Dianne Hackborn        CharSequence switchText = isChecked() ? mTextOn : mTextOff;
1421a7bb6fbeab933326d58aa806d8194b7b13239d34Dianne Hackborn        if (!TextUtils.isEmpty(switchText)) {
1422a83ce1dd2ad3a6b71e90ff4845afc1299fe17b9dDianne Hackborn            CharSequence oldText = structure.getText();
1423a7bb6fbeab933326d58aa806d8194b7b13239d34Dianne Hackborn            if (TextUtils.isEmpty(oldText)) {
1424a83ce1dd2ad3a6b71e90ff4845afc1299fe17b9dDianne Hackborn                structure.setText(switchText);
1425a7bb6fbeab933326d58aa806d8194b7b13239d34Dianne Hackborn            } else {
1426a7bb6fbeab933326d58aa806d8194b7b13239d34Dianne Hackborn                StringBuilder newText = new StringBuilder();
1427a7bb6fbeab933326d58aa806d8194b7b13239d34Dianne Hackborn                newText.append(oldText).append(' ').append(switchText);
1428a83ce1dd2ad3a6b71e90ff4845afc1299fe17b9dDianne Hackborn                structure.setText(newText);
1429a7bb6fbeab933326d58aa806d8194b7b13239d34Dianne Hackborn            }
14305cfaae4aae744574f0fcc0876cdc5473bc1a344dJames Cook            // The style of the label text is provided via the base TextView class. This is more
14315cfaae4aae744574f0fcc0876cdc5473bc1a344dJames Cook            // relevant than the style of the (optional) on/off text on the switch button itself,
14325cfaae4aae744574f0fcc0876cdc5473bc1a344dJames Cook            // so ignore the size/color/style stored this.mTextPaint.
1433a7bb6fbeab933326d58aa806d8194b7b13239d34Dianne Hackborn        }
14348a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    }
14358a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov
1436a54956a0bc611b1e9b3914edc7a604b59688f6b7Alan Viverette    /** @hide */
14378a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    @Override
1438a54956a0bc611b1e9b3914edc7a604b59688f6b7Alan Viverette    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
1439a54956a0bc611b1e9b3914edc7a604b59688f6b7Alan Viverette        super.onInitializeAccessibilityNodeInfoInternal(info);
144078bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov        CharSequence switchText = isChecked() ? mTextOn : mTextOff;
144178bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov        if (!TextUtils.isEmpty(switchText)) {
144278bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov            CharSequence oldText = info.getText();
144378bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov            if (TextUtils.isEmpty(oldText)) {
144478bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov                info.setText(switchText);
144578bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov            } else {
144678bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov                StringBuilder newText = new StringBuilder();
144778bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov                newText.append(oldText).append(' ').append(switchText);
144878bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov                info.setText(newText);
144978bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov            }
145078bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov        }
14518a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    }
1452cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette
1453cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    private static final FloatProperty<Switch> THUMB_POS = new FloatProperty<Switch>("thumbPos") {
1454cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        @Override
1455cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        public Float get(Switch object) {
1456cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette            return object.mThumbPosition;
1457cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        }
1458cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette
1459cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        @Override
1460cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        public void setValue(Switch object, float value) {
1461cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette            object.setThumbPosition(value);
1462cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        }
1463cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    };
146412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell}
1465