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;
42d4e7790fee10e21b41a1c387c2734722bda56a0bAlan Viveretteimport android.view.SoundEffectConstants;
4312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.view.VelocityTracker;
4412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.view.ViewConfiguration;
4563bce03cc69be4a45230aa8bbd89dbde60681067Svetoslav Ganovimport android.view.accessibility.AccessibilityEvent;
468a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganovimport android.view.accessibility.AccessibilityNodeInfo;
4712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
48be0a4535053bbfdebd215e244b154ac810fd8edcAdam Powellimport com.android.internal.R;
49be0a4535053bbfdebd215e244b154ac810fd8edcAdam Powell
5012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell/**
5112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell * A Switch is a two-state toggle switch widget that can select between two
5212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell * options. The user may drag the "thumb" back and forth to choose the selected option,
53150176d83023e3c486dba10edebb72af36b4099aChet Haase * or simply tap to toggle as if it were a checkbox. The {@link #setText(CharSequence) text}
54150176d83023e3c486dba10edebb72af36b4099aChet Haase * property controls the text displayed in the label for the switch, whereas the
55150176d83023e3c486dba10edebb72af36b4099aChet Haase * {@link #setTextOff(CharSequence) off} and {@link #setTextOn(CharSequence) on} text
56150176d83023e3c486dba10edebb72af36b4099aChet Haase * controls the text on the thumb. Similarly, the
57150176d83023e3c486dba10edebb72af36b4099aChet Haase * {@link #setTextAppearance(android.content.Context, int) textAppearance} and the related
58150176d83023e3c486dba10edebb72af36b4099aChet Haase * setTypeface() methods control the typeface and style of label text, whereas the
59150176d83023e3c486dba10edebb72af36b4099aChet Haase * {@link #setSwitchTextAppearance(android.content.Context, int) switchTextAppearance} and
60150176d83023e3c486dba10edebb72af36b4099aChet Haase * the related seSwitchTypeface() methods control that of the thumb.
6112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell *
624c359b76f9a030f92a302ba74a528faa170bad4eScott Main * <p>See the <a href="{@docRoot}guide/topics/ui/controls/togglebutton.html">Toggle Buttons</a>
634c359b76f9a030f92a302ba74a528faa170bad4eScott Main * guide.</p>
644c359b76f9a030f92a302ba74a528faa170bad4eScott Main *
654c359b76f9a030f92a302ba74a528faa170bad4eScott Main * @attr ref android.R.styleable#Switch_textOn
664c359b76f9a030f92a302ba74a528faa170bad4eScott Main * @attr ref android.R.styleable#Switch_textOff
674c359b76f9a030f92a302ba74a528faa170bad4eScott Main * @attr ref android.R.styleable#Switch_switchMinWidth
684c359b76f9a030f92a302ba74a528faa170bad4eScott Main * @attr ref android.R.styleable#Switch_switchPadding
694c359b76f9a030f92a302ba74a528faa170bad4eScott Main * @attr ref android.R.styleable#Switch_switchTextAppearance
704c359b76f9a030f92a302ba74a528faa170bad4eScott Main * @attr ref android.R.styleable#Switch_thumb
714c359b76f9a030f92a302ba74a528faa170bad4eScott Main * @attr ref android.R.styleable#Switch_thumbTextPadding
724c359b76f9a030f92a302ba74a528faa170bad4eScott Main * @attr ref android.R.styleable#Switch_track
7312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell */
7412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellpublic class Switch extends CompoundButton {
75cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    private static final int THUMB_ANIMATION_DURATION = 250;
76cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette
7712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int TOUCH_MODE_IDLE = 0;
7812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int TOUCH_MODE_DOWN = 1;
7912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int TOUCH_MODE_DRAGGING = 2;
8012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
8112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    // Enum for the "typeface" XML parameter.
8212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int SANS = 1;
8312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int SERIF = 2;
8412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int MONOSPACE = 3;
8512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
8612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private Drawable mThumbDrawable;
8712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private Drawable mTrackDrawable;
8812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mThumbTextPadding;
8912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchMinWidth;
9012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchPadding;
91661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    private boolean mSplitTrack;
9212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private CharSequence mTextOn;
9312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private CharSequence mTextOff;
942a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette    private boolean mShowText;
9512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
9612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mTouchMode;
9712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mTouchSlop;
9812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private float mTouchX;
9912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private float mTouchY;
10012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private VelocityTracker mVelocityTracker = VelocityTracker.obtain();
10112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mMinFlingVelocity;
10212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
10312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private float mThumbPosition;
1040c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
1050c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette    /**
1060c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     * Width required to draw the switch track and thumb. Includes padding and
1070c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     * optical bounds for both the track and thumb.
1080c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     */
10912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchWidth;
1100c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
1110c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette    /**
1120c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     * Height required to draw the switch track and thumb. Includes padding and
1130c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     * optical bounds for both the track and thumb.
1140c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     */
11512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchHeight;
11612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
1170c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette    /**
1180c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     * Width of the thumb's content region. Does not include padding or
1190c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     * optical bounds.
1200c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     */
1210c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette    private int mThumbWidth;
1220c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
1230c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette    /** Left bound for drawing the switch track and thumb. */
12412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchLeft;
1250c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
1260c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette    /** Top bound for drawing the switch track and thumb. */
12712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchTop;
1280c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
1290c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette    /** Right bound for drawing the switch track and thumb. */
13012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchRight;
1310c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
1320c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette    /** Bottom bound for drawing the switch track and thumb. */
13312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchBottom;
13412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
13512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private TextPaint mTextPaint;
13612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private ColorStateList mTextColors;
13712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private Layout mOnLayout;
13812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private Layout mOffLayout;
1394c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler    private TransformationMethod2 mSwitchTransformationMethod;
140cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    private ObjectAnimator mPositionAnimator;
14112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
142be0a4535053bbfdebd215e244b154ac810fd8edcAdam Powell    @SuppressWarnings("hiding")
14312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private final Rect mTempRect = new Rect();
14412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
14512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int[] CHECKED_STATE_SET = {
14612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        R.attr.state_checked
14712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    };
14812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
14912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
15012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Construct a new Switch with default styling.
15112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     *
15212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param context The Context that will determine this widget's theming.
15312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
15412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public Switch(Context context) {
15512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        this(context, null);
15612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
15712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
15812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
15912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Construct a new Switch with default styling, overriding specific style
16012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * attributes as requested.
16112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     *
16212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param context The Context that will determine this widget's theming.
16312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param attrs Specification of attributes that should deviate from default styling.
16412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
16512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public Switch(Context context, AttributeSet attrs) {
16612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        this(context, attrs, com.android.internal.R.attr.switchStyle);
16712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
16812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
16912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
17012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Construct a new Switch with a default style determined by the given theme attribute,
17112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * overriding specific style attributes as requested.
17212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     *
17312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param context The Context that will determine this widget's theming.
17412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param attrs Specification of attributes that should deviate from the default styling.
175617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     * @param defStyleAttr An attribute in the current theme that contains a
176617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        reference to a style resource that supplies default values for
177617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        the view. Can be 0 to not look for defaults.
17812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
179617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    public Switch(Context context, AttributeSet attrs, int defStyleAttr) {
180617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette        this(context, attrs, defStyleAttr, 0);
181617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    }
182617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette
183617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette
184617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    /**
185617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     * Construct a new Switch with a default style determined by the given theme
186617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     * attribute or style resource, overriding specific style attributes as
187617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     * requested.
188617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *
189617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     * @param context The Context that will determine this widget's theming.
190617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     * @param attrs Specification of attributes that should deviate from the
191617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        default styling.
192617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     * @param defStyleAttr An attribute in the current theme that contains a
193617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        reference to a style resource that supplies default values for
194617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        the view. Can be 0 to not look for defaults.
195617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     * @param defStyleRes A resource identifier of a style resource that
196617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        supplies default values for the view, used only if
197617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        defStyleAttr is 0 or can not be found in the theme. Can be 0
198617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        to not look for defaults.
199617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     */
200617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    public Switch(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
201617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette        super(context, attrs, defStyleAttr, defStyleRes);
20212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
20312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
204661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
205661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        final Resources res = getResources();
20612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextPaint.density = res.getDisplayMetrics().density;
20712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextPaint.setCompatibilityScaling(res.getCompatibilityInfo().applicationScale);
20812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
209617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette        final TypedArray a = context.obtainStyledAttributes(
210617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette                attrs, com.android.internal.R.styleable.Switch, defStyleAttr, defStyleRes);
211150176d83023e3c486dba10edebb72af36b4099aChet Haase        mThumbDrawable = a.getDrawable(com.android.internal.R.styleable.Switch_thumb);
212b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette        if (mThumbDrawable != null) {
213b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette            mThumbDrawable.setCallback(this);
214b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette        }
215150176d83023e3c486dba10edebb72af36b4099aChet Haase        mTrackDrawable = a.getDrawable(com.android.internal.R.styleable.Switch_track);
216b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette        if (mTrackDrawable != null) {
217b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette            mTrackDrawable.setCallback(this);
218b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette        }
21912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextOn = a.getText(com.android.internal.R.styleable.Switch_textOn);
22012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextOff = a.getText(com.android.internal.R.styleable.Switch_textOff);
2212a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette        mShowText = a.getBoolean(com.android.internal.R.styleable.Switch_showText, true);
22212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mThumbTextPadding = a.getDimensionPixelSize(
22312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                com.android.internal.R.styleable.Switch_thumbTextPadding, 0);
22412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchMinWidth = a.getDimensionPixelSize(
22512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                com.android.internal.R.styleable.Switch_switchMinWidth, 0);
22612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchPadding = a.getDimensionPixelSize(
22712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                com.android.internal.R.styleable.Switch_switchPadding, 0);
228661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        mSplitTrack = a.getBoolean(com.android.internal.R.styleable.Switch_splitTrack, false);
22912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
230661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        final int appearance = a.getResourceId(
23112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                com.android.internal.R.styleable.Switch_switchTextAppearance, 0);
23212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (appearance != 0) {
233150176d83023e3c486dba10edebb72af36b4099aChet Haase            setSwitchTextAppearance(context, appearance);
23412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
23512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        a.recycle();
23612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
237661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        final ViewConfiguration config = ViewConfiguration.get(context);
23812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTouchSlop = config.getScaledTouchSlop();
23912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mMinFlingVelocity = config.getScaledMinimumFlingVelocity();
24012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
24112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        // Refresh display with current params
242e724ee4b04d121556e9764f72f9b921a0e16392aGilles Debunne        refreshDrawableState();
24312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        setChecked(isChecked());
24412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
24512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
24612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
24712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Sets the switch text color, size, style, hint color, and highlight color
24812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * from the specified TextAppearance resource.
2496c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
2506c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_switchTextAppearance
25112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
252150176d83023e3c486dba10edebb72af36b4099aChet Haase    public void setSwitchTextAppearance(Context context, int resid) {
25312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        TypedArray appearance =
254150176d83023e3c486dba10edebb72af36b4099aChet Haase                context.obtainStyledAttributes(resid,
25512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        com.android.internal.R.styleable.TextAppearance);
25612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
25712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        ColorStateList colors;
25812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int ts;
25912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
26012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        colors = appearance.getColorStateList(com.android.internal.R.styleable.
26112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                TextAppearance_textColor);
26212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (colors != null) {
26312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mTextColors = colors;
264150176d83023e3c486dba10edebb72af36b4099aChet Haase        } else {
265150176d83023e3c486dba10edebb72af36b4099aChet Haase            // If no color set in TextAppearance, default to the view's textColor
266150176d83023e3c486dba10edebb72af36b4099aChet Haase            mTextColors = getTextColors();
26712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
26812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
26912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        ts = appearance.getDimensionPixelSize(com.android.internal.R.styleable.
27012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                TextAppearance_textSize, 0);
27112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (ts != 0) {
27212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            if (ts != mTextPaint.getTextSize()) {
27312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                mTextPaint.setTextSize(ts);
27412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                requestLayout();
27512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
27612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
27712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
27812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int typefaceIndex, styleIndex;
27912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
28012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        typefaceIndex = appearance.getInt(com.android.internal.R.styleable.
28112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                TextAppearance_typeface, -1);
28212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        styleIndex = appearance.getInt(com.android.internal.R.styleable.
28312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                TextAppearance_textStyle, -1);
28412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
28512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        setSwitchTypefaceByIndex(typefaceIndex, styleIndex);
28612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
2874c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler        boolean allCaps = appearance.getBoolean(com.android.internal.R.styleable.
2884c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler                TextAppearance_textAllCaps, false);
2894c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler        if (allCaps) {
2904c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler            mSwitchTransformationMethod = new AllCapsTransformationMethod(getContext());
2914c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler            mSwitchTransformationMethod.setLengthChangesAllowed(true);
2924c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler        } else {
2934c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler            mSwitchTransformationMethod = null;
2944c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler        }
2954c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler
29612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        appearance.recycle();
29712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
29812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
29912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private void setSwitchTypefaceByIndex(int typefaceIndex, int styleIndex) {
30012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        Typeface tf = null;
30112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        switch (typefaceIndex) {
30212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case SANS:
30312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                tf = Typeface.SANS_SERIF;
30412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
30512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
30612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case SERIF:
30712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                tf = Typeface.SERIF;
30812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
30912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
31012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MONOSPACE:
31112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                tf = Typeface.MONOSPACE;
31212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
31312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
31412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
31512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        setSwitchTypeface(tf, styleIndex);
31612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
31712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
31812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
31912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Sets the typeface and style in which the text should be displayed on the
32012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * switch, and turns on the fake bold and italic bits in the Paint if the
32112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Typeface that you provided does not have all the bits in the
32212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * style that you specified.
32312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
32412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void setSwitchTypeface(Typeface tf, int style) {
32512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (style > 0) {
32612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            if (tf == null) {
32712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                tf = Typeface.defaultFromStyle(style);
32812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            } else {
32912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                tf = Typeface.create(tf, style);
33012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
33112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
33212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            setSwitchTypeface(tf);
33312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            // now compute what (if any) algorithmic styling is needed
33412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            int typefaceStyle = tf != null ? tf.getStyle() : 0;
33512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            int need = style & ~typefaceStyle;
33612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mTextPaint.setFakeBoldText((need & Typeface.BOLD) != 0);
33712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mTextPaint.setTextSkewX((need & Typeface.ITALIC) != 0 ? -0.25f : 0);
33812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        } else {
339aa0980afab57a6aebb06e70f60e92511708fa5afVictoria Lease            mTextPaint.setFakeBoldText(false);
34012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mTextPaint.setTextSkewX(0);
34112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            setSwitchTypeface(tf);
34212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
34312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
34412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
34512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
346150176d83023e3c486dba10edebb72af36b4099aChet Haase     * Sets the typeface in which the text should be displayed on the switch.
34712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Note that not all Typeface families actually have bold and italic
34812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * variants, so you may need to use
34912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * {@link #setSwitchTypeface(Typeface, int)} to get the appearance
35012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * that you actually want.
35112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     *
35212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @attr ref android.R.styleable#TextView_typeface
35312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @attr ref android.R.styleable#TextView_textStyle
35412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
35512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void setSwitchTypeface(Typeface tf) {
35612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (mTextPaint.getTypeface() != tf) {
35712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mTextPaint.setTypeface(tf);
35812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
35912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            requestLayout();
36012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            invalidate();
36112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
36212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
36312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
36412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
3656c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Set the amount of horizontal padding between the switch and the associated text.
3666c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3676c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @param pixels Amount of padding in pixels
3686c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3696c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_switchPadding
3706c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
3716c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public void setSwitchPadding(int pixels) {
3726c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        mSwitchPadding = pixels;
3736c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        requestLayout();
3746c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
3756c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
3766c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
3776c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Get the amount of horizontal padding between the switch and the associated text.
3786c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3796c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @return Amount of padding in pixels
3806c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3816c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_switchPadding
3826c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
3836c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public int getSwitchPadding() {
3846c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        return mSwitchPadding;
3856c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
3866c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
3876c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
3886c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Set the minimum width of the switch in pixels. The switch's width will be the maximum
3896c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * of this value and its measured width as determined by the switch drawables and text used.
3906c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3916c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @param pixels Minimum width of the switch in pixels
3926c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3936c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_switchMinWidth
3946c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
3956c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public void setSwitchMinWidth(int pixels) {
3966c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        mSwitchMinWidth = pixels;
3976c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        requestLayout();
3986c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
3996c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
4006c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
4016c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Get the minimum width of the switch in pixels. The switch's width will be the maximum
4026c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * of this value and its measured width as determined by the switch drawables and text used.
4036c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4046c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @return Minimum width of the switch in pixels
4056c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4066c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_switchMinWidth
4076c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
4086c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public int getSwitchMinWidth() {
4096c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        return mSwitchMinWidth;
4106c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
4116c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
4126c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
4136c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Set the horizontal padding around the text drawn on the switch itself.
4146c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4156c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @param pixels Horizontal padding for switch thumb text in pixels
4166c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4176c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_thumbTextPadding
4186c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
4196c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public void setThumbTextPadding(int pixels) {
4206c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        mThumbTextPadding = pixels;
4216c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        requestLayout();
4226c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
4236c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
4246c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
4256c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Get the horizontal padding around the text drawn on the switch itself.
4266c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4276c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @return Horizontal padding for switch thumb text in pixels
4286c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4296c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_thumbTextPadding
4306c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
4316c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public int getThumbTextPadding() {
4326c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        return mThumbTextPadding;
4336c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
4346c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
4356c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
4366c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Set the drawable used for the track that the switch slides within.
4376c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4386c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @param track Track drawable
4396c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4406c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_track
4416c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
4426c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public void setTrackDrawable(Drawable track) {
443b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette        if (mTrackDrawable != null) {
444b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette            mTrackDrawable.setCallback(null);
445b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette        }
4466c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        mTrackDrawable = track;
447b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette        if (track != null) {
448b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette            track.setCallback(this);
449b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette        }
4506c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        requestLayout();
4516c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
4526c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
4536c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
454d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     * Set the drawable used for the track that the switch slides within.
455d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     *
456dca510e026e3e75759bac84c3860dc84b83a608fAdam Powell     * @param resId Resource ID of a track drawable
457d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     *
458d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     * @attr ref android.R.styleable#Switch_track
459d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     */
460d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell    public void setTrackResource(int resId) {
4618eea3ea5591e59f55cbb4f6b2b7e9363a285ced3Alan Viverette        setTrackDrawable(getContext().getDrawable(resId));
462d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell    }
463d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell
464d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell    /**
4656c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Get the drawable used for the track that the switch slides within.
4666c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4676c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @return Track drawable
4686c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4696c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_track
4706c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
4716c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public Drawable getTrackDrawable() {
4726c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        return mTrackDrawable;
4736c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
4746c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
4756c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
4766c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Set the drawable used for the switch "thumb" - the piece that the user
4776c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * can physically touch and drag along the track.
4786c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4796c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @param thumb Thumb drawable
4806c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4816c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_thumb
4826c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
4836c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public void setThumbDrawable(Drawable thumb) {
484b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette        if (mThumbDrawable != null) {
485b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette            mThumbDrawable.setCallback(null);
486b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette        }
4876c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        mThumbDrawable = thumb;
488b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette        if (thumb != null) {
489b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette            thumb.setCallback(this);
490b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette        }
4916c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        requestLayout();
4926c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
4936c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
4946c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
495d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     * Set the drawable used for the switch "thumb" - the piece that the user
496d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     * can physically touch and drag along the track.
497d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     *
498dca510e026e3e75759bac84c3860dc84b83a608fAdam Powell     * @param resId Resource ID of a thumb drawable
499d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     *
500d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     * @attr ref android.R.styleable#Switch_thumb
501d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     */
502d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell    public void setThumbResource(int resId) {
5038eea3ea5591e59f55cbb4f6b2b7e9363a285ced3Alan Viverette        setThumbDrawable(getContext().getDrawable(resId));
504d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell    }
505d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell
506d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell    /**
5076c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Get the drawable used for the switch "thumb" - the piece that the user
5086c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * can physically touch and drag along the track.
5096c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
5106c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @return Thumb drawable
5116c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
5126c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_thumb
5136c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
5146c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public Drawable getThumbDrawable() {
5156c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        return mThumbDrawable;
5166c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
5176c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
5186c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
519661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     * Specifies whether the track should be split by the thumb. When true,
520661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     * the thumb's optical bounds will be clipped out of the track drawable,
521661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     * then the thumb will be drawn into the resulting gap.
522661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     *
523661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     * @param splitTrack Whether the track should be split by the thumb
524661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     *
525661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     * @attr ref android.R.styleable#Switch_splitTrack
526661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     */
527661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    public void setSplitTrack(boolean splitTrack) {
528661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        mSplitTrack = splitTrack;
529661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        invalidate();
530661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    }
531661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
532661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    /**
533661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     * Returns whether the track should be split by the thumb.
534661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     *
535661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     * @attr ref android.R.styleable#Switch_splitTrack
536661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     */
537661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    public boolean getSplitTrack() {
538661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        return mSplitTrack;
539661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    }
540661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
541661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    /**
542150176d83023e3c486dba10edebb72af36b4099aChet Haase     * Returns the text displayed when the button is in the checked state.
5436c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
5446c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_textOn
54512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
54612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public CharSequence getTextOn() {
54712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return mTextOn;
54812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
54912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
55012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
551150176d83023e3c486dba10edebb72af36b4099aChet Haase     * Sets the text displayed when the button is in the checked state.
5526c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
5536c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_textOn
55412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
55512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void setTextOn(CharSequence textOn) {
55612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextOn = textOn;
55712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        requestLayout();
55812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
55912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
56012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
561150176d83023e3c486dba10edebb72af36b4099aChet Haase     * Returns the text displayed when the button is not in the checked state.
5626c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
5636c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_textOff
56412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
56512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public CharSequence getTextOff() {
56612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return mTextOff;
56712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
56812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
56912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
570150176d83023e3c486dba10edebb72af36b4099aChet Haase     * Sets the text displayed when the button is not in the checked state.
5716c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
5726c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_textOff
57312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
57412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void setTextOff(CharSequence textOff) {
57512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextOff = textOff;
57612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        requestLayout();
57712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
57812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
5792a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette    /**
5802a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette     * Sets whether the on/off text should be displayed.
5812a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette     *
5822a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette     * @param showText {@code true} to display on/off text
5830c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     * @attr ref android.R.styleable#Switch_showText
5842a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette     */
5852a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette    public void setShowText(boolean showText) {
5862a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette        if (mShowText != showText) {
5872a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette            mShowText = showText;
5882a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette            requestLayout();
5892a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette        }
5902a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette    }
5912a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette
5922a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette    /**
5932a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette     * @return whether the on/off text should be displayed
5940c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     * @attr ref android.R.styleable#Switch_showText
5952a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette     */
5962a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette    public boolean getShowText() {
5972a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette        return mShowText;
5982a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette    }
5992a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette
60012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
60112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
6022a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette        if (mShowText) {
6032a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette            if (mOnLayout == null) {
6042a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette                mOnLayout = makeLayout(mTextOn);
6052a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette            }
6065876ff4a0ac938297bfd114da6b5d8c9dcb4cef6Alan Viverette
6072a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette            if (mOffLayout == null) {
6082a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette                mOffLayout = makeLayout(mTextOff);
6092a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette            }
61012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
61112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
6129b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette        final Rect padding = mTempRect;
6139b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette        final int thumbWidth;
6149b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette        final int thumbHeight;
6158bb399069da4e46b231333cff6880a0cf35b9417Alan Viverette        if (mThumbDrawable != null) {
6160c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            // Cached thumb width does not include padding.
6170c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            mThumbDrawable.getPadding(padding);
6180c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            thumbWidth = mThumbDrawable.getIntrinsicWidth() - padding.left - padding.right;
6199b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette            thumbHeight = mThumbDrawable.getIntrinsicHeight();
6209b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette        } else {
6219b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette            thumbWidth = 0;
6229b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette            thumbHeight = 0;
6238bb399069da4e46b231333cff6880a0cf35b9417Alan Viverette        }
6248bb399069da4e46b231333cff6880a0cf35b9417Alan Viverette
6250c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        final int maxTextWidth;
6260c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        if (mShowText) {
6270c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            maxTextWidth = Math.max(mOnLayout.getWidth(), mOffLayout.getWidth())
6280c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                    + mThumbTextPadding * 2;
6290c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        } else {
6300c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            maxTextWidth = 0;
6310c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        }
6320c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
6339b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette        mThumbWidth = Math.max(maxTextWidth, thumbWidth);
6349b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette
6350c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        final int trackHeight;
6360c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        if (mTrackDrawable != null) {
6370c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            mTrackDrawable.getPadding(padding);
6380c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            trackHeight = mTrackDrawable.getIntrinsicHeight();
6390c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        } else {
6400c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            padding.setEmpty();
6410c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            trackHeight = 0;
6420c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        }
6430c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
6440c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        // Adjust left and right padding to ensure there's enough room for the
6450c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        // thumb's padding (when present).
6460c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        int paddingLeft = padding.left;
6470c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        int paddingRight = padding.right;
6480c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        if (mThumbDrawable != null) {
6490c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            final Insets inset = mThumbDrawable.getOpticalInsets();
6500c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            paddingLeft = Math.max(paddingLeft, inset.left);
6510c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            paddingRight = Math.max(paddingRight, inset.right);
6520c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        }
6530c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
65412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int switchWidth = Math.max(mSwitchMinWidth,
6550c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                2 * mThumbWidth + paddingLeft + paddingRight);
6564d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        final int switchHeight = Math.max(trackHeight, thumbHeight);
65712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchWidth = switchWidth;
65812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchHeight = switchHeight;
65912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
66012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
6614d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette
66212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int measuredHeight = getMeasuredHeight();
66312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (measuredHeight < switchHeight) {
664189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn            setMeasuredDimension(getMeasuredWidthAndState(), switchHeight);
66512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
66612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
66712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
66863bce03cc69be4a45230aa8bbd89dbde60681067Svetoslav Ganov    @Override
66963bce03cc69be4a45230aa8bbd89dbde60681067Svetoslav Ganov    public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
67063bce03cc69be4a45230aa8bbd89dbde60681067Svetoslav Ganov        super.onPopulateAccessibilityEvent(event);
6712a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette
6722a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette        final CharSequence text = isChecked() ? mTextOn : mTextOff;
6732a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette        if (text != null) {
6742a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette            event.getText().add(text);
6757650259a597dd24137420d32acc35efc44db381eSvetoslav Ganov        }
67663bce03cc69be4a45230aa8bbd89dbde60681067Svetoslav Ganov    }
67763bce03cc69be4a45230aa8bbd89dbde60681067Svetoslav Ganov
67812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private Layout makeLayout(CharSequence text) {
6794c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler        final CharSequence transformed = (mSwitchTransformationMethod != null)
6804c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler                    ? mSwitchTransformationMethod.getTransformation(text, this)
6814c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler                    : text;
6824c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler
6834c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler        return new StaticLayout(transformed, mTextPaint,
6844c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler                (int) Math.ceil(Layout.getDesiredWidth(transformed, mTextPaint)),
68512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                Layout.Alignment.ALIGN_NORMAL, 1.f, 0, true);
68612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
68712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
68812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
68912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @return true if (x, y) is within the target area of the switch thumb
69012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
69112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private boolean hitThumb(float x, float y) {
69201a09630060eccc471ba3d8d83b34a602871d5c1Alan Viverette        if (mThumbDrawable == null) {
69301a09630060eccc471ba3d8d83b34a602871d5c1Alan Viverette            return false;
69401a09630060eccc471ba3d8d83b34a602871d5c1Alan Viverette        }
69501a09630060eccc471ba3d8d83b34a602871d5c1Alan Viverette
696cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        // Relies on mTempRect, MUST be called first!
697cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        final int thumbOffset = getThumbOffset();
698cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette
69912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mThumbDrawable.getPadding(mTempRect);
70012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int thumbTop = mSwitchTop - mTouchSlop;
701cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        final int thumbLeft = mSwitchLeft + thumbOffset - mTouchSlop;
70212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int thumbRight = thumbLeft + mThumbWidth +
70312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                mTempRect.left + mTempRect.right + mTouchSlop;
70412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int thumbBottom = mSwitchBottom + mTouchSlop;
70512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return x > thumbLeft && x < thumbRight && y > thumbTop && y < thumbBottom;
70612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
70712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
70812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
70912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public boolean onTouchEvent(MotionEvent ev) {
71012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mVelocityTracker.addMovement(ev);
71112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int action = ev.getActionMasked();
71212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        switch (action) {
71312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MotionEvent.ACTION_DOWN: {
71412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                final float x = ev.getX();
71512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                final float y = ev.getY();
716c2ab0d665c9d1c332fbd726abf582a27cf7a6701Gilles Debunne                if (isEnabled() && hitThumb(x, y)) {
71712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    mTouchMode = TOUCH_MODE_DOWN;
71812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    mTouchX = x;
71912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    mTouchY = y;
72012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                }
72112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
72212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
72312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
72412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MotionEvent.ACTION_MOVE: {
72512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switch (mTouchMode) {
72612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    case TOUCH_MODE_IDLE:
72712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        // Didn't target the thumb, treat normally.
72812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        break;
72912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
73012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    case TOUCH_MODE_DOWN: {
73112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        final float x = ev.getX();
73212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        final float y = ev.getY();
73312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        if (Math.abs(x - mTouchX) > mTouchSlop ||
73412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                                Math.abs(y - mTouchY) > mTouchSlop) {
73512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            mTouchMode = TOUCH_MODE_DRAGGING;
73612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            getParent().requestDisallowInterceptTouchEvent(true);
73712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            mTouchX = x;
73812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            mTouchY = y;
73912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            return true;
74012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        }
74112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        break;
74212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    }
74312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
74412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    case TOUCH_MODE_DRAGGING: {
74512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        final float x = ev.getX();
746cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                        final int thumbScrollRange = getThumbScrollRange();
747cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                        final float thumbScrollOffset = x - mTouchX;
748cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                        float dPos;
749cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                        if (thumbScrollRange != 0) {
750cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                            dPos = thumbScrollOffset / thumbScrollRange;
751cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                        } else {
752cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                            // If the thumb scroll range is empty, just use the
753cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                            // movement direction to snap on or off.
754cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                            dPos = thumbScrollOffset > 0 ? 1 : -1;
755cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                        }
756cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                        if (isLayoutRtl()) {
757cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                            dPos = -dPos;
758cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                        }
759cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                        final float newPos = MathUtils.constrain(mThumbPosition + dPos, 0, 1);
76012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        if (newPos != mThumbPosition) {
76112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            mTouchX = x;
762cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                            setThumbPosition(newPos);
76312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        }
76412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        return true;
76512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    }
76612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                }
76712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
76812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
76912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
77012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MotionEvent.ACTION_UP:
77112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MotionEvent.ACTION_CANCEL: {
77212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                if (mTouchMode == TOUCH_MODE_DRAGGING) {
77312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    stopDrag(ev);
774ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette                    // Allow super class to handle pressed state, etc.
775ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette                    super.onTouchEvent(ev);
77612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    return true;
77712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                }
77812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                mTouchMode = TOUCH_MODE_IDLE;
77912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                mVelocityTracker.clear();
78012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
78112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
78212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
78312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
78412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return super.onTouchEvent(ev);
78512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
78612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
78712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private void cancelSuperTouch(MotionEvent ev) {
78812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        MotionEvent cancel = MotionEvent.obtain(ev);
78912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        cancel.setAction(MotionEvent.ACTION_CANCEL);
79012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.onTouchEvent(cancel);
79112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        cancel.recycle();
79212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
79312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
79412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
79512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Called from onTouchEvent to end a drag operation.
79612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     *
79712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param ev Event that triggered the end of drag mode - ACTION_UP or ACTION_CANCEL
79812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
79912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private void stopDrag(MotionEvent ev) {
80012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTouchMode = TOUCH_MODE_IDLE;
80112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
80286453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette        // Commit the change if the event is up and not canceled and the switch
80386453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette        // has not been disabled during the drag.
80486453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette        final boolean commitChange = ev.getAction() == MotionEvent.ACTION_UP && isEnabled();
805d4e7790fee10e21b41a1c387c2734722bda56a0bAlan Viverette        final boolean oldState = isChecked();
80686453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette        final boolean newState;
80712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (commitChange) {
80812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mVelocityTracker.computeCurrentVelocity(1000);
80986453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette            final float xvel = mVelocityTracker.getXVelocity();
81012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            if (Math.abs(xvel) > mMinFlingVelocity) {
81128efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio                newState = isLayoutRtl() ? (xvel < 0) : (xvel > 0);
81212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            } else {
81312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                newState = getTargetCheckedState();
81412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
81512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        } else {
816d4e7790fee10e21b41a1c387c2734722bda56a0bAlan Viverette            newState = oldState;
817d4e7790fee10e21b41a1c387c2734722bda56a0bAlan Viverette        }
818d4e7790fee10e21b41a1c387c2734722bda56a0bAlan Viverette
819d4e7790fee10e21b41a1c387c2734722bda56a0bAlan Viverette        if (newState != oldState) {
820d4e7790fee10e21b41a1c387c2734722bda56a0bAlan Viverette            playSoundEffect(SoundEffectConstants.CLICK);
821d4e7790fee10e21b41a1c387c2734722bda56a0bAlan Viverette            setChecked(newState);
82212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
82386453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette
82486453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette        cancelSuperTouch(ev);
82512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
82612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
82712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private void animateThumbToCheckedState(boolean newCheckedState) {
828cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        final float targetPosition = newCheckedState ? 1 : 0;
829cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        mPositionAnimator = ObjectAnimator.ofFloat(this, THUMB_POS, targetPosition);
830cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        mPositionAnimator.setDuration(THUMB_ANIMATION_DURATION);
831cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        mPositionAnimator.setAutoCancel(true);
832cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        mPositionAnimator.start();
83312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
83412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
835cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    private void cancelPositionAnimator() {
836cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        if (mPositionAnimator != null) {
837cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette            mPositionAnimator.cancel();
83828efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        }
83928efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio    }
84028efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio
841cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    private boolean getTargetCheckedState() {
842cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        return mThumbPosition > 0.5f;
843cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    }
844cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette
845cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    /**
846cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette     * Sets the thumb position as a decimal value between 0 (off) and 1 (on).
847cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette     *
848cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette     * @param position new position between [0,1]
849cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette     */
850cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    private void setThumbPosition(float position) {
851cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        mThumbPosition = position;
852cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        invalidate();
853cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    }
854cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette
855cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    @Override
856cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    public void toggle() {
85786453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette        setChecked(!isChecked());
85812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
85912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
86012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
86112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void setChecked(boolean checked) {
86212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.setChecked(checked);
863cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette
864467d629ca714cd74658043c1ddfec36c60d898c1Alan Viverette        // Calling the super method may result in setChecked() getting called
865467d629ca714cd74658043c1ddfec36c60d898c1Alan Viverette        // recursively with a different value, so load the REAL value...
866467d629ca714cd74658043c1ddfec36c60d898c1Alan Viverette        checked = isChecked();
867467d629ca714cd74658043c1ddfec36c60d898c1Alan Viverette
86886453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette        if (isAttachedToWindow() && isLaidOut()) {
86986453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette            animateThumbToCheckedState(checked);
87086453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette        } else {
87186453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette            // Immediately move the thumb to the new position.
87286453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette            cancelPositionAnimator();
87386453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette            setThumbPosition(checked ? 1 : 0);
87486453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette        }
87512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
87612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
87712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
87812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
87912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.onLayout(changed, left, top, right, bottom);
88012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
8810c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        int opticalInsetLeft = 0;
8820c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        int opticalInsetRight = 0;
8830c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        if (mThumbDrawable != null) {
8840c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            final Rect trackPadding = mTempRect;
8850c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            if (mTrackDrawable != null) {
8860c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                mTrackDrawable.getPadding(trackPadding);
8870c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            } else {
8880c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                trackPadding.setEmpty();
8890c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            }
8900c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
8910c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            final Insets insets = mThumbDrawable.getOpticalInsets();
8920c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            opticalInsetLeft = Math.max(0, insets.left - trackPadding.left);
8930c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            opticalInsetRight = Math.max(0, insets.right - trackPadding.right);
8940c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        }
89528efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio
8960c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        final int switchRight;
8970c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        final int switchLeft;
89828efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        if (isLayoutRtl()) {
8990c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            switchLeft = getPaddingLeft() + opticalInsetLeft;
9000c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            switchRight = switchLeft + mSwitchWidth - opticalInsetLeft - opticalInsetRight;
90128efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        } else {
9020c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            switchRight = getWidth() - getPaddingRight() - opticalInsetRight;
9030c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            switchLeft = switchRight - mSwitchWidth + opticalInsetLeft + opticalInsetRight;
90428efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        }
905c3eabb9b6ce7f556313c8e3870d76c5b443f1c51Joe Onorato
9060c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        final int switchTop;
9070c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        final int switchBottom;
90812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        switch (getGravity() & Gravity.VERTICAL_GRAVITY_MASK) {
90912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            default:
91012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case Gravity.TOP:
91112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchTop = getPaddingTop();
91212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchBottom = switchTop + mSwitchHeight;
91312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
91412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
91512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case Gravity.CENTER_VERTICAL:
91612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchTop = (getPaddingTop() + getHeight() - getPaddingBottom()) / 2 -
91712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        mSwitchHeight / 2;
91812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchBottom = switchTop + mSwitchHeight;
91912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
92012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
92112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case Gravity.BOTTOM:
92212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchBottom = getHeight() - getPaddingBottom();
92312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchTop = switchBottom - mSwitchHeight;
92412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
92512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
92612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
92712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchLeft = switchLeft;
92812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchTop = switchTop;
92912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchBottom = switchBottom;
93012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchRight = switchRight;
93112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
93212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
93312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
934ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    public void draw(Canvas c) {
9354d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        final Rect padding = mTempRect;
9365876ff4a0ac938297bfd114da6b5d8c9dcb4cef6Alan Viverette        final int switchLeft = mSwitchLeft;
9375876ff4a0ac938297bfd114da6b5d8c9dcb4cef6Alan Viverette        final int switchTop = mSwitchTop;
9385876ff4a0ac938297bfd114da6b5d8c9dcb4cef6Alan Viverette        final int switchRight = mSwitchRight;
9395876ff4a0ac938297bfd114da6b5d8c9dcb4cef6Alan Viverette        final int switchBottom = mSwitchBottom;
9400c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
9410c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        int thumbInitialLeft = switchLeft + getThumbOffset();
9420c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
9430c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        final Insets thumbInsets;
9440c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        if (mThumbDrawable != null) {
9450c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            thumbInsets = mThumbDrawable.getOpticalInsets();
9460c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        } else {
9470c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            thumbInsets = Insets.NONE;
9488bb399069da4e46b231333cff6880a0cf35b9417Alan Viverette        }
949cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette
9500c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        // Layout the track.
9510c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        if (mTrackDrawable != null) {
9520c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            mTrackDrawable.getPadding(padding);
9539b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette
9540c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            // Adjust thumb position for track padding.
9550c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            thumbInitialLeft += padding.left;
9560c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
9570c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            // If necessary, offset by the optical insets of the thumb asset.
9580c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            int trackLeft = switchLeft;
9590c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            int trackTop = switchTop;
9600c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            int trackRight = switchRight;
9610c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            int trackBottom = switchBottom;
9620c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            if (thumbInsets != Insets.NONE) {
9630c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                if (thumbInsets.left > padding.left) {
9640c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                    trackLeft += thumbInsets.left - padding.left;
9650c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                }
9660c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                if (thumbInsets.top > padding.top) {
9670c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                    trackTop += thumbInsets.top - padding.top;
9680c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                }
9690c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                if (thumbInsets.right > padding.right) {
9700c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                    trackRight -= thumbInsets.right - padding.right;
9710c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                }
9720c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                if (thumbInsets.bottom > padding.bottom) {
9730c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                    trackBottom -= thumbInsets.bottom - padding.bottom;
9740c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                }
9750c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            }
9760c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            mTrackDrawable.setBounds(trackLeft, trackTop, trackRight, trackBottom);
9770c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        }
9789b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette
979661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        // Layout the thumb.
9804d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        if (mThumbDrawable != null) {
9814d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            mThumbDrawable.getPadding(padding);
9820c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
9830c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            final int thumbLeft = thumbInitialLeft - padding.left;
9840c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            final int thumbRight = thumbInitialLeft + mThumbWidth + padding.right;
9854d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            mThumbDrawable.setBounds(thumbLeft, switchTop, thumbRight, switchBottom);
9864d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette
9874d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            final Drawable background = getBackground();
9884d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            if (background != null) {
9894d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                background.setHotspotBounds(thumbLeft, switchTop, thumbRight, switchBottom);
9904d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            }
99161956606818918194a38e045a8e35e7108480e5eAlan Viverette        }
99261956606818918194a38e045a8e35e7108480e5eAlan Viverette
993ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette        // Draw the background.
994ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette        super.draw(c);
995ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    }
996ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette
997ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    @Override
998ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    protected void onDraw(Canvas canvas) {
99961956606818918194a38e045a8e35e7108480e5eAlan Viverette        super.onDraw(canvas);
100061956606818918194a38e045a8e35e7108480e5eAlan Viverette
10014d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        final Rect padding = mTempRect;
1002ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette        final Drawable trackDrawable = mTrackDrawable;
10034d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        if (trackDrawable != null) {
10044d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            trackDrawable.getPadding(padding);
10054d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        } else {
10064d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            padding.setEmpty();
10074d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        }
1008ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette
1009ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette        final int switchTop = mSwitchTop;
1010ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette        final int switchBottom = mSwitchBottom;
10114d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        final int switchInnerTop = switchTop + padding.top;
10124d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        final int switchInnerBottom = switchBottom - padding.bottom;
10134d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette
10144d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        final Drawable thumbDrawable = mThumbDrawable;
10154d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        if (trackDrawable != null) {
10164d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            if (mSplitTrack && thumbDrawable != null) {
10174d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                final Insets insets = thumbDrawable.getOpticalInsets();
10184d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                thumbDrawable.copyBounds(padding);
10194d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                padding.left += insets.left;
10204d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                padding.right -= insets.right;
10214d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette
10224d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                final int saveCount = canvas.save();
10234d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                canvas.clipRect(padding, Op.DIFFERENCE);
10244d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                trackDrawable.draw(canvas);
10254d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                canvas.restoreToCount(saveCount);
10264d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            } else {
10274d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                trackDrawable.draw(canvas);
10284d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            }
1029661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        }
103061956606818918194a38e045a8e35e7108480e5eAlan Viverette
103161956606818918194a38e045a8e35e7108480e5eAlan Viverette        final int saveCount = canvas.save();
10324d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette
10334d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        if (thumbDrawable != null) {
10344d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            thumbDrawable.draw(canvas);
10354d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        }
103612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
10375876ff4a0ac938297bfd114da6b5d8c9dcb4cef6Alan Viverette        final Layout switchText = getTargetCheckedState() ? mOnLayout : mOffLayout;
1038be06e3292b295324b3b47d13f9a40787b666309fFabrice Di Meglio        if (switchText != null) {
1039661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            final int drawableState[] = getDrawableState();
1040661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            if (mTextColors != null) {
1041661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette                mTextPaint.setColor(mTextColors.getColorForState(drawableState, 0));
1042661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            }
1043661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            mTextPaint.drawableState = drawableState;
1044661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
10454d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            final int cX;
10464d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            if (thumbDrawable != null) {
10474d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                final Rect bounds = thumbDrawable.getBounds();
10484d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                cX = bounds.left + bounds.right;
10494d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            } else {
1050dec17299fef93f673d8e8cab0ec0f734bf6b8539Alan Viverette                cX = getWidth();
10514d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            }
10524d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette
10534d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            final int left = cX / 2 - switchText.getWidth() / 2;
10545876ff4a0ac938297bfd114da6b5d8c9dcb4cef6Alan Viverette            final int top = (switchInnerTop + switchInnerBottom) / 2 - switchText.getHeight() / 2;
10555876ff4a0ac938297bfd114da6b5d8c9dcb4cef6Alan Viverette            canvas.translate(left, top);
1056be06e3292b295324b3b47d13f9a40787b666309fFabrice Di Meglio            switchText.draw(canvas);
1057be06e3292b295324b3b47d13f9a40787b666309fFabrice Di Meglio        }
105812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
10595876ff4a0ac938297bfd114da6b5d8c9dcb4cef6Alan Viverette        canvas.restoreToCount(saveCount);
106012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
106112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
106212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
106328efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio    public int getCompoundPaddingLeft() {
106428efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        if (!isLayoutRtl()) {
106528efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio            return super.getCompoundPaddingLeft();
106628efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        }
106728efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        int padding = super.getCompoundPaddingLeft() + mSwitchWidth;
106828efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        if (!TextUtils.isEmpty(getText())) {
106928efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio            padding += mSwitchPadding;
107028efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        }
107128efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        return padding;
107228efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio    }
107328efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio
107428efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio    @Override
107512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public int getCompoundPaddingRight() {
107628efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        if (isLayoutRtl()) {
107728efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio            return super.getCompoundPaddingRight();
107828efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        }
107912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int padding = super.getCompoundPaddingRight() + mSwitchWidth;
108012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (!TextUtils.isEmpty(getText())) {
108112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            padding += mSwitchPadding;
108212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
108312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return padding;
108412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
108512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
1086cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    /**
1087cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette     * Translates thumb position to offset according to current RTL setting and
10880c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     * thumb scroll range. Accounts for both track and thumb padding.
1089cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette     *
1090cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette     * @return thumb offset
1091cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette     */
1092cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    private int getThumbOffset() {
1093cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        final float thumbPosition;
1094cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        if (isLayoutRtl()) {
1095cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette            thumbPosition = 1 - mThumbPosition;
1096cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        } else {
1097cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette            thumbPosition = mThumbPosition;
1098cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        }
1099cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        return (int) (thumbPosition * getThumbScrollRange() + 0.5f);
1100cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    }
1101cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette
110212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int getThumbScrollRange() {
11034d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        if (mTrackDrawable != null) {
11040c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            final Rect padding = mTempRect;
11050c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            mTrackDrawable.getPadding(padding);
11060c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
11070c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            final Insets insets;
11080c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            if (mThumbDrawable != null) {
11090c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                insets = mThumbDrawable.getOpticalInsets();
11100c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            } else {
11110c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                insets = Insets.NONE;
11120c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            }
11130c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
11140c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            return mSwitchWidth - mThumbWidth - padding.left - padding.right
11150c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                    - insets.left - insets.right;
11164d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        } else {
111712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            return 0;
111812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
111912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
112012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
112112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
112212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    protected int[] onCreateDrawableState(int extraSpace) {
112312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
112412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (isChecked()) {
112512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mergeDrawableStates(drawableState, CHECKED_STATE_SET);
112612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
112712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return drawableState;
112812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
112912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
113012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
113112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    protected void drawableStateChanged() {
113212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.drawableStateChanged();
113312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
1134661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        final int[] myDrawableState = getDrawableState();
1135661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
11362356c5e69b0911e6334ebf6374217898371be5acAlan Viverette        if (mThumbDrawable != null) {
11372356c5e69b0911e6334ebf6374217898371be5acAlan Viverette            mThumbDrawable.setState(myDrawableState);
1138661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        }
113912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
1140661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        if (mTrackDrawable != null) {
1141661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            mTrackDrawable.setState(myDrawableState);
1142661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        }
114312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
114412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        invalidate();
114512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
114612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
1147cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette    @Override
11488de1494557cf1d00c1c3fce439138a28de7fbd61Alan Viverette    public void drawableHotspotChanged(float x, float y) {
11498de1494557cf1d00c1c3fce439138a28de7fbd61Alan Viverette        super.drawableHotspotChanged(x, y);
1150cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette
1151cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette        if (mThumbDrawable != null) {
1152cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette            mThumbDrawable.setHotspot(x, y);
1153cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette        }
1154cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette
1155cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette        if (mTrackDrawable != null) {
1156cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette            mTrackDrawable.setHotspot(x, y);
1157cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette        }
1158cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette    }
1159cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette
116012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
116112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    protected boolean verifyDrawable(Drawable who) {
116212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return super.verifyDrawable(who) || who == mThumbDrawable || who == mTrackDrawable;
116312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
116412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
116512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
116612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void jumpDrawablesToCurrentState() {
116712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.jumpDrawablesToCurrentState();
11684d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette
11694d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        if (mThumbDrawable != null) {
11704d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            mThumbDrawable.jumpToCurrentState();
11714d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        }
11724d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette
11734d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        if (mTrackDrawable != null) {
11744d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            mTrackDrawable.jumpToCurrentState();
11754d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        }
11764d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette
11774d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        if (mPositionAnimator != null && mPositionAnimator.isRunning()) {
11784d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            mPositionAnimator.end();
11794d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            mPositionAnimator = null;
11804d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        }
118112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
11828a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov
11838a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    @Override
11848a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
11858a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        super.onInitializeAccessibilityEvent(event);
11868a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        event.setClassName(Switch.class.getName());
11878a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    }
11888a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov
11898a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    @Override
11908a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
11918a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        super.onInitializeAccessibilityNodeInfo(info);
11928a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        info.setClassName(Switch.class.getName());
119378bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov        CharSequence switchText = isChecked() ? mTextOn : mTextOff;
119478bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov        if (!TextUtils.isEmpty(switchText)) {
119578bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov            CharSequence oldText = info.getText();
119678bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov            if (TextUtils.isEmpty(oldText)) {
119778bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov                info.setText(switchText);
119878bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov            } else {
119978bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov                StringBuilder newText = new StringBuilder();
120078bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov                newText.append(oldText).append(' ').append(switchText);
120178bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov                info.setText(newText);
120278bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov            }
120378bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov        }
12048a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    }
1205cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette
1206cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    private static final FloatProperty<Switch> THUMB_POS = new FloatProperty<Switch>("thumbPos") {
1207cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        @Override
1208cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        public Float get(Switch object) {
1209cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette            return object.mThumbPosition;
1210cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        }
1211cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette
1212cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        @Override
1213cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        public void setValue(Switch object, float value) {
1214cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette            object.setThumbPosition(value);
1215cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        }
1216cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    };
121712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell}
1218