Switch.java revision 0c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6
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;
2012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.content.Context;
2112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.content.res.ColorStateList;
2212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.content.res.Resources;
2312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.content.res.TypedArray;
2412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.graphics.Canvas;
25661e63658da39cccfe49a129e4860455716ff3c9Alan Viveretteimport android.graphics.Insets;
2612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.graphics.Paint;
2712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.graphics.Rect;
2812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.graphics.Typeface;
29661e63658da39cccfe49a129e4860455716ff3c9Alan Viveretteimport android.graphics.Region.Op;
3012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.graphics.drawable.Drawable;
3112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.text.Layout;
3212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.text.StaticLayout;
3312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.text.TextPaint;
3412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.text.TextUtils;
354c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandlerimport android.text.method.AllCapsTransformationMethod;
364c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandlerimport android.text.method.TransformationMethod2;
3712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.util.AttributeSet;
38cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viveretteimport android.util.FloatProperty;
39cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viveretteimport android.util.MathUtils;
4012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.view.Gravity;
4112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.view.MotionEvent;
4212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.view.VelocityTracker;
4312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.view.ViewConfiguration;
4463bce03cc69be4a45230aa8bbd89dbde60681067Svetoslav Ganovimport android.view.accessibility.AccessibilityEvent;
458a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganovimport android.view.accessibility.AccessibilityNodeInfo;
4612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
47be0a4535053bbfdebd215e244b154ac810fd8edcAdam Powellimport com.android.internal.R;
48be0a4535053bbfdebd215e244b154ac810fd8edcAdam Powell
4912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell/**
5012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell * A Switch is a two-state toggle switch widget that can select between two
5112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell * options. The user may drag the "thumb" back and forth to choose the selected option,
52150176d83023e3c486dba10edebb72af36b4099aChet Haase * or simply tap to toggle as if it were a checkbox. The {@link #setText(CharSequence) text}
53150176d83023e3c486dba10edebb72af36b4099aChet Haase * property controls the text displayed in the label for the switch, whereas the
54150176d83023e3c486dba10edebb72af36b4099aChet Haase * {@link #setTextOff(CharSequence) off} and {@link #setTextOn(CharSequence) on} text
55150176d83023e3c486dba10edebb72af36b4099aChet Haase * controls the text on the thumb. Similarly, the
56150176d83023e3c486dba10edebb72af36b4099aChet Haase * {@link #setTextAppearance(android.content.Context, int) textAppearance} and the related
57150176d83023e3c486dba10edebb72af36b4099aChet Haase * setTypeface() methods control the typeface and style of label text, whereas the
58150176d83023e3c486dba10edebb72af36b4099aChet Haase * {@link #setSwitchTextAppearance(android.content.Context, int) switchTextAppearance} and
59150176d83023e3c486dba10edebb72af36b4099aChet Haase * the related seSwitchTypeface() methods control that of the thumb.
6012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell *
614c359b76f9a030f92a302ba74a528faa170bad4eScott Main * <p>See the <a href="{@docRoot}guide/topics/ui/controls/togglebutton.html">Toggle Buttons</a>
624c359b76f9a030f92a302ba74a528faa170bad4eScott Main * guide.</p>
634c359b76f9a030f92a302ba74a528faa170bad4eScott Main *
644c359b76f9a030f92a302ba74a528faa170bad4eScott Main * @attr ref android.R.styleable#Switch_textOn
654c359b76f9a030f92a302ba74a528faa170bad4eScott Main * @attr ref android.R.styleable#Switch_textOff
664c359b76f9a030f92a302ba74a528faa170bad4eScott Main * @attr ref android.R.styleable#Switch_switchMinWidth
674c359b76f9a030f92a302ba74a528faa170bad4eScott Main * @attr ref android.R.styleable#Switch_switchPadding
684c359b76f9a030f92a302ba74a528faa170bad4eScott Main * @attr ref android.R.styleable#Switch_switchTextAppearance
694c359b76f9a030f92a302ba74a528faa170bad4eScott Main * @attr ref android.R.styleable#Switch_thumb
704c359b76f9a030f92a302ba74a528faa170bad4eScott Main * @attr ref android.R.styleable#Switch_thumbTextPadding
714c359b76f9a030f92a302ba74a528faa170bad4eScott Main * @attr ref android.R.styleable#Switch_track
7212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell */
7312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellpublic class Switch extends CompoundButton {
74cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    private static final int THUMB_ANIMATION_DURATION = 250;
75cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette
7612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int TOUCH_MODE_IDLE = 0;
7712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int TOUCH_MODE_DOWN = 1;
7812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int TOUCH_MODE_DRAGGING = 2;
7912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
8012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    // Enum for the "typeface" XML parameter.
8112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int SANS = 1;
8212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int SERIF = 2;
8312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int MONOSPACE = 3;
8412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
8512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private Drawable mThumbDrawable;
8612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private Drawable mTrackDrawable;
8712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mThumbTextPadding;
8812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchMinWidth;
8912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchPadding;
90661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    private boolean mSplitTrack;
9112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private CharSequence mTextOn;
9212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private CharSequence mTextOff;
932a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette    private boolean mShowText;
9412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
9512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mTouchMode;
9612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mTouchSlop;
9712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private float mTouchX;
9812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private float mTouchY;
9912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private VelocityTracker mVelocityTracker = VelocityTracker.obtain();
10012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mMinFlingVelocity;
10112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
10212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private float mThumbPosition;
1030c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
1040c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette    /**
1050c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     * Width required to draw the switch track and thumb. Includes padding and
1060c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     * optical bounds for both the track and thumb.
1070c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     */
10812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchWidth;
1090c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
1100c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette    /**
1110c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     * Height required to draw the switch track and thumb. Includes padding and
1120c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     * optical bounds for both the track and thumb.
1130c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     */
11412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchHeight;
11512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
1160c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette    /**
1170c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     * Width of the thumb's content region. Does not include padding or
1180c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     * optical bounds.
1190c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     */
1200c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette    private int mThumbWidth;
1210c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
1220c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette    /** Left bound for drawing the switch track and thumb. */
12312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchLeft;
1240c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
1250c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette    /** Top bound for drawing the switch track and thumb. */
12612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchTop;
1270c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
1280c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette    /** Right bound for drawing the switch track and thumb. */
12912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchRight;
1300c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
1310c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette    /** Bottom bound for drawing the switch track and thumb. */
13212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchBottom;
13312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
13412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private TextPaint mTextPaint;
13512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private ColorStateList mTextColors;
13612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private Layout mOnLayout;
13712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private Layout mOffLayout;
1384c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler    private TransformationMethod2 mSwitchTransformationMethod;
139cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    private ObjectAnimator mPositionAnimator;
14012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
141be0a4535053bbfdebd215e244b154ac810fd8edcAdam Powell    @SuppressWarnings("hiding")
14212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private final Rect mTempRect = new Rect();
14312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
14412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int[] CHECKED_STATE_SET = {
14512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        R.attr.state_checked
14612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    };
14712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
14812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
14912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Construct a new Switch with default styling.
15012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     *
15112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param context The Context that will determine this widget's theming.
15212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
15312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public Switch(Context context) {
15412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        this(context, null);
15512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
15612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
15712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
15812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Construct a new Switch with default styling, overriding specific style
15912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * attributes as requested.
16012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     *
16112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param context The Context that will determine this widget's theming.
16212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param attrs Specification of attributes that should deviate from default styling.
16312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
16412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public Switch(Context context, AttributeSet attrs) {
16512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        this(context, attrs, com.android.internal.R.attr.switchStyle);
16612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
16712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
16812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
16912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Construct a new Switch with a default style determined by the given theme attribute,
17012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * overriding specific style attributes as requested.
17112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     *
17212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param context The Context that will determine this widget's theming.
17312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param attrs Specification of attributes that should deviate from the default styling.
174617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     * @param defStyleAttr An attribute in the current theme that contains a
175617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        reference to a style resource that supplies default values for
176617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        the view. Can be 0 to not look for defaults.
17712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
178617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    public Switch(Context context, AttributeSet attrs, int defStyleAttr) {
179617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette        this(context, attrs, defStyleAttr, 0);
180617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    }
181617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette
182617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette
183617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    /**
184617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     * Construct a new Switch with a default style determined by the given theme
185617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     * attribute or style resource, overriding specific style attributes as
186617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     * requested.
187617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *
188617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     * @param context The Context that will determine this widget's theming.
189617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     * @param attrs Specification of attributes that should deviate from the
190617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        default styling.
191617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     * @param defStyleAttr An attribute in the current theme that contains a
192617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        reference to a style resource that supplies default values for
193617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        the view. Can be 0 to not look for defaults.
194617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     * @param defStyleRes A resource identifier of a style resource that
195617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        supplies default values for the view, used only if
196617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        defStyleAttr is 0 or can not be found in the theme. Can be 0
197617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        to not look for defaults.
198617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     */
199617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    public Switch(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
200617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette        super(context, attrs, defStyleAttr, defStyleRes);
20112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
20212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
203661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
204661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        final Resources res = getResources();
20512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextPaint.density = res.getDisplayMetrics().density;
20612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextPaint.setCompatibilityScaling(res.getCompatibilityInfo().applicationScale);
20712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
208617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette        final TypedArray a = context.obtainStyledAttributes(
209617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette                attrs, com.android.internal.R.styleable.Switch, defStyleAttr, defStyleRes);
210150176d83023e3c486dba10edebb72af36b4099aChet Haase        mThumbDrawable = a.getDrawable(com.android.internal.R.styleable.Switch_thumb);
211150176d83023e3c486dba10edebb72af36b4099aChet Haase        mTrackDrawable = a.getDrawable(com.android.internal.R.styleable.Switch_track);
21212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextOn = a.getText(com.android.internal.R.styleable.Switch_textOn);
21312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextOff = a.getText(com.android.internal.R.styleable.Switch_textOff);
2142a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette        mShowText = a.getBoolean(com.android.internal.R.styleable.Switch_showText, true);
21512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mThumbTextPadding = a.getDimensionPixelSize(
21612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                com.android.internal.R.styleable.Switch_thumbTextPadding, 0);
21712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchMinWidth = a.getDimensionPixelSize(
21812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                com.android.internal.R.styleable.Switch_switchMinWidth, 0);
21912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchPadding = a.getDimensionPixelSize(
22012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                com.android.internal.R.styleable.Switch_switchPadding, 0);
221661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        mSplitTrack = a.getBoolean(com.android.internal.R.styleable.Switch_splitTrack, false);
22212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
223661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        final int appearance = a.getResourceId(
22412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                com.android.internal.R.styleable.Switch_switchTextAppearance, 0);
22512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (appearance != 0) {
226150176d83023e3c486dba10edebb72af36b4099aChet Haase            setSwitchTextAppearance(context, appearance);
22712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
22812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        a.recycle();
22912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
230661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        final ViewConfiguration config = ViewConfiguration.get(context);
23112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTouchSlop = config.getScaledTouchSlop();
23212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mMinFlingVelocity = config.getScaledMinimumFlingVelocity();
23312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
23412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        // Refresh display with current params
235e724ee4b04d121556e9764f72f9b921a0e16392aGilles Debunne        refreshDrawableState();
23612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        setChecked(isChecked());
23712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
23812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
23912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
24012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Sets the switch text color, size, style, hint color, and highlight color
24112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * from the specified TextAppearance resource.
2426c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
2436c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_switchTextAppearance
24412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
245150176d83023e3c486dba10edebb72af36b4099aChet Haase    public void setSwitchTextAppearance(Context context, int resid) {
24612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        TypedArray appearance =
247150176d83023e3c486dba10edebb72af36b4099aChet Haase                context.obtainStyledAttributes(resid,
24812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        com.android.internal.R.styleable.TextAppearance);
24912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
25012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        ColorStateList colors;
25112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int ts;
25212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
25312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        colors = appearance.getColorStateList(com.android.internal.R.styleable.
25412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                TextAppearance_textColor);
25512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (colors != null) {
25612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mTextColors = colors;
257150176d83023e3c486dba10edebb72af36b4099aChet Haase        } else {
258150176d83023e3c486dba10edebb72af36b4099aChet Haase            // If no color set in TextAppearance, default to the view's textColor
259150176d83023e3c486dba10edebb72af36b4099aChet Haase            mTextColors = getTextColors();
26012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
26112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
26212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        ts = appearance.getDimensionPixelSize(com.android.internal.R.styleable.
26312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                TextAppearance_textSize, 0);
26412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (ts != 0) {
26512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            if (ts != mTextPaint.getTextSize()) {
26612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                mTextPaint.setTextSize(ts);
26712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                requestLayout();
26812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
26912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
27012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
27112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int typefaceIndex, styleIndex;
27212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
27312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        typefaceIndex = appearance.getInt(com.android.internal.R.styleable.
27412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                TextAppearance_typeface, -1);
27512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        styleIndex = appearance.getInt(com.android.internal.R.styleable.
27612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                TextAppearance_textStyle, -1);
27712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
27812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        setSwitchTypefaceByIndex(typefaceIndex, styleIndex);
27912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
2804c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler        boolean allCaps = appearance.getBoolean(com.android.internal.R.styleable.
2814c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler                TextAppearance_textAllCaps, false);
2824c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler        if (allCaps) {
2834c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler            mSwitchTransformationMethod = new AllCapsTransformationMethod(getContext());
2844c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler            mSwitchTransformationMethod.setLengthChangesAllowed(true);
2854c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler        } else {
2864c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler            mSwitchTransformationMethod = null;
2874c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler        }
2884c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler
28912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        appearance.recycle();
29012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
29112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
29212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private void setSwitchTypefaceByIndex(int typefaceIndex, int styleIndex) {
29312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        Typeface tf = null;
29412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        switch (typefaceIndex) {
29512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case SANS:
29612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                tf = Typeface.SANS_SERIF;
29712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
29812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
29912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case SERIF:
30012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                tf = Typeface.SERIF;
30112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
30212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
30312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MONOSPACE:
30412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                tf = Typeface.MONOSPACE;
30512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
30612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
30712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
30812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        setSwitchTypeface(tf, styleIndex);
30912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
31012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
31112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
31212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Sets the typeface and style in which the text should be displayed on the
31312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * switch, and turns on the fake bold and italic bits in the Paint if the
31412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Typeface that you provided does not have all the bits in the
31512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * style that you specified.
31612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
31712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void setSwitchTypeface(Typeface tf, int style) {
31812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (style > 0) {
31912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            if (tf == null) {
32012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                tf = Typeface.defaultFromStyle(style);
32112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            } else {
32212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                tf = Typeface.create(tf, style);
32312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
32412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
32512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            setSwitchTypeface(tf);
32612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            // now compute what (if any) algorithmic styling is needed
32712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            int typefaceStyle = tf != null ? tf.getStyle() : 0;
32812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            int need = style & ~typefaceStyle;
32912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mTextPaint.setFakeBoldText((need & Typeface.BOLD) != 0);
33012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mTextPaint.setTextSkewX((need & Typeface.ITALIC) != 0 ? -0.25f : 0);
33112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        } else {
332aa0980afab57a6aebb06e70f60e92511708fa5afVictoria Lease            mTextPaint.setFakeBoldText(false);
33312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mTextPaint.setTextSkewX(0);
33412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            setSwitchTypeface(tf);
33512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
33612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
33712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
33812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
339150176d83023e3c486dba10edebb72af36b4099aChet Haase     * Sets the typeface in which the text should be displayed on the switch.
34012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Note that not all Typeface families actually have bold and italic
34112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * variants, so you may need to use
34212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * {@link #setSwitchTypeface(Typeface, int)} to get the appearance
34312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * that you actually want.
34412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     *
34512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @attr ref android.R.styleable#TextView_typeface
34612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @attr ref android.R.styleable#TextView_textStyle
34712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
34812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void setSwitchTypeface(Typeface tf) {
34912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (mTextPaint.getTypeface() != tf) {
35012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mTextPaint.setTypeface(tf);
35112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
35212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            requestLayout();
35312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            invalidate();
35412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
35512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
35612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
35712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
3586c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Set the amount of horizontal padding between the switch and the associated text.
3596c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3606c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @param pixels Amount of padding in pixels
3616c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3626c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_switchPadding
3636c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
3646c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public void setSwitchPadding(int pixels) {
3656c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        mSwitchPadding = pixels;
3666c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        requestLayout();
3676c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
3686c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
3696c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
3706c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Get the amount of horizontal padding between the switch and the associated text.
3716c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3726c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @return Amount of padding in pixels
3736c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3746c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_switchPadding
3756c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
3766c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public int getSwitchPadding() {
3776c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        return mSwitchPadding;
3786c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
3796c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
3806c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
3816c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Set the minimum width of the switch in pixels. The switch's width will be the maximum
3826c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * of this value and its measured width as determined by the switch drawables and text used.
3836c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3846c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @param pixels Minimum width of the switch in pixels
3856c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3866c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_switchMinWidth
3876c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
3886c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public void setSwitchMinWidth(int pixels) {
3896c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        mSwitchMinWidth = pixels;
3906c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        requestLayout();
3916c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
3926c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
3936c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
3946c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Get the minimum width of the switch in pixels. The switch's width will be the maximum
3956c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * of this value and its measured width as determined by the switch drawables and text used.
3966c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3976c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @return Minimum width of the switch in pixels
3986c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3996c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_switchMinWidth
4006c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
4016c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public int getSwitchMinWidth() {
4026c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        return mSwitchMinWidth;
4036c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
4046c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
4056c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
4066c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Set the horizontal padding around the text drawn on the switch itself.
4076c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4086c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @param pixels Horizontal padding for switch thumb text in pixels
4096c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4106c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_thumbTextPadding
4116c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
4126c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public void setThumbTextPadding(int pixels) {
4136c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        mThumbTextPadding = pixels;
4146c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        requestLayout();
4156c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
4166c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
4176c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
4186c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Get the horizontal padding around the text drawn on the switch itself.
4196c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4206c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @return Horizontal padding for switch thumb text in pixels
4216c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4226c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_thumbTextPadding
4236c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
4246c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public int getThumbTextPadding() {
4256c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        return mThumbTextPadding;
4266c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
4276c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
4286c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
4296c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Set the drawable used for the track that the switch slides within.
4306c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4316c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @param track Track drawable
4326c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4336c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_track
4346c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
4356c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public void setTrackDrawable(Drawable track) {
4366c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        mTrackDrawable = track;
4376c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        requestLayout();
4386c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
4396c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
4406c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
441d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     * Set the drawable used for the track that the switch slides within.
442d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     *
443dca510e026e3e75759bac84c3860dc84b83a608fAdam Powell     * @param resId Resource ID of a track drawable
444d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     *
445d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     * @attr ref android.R.styleable#Switch_track
446d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     */
447d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell    public void setTrackResource(int resId) {
4488eea3ea5591e59f55cbb4f6b2b7e9363a285ced3Alan Viverette        setTrackDrawable(getContext().getDrawable(resId));
449d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell    }
450d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell
451d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell    /**
4526c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Get the drawable used for the track that the switch slides within.
4536c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4546c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @return Track drawable
4556c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4566c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_track
4576c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
4586c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public Drawable getTrackDrawable() {
4596c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        return mTrackDrawable;
4606c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
4616c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
4626c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
4636c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Set the drawable used for the switch "thumb" - the piece that the user
4646c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * can physically touch and drag along the track.
4656c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4666c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @param thumb Thumb drawable
4676c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4686c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_thumb
4696c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
4706c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public void setThumbDrawable(Drawable thumb) {
4716c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        mThumbDrawable = thumb;
4726c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        requestLayout();
4736c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
4746c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
4756c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
476d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     * Set the drawable used for the switch "thumb" - the piece that the user
477d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     * can physically touch and drag along the track.
478d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     *
479dca510e026e3e75759bac84c3860dc84b83a608fAdam Powell     * @param resId Resource ID of a thumb drawable
480d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     *
481d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     * @attr ref android.R.styleable#Switch_thumb
482d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     */
483d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell    public void setThumbResource(int resId) {
4848eea3ea5591e59f55cbb4f6b2b7e9363a285ced3Alan Viverette        setThumbDrawable(getContext().getDrawable(resId));
485d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell    }
486d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell
487d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell    /**
4886c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Get the drawable used for the switch "thumb" - the piece that the user
4896c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * can physically touch and drag along the track.
4906c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4916c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @return Thumb drawable
4926c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4936c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_thumb
4946c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
4956c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public Drawable getThumbDrawable() {
4966c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        return mThumbDrawable;
4976c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
4986c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
4996c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
500661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     * Specifies whether the track should be split by the thumb. When true,
501661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     * the thumb's optical bounds will be clipped out of the track drawable,
502661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     * then the thumb will be drawn into the resulting gap.
503661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     *
504661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     * @param splitTrack Whether the track should be split by the thumb
505661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     *
506661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     * @attr ref android.R.styleable#Switch_splitTrack
507661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     */
508661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    public void setSplitTrack(boolean splitTrack) {
509661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        mSplitTrack = splitTrack;
510661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        invalidate();
511661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    }
512661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
513661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    /**
514661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     * Returns whether the track should be split by the thumb.
515661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     *
516661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     * @attr ref android.R.styleable#Switch_splitTrack
517661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     */
518661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    public boolean getSplitTrack() {
519661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        return mSplitTrack;
520661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    }
521661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
522661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    /**
523150176d83023e3c486dba10edebb72af36b4099aChet Haase     * Returns the text displayed when the button is in the checked state.
5246c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
5256c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_textOn
52612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
52712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public CharSequence getTextOn() {
52812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return mTextOn;
52912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
53012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
53112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
532150176d83023e3c486dba10edebb72af36b4099aChet Haase     * Sets the text displayed when the button is in the checked state.
5336c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
5346c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_textOn
53512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
53612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void setTextOn(CharSequence textOn) {
53712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextOn = textOn;
53812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        requestLayout();
53912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
54012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
54112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
542150176d83023e3c486dba10edebb72af36b4099aChet Haase     * Returns the text displayed when the button is not in the checked state.
5436c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
5446c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_textOff
54512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
54612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public CharSequence getTextOff() {
54712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return mTextOff;
54812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
54912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
55012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
551150176d83023e3c486dba10edebb72af36b4099aChet Haase     * Sets the text displayed when the button is not in the checked state.
5526c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
5536c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_textOff
55412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
55512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void setTextOff(CharSequence textOff) {
55612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextOff = textOff;
55712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        requestLayout();
55812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
55912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
5602a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette    /**
5612a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette     * Sets whether the on/off text should be displayed.
5622a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette     *
5632a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette     * @param showText {@code true} to display on/off text
5640c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     * @attr ref android.R.styleable#Switch_showText
5652a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette     */
5662a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette    public void setShowText(boolean showText) {
5672a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette        if (mShowText != showText) {
5682a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette            mShowText = showText;
5692a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette            requestLayout();
5702a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette        }
5712a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette    }
5722a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette
5732a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette    /**
5742a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette     * @return whether the on/off text should be displayed
5750c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     * @attr ref android.R.styleable#Switch_showText
5762a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette     */
5772a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette    public boolean getShowText() {
5782a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette        return mShowText;
5792a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette    }
5802a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette
58112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
58212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
5832a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette        if (mShowText) {
5842a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette            if (mOnLayout == null) {
5852a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette                mOnLayout = makeLayout(mTextOn);
5862a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette            }
5875876ff4a0ac938297bfd114da6b5d8c9dcb4cef6Alan Viverette
5882a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette            if (mOffLayout == null) {
5892a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette                mOffLayout = makeLayout(mTextOff);
5902a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette            }
59112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
59212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
5939b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette        final Rect padding = mTempRect;
5949b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette        final int thumbWidth;
5959b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette        final int thumbHeight;
5968bb399069da4e46b231333cff6880a0cf35b9417Alan Viverette        if (mThumbDrawable != null) {
5970c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            // Cached thumb width does not include padding.
5980c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            mThumbDrawable.getPadding(padding);
5990c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            thumbWidth = mThumbDrawable.getIntrinsicWidth() - padding.left - padding.right;
6009b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette            thumbHeight = mThumbDrawable.getIntrinsicHeight();
6019b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette        } else {
6029b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette            thumbWidth = 0;
6039b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette            thumbHeight = 0;
6048bb399069da4e46b231333cff6880a0cf35b9417Alan Viverette        }
6058bb399069da4e46b231333cff6880a0cf35b9417Alan Viverette
6060c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        final int maxTextWidth;
6070c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        if (mShowText) {
6080c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            maxTextWidth = Math.max(mOnLayout.getWidth(), mOffLayout.getWidth())
6090c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                    + mThumbTextPadding * 2;
6100c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        } else {
6110c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            maxTextWidth = 0;
6120c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        }
6130c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
6149b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette        mThumbWidth = Math.max(maxTextWidth, thumbWidth);
6159b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette
6160c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        final int trackHeight;
6170c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        if (mTrackDrawable != null) {
6180c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            mTrackDrawable.getPadding(padding);
6190c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            trackHeight = mTrackDrawable.getIntrinsicHeight();
6200c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        } else {
6210c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            padding.setEmpty();
6220c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            trackHeight = 0;
6230c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        }
6240c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
6250c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        // Adjust left and right padding to ensure there's enough room for the
6260c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        // thumb's padding (when present).
6270c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        int paddingLeft = padding.left;
6280c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        int paddingRight = padding.right;
6290c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        if (mThumbDrawable != null) {
6300c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            final Insets inset = mThumbDrawable.getOpticalInsets();
6310c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            paddingLeft = Math.max(paddingLeft, inset.left);
6320c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            paddingRight = Math.max(paddingRight, inset.right);
6330c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        }
6340c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
63512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int switchWidth = Math.max(mSwitchMinWidth,
6360c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                2 * mThumbWidth + paddingLeft + paddingRight);
6374d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        final int switchHeight = Math.max(trackHeight, thumbHeight);
63812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchWidth = switchWidth;
63912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchHeight = switchHeight;
64012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
64112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
6424d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette
64312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int measuredHeight = getMeasuredHeight();
64412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (measuredHeight < switchHeight) {
645189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn            setMeasuredDimension(getMeasuredWidthAndState(), switchHeight);
64612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
64712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
64812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
64963bce03cc69be4a45230aa8bbd89dbde60681067Svetoslav Ganov    @Override
65063bce03cc69be4a45230aa8bbd89dbde60681067Svetoslav Ganov    public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
65163bce03cc69be4a45230aa8bbd89dbde60681067Svetoslav Ganov        super.onPopulateAccessibilityEvent(event);
6522a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette
6532a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette        final CharSequence text = isChecked() ? mTextOn : mTextOff;
6542a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette        if (text != null) {
6552a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette            event.getText().add(text);
6567650259a597dd24137420d32acc35efc44db381eSvetoslav Ganov        }
65763bce03cc69be4a45230aa8bbd89dbde60681067Svetoslav Ganov    }
65863bce03cc69be4a45230aa8bbd89dbde60681067Svetoslav Ganov
65912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private Layout makeLayout(CharSequence text) {
6604c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler        final CharSequence transformed = (mSwitchTransformationMethod != null)
6614c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler                    ? mSwitchTransformationMethod.getTransformation(text, this)
6624c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler                    : text;
6634c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler
6644c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler        return new StaticLayout(transformed, mTextPaint,
6654c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler                (int) Math.ceil(Layout.getDesiredWidth(transformed, mTextPaint)),
66612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                Layout.Alignment.ALIGN_NORMAL, 1.f, 0, true);
66712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
66812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
66912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
67012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @return true if (x, y) is within the target area of the switch thumb
67112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
67212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private boolean hitThumb(float x, float y) {
673cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        // Relies on mTempRect, MUST be called first!
674cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        final int thumbOffset = getThumbOffset();
675cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette
67612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mThumbDrawable.getPadding(mTempRect);
67712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int thumbTop = mSwitchTop - mTouchSlop;
678cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        final int thumbLeft = mSwitchLeft + thumbOffset - mTouchSlop;
67912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int thumbRight = thumbLeft + mThumbWidth +
68012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                mTempRect.left + mTempRect.right + mTouchSlop;
68112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int thumbBottom = mSwitchBottom + mTouchSlop;
68212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return x > thumbLeft && x < thumbRight && y > thumbTop && y < thumbBottom;
68312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
68412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
68512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
68612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public boolean onTouchEvent(MotionEvent ev) {
68712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mVelocityTracker.addMovement(ev);
68812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int action = ev.getActionMasked();
68912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        switch (action) {
69012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MotionEvent.ACTION_DOWN: {
69112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                final float x = ev.getX();
69212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                final float y = ev.getY();
693c2ab0d665c9d1c332fbd726abf582a27cf7a6701Gilles Debunne                if (isEnabled() && hitThumb(x, y)) {
69412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    mTouchMode = TOUCH_MODE_DOWN;
69512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    mTouchX = x;
69612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    mTouchY = y;
69712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                }
69812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
69912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
70012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
70112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MotionEvent.ACTION_MOVE: {
70212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switch (mTouchMode) {
70312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    case TOUCH_MODE_IDLE:
70412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        // Didn't target the thumb, treat normally.
70512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        break;
70612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
70712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    case TOUCH_MODE_DOWN: {
70812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        final float x = ev.getX();
70912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        final float y = ev.getY();
71012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        if (Math.abs(x - mTouchX) > mTouchSlop ||
71112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                                Math.abs(y - mTouchY) > mTouchSlop) {
71212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            mTouchMode = TOUCH_MODE_DRAGGING;
71312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            getParent().requestDisallowInterceptTouchEvent(true);
71412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            mTouchX = x;
71512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            mTouchY = y;
71612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            return true;
71712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        }
71812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        break;
71912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    }
72012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
72112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    case TOUCH_MODE_DRAGGING: {
72212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        final float x = ev.getX();
723cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                        final int thumbScrollRange = getThumbScrollRange();
724cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                        final float thumbScrollOffset = x - mTouchX;
725cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                        float dPos;
726cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                        if (thumbScrollRange != 0) {
727cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                            dPos = thumbScrollOffset / thumbScrollRange;
728cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                        } else {
729cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                            // If the thumb scroll range is empty, just use the
730cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                            // movement direction to snap on or off.
731cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                            dPos = thumbScrollOffset > 0 ? 1 : -1;
732cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                        }
733cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                        if (isLayoutRtl()) {
734cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                            dPos = -dPos;
735cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                        }
736cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                        final float newPos = MathUtils.constrain(mThumbPosition + dPos, 0, 1);
73712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        if (newPos != mThumbPosition) {
73812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            mTouchX = x;
739cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                            setThumbPosition(newPos);
74012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        }
74112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        return true;
74212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    }
74312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                }
74412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
74512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
74612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
74712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MotionEvent.ACTION_UP:
74812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MotionEvent.ACTION_CANCEL: {
74912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                if (mTouchMode == TOUCH_MODE_DRAGGING) {
75012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    stopDrag(ev);
751ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette                    // Allow super class to handle pressed state, etc.
752ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette                    super.onTouchEvent(ev);
75312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    return true;
75412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                }
75512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                mTouchMode = TOUCH_MODE_IDLE;
75612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                mVelocityTracker.clear();
75712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
75812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
75912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
76012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
76112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return super.onTouchEvent(ev);
76212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
76312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
76412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private void cancelSuperTouch(MotionEvent ev) {
76512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        MotionEvent cancel = MotionEvent.obtain(ev);
76612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        cancel.setAction(MotionEvent.ACTION_CANCEL);
76712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.onTouchEvent(cancel);
76812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        cancel.recycle();
76912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
77012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
77112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
77212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Called from onTouchEvent to end a drag operation.
77312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     *
77412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param ev Event that triggered the end of drag mode - ACTION_UP or ACTION_CANCEL
77512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
77612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private void stopDrag(MotionEvent ev) {
77712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTouchMode = TOUCH_MODE_IDLE;
77812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
77986453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette        // Commit the change if the event is up and not canceled and the switch
78086453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette        // has not been disabled during the drag.
78186453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette        final boolean commitChange = ev.getAction() == MotionEvent.ACTION_UP && isEnabled();
78286453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette        final boolean newState;
78312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (commitChange) {
78412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mVelocityTracker.computeCurrentVelocity(1000);
78586453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette            final float xvel = mVelocityTracker.getXVelocity();
78612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            if (Math.abs(xvel) > mMinFlingVelocity) {
78728efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio                newState = isLayoutRtl() ? (xvel < 0) : (xvel > 0);
78812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            } else {
78912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                newState = getTargetCheckedState();
79012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
79112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        } else {
79286453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette            newState = isChecked();
79312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
79486453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette
79586453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette        setChecked(newState);
79686453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette        cancelSuperTouch(ev);
79712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
79812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
79912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private void animateThumbToCheckedState(boolean newCheckedState) {
800cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        final float targetPosition = newCheckedState ? 1 : 0;
801cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        mPositionAnimator = ObjectAnimator.ofFloat(this, THUMB_POS, targetPosition);
802cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        mPositionAnimator.setDuration(THUMB_ANIMATION_DURATION);
803cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        mPositionAnimator.setAutoCancel(true);
804cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        mPositionAnimator.start();
80512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
80612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
807cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    private void cancelPositionAnimator() {
808cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        if (mPositionAnimator != null) {
809cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette            mPositionAnimator.cancel();
81028efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        }
81128efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio    }
81228efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio
813cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    private boolean getTargetCheckedState() {
814cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        return mThumbPosition > 0.5f;
815cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    }
816cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette
817cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    /**
818cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette     * Sets the thumb position as a decimal value between 0 (off) and 1 (on).
819cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette     *
820cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette     * @param position new position between [0,1]
821cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette     */
822cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    private void setThumbPosition(float position) {
823cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        mThumbPosition = position;
824cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        invalidate();
825cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    }
826cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette
827cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    @Override
828cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    public void toggle() {
82986453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette        setChecked(!isChecked());
83012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
83112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
83212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
83312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void setChecked(boolean checked) {
83412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.setChecked(checked);
835cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette
83686453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette        if (isAttachedToWindow() && isLaidOut()) {
83786453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette            animateThumbToCheckedState(checked);
83886453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette        } else {
83986453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette            // Immediately move the thumb to the new position.
84086453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette            cancelPositionAnimator();
84186453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette            setThumbPosition(checked ? 1 : 0);
84286453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette        }
84312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
84412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
84512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
84612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
84712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.onLayout(changed, left, top, right, bottom);
84812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
8490c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        int opticalInsetLeft = 0;
8500c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        int opticalInsetRight = 0;
8510c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        if (mThumbDrawable != null) {
8520c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            final Rect trackPadding = mTempRect;
8530c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            if (mTrackDrawable != null) {
8540c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                mTrackDrawable.getPadding(trackPadding);
8550c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            } else {
8560c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                trackPadding.setEmpty();
8570c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            }
8580c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
8590c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            final Insets insets = mThumbDrawable.getOpticalInsets();
8600c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            opticalInsetLeft = Math.max(0, insets.left - trackPadding.left);
8610c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            opticalInsetRight = Math.max(0, insets.right - trackPadding.right);
8620c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        }
86328efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio
8640c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        final int switchRight;
8650c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        final int switchLeft;
86628efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        if (isLayoutRtl()) {
8670c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            switchLeft = getPaddingLeft() + opticalInsetLeft;
8680c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            switchRight = switchLeft + mSwitchWidth - opticalInsetLeft - opticalInsetRight;
86928efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        } else {
8700c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            switchRight = getWidth() - getPaddingRight() - opticalInsetRight;
8710c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            switchLeft = switchRight - mSwitchWidth + opticalInsetLeft + opticalInsetRight;
87228efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        }
873c3eabb9b6ce7f556313c8e3870d76c5b443f1c51Joe Onorato
8740c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        final int switchTop;
8750c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        final int switchBottom;
87612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        switch (getGravity() & Gravity.VERTICAL_GRAVITY_MASK) {
87712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            default:
87812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case Gravity.TOP:
87912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchTop = getPaddingTop();
88012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchBottom = switchTop + mSwitchHeight;
88112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
88212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
88312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case Gravity.CENTER_VERTICAL:
88412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchTop = (getPaddingTop() + getHeight() - getPaddingBottom()) / 2 -
88512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        mSwitchHeight / 2;
88612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchBottom = switchTop + mSwitchHeight;
88712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
88812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
88912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case Gravity.BOTTOM:
89012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchBottom = getHeight() - getPaddingBottom();
89112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchTop = switchBottom - mSwitchHeight;
89212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
89312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
89412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
89512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchLeft = switchLeft;
89612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchTop = switchTop;
89712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchBottom = switchBottom;
89812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchRight = switchRight;
89912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
90012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
90112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
902ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    public void draw(Canvas c) {
9034d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        final Rect padding = mTempRect;
9045876ff4a0ac938297bfd114da6b5d8c9dcb4cef6Alan Viverette        final int switchLeft = mSwitchLeft;
9055876ff4a0ac938297bfd114da6b5d8c9dcb4cef6Alan Viverette        final int switchTop = mSwitchTop;
9065876ff4a0ac938297bfd114da6b5d8c9dcb4cef6Alan Viverette        final int switchRight = mSwitchRight;
9075876ff4a0ac938297bfd114da6b5d8c9dcb4cef6Alan Viverette        final int switchBottom = mSwitchBottom;
9080c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
9090c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        int thumbInitialLeft = switchLeft + getThumbOffset();
9100c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
9110c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        final Insets thumbInsets;
9120c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        if (mThumbDrawable != null) {
9130c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            thumbInsets = mThumbDrawable.getOpticalInsets();
9140c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        } else {
9150c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            thumbInsets = Insets.NONE;
9168bb399069da4e46b231333cff6880a0cf35b9417Alan Viverette        }
917cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette
9180c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        // Layout the track.
9190c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        if (mTrackDrawable != null) {
9200c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            mTrackDrawable.getPadding(padding);
9219b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette
9220c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            // Adjust thumb position for track padding.
9230c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            thumbInitialLeft += padding.left;
9240c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
9250c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            // If necessary, offset by the optical insets of the thumb asset.
9260c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            int trackLeft = switchLeft;
9270c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            int trackTop = switchTop;
9280c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            int trackRight = switchRight;
9290c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            int trackBottom = switchBottom;
9300c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            if (thumbInsets != Insets.NONE) {
9310c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                if (thumbInsets.left > padding.left) {
9320c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                    trackLeft += thumbInsets.left - padding.left;
9330c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                }
9340c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                if (thumbInsets.top > padding.top) {
9350c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                    trackTop += thumbInsets.top - padding.top;
9360c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                }
9370c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                if (thumbInsets.right > padding.right) {
9380c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                    trackRight -= thumbInsets.right - padding.right;
9390c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                }
9400c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                if (thumbInsets.bottom > padding.bottom) {
9410c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                    trackBottom -= thumbInsets.bottom - padding.bottom;
9420c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                }
9430c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            }
9440c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            mTrackDrawable.setBounds(trackLeft, trackTop, trackRight, trackBottom);
9450c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        }
9469b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette
947661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        // Layout the thumb.
9484d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        if (mThumbDrawable != null) {
9494d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            mThumbDrawable.getPadding(padding);
9500c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
9510c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            final int thumbLeft = thumbInitialLeft - padding.left;
9520c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            final int thumbRight = thumbInitialLeft + mThumbWidth + padding.right;
9534d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            mThumbDrawable.setBounds(thumbLeft, switchTop, thumbRight, switchBottom);
9544d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette
9554d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            final Drawable background = getBackground();
9564d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            if (background != null) {
9574d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                background.setHotspotBounds(thumbLeft, switchTop, thumbRight, switchBottom);
9584d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            }
95961956606818918194a38e045a8e35e7108480e5eAlan Viverette        }
96061956606818918194a38e045a8e35e7108480e5eAlan Viverette
961ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette        // Draw the background.
962ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette        super.draw(c);
963ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    }
964ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette
965ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    @Override
966ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    protected void onDraw(Canvas canvas) {
96761956606818918194a38e045a8e35e7108480e5eAlan Viverette        super.onDraw(canvas);
96861956606818918194a38e045a8e35e7108480e5eAlan Viverette
9694d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        final Rect padding = mTempRect;
970ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette        final Drawable trackDrawable = mTrackDrawable;
9714d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        if (trackDrawable != null) {
9724d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            trackDrawable.getPadding(padding);
9734d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        } else {
9744d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            padding.setEmpty();
9754d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        }
976ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette
977ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette        final int switchTop = mSwitchTop;
978ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette        final int switchBottom = mSwitchBottom;
9794d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        final int switchInnerTop = switchTop + padding.top;
9804d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        final int switchInnerBottom = switchBottom - padding.bottom;
9814d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette
9824d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        final Drawable thumbDrawable = mThumbDrawable;
9834d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        if (trackDrawable != null) {
9844d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            if (mSplitTrack && thumbDrawable != null) {
9854d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                final Insets insets = thumbDrawable.getOpticalInsets();
9864d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                thumbDrawable.copyBounds(padding);
9874d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                padding.left += insets.left;
9884d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                padding.right -= insets.right;
9894d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette
9904d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                final int saveCount = canvas.save();
9914d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                canvas.clipRect(padding, Op.DIFFERENCE);
9924d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                trackDrawable.draw(canvas);
9934d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                canvas.restoreToCount(saveCount);
9944d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            } else {
9954d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                trackDrawable.draw(canvas);
9964d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            }
997661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        }
99861956606818918194a38e045a8e35e7108480e5eAlan Viverette
99961956606818918194a38e045a8e35e7108480e5eAlan Viverette        final int saveCount = canvas.save();
10004d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette
10014d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        if (thumbDrawable != null) {
10024d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            thumbDrawable.draw(canvas);
10034d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        }
100412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
10055876ff4a0ac938297bfd114da6b5d8c9dcb4cef6Alan Viverette        final Layout switchText = getTargetCheckedState() ? mOnLayout : mOffLayout;
1006be06e3292b295324b3b47d13f9a40787b666309fFabrice Di Meglio        if (switchText != null) {
1007661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            final int drawableState[] = getDrawableState();
1008661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            if (mTextColors != null) {
1009661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette                mTextPaint.setColor(mTextColors.getColorForState(drawableState, 0));
1010661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            }
1011661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            mTextPaint.drawableState = drawableState;
1012661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
10134d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            final int cX;
10144d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            if (thumbDrawable != null) {
10154d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                final Rect bounds = thumbDrawable.getBounds();
10164d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                cX = bounds.left + bounds.right;
10174d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            } else {
1018dec17299fef93f673d8e8cab0ec0f734bf6b8539Alan Viverette                cX = getWidth();
10194d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            }
10204d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette
10214d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            final int left = cX / 2 - switchText.getWidth() / 2;
10225876ff4a0ac938297bfd114da6b5d8c9dcb4cef6Alan Viverette            final int top = (switchInnerTop + switchInnerBottom) / 2 - switchText.getHeight() / 2;
10235876ff4a0ac938297bfd114da6b5d8c9dcb4cef6Alan Viverette            canvas.translate(left, top);
1024be06e3292b295324b3b47d13f9a40787b666309fFabrice Di Meglio            switchText.draw(canvas);
1025be06e3292b295324b3b47d13f9a40787b666309fFabrice Di Meglio        }
102612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
10275876ff4a0ac938297bfd114da6b5d8c9dcb4cef6Alan Viverette        canvas.restoreToCount(saveCount);
102812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
102912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
103012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
103128efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio    public int getCompoundPaddingLeft() {
103228efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        if (!isLayoutRtl()) {
103328efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio            return super.getCompoundPaddingLeft();
103428efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        }
103528efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        int padding = super.getCompoundPaddingLeft() + mSwitchWidth;
103628efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        if (!TextUtils.isEmpty(getText())) {
103728efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio            padding += mSwitchPadding;
103828efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        }
103928efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        return padding;
104028efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio    }
104128efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio
104228efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio    @Override
104312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public int getCompoundPaddingRight() {
104428efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        if (isLayoutRtl()) {
104528efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio            return super.getCompoundPaddingRight();
104628efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        }
104712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int padding = super.getCompoundPaddingRight() + mSwitchWidth;
104812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (!TextUtils.isEmpty(getText())) {
104912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            padding += mSwitchPadding;
105012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
105112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return padding;
105212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
105312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
1054cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    /**
1055cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette     * Translates thumb position to offset according to current RTL setting and
10560c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     * thumb scroll range. Accounts for both track and thumb padding.
1057cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette     *
1058cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette     * @return thumb offset
1059cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette     */
1060cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    private int getThumbOffset() {
1061cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        final float thumbPosition;
1062cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        if (isLayoutRtl()) {
1063cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette            thumbPosition = 1 - mThumbPosition;
1064cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        } else {
1065cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette            thumbPosition = mThumbPosition;
1066cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        }
1067cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        return (int) (thumbPosition * getThumbScrollRange() + 0.5f);
1068cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    }
1069cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette
107012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int getThumbScrollRange() {
10714d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        if (mTrackDrawable != null) {
10720c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            final Rect padding = mTempRect;
10730c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            mTrackDrawable.getPadding(padding);
10740c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
10750c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            final Insets insets;
10760c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            if (mThumbDrawable != null) {
10770c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                insets = mThumbDrawable.getOpticalInsets();
10780c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            } else {
10790c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                insets = Insets.NONE;
10800c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            }
10810c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
10820c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            return mSwitchWidth - mThumbWidth - padding.left - padding.right
10830c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                    - insets.left - insets.right;
10844d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        } else {
108512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            return 0;
108612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
108712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
108812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
108912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
109012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    protected int[] onCreateDrawableState(int extraSpace) {
109112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
109212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (isChecked()) {
109312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mergeDrawableStates(drawableState, CHECKED_STATE_SET);
109412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
109512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return drawableState;
109612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
109712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
109812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
109912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    protected void drawableStateChanged() {
110012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.drawableStateChanged();
110112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
1102661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        final int[] myDrawableState = getDrawableState();
1103661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
11042356c5e69b0911e6334ebf6374217898371be5acAlan Viverette        if (mThumbDrawable != null) {
11052356c5e69b0911e6334ebf6374217898371be5acAlan Viverette            mThumbDrawable.setState(myDrawableState);
1106661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        }
110712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
1108661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        if (mTrackDrawable != null) {
1109661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            mTrackDrawable.setState(myDrawableState);
1110661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        }
111112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
111212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        invalidate();
111312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
111412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
1115cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette    @Override
11168de1494557cf1d00c1c3fce439138a28de7fbd61Alan Viverette    public void drawableHotspotChanged(float x, float y) {
11178de1494557cf1d00c1c3fce439138a28de7fbd61Alan Viverette        super.drawableHotspotChanged(x, y);
1118cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette
1119cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette        if (mThumbDrawable != null) {
1120cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette            mThumbDrawable.setHotspot(x, y);
1121cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette        }
1122cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette
1123cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette        if (mTrackDrawable != null) {
1124cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette            mTrackDrawable.setHotspot(x, y);
1125cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette        }
1126cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette    }
1127cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette
112812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
112912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    protected boolean verifyDrawable(Drawable who) {
113012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return super.verifyDrawable(who) || who == mThumbDrawable || who == mTrackDrawable;
113112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
113212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
113312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
113412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void jumpDrawablesToCurrentState() {
113512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.jumpDrawablesToCurrentState();
11364d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette
11374d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        if (mThumbDrawable != null) {
11384d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            mThumbDrawable.jumpToCurrentState();
11394d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        }
11404d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette
11414d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        if (mTrackDrawable != null) {
11424d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            mTrackDrawable.jumpToCurrentState();
11434d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        }
11444d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette
11454d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        if (mPositionAnimator != null && mPositionAnimator.isRunning()) {
11464d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            mPositionAnimator.end();
11474d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            mPositionAnimator = null;
11484d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        }
114912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
11508a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov
11518a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    @Override
11528a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
11538a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        super.onInitializeAccessibilityEvent(event);
11548a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        event.setClassName(Switch.class.getName());
11558a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    }
11568a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov
11578a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    @Override
11588a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
11598a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        super.onInitializeAccessibilityNodeInfo(info);
11608a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        info.setClassName(Switch.class.getName());
116178bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov        CharSequence switchText = isChecked() ? mTextOn : mTextOff;
116278bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov        if (!TextUtils.isEmpty(switchText)) {
116378bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov            CharSequence oldText = info.getText();
116478bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov            if (TextUtils.isEmpty(oldText)) {
116578bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov                info.setText(switchText);
116678bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov            } else {
116778bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov                StringBuilder newText = new StringBuilder();
116878bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov                newText.append(oldText).append(' ').append(switchText);
116978bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov                info.setText(newText);
117078bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov            }
117178bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov        }
11728a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    }
1173cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette
1174cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    private static final FloatProperty<Switch> THUMB_POS = new FloatProperty<Switch>("thumbPos") {
1175cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        @Override
1176cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        public Float get(Switch object) {
1177cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette            return object.mThumbPosition;
1178cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        }
1179cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette
1180cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        @Override
1181cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        public void setValue(Switch object, float value) {
1182cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette            object.setThumbPosition(value);
1183cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        }
1184cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    };
118512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell}
1186