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
1912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.content.Context;
2012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.content.res.ColorStateList;
2112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.content.res.Resources;
2212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.content.res.TypedArray;
2312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.graphics.Canvas;
2412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.graphics.Paint;
2512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.graphics.Rect;
2612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.graphics.Typeface;
2712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.graphics.drawable.Drawable;
2812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.text.Layout;
2912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.text.StaticLayout;
3012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.text.TextPaint;
3112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.text.TextUtils;
324c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandlerimport android.text.method.AllCapsTransformationMethod;
334c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandlerimport android.text.method.TransformationMethod2;
3412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.util.AttributeSet;
3512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.view.Gravity;
3612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.view.MotionEvent;
3712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.view.VelocityTracker;
3812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.view.ViewConfiguration;
3963bce03cc69be4a45230aa8bbd89dbde60681067Svetoslav Ganovimport android.view.accessibility.AccessibilityEvent;
408a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganovimport android.view.accessibility.AccessibilityNodeInfo;
4112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
42be0a4535053bbfdebd215e244b154ac810fd8edcAdam Powellimport com.android.internal.R;
43be0a4535053bbfdebd215e244b154ac810fd8edcAdam Powell
4412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell/**
4512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell * A Switch is a two-state toggle switch widget that can select between two
4612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell * options. The user may drag the "thumb" back and forth to choose the selected option,
47150176d83023e3c486dba10edebb72af36b4099aChet Haase * or simply tap to toggle as if it were a checkbox. The {@link #setText(CharSequence) text}
48150176d83023e3c486dba10edebb72af36b4099aChet Haase * property controls the text displayed in the label for the switch, whereas the
49150176d83023e3c486dba10edebb72af36b4099aChet Haase * {@link #setTextOff(CharSequence) off} and {@link #setTextOn(CharSequence) on} text
50150176d83023e3c486dba10edebb72af36b4099aChet Haase * controls the text on the thumb. Similarly, the
51150176d83023e3c486dba10edebb72af36b4099aChet Haase * {@link #setTextAppearance(android.content.Context, int) textAppearance} and the related
52150176d83023e3c486dba10edebb72af36b4099aChet Haase * setTypeface() methods control the typeface and style of label text, whereas the
53150176d83023e3c486dba10edebb72af36b4099aChet Haase * {@link #setSwitchTextAppearance(android.content.Context, int) switchTextAppearance} and
54150176d83023e3c486dba10edebb72af36b4099aChet Haase * the related seSwitchTypeface() methods control that of the thumb.
5512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell *
564c359b76f9a030f92a302ba74a528faa170bad4eScott Main * <p>See the <a href="{@docRoot}guide/topics/ui/controls/togglebutton.html">Toggle Buttons</a>
574c359b76f9a030f92a302ba74a528faa170bad4eScott Main * guide.</p>
584c359b76f9a030f92a302ba74a528faa170bad4eScott Main *
594c359b76f9a030f92a302ba74a528faa170bad4eScott Main * @attr ref android.R.styleable#Switch_textOn
604c359b76f9a030f92a302ba74a528faa170bad4eScott Main * @attr ref android.R.styleable#Switch_textOff
614c359b76f9a030f92a302ba74a528faa170bad4eScott Main * @attr ref android.R.styleable#Switch_switchMinWidth
624c359b76f9a030f92a302ba74a528faa170bad4eScott Main * @attr ref android.R.styleable#Switch_switchPadding
634c359b76f9a030f92a302ba74a528faa170bad4eScott Main * @attr ref android.R.styleable#Switch_switchTextAppearance
644c359b76f9a030f92a302ba74a528faa170bad4eScott Main * @attr ref android.R.styleable#Switch_thumb
654c359b76f9a030f92a302ba74a528faa170bad4eScott Main * @attr ref android.R.styleable#Switch_thumbTextPadding
664c359b76f9a030f92a302ba74a528faa170bad4eScott Main * @attr ref android.R.styleable#Switch_track
6712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell */
6812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellpublic class Switch extends CompoundButton {
6912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int TOUCH_MODE_IDLE = 0;
7012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int TOUCH_MODE_DOWN = 1;
7112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int TOUCH_MODE_DRAGGING = 2;
7212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
7312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    // Enum for the "typeface" XML parameter.
7412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int SANS = 1;
7512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int SERIF = 2;
7612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int MONOSPACE = 3;
7712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
7812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private Drawable mThumbDrawable;
7912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private Drawable mTrackDrawable;
8012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mThumbTextPadding;
8112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchMinWidth;
8212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchPadding;
8312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private CharSequence mTextOn;
8412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private CharSequence mTextOff;
8512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
8612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mTouchMode;
8712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mTouchSlop;
8812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private float mTouchX;
8912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private float mTouchY;
9012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private VelocityTracker mVelocityTracker = VelocityTracker.obtain();
9112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mMinFlingVelocity;
9212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
9312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private float mThumbPosition;
9412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchWidth;
9512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchHeight;
9612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mThumbWidth; // Does not include padding
9712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
9812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchLeft;
9912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchTop;
10012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchRight;
10112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchBottom;
10212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
10312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private TextPaint mTextPaint;
10412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private ColorStateList mTextColors;
10512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private Layout mOnLayout;
10612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private Layout mOffLayout;
1074c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler    private TransformationMethod2 mSwitchTransformationMethod;
10812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
109be0a4535053bbfdebd215e244b154ac810fd8edcAdam Powell    @SuppressWarnings("hiding")
11012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private final Rect mTempRect = new Rect();
11112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
11212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int[] CHECKED_STATE_SET = {
11312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        R.attr.state_checked
11412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    };
11512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
11612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
11712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Construct a new Switch with default styling.
11812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     *
11912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param context The Context that will determine this widget's theming.
12012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
12112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public Switch(Context context) {
12212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        this(context, null);
12312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
12412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
12512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
12612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Construct a new Switch with default styling, overriding specific style
12712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * attributes as requested.
12812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     *
12912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param context The Context that will determine this widget's theming.
13012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param attrs Specification of attributes that should deviate from default styling.
13112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
13212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public Switch(Context context, AttributeSet attrs) {
13312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        this(context, attrs, com.android.internal.R.attr.switchStyle);
13412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
13512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
13612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
13712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Construct a new Switch with a default style determined by the given theme attribute,
13812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * overriding specific style attributes as requested.
13912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     *
14012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param context The Context that will determine this widget's theming.
14112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param attrs Specification of attributes that should deviate from the default styling.
14212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param defStyle An attribute ID within the active theme containing a reference to the
14312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     *                 default style for this widget. e.g. android.R.attr.switchStyle.
14412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
14512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public Switch(Context context, AttributeSet attrs, int defStyle) {
14612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super(context, attrs, defStyle);
14712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
14812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
14912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        Resources res = getResources();
15012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextPaint.density = res.getDisplayMetrics().density;
15112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextPaint.setCompatibilityScaling(res.getCompatibilityInfo().applicationScale);
15212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
15312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        TypedArray a = context.obtainStyledAttributes(attrs,
15412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                com.android.internal.R.styleable.Switch, defStyle, 0);
15512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
156150176d83023e3c486dba10edebb72af36b4099aChet Haase        mThumbDrawable = a.getDrawable(com.android.internal.R.styleable.Switch_thumb);
157150176d83023e3c486dba10edebb72af36b4099aChet Haase        mTrackDrawable = a.getDrawable(com.android.internal.R.styleable.Switch_track);
15812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextOn = a.getText(com.android.internal.R.styleable.Switch_textOn);
15912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextOff = a.getText(com.android.internal.R.styleable.Switch_textOff);
16012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mThumbTextPadding = a.getDimensionPixelSize(
16112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                com.android.internal.R.styleable.Switch_thumbTextPadding, 0);
16212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchMinWidth = a.getDimensionPixelSize(
16312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                com.android.internal.R.styleable.Switch_switchMinWidth, 0);
16412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchPadding = a.getDimensionPixelSize(
16512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                com.android.internal.R.styleable.Switch_switchPadding, 0);
16612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
16712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int appearance = a.getResourceId(
16812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                com.android.internal.R.styleable.Switch_switchTextAppearance, 0);
16912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (appearance != 0) {
170150176d83023e3c486dba10edebb72af36b4099aChet Haase            setSwitchTextAppearance(context, appearance);
17112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
17212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        a.recycle();
17312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
17412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        ViewConfiguration config = ViewConfiguration.get(context);
17512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTouchSlop = config.getScaledTouchSlop();
17612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mMinFlingVelocity = config.getScaledMinimumFlingVelocity();
17712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
17812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        // Refresh display with current params
179e724ee4b04d121556e9764f72f9b921a0e16392aGilles Debunne        refreshDrawableState();
18012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        setChecked(isChecked());
18112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
18212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
18312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
18412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Sets the switch text color, size, style, hint color, and highlight color
18512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * from the specified TextAppearance resource.
1866c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
1876c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_switchTextAppearance
18812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
189150176d83023e3c486dba10edebb72af36b4099aChet Haase    public void setSwitchTextAppearance(Context context, int resid) {
19012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        TypedArray appearance =
191150176d83023e3c486dba10edebb72af36b4099aChet Haase                context.obtainStyledAttributes(resid,
19212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        com.android.internal.R.styleable.TextAppearance);
19312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
19412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        ColorStateList colors;
19512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int ts;
19612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
19712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        colors = appearance.getColorStateList(com.android.internal.R.styleable.
19812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                TextAppearance_textColor);
19912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (colors != null) {
20012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mTextColors = colors;
201150176d83023e3c486dba10edebb72af36b4099aChet Haase        } else {
202150176d83023e3c486dba10edebb72af36b4099aChet Haase            // If no color set in TextAppearance, default to the view's textColor
203150176d83023e3c486dba10edebb72af36b4099aChet Haase            mTextColors = getTextColors();
20412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
20512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
20612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        ts = appearance.getDimensionPixelSize(com.android.internal.R.styleable.
20712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                TextAppearance_textSize, 0);
20812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (ts != 0) {
20912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            if (ts != mTextPaint.getTextSize()) {
21012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                mTextPaint.setTextSize(ts);
21112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                requestLayout();
21212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
21312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
21412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
21512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int typefaceIndex, styleIndex;
21612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
21712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        typefaceIndex = appearance.getInt(com.android.internal.R.styleable.
21812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                TextAppearance_typeface, -1);
21912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        styleIndex = appearance.getInt(com.android.internal.R.styleable.
22012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                TextAppearance_textStyle, -1);
22112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
22212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        setSwitchTypefaceByIndex(typefaceIndex, styleIndex);
22312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
2244c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler        boolean allCaps = appearance.getBoolean(com.android.internal.R.styleable.
2254c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler                TextAppearance_textAllCaps, false);
2264c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler        if (allCaps) {
2274c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler            mSwitchTransformationMethod = new AllCapsTransformationMethod(getContext());
2284c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler            mSwitchTransformationMethod.setLengthChangesAllowed(true);
2294c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler        } else {
2304c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler            mSwitchTransformationMethod = null;
2314c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler        }
2324c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler
23312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        appearance.recycle();
23412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
23512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
23612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private void setSwitchTypefaceByIndex(int typefaceIndex, int styleIndex) {
23712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        Typeface tf = null;
23812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        switch (typefaceIndex) {
23912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case SANS:
24012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                tf = Typeface.SANS_SERIF;
24112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
24212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
24312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case SERIF:
24412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                tf = Typeface.SERIF;
24512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
24612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
24712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MONOSPACE:
24812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                tf = Typeface.MONOSPACE;
24912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
25012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
25112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
25212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        setSwitchTypeface(tf, styleIndex);
25312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
25412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
25512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
25612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Sets the typeface and style in which the text should be displayed on the
25712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * switch, and turns on the fake bold and italic bits in the Paint if the
25812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Typeface that you provided does not have all the bits in the
25912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * style that you specified.
26012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
26112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void setSwitchTypeface(Typeface tf, int style) {
26212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (style > 0) {
26312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            if (tf == null) {
26412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                tf = Typeface.defaultFromStyle(style);
26512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            } else {
26612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                tf = Typeface.create(tf, style);
26712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
26812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
26912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            setSwitchTypeface(tf);
27012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            // now compute what (if any) algorithmic styling is needed
27112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            int typefaceStyle = tf != null ? tf.getStyle() : 0;
27212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            int need = style & ~typefaceStyle;
27312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mTextPaint.setFakeBoldText((need & Typeface.BOLD) != 0);
27412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mTextPaint.setTextSkewX((need & Typeface.ITALIC) != 0 ? -0.25f : 0);
27512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        } else {
276aa0980afab57a6aebb06e70f60e92511708fa5afVictoria Lease            mTextPaint.setFakeBoldText(false);
27712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mTextPaint.setTextSkewX(0);
27812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            setSwitchTypeface(tf);
27912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
28012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
28112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
28212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
283150176d83023e3c486dba10edebb72af36b4099aChet Haase     * Sets the typeface in which the text should be displayed on the switch.
28412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Note that not all Typeface families actually have bold and italic
28512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * variants, so you may need to use
28612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * {@link #setSwitchTypeface(Typeface, int)} to get the appearance
28712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * that you actually want.
28812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     *
28912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @attr ref android.R.styleable#TextView_typeface
29012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @attr ref android.R.styleable#TextView_textStyle
29112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
29212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void setSwitchTypeface(Typeface tf) {
29312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (mTextPaint.getTypeface() != tf) {
29412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mTextPaint.setTypeface(tf);
29512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
29612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            requestLayout();
29712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            invalidate();
29812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
29912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
30012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
30112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
3026c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Set the amount of horizontal padding between the switch and the associated text.
3036c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3046c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @param pixels Amount of padding in pixels
3056c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3066c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_switchPadding
3076c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
3086c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public void setSwitchPadding(int pixels) {
3096c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        mSwitchPadding = pixels;
3106c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        requestLayout();
3116c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
3126c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
3136c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
3146c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Get the amount of horizontal padding between the switch and the associated text.
3156c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3166c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @return Amount of padding in pixels
3176c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3186c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_switchPadding
3196c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
3206c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public int getSwitchPadding() {
3216c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        return mSwitchPadding;
3226c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
3236c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
3246c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
3256c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Set the minimum width of the switch in pixels. The switch's width will be the maximum
3266c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * of this value and its measured width as determined by the switch drawables and text used.
3276c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3286c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @param pixels Minimum width of the switch in pixels
3296c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3306c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_switchMinWidth
3316c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
3326c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public void setSwitchMinWidth(int pixels) {
3336c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        mSwitchMinWidth = pixels;
3346c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        requestLayout();
3356c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
3366c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
3376c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
3386c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Get the minimum width of the switch in pixels. The switch's width will be the maximum
3396c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * of this value and its measured width as determined by the switch drawables and text used.
3406c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3416c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @return Minimum width of the switch in pixels
3426c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3436c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_switchMinWidth
3446c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
3456c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public int getSwitchMinWidth() {
3466c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        return mSwitchMinWidth;
3476c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
3486c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
3496c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
3506c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Set the horizontal padding around the text drawn on the switch itself.
3516c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3526c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @param pixels Horizontal padding for switch thumb text in pixels
3536c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3546c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_thumbTextPadding
3556c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
3566c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public void setThumbTextPadding(int pixels) {
3576c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        mThumbTextPadding = pixels;
3586c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        requestLayout();
3596c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
3606c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
3616c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
3626c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Get the horizontal padding around the text drawn on the switch itself.
3636c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3646c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @return Horizontal padding for switch thumb text in pixels
3656c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3666c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_thumbTextPadding
3676c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
3686c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public int getThumbTextPadding() {
3696c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        return mThumbTextPadding;
3706c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
3716c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
3726c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
3736c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Set the drawable used for the track that the switch slides within.
3746c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3756c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @param track Track drawable
3766c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3776c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_track
3786c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
3796c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public void setTrackDrawable(Drawable track) {
3806c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        mTrackDrawable = track;
3816c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        requestLayout();
3826c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
3836c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
3846c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
385d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     * Set the drawable used for the track that the switch slides within.
386d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     *
387dca510e026e3e75759bac84c3860dc84b83a608fAdam Powell     * @param resId Resource ID of a track drawable
388d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     *
389d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     * @attr ref android.R.styleable#Switch_track
390d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     */
391d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell    public void setTrackResource(int resId) {
392d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell        setTrackDrawable(getContext().getResources().getDrawable(resId));
393d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell    }
394d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell
395d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell    /**
3966c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Get the drawable used for the track that the switch slides within.
3976c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3986c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @return Track drawable
3996c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4006c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_track
4016c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
4026c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public Drawable getTrackDrawable() {
4036c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        return mTrackDrawable;
4046c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
4056c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
4066c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
4076c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Set the drawable used for the switch "thumb" - the piece that the user
4086c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * can physically touch and drag along the track.
4096c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4106c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @param thumb Thumb drawable
4116c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4126c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_thumb
4136c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
4146c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public void setThumbDrawable(Drawable thumb) {
4156c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        mThumbDrawable = thumb;
4166c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        requestLayout();
4176c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
4186c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
4196c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
420d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     * Set the drawable used for the switch "thumb" - the piece that the user
421d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     * can physically touch and drag along the track.
422d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     *
423dca510e026e3e75759bac84c3860dc84b83a608fAdam Powell     * @param resId Resource ID of a thumb drawable
424d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     *
425d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     * @attr ref android.R.styleable#Switch_thumb
426d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     */
427d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell    public void setThumbResource(int resId) {
428d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell        setThumbDrawable(getContext().getResources().getDrawable(resId));
429d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell    }
430d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell
431d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell    /**
4326c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Get the drawable used for the switch "thumb" - the piece that the user
4336c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * can physically touch and drag along the track.
4346c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4356c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @return Thumb drawable
4366c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4376c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_thumb
4386c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
4396c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public Drawable getThumbDrawable() {
4406c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        return mThumbDrawable;
4416c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
4426c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
4436c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
444150176d83023e3c486dba10edebb72af36b4099aChet Haase     * Returns the text displayed when the button is in the checked state.
4456c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4466c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_textOn
44712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
44812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public CharSequence getTextOn() {
44912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return mTextOn;
45012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
45112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
45212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
453150176d83023e3c486dba10edebb72af36b4099aChet Haase     * Sets the text displayed when the button is in the checked state.
4546c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4556c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_textOn
45612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
45712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void setTextOn(CharSequence textOn) {
45812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextOn = textOn;
45912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        requestLayout();
46012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
46112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
46212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
463150176d83023e3c486dba10edebb72af36b4099aChet Haase     * Returns the text displayed when the button is not in the checked state.
4646c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4656c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_textOff
46612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
46712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public CharSequence getTextOff() {
46812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return mTextOff;
46912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
47012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
47112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
472150176d83023e3c486dba10edebb72af36b4099aChet Haase     * Sets the text displayed when the button is not in the checked state.
4736c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4746c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_textOff
47512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
47612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void setTextOff(CharSequence textOff) {
47712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextOff = textOff;
47812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        requestLayout();
47912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
48012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
48112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
48212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
48312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (mOnLayout == null) {
48412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mOnLayout = makeLayout(mTextOn);
48512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
48612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (mOffLayout == null) {
48712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mOffLayout = makeLayout(mTextOff);
48812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
48912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
49012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTrackDrawable.getPadding(mTempRect);
49112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int maxTextWidth = Math.max(mOnLayout.getWidth(), mOffLayout.getWidth());
49212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int switchWidth = Math.max(mSwitchMinWidth,
49312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                maxTextWidth * 2 + mThumbTextPadding * 4 + mTempRect.left + mTempRect.right);
49412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int switchHeight = mTrackDrawable.getIntrinsicHeight();
49512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
49612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mThumbWidth = maxTextWidth + mThumbTextPadding * 2;
49712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
49812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchWidth = switchWidth;
49912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchHeight = switchHeight;
50012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
50112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
50212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int measuredHeight = getMeasuredHeight();
50312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (measuredHeight < switchHeight) {
504189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn            setMeasuredDimension(getMeasuredWidthAndState(), switchHeight);
50512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
50612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
50712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
50863bce03cc69be4a45230aa8bbd89dbde60681067Svetoslav Ganov    @Override
50963bce03cc69be4a45230aa8bbd89dbde60681067Svetoslav Ganov    public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
51063bce03cc69be4a45230aa8bbd89dbde60681067Svetoslav Ganov        super.onPopulateAccessibilityEvent(event);
511b8c50e8e44bb757d18fc7f069332c186099aca77Svetoslav Ganov        Layout layout =  isChecked() ? mOnLayout : mOffLayout;
512b8c50e8e44bb757d18fc7f069332c186099aca77Svetoslav Ganov        if (layout != null && !TextUtils.isEmpty(layout.getText())) {
513b8c50e8e44bb757d18fc7f069332c186099aca77Svetoslav Ganov            event.getText().add(layout.getText());
5147650259a597dd24137420d32acc35efc44db381eSvetoslav Ganov        }
51563bce03cc69be4a45230aa8bbd89dbde60681067Svetoslav Ganov    }
51663bce03cc69be4a45230aa8bbd89dbde60681067Svetoslav Ganov
51712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private Layout makeLayout(CharSequence text) {
5184c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler        final CharSequence transformed = (mSwitchTransformationMethod != null)
5194c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler                    ? mSwitchTransformationMethod.getTransformation(text, this)
5204c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler                    : text;
5214c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler
5224c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler        return new StaticLayout(transformed, mTextPaint,
5234c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler                (int) Math.ceil(Layout.getDesiredWidth(transformed, mTextPaint)),
52412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                Layout.Alignment.ALIGN_NORMAL, 1.f, 0, true);
52512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
52612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
52712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
52812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @return true if (x, y) is within the target area of the switch thumb
52912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
53012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private boolean hitThumb(float x, float y) {
53112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mThumbDrawable.getPadding(mTempRect);
53212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int thumbTop = mSwitchTop - mTouchSlop;
53312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int thumbLeft = mSwitchLeft + (int) (mThumbPosition + 0.5f) - mTouchSlop;
53412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int thumbRight = thumbLeft + mThumbWidth +
53512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                mTempRect.left + mTempRect.right + mTouchSlop;
53612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int thumbBottom = mSwitchBottom + mTouchSlop;
53712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return x > thumbLeft && x < thumbRight && y > thumbTop && y < thumbBottom;
53812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
53912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
54012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
54112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public boolean onTouchEvent(MotionEvent ev) {
54212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mVelocityTracker.addMovement(ev);
54312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int action = ev.getActionMasked();
54412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        switch (action) {
54512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MotionEvent.ACTION_DOWN: {
54612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                final float x = ev.getX();
54712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                final float y = ev.getY();
548c2ab0d665c9d1c332fbd726abf582a27cf7a6701Gilles Debunne                if (isEnabled() && hitThumb(x, y)) {
54912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    mTouchMode = TOUCH_MODE_DOWN;
55012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    mTouchX = x;
55112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    mTouchY = y;
55212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                }
55312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
55412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
55512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
55612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MotionEvent.ACTION_MOVE: {
55712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switch (mTouchMode) {
55812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    case TOUCH_MODE_IDLE:
55912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        // Didn't target the thumb, treat normally.
56012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        break;
56112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
56212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    case TOUCH_MODE_DOWN: {
56312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        final float x = ev.getX();
56412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        final float y = ev.getY();
56512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        if (Math.abs(x - mTouchX) > mTouchSlop ||
56612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                                Math.abs(y - mTouchY) > mTouchSlop) {
56712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            mTouchMode = TOUCH_MODE_DRAGGING;
56812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            getParent().requestDisallowInterceptTouchEvent(true);
56912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            mTouchX = x;
57012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            mTouchY = y;
57112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            return true;
57212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        }
57312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        break;
57412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    }
57512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
57612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    case TOUCH_MODE_DRAGGING: {
57712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        final float x = ev.getX();
57812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        final float dx = x - mTouchX;
57912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        float newPos = Math.max(0,
58012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                                Math.min(mThumbPosition + dx, getThumbScrollRange()));
58112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        if (newPos != mThumbPosition) {
58212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            mThumbPosition = newPos;
58312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            mTouchX = x;
58412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            invalidate();
58512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        }
58612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        return true;
58712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    }
58812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                }
58912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
59012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
59112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
59212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MotionEvent.ACTION_UP:
59312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MotionEvent.ACTION_CANCEL: {
59412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                if (mTouchMode == TOUCH_MODE_DRAGGING) {
59512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    stopDrag(ev);
59612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    return true;
59712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                }
59812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                mTouchMode = TOUCH_MODE_IDLE;
59912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                mVelocityTracker.clear();
60012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
60112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
60212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
60312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
60412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return super.onTouchEvent(ev);
60512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
60612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
60712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private void cancelSuperTouch(MotionEvent ev) {
60812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        MotionEvent cancel = MotionEvent.obtain(ev);
60912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        cancel.setAction(MotionEvent.ACTION_CANCEL);
61012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.onTouchEvent(cancel);
61112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        cancel.recycle();
61212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
61312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
61412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
61512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Called from onTouchEvent to end a drag operation.
61612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     *
61712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param ev Event that triggered the end of drag mode - ACTION_UP or ACTION_CANCEL
61812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
61912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private void stopDrag(MotionEvent ev) {
62012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTouchMode = TOUCH_MODE_IDLE;
621c2ab0d665c9d1c332fbd726abf582a27cf7a6701Gilles Debunne        // Up and not canceled, also checks the switch has not been disabled during the drag
622c2ab0d665c9d1c332fbd726abf582a27cf7a6701Gilles Debunne        boolean commitChange = ev.getAction() == MotionEvent.ACTION_UP && isEnabled();
62312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
62412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        cancelSuperTouch(ev);
62512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
62612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (commitChange) {
62712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            boolean newState;
62812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mVelocityTracker.computeCurrentVelocity(1000);
62912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            float xvel = mVelocityTracker.getXVelocity();
63012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            if (Math.abs(xvel) > mMinFlingVelocity) {
63128efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio                newState = isLayoutRtl() ? (xvel < 0) : (xvel > 0);
63212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            } else {
63312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                newState = getTargetCheckedState();
63412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
63512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            animateThumbToCheckedState(newState);
63612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        } else {
63712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            animateThumbToCheckedState(isChecked());
63812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
63912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
64012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
64112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private void animateThumbToCheckedState(boolean newCheckedState) {
64212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        // TODO animate!
643c3eabb9b6ce7f556313c8e3870d76c5b443f1c51Joe Onorato        //float targetPos = newCheckedState ? 0 : getThumbScrollRange();
644c3eabb9b6ce7f556313c8e3870d76c5b443f1c51Joe Onorato        //mThumbPosition = targetPos;
64512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        setChecked(newCheckedState);
64612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
64712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
64812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private boolean getTargetCheckedState() {
64928efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        if (isLayoutRtl()) {
65028efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio            return mThumbPosition <= getThumbScrollRange() / 2;
65128efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        } else {
65228efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio            return mThumbPosition >= getThumbScrollRange() / 2;
65328efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        }
65428efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio    }
65528efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio
65628efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio    private void setThumbPosition(boolean checked) {
65728efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        if (isLayoutRtl()) {
65828efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio            mThumbPosition = checked ? 0 : getThumbScrollRange();
65928efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        } else {
66028efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio            mThumbPosition = checked ? getThumbScrollRange() : 0;
66128efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        }
66212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
66312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
66412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
66512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void setChecked(boolean checked) {
66612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.setChecked(checked);
667acbbd1142db522b15d06d6a1e076463e5c55c8b3Jean-Baptiste Queru        setThumbPosition(isChecked());
668c3eabb9b6ce7f556313c8e3870d76c5b443f1c51Joe Onorato        invalidate();
66912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
67012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
67112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
67212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
67312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.onLayout(changed, left, top, right, bottom);
67412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
67528efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        setThumbPosition(isChecked());
67628efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio
67728efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        int switchRight;
67828efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        int switchLeft;
67928efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio
68028efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        if (isLayoutRtl()) {
68128efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio            switchLeft = getPaddingLeft();
68228efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio            switchRight = switchLeft + mSwitchWidth;
68328efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        } else {
68428efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio            switchRight = getWidth() - getPaddingRight();
68528efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio            switchLeft = switchRight - mSwitchWidth;
68628efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        }
687c3eabb9b6ce7f556313c8e3870d76c5b443f1c51Joe Onorato
68812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int switchTop = 0;
68912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int switchBottom = 0;
69012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        switch (getGravity() & Gravity.VERTICAL_GRAVITY_MASK) {
69112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            default:
69212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case Gravity.TOP:
69312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchTop = getPaddingTop();
69412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchBottom = switchTop + mSwitchHeight;
69512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
69612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
69712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case Gravity.CENTER_VERTICAL:
69812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchTop = (getPaddingTop() + getHeight() - getPaddingBottom()) / 2 -
69912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        mSwitchHeight / 2;
70012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchBottom = switchTop + mSwitchHeight;
70112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
70212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
70312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case Gravity.BOTTOM:
70412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchBottom = getHeight() - getPaddingBottom();
70512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchTop = switchBottom - mSwitchHeight;
70612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
70712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
70812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
70912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchLeft = switchLeft;
71012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchTop = switchTop;
71112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchBottom = switchBottom;
71212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchRight = switchRight;
71312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
71412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
71512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
71612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    protected void onDraw(Canvas canvas) {
71712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.onDraw(canvas);
71812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
71912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        // Draw the switch
72012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int switchLeft = mSwitchLeft;
72112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int switchTop = mSwitchTop;
72212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int switchRight = mSwitchRight;
72312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int switchBottom = mSwitchBottom;
72412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
72512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTrackDrawable.setBounds(switchLeft, switchTop, switchRight, switchBottom);
72612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTrackDrawable.draw(canvas);
72712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
72812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        canvas.save();
72912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
73012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTrackDrawable.getPadding(mTempRect);
73112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int switchInnerLeft = switchLeft + mTempRect.left;
73212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int switchInnerTop = switchTop + mTempRect.top;
73312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int switchInnerRight = switchRight - mTempRect.right;
73412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int switchInnerBottom = switchBottom - mTempRect.bottom;
73512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        canvas.clipRect(switchInnerLeft, switchTop, switchInnerRight, switchBottom);
73612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
73712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mThumbDrawable.getPadding(mTempRect);
73812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int thumbPos = (int) (mThumbPosition + 0.5f);
73912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int thumbLeft = switchInnerLeft - mTempRect.left + thumbPos;
74012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int thumbRight = switchInnerLeft + thumbPos + mThumbWidth + mTempRect.right;
74112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
74212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mThumbDrawable.setBounds(thumbLeft, switchTop, thumbRight, switchBottom);
74312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mThumbDrawable.draw(canvas);
74412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
745150176d83023e3c486dba10edebb72af36b4099aChet Haase        // mTextColors should not be null, but just in case
746150176d83023e3c486dba10edebb72af36b4099aChet Haase        if (mTextColors != null) {
747150176d83023e3c486dba10edebb72af36b4099aChet Haase            mTextPaint.setColor(mTextColors.getColorForState(getDrawableState(),
748150176d83023e3c486dba10edebb72af36b4099aChet Haase                    mTextColors.getDefaultColor()));
749150176d83023e3c486dba10edebb72af36b4099aChet Haase        }
75012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextPaint.drawableState = getDrawableState();
75112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
75212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        Layout switchText = getTargetCheckedState() ? mOnLayout : mOffLayout;
753be06e3292b295324b3b47d13f9a40787b666309fFabrice Di Meglio        if (switchText != null) {
754be06e3292b295324b3b47d13f9a40787b666309fFabrice Di Meglio            canvas.translate((thumbLeft + thumbRight) / 2 - switchText.getWidth() / 2,
755be06e3292b295324b3b47d13f9a40787b666309fFabrice Di Meglio                    (switchInnerTop + switchInnerBottom) / 2 - switchText.getHeight() / 2);
756be06e3292b295324b3b47d13f9a40787b666309fFabrice Di Meglio            switchText.draw(canvas);
757be06e3292b295324b3b47d13f9a40787b666309fFabrice Di Meglio        }
75812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
75912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        canvas.restore();
76012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
76112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
76212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
76328efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio    public int getCompoundPaddingLeft() {
76428efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        if (!isLayoutRtl()) {
76528efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio            return super.getCompoundPaddingLeft();
76628efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        }
76728efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        int padding = super.getCompoundPaddingLeft() + mSwitchWidth;
76828efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        if (!TextUtils.isEmpty(getText())) {
76928efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio            padding += mSwitchPadding;
77028efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        }
77128efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        return padding;
77228efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio    }
77328efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio
77428efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio    @Override
77512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public int getCompoundPaddingRight() {
77628efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        if (isLayoutRtl()) {
77728efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio            return super.getCompoundPaddingRight();
77828efba38c07c78f4a349d599b7ad3d7b517c5e97Fabrice Di Meglio        }
77912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int padding = super.getCompoundPaddingRight() + mSwitchWidth;
78012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (!TextUtils.isEmpty(getText())) {
78112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            padding += mSwitchPadding;
78212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
78312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return padding;
78412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
78512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
78612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int getThumbScrollRange() {
78712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (mTrackDrawable == null) {
78812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            return 0;
78912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
79012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTrackDrawable.getPadding(mTempRect);
79112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return mSwitchWidth - mThumbWidth - mTempRect.left - mTempRect.right;
79212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
79312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
79412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
79512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    protected int[] onCreateDrawableState(int extraSpace) {
79612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
79712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (isChecked()) {
79812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mergeDrawableStates(drawableState, CHECKED_STATE_SET);
79912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
80012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return drawableState;
80112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
80212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
80312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
80412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    protected void drawableStateChanged() {
80512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.drawableStateChanged();
80612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
80712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int[] myDrawableState = getDrawableState();
80812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
80912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        // Set the state of the Drawable
810e724ee4b04d121556e9764f72f9b921a0e16392aGilles Debunne        // Drawable may be null when checked state is set from XML, from super constructor
811e724ee4b04d121556e9764f72f9b921a0e16392aGilles Debunne        if (mThumbDrawable != null) mThumbDrawable.setState(myDrawableState);
812e724ee4b04d121556e9764f72f9b921a0e16392aGilles Debunne        if (mTrackDrawable != null) mTrackDrawable.setState(myDrawableState);
81312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
81412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        invalidate();
81512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
81612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
81712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
81812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    protected boolean verifyDrawable(Drawable who) {
81912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return super.verifyDrawable(who) || who == mThumbDrawable || who == mTrackDrawable;
82012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
82112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
82212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
82312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void jumpDrawablesToCurrentState() {
82412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.jumpDrawablesToCurrentState();
82512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mThumbDrawable.jumpToCurrentState();
82612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTrackDrawable.jumpToCurrentState();
82712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
8288a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov
8298a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    @Override
8308a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
8318a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        super.onInitializeAccessibilityEvent(event);
8328a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        event.setClassName(Switch.class.getName());
8338a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    }
8348a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov
8358a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    @Override
8368a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
8378a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        super.onInitializeAccessibilityNodeInfo(info);
8388a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        info.setClassName(Switch.class.getName());
83978bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov        CharSequence switchText = isChecked() ? mTextOn : mTextOff;
84078bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov        if (!TextUtils.isEmpty(switchText)) {
84178bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov            CharSequence oldText = info.getText();
84278bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov            if (TextUtils.isEmpty(oldText)) {
84378bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov                info.setText(switchText);
84478bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov            } else {
84578bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov                StringBuilder newText = new StringBuilder();
84678bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov                newText.append(oldText).append(' ').append(switchText);
84778bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov                info.setText(newText);
84878bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov            }
84978bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov        }
8508a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    }
85112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell}
852