Switch.java revision b067405bf453289a6b6bfd34b06700f08be58c24
112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell/*
212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell * Copyright (C) 2010 The Android Open Source Project
312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell *
412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell * Licensed under the Apache License, Version 2.0 (the "License");
512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell * you may not use this file except in compliance with the License.
612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell * You may obtain a copy of the License at
712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell *
812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell *      http://www.apache.org/licenses/LICENSE-2.0
912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell *
1012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell * Unless required by applicable law or agreed to in writing, software
1112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell * distributed under the License is distributed on an "AS IS" BASIS,
1212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell * See the License for the specific language governing permissions and
1412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell * limitations under the License.
1512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell */
1612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
1712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellpackage android.widget;
1812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
19cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viveretteimport android.animation.ObjectAnimator;
2012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.content.Context;
2112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.content.res.ColorStateList;
2212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.content.res.Resources;
2312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.content.res.TypedArray;
2412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.graphics.Canvas;
25661e63658da39cccfe49a129e4860455716ff3c9Alan Viveretteimport android.graphics.Insets;
2612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.graphics.Paint;
2712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.graphics.Rect;
2812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.graphics.Typeface;
29661e63658da39cccfe49a129e4860455716ff3c9Alan Viveretteimport android.graphics.Region.Op;
3012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.graphics.drawable.Drawable;
3112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.text.Layout;
3212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.text.StaticLayout;
3312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.text.TextPaint;
3412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.text.TextUtils;
354c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandlerimport android.text.method.AllCapsTransformationMethod;
364c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandlerimport android.text.method.TransformationMethod2;
3712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.util.AttributeSet;
38cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viveretteimport android.util.FloatProperty;
39cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viveretteimport android.util.MathUtils;
4012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.view.Gravity;
4112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.view.MotionEvent;
4212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.view.VelocityTracker;
4312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.view.ViewConfiguration;
4463bce03cc69be4a45230aa8bbd89dbde60681067Svetoslav Ganovimport android.view.accessibility.AccessibilityEvent;
458a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganovimport android.view.accessibility.AccessibilityNodeInfo;
4612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
47be0a4535053bbfdebd215e244b154ac810fd8edcAdam Powellimport com.android.internal.R;
48be0a4535053bbfdebd215e244b154ac810fd8edcAdam Powell
4912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell/**
5012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell * A Switch is a two-state toggle switch widget that can select between two
5112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell * options. The user may drag the "thumb" back and forth to choose the selected option,
52150176d83023e3c486dba10edebb72af36b4099aChet Haase * or simply tap to toggle as if it were a checkbox. The {@link #setText(CharSequence) text}
53150176d83023e3c486dba10edebb72af36b4099aChet Haase * property controls the text displayed in the label for the switch, whereas the
54150176d83023e3c486dba10edebb72af36b4099aChet Haase * {@link #setTextOff(CharSequence) off} and {@link #setTextOn(CharSequence) on} text
55150176d83023e3c486dba10edebb72af36b4099aChet Haase * controls the text on the thumb. Similarly, the
56150176d83023e3c486dba10edebb72af36b4099aChet Haase * {@link #setTextAppearance(android.content.Context, int) textAppearance} and the related
57150176d83023e3c486dba10edebb72af36b4099aChet Haase * setTypeface() methods control the typeface and style of label text, whereas the
58150176d83023e3c486dba10edebb72af36b4099aChet Haase * {@link #setSwitchTextAppearance(android.content.Context, int) switchTextAppearance} and
59150176d83023e3c486dba10edebb72af36b4099aChet Haase * the related seSwitchTypeface() methods control that of the thumb.
6012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell *
614c359b76f9a030f92a302ba74a528faa170bad4eScott Main * <p>See the <a href="{@docRoot}guide/topics/ui/controls/togglebutton.html">Toggle Buttons</a>
624c359b76f9a030f92a302ba74a528faa170bad4eScott Main * guide.</p>
634c359b76f9a030f92a302ba74a528faa170bad4eScott Main *
644c359b76f9a030f92a302ba74a528faa170bad4eScott Main * @attr ref android.R.styleable#Switch_textOn
654c359b76f9a030f92a302ba74a528faa170bad4eScott Main * @attr ref android.R.styleable#Switch_textOff
664c359b76f9a030f92a302ba74a528faa170bad4eScott Main * @attr ref android.R.styleable#Switch_switchMinWidth
674c359b76f9a030f92a302ba74a528faa170bad4eScott Main * @attr ref android.R.styleable#Switch_switchPadding
684c359b76f9a030f92a302ba74a528faa170bad4eScott Main * @attr ref android.R.styleable#Switch_switchTextAppearance
694c359b76f9a030f92a302ba74a528faa170bad4eScott Main * @attr ref android.R.styleable#Switch_thumb
704c359b76f9a030f92a302ba74a528faa170bad4eScott Main * @attr ref android.R.styleable#Switch_thumbTextPadding
714c359b76f9a030f92a302ba74a528faa170bad4eScott Main * @attr ref android.R.styleable#Switch_track
7212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell */
7312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellpublic class Switch extends CompoundButton {
74cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    private static final int THUMB_ANIMATION_DURATION = 250;
75cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette
7612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int TOUCH_MODE_IDLE = 0;
7712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int TOUCH_MODE_DOWN = 1;
7812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int TOUCH_MODE_DRAGGING = 2;
7912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
8012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    // Enum for the "typeface" XML parameter.
8112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int SANS = 1;
8212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int SERIF = 2;
8312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int MONOSPACE = 3;
8412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
8512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private Drawable mThumbDrawable;
8612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private Drawable mTrackDrawable;
8712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mThumbTextPadding;
8812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchMinWidth;
8912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchPadding;
90661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    private boolean mSplitTrack;
9112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private CharSequence mTextOn;
9212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private CharSequence mTextOff;
932a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette    private boolean mShowText;
9412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
9512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mTouchMode;
9612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mTouchSlop;
9712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private float mTouchX;
9812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private float mTouchY;
9912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private VelocityTracker mVelocityTracker = VelocityTracker.obtain();
10012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mMinFlingVelocity;
10112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
10212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private float mThumbPosition;
1030c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
1040c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette    /**
1050c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     * Width required to draw the switch track and thumb. Includes padding and
1060c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     * optical bounds for both the track and thumb.
1070c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     */
10812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchWidth;
1090c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
1100c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette    /**
1110c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     * Height required to draw the switch track and thumb. Includes padding and
1120c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     * optical bounds for both the track and thumb.
1130c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     */
11412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchHeight;
11512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
1160c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette    /**
1170c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     * Width of the thumb's content region. Does not include padding or
1180c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     * optical bounds.
1190c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     */
1200c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette    private int mThumbWidth;
1210c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
1220c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette    /** Left bound for drawing the switch track and thumb. */
12312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchLeft;
1240c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
1250c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette    /** Top bound for drawing the switch track and thumb. */
12612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchTop;
1270c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
1280c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette    /** Right bound for drawing the switch track and thumb. */
12912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchRight;
1300c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
1310c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette    /** Bottom bound for drawing the switch track and thumb. */
13212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchBottom;
13312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
13412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private TextPaint mTextPaint;
13512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private ColorStateList mTextColors;
13612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private Layout mOnLayout;
13712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private Layout mOffLayout;
1384c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler    private TransformationMethod2 mSwitchTransformationMethod;
139cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    private ObjectAnimator mPositionAnimator;
14012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
141be0a4535053bbfdebd215e244b154ac810fd8edcAdam Powell    @SuppressWarnings("hiding")
14212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private final Rect mTempRect = new Rect();
14312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
14412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int[] CHECKED_STATE_SET = {
14512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        R.attr.state_checked
14612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    };
14712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
14812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
14912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Construct a new Switch with default styling.
15012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     *
15112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param context The Context that will determine this widget's theming.
15212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
15312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public Switch(Context context) {
15412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        this(context, null);
15512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
15612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
15712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
15812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Construct a new Switch with default styling, overriding specific style
15912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * attributes as requested.
16012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     *
16112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param context The Context that will determine this widget's theming.
16212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param attrs Specification of attributes that should deviate from default styling.
16312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
16412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public Switch(Context context, AttributeSet attrs) {
16512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        this(context, attrs, com.android.internal.R.attr.switchStyle);
16612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
16712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
16812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
16912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Construct a new Switch with a default style determined by the given theme attribute,
17012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * overriding specific style attributes as requested.
17112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     *
17212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param context The Context that will determine this widget's theming.
17312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param attrs Specification of attributes that should deviate from the default styling.
174617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     * @param defStyleAttr An attribute in the current theme that contains a
175617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        reference to a style resource that supplies default values for
176617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        the view. Can be 0 to not look for defaults.
17712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
178617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    public Switch(Context context, AttributeSet attrs, int defStyleAttr) {
179617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette        this(context, attrs, defStyleAttr, 0);
180617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    }
181617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette
182617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette
183617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    /**
184617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     * Construct a new Switch with a default style determined by the given theme
185617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     * attribute or style resource, overriding specific style attributes as
186617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     * requested.
187617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *
188617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     * @param context The Context that will determine this widget's theming.
189617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     * @param attrs Specification of attributes that should deviate from the
190617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        default styling.
191617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     * @param defStyleAttr An attribute in the current theme that contains a
192617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        reference to a style resource that supplies default values for
193617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        the view. Can be 0 to not look for defaults.
194617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     * @param defStyleRes A resource identifier of a style resource that
195617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        supplies default values for the view, used only if
196617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        defStyleAttr is 0 or can not be found in the theme. Can be 0
197617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        to not look for defaults.
198617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     */
199617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    public Switch(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
200617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette        super(context, attrs, defStyleAttr, defStyleRes);
20112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
20212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
203661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
204661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        final Resources res = getResources();
20512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextPaint.density = res.getDisplayMetrics().density;
20612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextPaint.setCompatibilityScaling(res.getCompatibilityInfo().applicationScale);
20712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
208617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette        final TypedArray a = context.obtainStyledAttributes(
209617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette                attrs, com.android.internal.R.styleable.Switch, defStyleAttr, defStyleRes);
210150176d83023e3c486dba10edebb72af36b4099aChet Haase        mThumbDrawable = a.getDrawable(com.android.internal.R.styleable.Switch_thumb);
211b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette        if (mThumbDrawable != null) {
212b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette            mThumbDrawable.setCallback(this);
213b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette        }
214150176d83023e3c486dba10edebb72af36b4099aChet Haase        mTrackDrawable = a.getDrawable(com.android.internal.R.styleable.Switch_track);
215b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette        if (mTrackDrawable != null) {
216b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette            mTrackDrawable.setCallback(this);
217b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette        }
21812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextOn = a.getText(com.android.internal.R.styleable.Switch_textOn);
21912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextOff = a.getText(com.android.internal.R.styleable.Switch_textOff);
2202a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette        mShowText = a.getBoolean(com.android.internal.R.styleable.Switch_showText, true);
22112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mThumbTextPadding = a.getDimensionPixelSize(
22212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                com.android.internal.R.styleable.Switch_thumbTextPadding, 0);
22312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchMinWidth = a.getDimensionPixelSize(
22412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                com.android.internal.R.styleable.Switch_switchMinWidth, 0);
22512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchPadding = a.getDimensionPixelSize(
22612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                com.android.internal.R.styleable.Switch_switchPadding, 0);
227661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        mSplitTrack = a.getBoolean(com.android.internal.R.styleable.Switch_splitTrack, false);
22812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
229661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        final int appearance = a.getResourceId(
23012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                com.android.internal.R.styleable.Switch_switchTextAppearance, 0);
23112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (appearance != 0) {
232150176d83023e3c486dba10edebb72af36b4099aChet Haase            setSwitchTextAppearance(context, appearance);
23312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
23412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        a.recycle();
23512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
236661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        final ViewConfiguration config = ViewConfiguration.get(context);
23712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTouchSlop = config.getScaledTouchSlop();
23812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mMinFlingVelocity = config.getScaledMinimumFlingVelocity();
23912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
24012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        // Refresh display with current params
241e724ee4b04d121556e9764f72f9b921a0e16392aGilles Debunne        refreshDrawableState();
24212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        setChecked(isChecked());
24312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
24412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
24512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
24612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Sets the switch text color, size, style, hint color, and highlight color
24712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * from the specified TextAppearance resource.
2486c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
2496c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_switchTextAppearance
25012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
251150176d83023e3c486dba10edebb72af36b4099aChet Haase    public void setSwitchTextAppearance(Context context, int resid) {
25212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        TypedArray appearance =
253150176d83023e3c486dba10edebb72af36b4099aChet Haase                context.obtainStyledAttributes(resid,
25412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        com.android.internal.R.styleable.TextAppearance);
25512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
25612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        ColorStateList colors;
25712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int ts;
25812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
25912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        colors = appearance.getColorStateList(com.android.internal.R.styleable.
26012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                TextAppearance_textColor);
26112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (colors != null) {
26212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mTextColors = colors;
263150176d83023e3c486dba10edebb72af36b4099aChet Haase        } else {
264150176d83023e3c486dba10edebb72af36b4099aChet Haase            // If no color set in TextAppearance, default to the view's textColor
265150176d83023e3c486dba10edebb72af36b4099aChet Haase            mTextColors = getTextColors();
26612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
26712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
26812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        ts = appearance.getDimensionPixelSize(com.android.internal.R.styleable.
26912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                TextAppearance_textSize, 0);
27012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (ts != 0) {
27112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            if (ts != mTextPaint.getTextSize()) {
27212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                mTextPaint.setTextSize(ts);
27312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                requestLayout();
27412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
27512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
27612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
27712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int typefaceIndex, styleIndex;
27812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
27912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        typefaceIndex = appearance.getInt(com.android.internal.R.styleable.
28012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                TextAppearance_typeface, -1);
28112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        styleIndex = appearance.getInt(com.android.internal.R.styleable.
28212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                TextAppearance_textStyle, -1);
28312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
28412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        setSwitchTypefaceByIndex(typefaceIndex, styleIndex);
28512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
2864c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler        boolean allCaps = appearance.getBoolean(com.android.internal.R.styleable.
2874c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler                TextAppearance_textAllCaps, false);
2884c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler        if (allCaps) {
2894c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler            mSwitchTransformationMethod = new AllCapsTransformationMethod(getContext());
2904c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler            mSwitchTransformationMethod.setLengthChangesAllowed(true);
2914c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler        } else {
2924c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler            mSwitchTransformationMethod = null;
2934c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler        }
2944c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler
29512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        appearance.recycle();
29612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
29712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
29812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private void setSwitchTypefaceByIndex(int typefaceIndex, int styleIndex) {
29912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        Typeface tf = null;
30012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        switch (typefaceIndex) {
30112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case SANS:
30212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                tf = Typeface.SANS_SERIF;
30312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
30412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
30512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case SERIF:
30612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                tf = Typeface.SERIF;
30712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
30812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
30912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MONOSPACE:
31012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                tf = Typeface.MONOSPACE;
31112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
31212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
31312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
31412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        setSwitchTypeface(tf, styleIndex);
31512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
31612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
31712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
31812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Sets the typeface and style in which the text should be displayed on the
31912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * switch, and turns on the fake bold and italic bits in the Paint if the
32012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Typeface that you provided does not have all the bits in the
32112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * style that you specified.
32212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
32312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void setSwitchTypeface(Typeface tf, int style) {
32412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (style > 0) {
32512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            if (tf == null) {
32612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                tf = Typeface.defaultFromStyle(style);
32712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            } else {
32812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                tf = Typeface.create(tf, style);
32912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
33012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
33112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            setSwitchTypeface(tf);
33212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            // now compute what (if any) algorithmic styling is needed
33312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            int typefaceStyle = tf != null ? tf.getStyle() : 0;
33412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            int need = style & ~typefaceStyle;
33512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mTextPaint.setFakeBoldText((need & Typeface.BOLD) != 0);
33612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mTextPaint.setTextSkewX((need & Typeface.ITALIC) != 0 ? -0.25f : 0);
33712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        } else {
338aa0980afab57a6aebb06e70f60e92511708fa5afVictoria Lease            mTextPaint.setFakeBoldText(false);
33912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mTextPaint.setTextSkewX(0);
34012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            setSwitchTypeface(tf);
34112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
34212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
34312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
34412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
345150176d83023e3c486dba10edebb72af36b4099aChet Haase     * Sets the typeface in which the text should be displayed on the switch.
34612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Note that not all Typeface families actually have bold and italic
34712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * variants, so you may need to use
34812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * {@link #setSwitchTypeface(Typeface, int)} to get the appearance
34912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * that you actually want.
35012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     *
35112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @attr ref android.R.styleable#TextView_typeface
35212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @attr ref android.R.styleable#TextView_textStyle
35312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
35412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void setSwitchTypeface(Typeface tf) {
35512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (mTextPaint.getTypeface() != tf) {
35612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mTextPaint.setTypeface(tf);
35712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
35812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            requestLayout();
35912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            invalidate();
36012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
36112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
36212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
36312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
3646c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Set the amount of horizontal padding between the switch and the associated text.
3656c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3666c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @param pixels Amount of padding in pixels
3676c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3686c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_switchPadding
3696c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
3706c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public void setSwitchPadding(int pixels) {
3716c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        mSwitchPadding = pixels;
3726c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        requestLayout();
3736c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
3746c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
3756c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
3766c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Get the amount of horizontal padding between the switch and the associated text.
3776c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3786c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @return Amount of padding in pixels
3796c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3806c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_switchPadding
3816c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
3826c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public int getSwitchPadding() {
3836c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        return mSwitchPadding;
3846c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
3856c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
3866c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
3876c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Set the minimum width of the switch in pixels. The switch's width will be the maximum
3886c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * of this value and its measured width as determined by the switch drawables and text used.
3896c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3906c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @param pixels Minimum width of the switch in pixels
3916c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3926c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_switchMinWidth
3936c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
3946c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public void setSwitchMinWidth(int pixels) {
3956c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        mSwitchMinWidth = pixels;
3966c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        requestLayout();
3976c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
3986c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
3996c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
4006c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Get the minimum width of the switch in pixels. The switch's width will be the maximum
4016c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * of this value and its measured width as determined by the switch drawables and text used.
4026c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4036c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @return Minimum width of the switch in pixels
4046c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4056c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_switchMinWidth
4066c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
4076c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public int getSwitchMinWidth() {
4086c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        return mSwitchMinWidth;
4096c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
4106c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
4116c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
4126c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Set the horizontal padding around the text drawn on the switch itself.
4136c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4146c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @param pixels Horizontal padding for switch thumb text in pixels
4156c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4166c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_thumbTextPadding
4176c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
4186c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public void setThumbTextPadding(int pixels) {
4196c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        mThumbTextPadding = pixels;
4206c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        requestLayout();
4216c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
4226c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
4236c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
4246c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Get the horizontal padding around the text drawn on the switch itself.
4256c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4266c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @return Horizontal padding for switch thumb text in pixels
4276c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4286c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_thumbTextPadding
4296c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
4306c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public int getThumbTextPadding() {
4316c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        return mThumbTextPadding;
4326c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
4336c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
4346c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
4356c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Set the drawable used for the track that the switch slides within.
4366c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4376c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @param track Track drawable
4386c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4396c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_track
4406c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
4416c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public void setTrackDrawable(Drawable track) {
442b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette        if (mTrackDrawable != null) {
443b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette            mTrackDrawable.setCallback(null);
444b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette        }
4456c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        mTrackDrawable = track;
446b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette        if (track != null) {
447b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette            track.setCallback(this);
448b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette        }
4496c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        requestLayout();
4506c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
4516c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
4526c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
453d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     * Set the drawable used for the track that the switch slides within.
454d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     *
455dca510e026e3e75759bac84c3860dc84b83a608fAdam Powell     * @param resId Resource ID of a track drawable
456d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     *
457d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     * @attr ref android.R.styleable#Switch_track
458d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     */
459d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell    public void setTrackResource(int resId) {
4608eea3ea5591e59f55cbb4f6b2b7e9363a285ced3Alan Viverette        setTrackDrawable(getContext().getDrawable(resId));
461d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell    }
462d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell
463d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell    /**
4646c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Get the drawable used for the track that the switch slides within.
4656c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4666c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @return Track drawable
4676c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4686c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_track
4696c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
4706c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public Drawable getTrackDrawable() {
4716c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        return mTrackDrawable;
4726c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
4736c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
4746c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
4756c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Set the drawable used for the switch "thumb" - the piece that the user
4766c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * can physically touch and drag along the track.
4776c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4786c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @param thumb Thumb drawable
4796c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4806c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_thumb
4816c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
4826c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public void setThumbDrawable(Drawable thumb) {
483b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette        if (mThumbDrawable != null) {
484b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette            mThumbDrawable.setCallback(null);
485b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette        }
4866c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        mThumbDrawable = thumb;
487b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette        if (thumb != null) {
488b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette            thumb.setCallback(this);
489b067405bf453289a6b6bfd34b06700f08be58c24Alan Viverette        }
4906c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        requestLayout();
4916c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
4926c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
4936c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
494d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     * Set the drawable used for the switch "thumb" - the piece that the user
495d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     * can physically touch and drag along the track.
496d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     *
497dca510e026e3e75759bac84c3860dc84b83a608fAdam Powell     * @param resId Resource ID of a thumb drawable
498d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     *
499d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     * @attr ref android.R.styleable#Switch_thumb
500d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     */
501d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell    public void setThumbResource(int resId) {
5028eea3ea5591e59f55cbb4f6b2b7e9363a285ced3Alan Viverette        setThumbDrawable(getContext().getDrawable(resId));
503d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell    }
504d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell
505d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell    /**
5066c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Get the drawable used for the switch "thumb" - the piece that the user
5076c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * can physically touch and drag along the track.
5086c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
5096c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @return Thumb drawable
5106c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
5116c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_thumb
5126c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
5136c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public Drawable getThumbDrawable() {
5146c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        return mThumbDrawable;
5156c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
5166c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
5176c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
518661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     * Specifies whether the track should be split by the thumb. When true,
519661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     * the thumb's optical bounds will be clipped out of the track drawable,
520661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     * then the thumb will be drawn into the resulting gap.
521661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     *
522661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     * @param splitTrack Whether the track should be split by the thumb
523661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     *
524661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     * @attr ref android.R.styleable#Switch_splitTrack
525661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     */
526661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    public void setSplitTrack(boolean splitTrack) {
527661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        mSplitTrack = splitTrack;
528661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        invalidate();
529661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    }
530661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
531661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    /**
532661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     * Returns whether the track should be split by the thumb.
533661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     *
534661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     * @attr ref android.R.styleable#Switch_splitTrack
535661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     */
536661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    public boolean getSplitTrack() {
537661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        return mSplitTrack;
538661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    }
539661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
540661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    /**
541150176d83023e3c486dba10edebb72af36b4099aChet Haase     * Returns the text displayed when the button is in the checked state.
5426c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
5436c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_textOn
54412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
54512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public CharSequence getTextOn() {
54612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return mTextOn;
54712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
54812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
54912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
550150176d83023e3c486dba10edebb72af36b4099aChet Haase     * Sets the text displayed when the button is in the checked state.
5516c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
5526c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_textOn
55312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
55412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void setTextOn(CharSequence textOn) {
55512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextOn = textOn;
55612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        requestLayout();
55712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
55812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
55912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
560150176d83023e3c486dba10edebb72af36b4099aChet Haase     * Returns the text displayed when the button is not in the checked state.
5616c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
5626c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_textOff
56312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
56412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public CharSequence getTextOff() {
56512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return mTextOff;
56612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
56712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
56812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
569150176d83023e3c486dba10edebb72af36b4099aChet Haase     * Sets the text displayed when the button is not in the checked state.
5706c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
5716c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_textOff
57212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
57312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void setTextOff(CharSequence textOff) {
57412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextOff = textOff;
57512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        requestLayout();
57612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
57712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
5782a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette    /**
5792a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette     * Sets whether the on/off text should be displayed.
5802a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette     *
5812a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette     * @param showText {@code true} to display on/off text
5820c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     * @attr ref android.R.styleable#Switch_showText
5832a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette     */
5842a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette    public void setShowText(boolean showText) {
5852a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette        if (mShowText != showText) {
5862a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette            mShowText = showText;
5872a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette            requestLayout();
5882a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette        }
5892a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette    }
5902a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette
5912a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette    /**
5922a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette     * @return whether the on/off text should be displayed
5930c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     * @attr ref android.R.styleable#Switch_showText
5942a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette     */
5952a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette    public boolean getShowText() {
5962a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette        return mShowText;
5972a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette    }
5982a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette
59912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
60012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
6012a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette        if (mShowText) {
6022a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette            if (mOnLayout == null) {
6032a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette                mOnLayout = makeLayout(mTextOn);
6042a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette            }
6055876ff4a0ac938297bfd114da6b5d8c9dcb4cef6Alan Viverette
6062a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette            if (mOffLayout == null) {
6072a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette                mOffLayout = makeLayout(mTextOff);
6082a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette            }
60912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
61012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
6119b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette        final Rect padding = mTempRect;
6129b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette        final int thumbWidth;
6139b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette        final int thumbHeight;
6148bb399069da4e46b231333cff6880a0cf35b9417Alan Viverette        if (mThumbDrawable != null) {
6150c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            // Cached thumb width does not include padding.
6160c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            mThumbDrawable.getPadding(padding);
6170c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            thumbWidth = mThumbDrawable.getIntrinsicWidth() - padding.left - padding.right;
6189b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette            thumbHeight = mThumbDrawable.getIntrinsicHeight();
6199b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette        } else {
6209b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette            thumbWidth = 0;
6219b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette            thumbHeight = 0;
6228bb399069da4e46b231333cff6880a0cf35b9417Alan Viverette        }
6238bb399069da4e46b231333cff6880a0cf35b9417Alan Viverette
6240c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        final int maxTextWidth;
6250c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        if (mShowText) {
6260c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            maxTextWidth = Math.max(mOnLayout.getWidth(), mOffLayout.getWidth())
6270c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                    + mThumbTextPadding * 2;
6280c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        } else {
6290c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            maxTextWidth = 0;
6300c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        }
6310c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
6329b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette        mThumbWidth = Math.max(maxTextWidth, thumbWidth);
6339b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette
6340c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        final int trackHeight;
6350c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        if (mTrackDrawable != null) {
6360c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            mTrackDrawable.getPadding(padding);
6370c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            trackHeight = mTrackDrawable.getIntrinsicHeight();
6380c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        } else {
6390c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            padding.setEmpty();
6400c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            trackHeight = 0;
6410c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        }
6420c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
6430c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        // Adjust left and right padding to ensure there's enough room for the
6440c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        // thumb's padding (when present).
6450c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        int paddingLeft = padding.left;
6460c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        int paddingRight = padding.right;
6470c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        if (mThumbDrawable != null) {
6480c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            final Insets inset = mThumbDrawable.getOpticalInsets();
6490c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            paddingLeft = Math.max(paddingLeft, inset.left);
6500c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            paddingRight = Math.max(paddingRight, inset.right);
6510c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        }
6520c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
65312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int switchWidth = Math.max(mSwitchMinWidth,
6540c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                2 * mThumbWidth + paddingLeft + paddingRight);
6554d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        final int switchHeight = Math.max(trackHeight, thumbHeight);
65612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchWidth = switchWidth;
65712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchHeight = switchHeight;
65812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
65912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
6604d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette
66112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int measuredHeight = getMeasuredHeight();
66212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (measuredHeight < switchHeight) {
663189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn            setMeasuredDimension(getMeasuredWidthAndState(), switchHeight);
66412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
66512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
66612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
66763bce03cc69be4a45230aa8bbd89dbde60681067Svetoslav Ganov    @Override
66863bce03cc69be4a45230aa8bbd89dbde60681067Svetoslav Ganov    public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
66963bce03cc69be4a45230aa8bbd89dbde60681067Svetoslav Ganov        super.onPopulateAccessibilityEvent(event);
6702a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette
6712a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette        final CharSequence text = isChecked() ? mTextOn : mTextOff;
6722a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette        if (text != null) {
6732a37cf8d763750853e2b4e036bc7cb4486c78e1dAlan Viverette            event.getText().add(text);
6747650259a597dd24137420d32acc35efc44db381eSvetoslav Ganov        }
67563bce03cc69be4a45230aa8bbd89dbde60681067Svetoslav Ganov    }
67663bce03cc69be4a45230aa8bbd89dbde60681067Svetoslav Ganov
67712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private Layout makeLayout(CharSequence text) {
6784c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler        final CharSequence transformed = (mSwitchTransformationMethod != null)
6794c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler                    ? mSwitchTransformationMethod.getTransformation(text, this)
6804c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler                    : text;
6814c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler
6824c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler        return new StaticLayout(transformed, mTextPaint,
6834c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler                (int) Math.ceil(Layout.getDesiredWidth(transformed, mTextPaint)),
68412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                Layout.Alignment.ALIGN_NORMAL, 1.f, 0, true);
68512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
68612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
68712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
68812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @return true if (x, y) is within the target area of the switch thumb
68912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
69012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private boolean hitThumb(float x, float y) {
691cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        // Relies on mTempRect, MUST be called first!
692cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        final int thumbOffset = getThumbOffset();
693cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette
69412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mThumbDrawable.getPadding(mTempRect);
69512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int thumbTop = mSwitchTop - mTouchSlop;
696cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        final int thumbLeft = mSwitchLeft + thumbOffset - mTouchSlop;
69712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int thumbRight = thumbLeft + mThumbWidth +
69812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                mTempRect.left + mTempRect.right + mTouchSlop;
69912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int thumbBottom = mSwitchBottom + mTouchSlop;
70012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return x > thumbLeft && x < thumbRight && y > thumbTop && y < thumbBottom;
70112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
70212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
70312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
70412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public boolean onTouchEvent(MotionEvent ev) {
70512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mVelocityTracker.addMovement(ev);
70612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int action = ev.getActionMasked();
70712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        switch (action) {
70812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MotionEvent.ACTION_DOWN: {
70912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                final float x = ev.getX();
71012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                final float y = ev.getY();
711c2ab0d665c9d1c332fbd726abf582a27cf7a6701Gilles Debunne                if (isEnabled() && hitThumb(x, y)) {
71212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    mTouchMode = TOUCH_MODE_DOWN;
71312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    mTouchX = x;
71412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    mTouchY = y;
71512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                }
71612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
71712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
71812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
71912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MotionEvent.ACTION_MOVE: {
72012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switch (mTouchMode) {
72112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    case TOUCH_MODE_IDLE:
72212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        // Didn't target the thumb, treat normally.
72312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        break;
72412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
72512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    case TOUCH_MODE_DOWN: {
72612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        final float x = ev.getX();
72712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        final float y = ev.getY();
72812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        if (Math.abs(x - mTouchX) > mTouchSlop ||
72912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                                Math.abs(y - mTouchY) > mTouchSlop) {
73012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            mTouchMode = TOUCH_MODE_DRAGGING;
73112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            getParent().requestDisallowInterceptTouchEvent(true);
73212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            mTouchX = x;
73312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            mTouchY = y;
73412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            return true;
73512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        }
73612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        break;
73712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    }
73812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
73912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    case TOUCH_MODE_DRAGGING: {
74012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        final float x = ev.getX();
741cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                        final int thumbScrollRange = getThumbScrollRange();
742cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                        final float thumbScrollOffset = x - mTouchX;
743cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                        float dPos;
744cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                        if (thumbScrollRange != 0) {
745cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                            dPos = thumbScrollOffset / thumbScrollRange;
746cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                        } else {
747cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                            // If the thumb scroll range is empty, just use the
748cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                            // movement direction to snap on or off.
749cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                            dPos = thumbScrollOffset > 0 ? 1 : -1;
750cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                        }
751cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                        if (isLayoutRtl()) {
752cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                            dPos = -dPos;
753cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                        }
754cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                        final float newPos = MathUtils.constrain(mThumbPosition + dPos, 0, 1);
75512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        if (newPos != mThumbPosition) {
75612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            mTouchX = x;
757cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette                            setThumbPosition(newPos);
75812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        }
75912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        return true;
76012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    }
76112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                }
76212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
76312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
76412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
76512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MotionEvent.ACTION_UP:
76612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MotionEvent.ACTION_CANCEL: {
76712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                if (mTouchMode == TOUCH_MODE_DRAGGING) {
76812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    stopDrag(ev);
769ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette                    // Allow super class to handle pressed state, etc.
770ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette                    super.onTouchEvent(ev);
77112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    return true;
77212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                }
77312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                mTouchMode = TOUCH_MODE_IDLE;
77412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                mVelocityTracker.clear();
77512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
77612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
77712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
77812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
77912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return super.onTouchEvent(ev);
78012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
78112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
78212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private void cancelSuperTouch(MotionEvent ev) {
78312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        MotionEvent cancel = MotionEvent.obtain(ev);
78412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        cancel.setAction(MotionEvent.ACTION_CANCEL);
78512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.onTouchEvent(cancel);
78612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        cancel.recycle();
78712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
78812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
78912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
79012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Called from onTouchEvent to end a drag operation.
79112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     *
79212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param ev Event that triggered the end of drag mode - ACTION_UP or ACTION_CANCEL
79312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
79412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private void stopDrag(MotionEvent ev) {
79512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTouchMode = TOUCH_MODE_IDLE;
79612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
79786453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette        // Commit the change if the event is up and not canceled and the switch
79886453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette        // has not been disabled during the drag.
79986453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette        final boolean commitChange = ev.getAction() == MotionEvent.ACTION_UP && isEnabled();
80086453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette        final boolean newState;
80112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (commitChange) {
80212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mVelocityTracker.computeCurrentVelocity(1000);
80386453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette            final float xvel = mVelocityTracker.getXVelocity();
80412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            if (Math.abs(xvel) > mMinFlingVelocity) {
80528efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio                newState = isLayoutRtl() ? (xvel < 0) : (xvel > 0);
80612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            } else {
80712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                newState = getTargetCheckedState();
80812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
80912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        } else {
81086453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette            newState = isChecked();
81112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
81286453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette
81386453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette        setChecked(newState);
81486453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette        cancelSuperTouch(ev);
81512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
81612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
81712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private void animateThumbToCheckedState(boolean newCheckedState) {
818cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        final float targetPosition = newCheckedState ? 1 : 0;
819cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        mPositionAnimator = ObjectAnimator.ofFloat(this, THUMB_POS, targetPosition);
820cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        mPositionAnimator.setDuration(THUMB_ANIMATION_DURATION);
821cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        mPositionAnimator.setAutoCancel(true);
822cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        mPositionAnimator.start();
82312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
82412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
825cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    private void cancelPositionAnimator() {
826cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        if (mPositionAnimator != null) {
827cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette            mPositionAnimator.cancel();
82828efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        }
82928efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio    }
83028efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio
831cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    private boolean getTargetCheckedState() {
832cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        return mThumbPosition > 0.5f;
833cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    }
834cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette
835cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    /**
836cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette     * Sets the thumb position as a decimal value between 0 (off) and 1 (on).
837cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette     *
838cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette     * @param position new position between [0,1]
839cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette     */
840cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    private void setThumbPosition(float position) {
841cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        mThumbPosition = position;
842cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        invalidate();
843cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    }
844cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette
845cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    @Override
846cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    public void toggle() {
84786453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette        setChecked(!isChecked());
84812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
84912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
85012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
85112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void setChecked(boolean checked) {
85212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.setChecked(checked);
853cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette
854467d629ca714cd74658043c1ddfec36c60d898c1Alan Viverette        // Calling the super method may result in setChecked() getting called
855467d629ca714cd74658043c1ddfec36c60d898c1Alan Viverette        // recursively with a different value, so load the REAL value...
856467d629ca714cd74658043c1ddfec36c60d898c1Alan Viverette        checked = isChecked();
857467d629ca714cd74658043c1ddfec36c60d898c1Alan Viverette
85886453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette        if (isAttachedToWindow() && isLaidOut()) {
85986453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette            animateThumbToCheckedState(checked);
86086453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette        } else {
86186453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette            // Immediately move the thumb to the new position.
86286453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette            cancelPositionAnimator();
86386453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette            setThumbPosition(checked ? 1 : 0);
86486453ff147f28b0c16bea73da5b261feed50efb7Alan Viverette        }
86512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
86612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
86712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
86812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
86912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.onLayout(changed, left, top, right, bottom);
87012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
8710c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        int opticalInsetLeft = 0;
8720c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        int opticalInsetRight = 0;
8730c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        if (mThumbDrawable != null) {
8740c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            final Rect trackPadding = mTempRect;
8750c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            if (mTrackDrawable != null) {
8760c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                mTrackDrawable.getPadding(trackPadding);
8770c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            } else {
8780c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                trackPadding.setEmpty();
8790c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            }
8800c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
8810c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            final Insets insets = mThumbDrawable.getOpticalInsets();
8820c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            opticalInsetLeft = Math.max(0, insets.left - trackPadding.left);
8830c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            opticalInsetRight = Math.max(0, insets.right - trackPadding.right);
8840c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        }
88528efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio
8860c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        final int switchRight;
8870c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        final int switchLeft;
88828efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        if (isLayoutRtl()) {
8890c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            switchLeft = getPaddingLeft() + opticalInsetLeft;
8900c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            switchRight = switchLeft + mSwitchWidth - opticalInsetLeft - opticalInsetRight;
89128efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        } else {
8920c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            switchRight = getWidth() - getPaddingRight() - opticalInsetRight;
8930c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            switchLeft = switchRight - mSwitchWidth + opticalInsetLeft + opticalInsetRight;
89428efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        }
895c3eabb9b6ce7f556313c8e3870d76c5b443f1c51Joe Onorato
8960c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        final int switchTop;
8970c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        final int switchBottom;
89812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        switch (getGravity() & Gravity.VERTICAL_GRAVITY_MASK) {
89912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            default:
90012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case Gravity.TOP:
90112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchTop = getPaddingTop();
90212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchBottom = switchTop + mSwitchHeight;
90312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
90412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
90512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case Gravity.CENTER_VERTICAL:
90612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchTop = (getPaddingTop() + getHeight() - getPaddingBottom()) / 2 -
90712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        mSwitchHeight / 2;
90812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchBottom = switchTop + mSwitchHeight;
90912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
91012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
91112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case Gravity.BOTTOM:
91212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchBottom = getHeight() - getPaddingBottom();
91312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchTop = switchBottom - mSwitchHeight;
91412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
91512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
91612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
91712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchLeft = switchLeft;
91812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchTop = switchTop;
91912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchBottom = switchBottom;
92012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchRight = switchRight;
92112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
92212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
92312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
924ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    public void draw(Canvas c) {
9254d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        final Rect padding = mTempRect;
9265876ff4a0ac938297bfd114da6b5d8c9dcb4cef6Alan Viverette        final int switchLeft = mSwitchLeft;
9275876ff4a0ac938297bfd114da6b5d8c9dcb4cef6Alan Viverette        final int switchTop = mSwitchTop;
9285876ff4a0ac938297bfd114da6b5d8c9dcb4cef6Alan Viverette        final int switchRight = mSwitchRight;
9295876ff4a0ac938297bfd114da6b5d8c9dcb4cef6Alan Viverette        final int switchBottom = mSwitchBottom;
9300c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
9310c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        int thumbInitialLeft = switchLeft + getThumbOffset();
9320c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
9330c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        final Insets thumbInsets;
9340c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        if (mThumbDrawable != null) {
9350c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            thumbInsets = mThumbDrawable.getOpticalInsets();
9360c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        } else {
9370c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            thumbInsets = Insets.NONE;
9388bb399069da4e46b231333cff6880a0cf35b9417Alan Viverette        }
939cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette
9400c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        // Layout the track.
9410c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        if (mTrackDrawable != null) {
9420c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            mTrackDrawable.getPadding(padding);
9439b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette
9440c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            // Adjust thumb position for track padding.
9450c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            thumbInitialLeft += padding.left;
9460c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
9470c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            // If necessary, offset by the optical insets of the thumb asset.
9480c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            int trackLeft = switchLeft;
9490c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            int trackTop = switchTop;
9500c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            int trackRight = switchRight;
9510c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            int trackBottom = switchBottom;
9520c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            if (thumbInsets != Insets.NONE) {
9530c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                if (thumbInsets.left > padding.left) {
9540c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                    trackLeft += thumbInsets.left - padding.left;
9550c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                }
9560c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                if (thumbInsets.top > padding.top) {
9570c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                    trackTop += thumbInsets.top - padding.top;
9580c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                }
9590c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                if (thumbInsets.right > padding.right) {
9600c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                    trackRight -= thumbInsets.right - padding.right;
9610c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                }
9620c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                if (thumbInsets.bottom > padding.bottom) {
9630c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                    trackBottom -= thumbInsets.bottom - padding.bottom;
9640c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                }
9650c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            }
9660c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            mTrackDrawable.setBounds(trackLeft, trackTop, trackRight, trackBottom);
9670c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette        }
9689b38f6c2cd1d97bb0d1a21e2f9545e02fae851e0Alan Viverette
969661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        // Layout the thumb.
9704d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        if (mThumbDrawable != null) {
9714d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            mThumbDrawable.getPadding(padding);
9720c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
9730c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            final int thumbLeft = thumbInitialLeft - padding.left;
9740c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            final int thumbRight = thumbInitialLeft + mThumbWidth + padding.right;
9754d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            mThumbDrawable.setBounds(thumbLeft, switchTop, thumbRight, switchBottom);
9764d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette
9774d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            final Drawable background = getBackground();
9784d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            if (background != null) {
9794d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                background.setHotspotBounds(thumbLeft, switchTop, thumbRight, switchBottom);
9804d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            }
98161956606818918194a38e045a8e35e7108480e5eAlan Viverette        }
98261956606818918194a38e045a8e35e7108480e5eAlan Viverette
983ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette        // Draw the background.
984ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette        super.draw(c);
985ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    }
986ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette
987ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    @Override
988ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    protected void onDraw(Canvas canvas) {
98961956606818918194a38e045a8e35e7108480e5eAlan Viverette        super.onDraw(canvas);
99061956606818918194a38e045a8e35e7108480e5eAlan Viverette
9914d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        final Rect padding = mTempRect;
992ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette        final Drawable trackDrawable = mTrackDrawable;
9934d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        if (trackDrawable != null) {
9944d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            trackDrawable.getPadding(padding);
9954d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        } else {
9964d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            padding.setEmpty();
9974d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        }
998ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette
999ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette        final int switchTop = mSwitchTop;
1000ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette        final int switchBottom = mSwitchBottom;
10014d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        final int switchInnerTop = switchTop + padding.top;
10024d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        final int switchInnerBottom = switchBottom - padding.bottom;
10034d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette
10044d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        final Drawable thumbDrawable = mThumbDrawable;
10054d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        if (trackDrawable != null) {
10064d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            if (mSplitTrack && thumbDrawable != null) {
10074d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                final Insets insets = thumbDrawable.getOpticalInsets();
10084d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                thumbDrawable.copyBounds(padding);
10094d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                padding.left += insets.left;
10104d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                padding.right -= insets.right;
10114d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette
10124d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                final int saveCount = canvas.save();
10134d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                canvas.clipRect(padding, Op.DIFFERENCE);
10144d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                trackDrawable.draw(canvas);
10154d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                canvas.restoreToCount(saveCount);
10164d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            } else {
10174d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                trackDrawable.draw(canvas);
10184d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            }
1019661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        }
102061956606818918194a38e045a8e35e7108480e5eAlan Viverette
102161956606818918194a38e045a8e35e7108480e5eAlan Viverette        final int saveCount = canvas.save();
10224d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette
10234d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        if (thumbDrawable != null) {
10244d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            thumbDrawable.draw(canvas);
10254d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        }
102612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
10275876ff4a0ac938297bfd114da6b5d8c9dcb4cef6Alan Viverette        final Layout switchText = getTargetCheckedState() ? mOnLayout : mOffLayout;
1028be06e3292b295324b3b47d13f9a40787b666309fFabrice Di Meglio        if (switchText != null) {
1029661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            final int drawableState[] = getDrawableState();
1030661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            if (mTextColors != null) {
1031661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette                mTextPaint.setColor(mTextColors.getColorForState(drawableState, 0));
1032661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            }
1033661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            mTextPaint.drawableState = drawableState;
1034661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
10354d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            final int cX;
10364d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            if (thumbDrawable != null) {
10374d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                final Rect bounds = thumbDrawable.getBounds();
10384d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette                cX = bounds.left + bounds.right;
10394d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            } else {
1040dec17299fef93f673d8e8cab0ec0f734bf6b8539Alan Viverette                cX = getWidth();
10414d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            }
10424d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette
10434d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            final int left = cX / 2 - switchText.getWidth() / 2;
10445876ff4a0ac938297bfd114da6b5d8c9dcb4cef6Alan Viverette            final int top = (switchInnerTop + switchInnerBottom) / 2 - switchText.getHeight() / 2;
10455876ff4a0ac938297bfd114da6b5d8c9dcb4cef6Alan Viverette            canvas.translate(left, top);
1046be06e3292b295324b3b47d13f9a40787b666309fFabrice Di Meglio            switchText.draw(canvas);
1047be06e3292b295324b3b47d13f9a40787b666309fFabrice Di Meglio        }
104812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
10495876ff4a0ac938297bfd114da6b5d8c9dcb4cef6Alan Viverette        canvas.restoreToCount(saveCount);
105012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
105112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
105212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
105328efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio    public int getCompoundPaddingLeft() {
105428efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        if (!isLayoutRtl()) {
105528efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio            return super.getCompoundPaddingLeft();
105628efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        }
105728efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        int padding = super.getCompoundPaddingLeft() + mSwitchWidth;
105828efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        if (!TextUtils.isEmpty(getText())) {
105928efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio            padding += mSwitchPadding;
106028efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        }
106128efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        return padding;
106228efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio    }
106328efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio
106428efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio    @Override
106512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public int getCompoundPaddingRight() {
106628efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        if (isLayoutRtl()) {
106728efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio            return super.getCompoundPaddingRight();
106828efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        }
106912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int padding = super.getCompoundPaddingRight() + mSwitchWidth;
107012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (!TextUtils.isEmpty(getText())) {
107112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            padding += mSwitchPadding;
107212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
107312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return padding;
107412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
107512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
1076cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    /**
1077cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette     * Translates thumb position to offset according to current RTL setting and
10780c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette     * thumb scroll range. Accounts for both track and thumb padding.
1079cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette     *
1080cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette     * @return thumb offset
1081cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette     */
1082cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    private int getThumbOffset() {
1083cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        final float thumbPosition;
1084cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        if (isLayoutRtl()) {
1085cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette            thumbPosition = 1 - mThumbPosition;
1086cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        } else {
1087cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette            thumbPosition = mThumbPosition;
1088cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        }
1089cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        return (int) (thumbPosition * getThumbScrollRange() + 0.5f);
1090cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    }
1091cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette
109212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int getThumbScrollRange() {
10934d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        if (mTrackDrawable != null) {
10940c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            final Rect padding = mTempRect;
10950c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            mTrackDrawable.getPadding(padding);
10960c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
10970c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            final Insets insets;
10980c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            if (mThumbDrawable != null) {
10990c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                insets = mThumbDrawable.getOpticalInsets();
11000c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            } else {
11010c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                insets = Insets.NONE;
11020c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            }
11030c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette
11040c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette            return mSwitchWidth - mThumbWidth - padding.left - padding.right
11050c0dde7171c7ea35bbc6d64a41f94b428cb4d1f6Alan Viverette                    - insets.left - insets.right;
11064d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        } else {
110712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            return 0;
110812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
110912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
111012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
111112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
111212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    protected int[] onCreateDrawableState(int extraSpace) {
111312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
111412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (isChecked()) {
111512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mergeDrawableStates(drawableState, CHECKED_STATE_SET);
111612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
111712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return drawableState;
111812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
111912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
112012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
112112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    protected void drawableStateChanged() {
112212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.drawableStateChanged();
112312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
1124661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        final int[] myDrawableState = getDrawableState();
1125661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
11262356c5e69b0911e6334ebf6374217898371be5acAlan Viverette        if (mThumbDrawable != null) {
11272356c5e69b0911e6334ebf6374217898371be5acAlan Viverette            mThumbDrawable.setState(myDrawableState);
1128661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        }
112912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
1130661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        if (mTrackDrawable != null) {
1131661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            mTrackDrawable.setState(myDrawableState);
1132661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        }
113312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
113412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        invalidate();
113512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
113612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
1137cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette    @Override
11388de1494557cf1d00c1c3fce439138a28de7fbd61Alan Viverette    public void drawableHotspotChanged(float x, float y) {
11398de1494557cf1d00c1c3fce439138a28de7fbd61Alan Viverette        super.drawableHotspotChanged(x, y);
1140cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette
1141cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette        if (mThumbDrawable != null) {
1142cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette            mThumbDrawable.setHotspot(x, y);
1143cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette        }
1144cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette
1145cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette        if (mTrackDrawable != null) {
1146cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette            mTrackDrawable.setHotspot(x, y);
1147cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette        }
1148cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette    }
1149cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette
115012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
115112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    protected boolean verifyDrawable(Drawable who) {
115212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return super.verifyDrawable(who) || who == mThumbDrawable || who == mTrackDrawable;
115312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
115412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
115512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
115612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void jumpDrawablesToCurrentState() {
115712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.jumpDrawablesToCurrentState();
11584d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette
11594d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        if (mThumbDrawable != null) {
11604d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            mThumbDrawable.jumpToCurrentState();
11614d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        }
11624d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette
11634d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        if (mTrackDrawable != null) {
11644d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            mTrackDrawable.jumpToCurrentState();
11654d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        }
11664d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette
11674d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        if (mPositionAnimator != null && mPositionAnimator.isRunning()) {
11684d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            mPositionAnimator.end();
11694d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette            mPositionAnimator = null;
11704d065a04ce42c07569cf20651c949c4da97aa4a9Alan Viverette        }
117112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
11728a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov
11738a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    @Override
11748a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
11758a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        super.onInitializeAccessibilityEvent(event);
11768a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        event.setClassName(Switch.class.getName());
11778a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    }
11788a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov
11798a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    @Override
11808a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
11818a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        super.onInitializeAccessibilityNodeInfo(info);
11828a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        info.setClassName(Switch.class.getName());
118378bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov        CharSequence switchText = isChecked() ? mTextOn : mTextOff;
118478bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov        if (!TextUtils.isEmpty(switchText)) {
118578bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov            CharSequence oldText = info.getText();
118678bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov            if (TextUtils.isEmpty(oldText)) {
118778bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov                info.setText(switchText);
118878bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov            } else {
118978bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov                StringBuilder newText = new StringBuilder();
119078bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov                newText.append(oldText).append(' ').append(switchText);
119178bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov                info.setText(newText);
119278bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov            }
119378bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov        }
11948a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    }
1195cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette
1196cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    private static final FloatProperty<Switch> THUMB_POS = new FloatProperty<Switch>("thumbPos") {
1197cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        @Override
1198cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        public Float get(Switch object) {
1199cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette            return object.mThumbPosition;
1200cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        }
1201cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette
1202cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        @Override
1203cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        public void setValue(Switch object, float value) {
1204cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette            object.setThumbPosition(value);
1205cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette        }
1206cc2688d18af3f434fc6ac63289a69f6c1a9f8d9fAlan Viverette    };
120712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell}
1208