Switch.java revision 78bcc15b6c5959cc3eb9bbe2459af93451b74a22
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;
3212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.util.AttributeSet;
3312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.view.Gravity;
3412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.view.MotionEvent;
3512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.view.VelocityTracker;
3612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellimport android.view.ViewConfiguration;
3763bce03cc69be4a45230aa8bbd89dbde60681067Svetoslav Ganovimport android.view.accessibility.AccessibilityEvent;
388a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganovimport android.view.accessibility.AccessibilityNodeInfo;
3912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
40be0a4535053bbfdebd215e244b154ac810fd8edcAdam Powellimport com.android.internal.R;
41be0a4535053bbfdebd215e244b154ac810fd8edcAdam Powell
4212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell/**
4312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell * A Switch is a two-state toggle switch widget that can select between two
4412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell * options. The user may drag the "thumb" back and forth to choose the selected option,
45150176d83023e3c486dba10edebb72af36b4099aChet Haase * or simply tap to toggle as if it were a checkbox. The {@link #setText(CharSequence) text}
46150176d83023e3c486dba10edebb72af36b4099aChet Haase * property controls the text displayed in the label for the switch, whereas the
47150176d83023e3c486dba10edebb72af36b4099aChet Haase * {@link #setTextOff(CharSequence) off} and {@link #setTextOn(CharSequence) on} text
48150176d83023e3c486dba10edebb72af36b4099aChet Haase * controls the text on the thumb. Similarly, the
49150176d83023e3c486dba10edebb72af36b4099aChet Haase * {@link #setTextAppearance(android.content.Context, int) textAppearance} and the related
50150176d83023e3c486dba10edebb72af36b4099aChet Haase * setTypeface() methods control the typeface and style of label text, whereas the
51150176d83023e3c486dba10edebb72af36b4099aChet Haase * {@link #setSwitchTextAppearance(android.content.Context, int) switchTextAppearance} and
52150176d83023e3c486dba10edebb72af36b4099aChet Haase * the related seSwitchTypeface() methods control that of the thumb.
5312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell *
5412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell */
5512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellpublic class Switch extends CompoundButton {
5612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int TOUCH_MODE_IDLE = 0;
5712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int TOUCH_MODE_DOWN = 1;
5812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int TOUCH_MODE_DRAGGING = 2;
5912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
6012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    // Enum for the "typeface" XML parameter.
6112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int SANS = 1;
6212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int SERIF = 2;
6312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int MONOSPACE = 3;
6412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
6512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private Drawable mThumbDrawable;
6612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private Drawable mTrackDrawable;
6712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mThumbTextPadding;
6812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchMinWidth;
6912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchPadding;
7012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private CharSequence mTextOn;
7112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private CharSequence mTextOff;
7212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
7312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mTouchMode;
7412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mTouchSlop;
7512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private float mTouchX;
7612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private float mTouchY;
7712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private VelocityTracker mVelocityTracker = VelocityTracker.obtain();
7812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mMinFlingVelocity;
7912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
8012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private float mThumbPosition;
8112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchWidth;
8212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchHeight;
8312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mThumbWidth; // Does not include padding
8412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
8512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchLeft;
8612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchTop;
8712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchRight;
8812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchBottom;
8912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
9012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private TextPaint mTextPaint;
9112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private ColorStateList mTextColors;
9212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private Layout mOnLayout;
9312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private Layout mOffLayout;
9412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
95be0a4535053bbfdebd215e244b154ac810fd8edcAdam Powell    @SuppressWarnings("hiding")
9612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private final Rect mTempRect = new Rect();
9712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
9812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int[] CHECKED_STATE_SET = {
9912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        R.attr.state_checked
10012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    };
10112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
10212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
10312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Construct a new Switch with default styling.
10412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     *
10512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param context The Context that will determine this widget's theming.
10612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
10712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public Switch(Context context) {
10812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        this(context, null);
10912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
11012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
11112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
11212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Construct a new Switch with default styling, overriding specific style
11312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * attributes as requested.
11412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     *
11512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param context The Context that will determine this widget's theming.
11612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param attrs Specification of attributes that should deviate from default styling.
11712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
11812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public Switch(Context context, AttributeSet attrs) {
11912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        this(context, attrs, com.android.internal.R.attr.switchStyle);
12012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
12112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
12212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
12312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Construct a new Switch with a default style determined by the given theme attribute,
12412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * overriding specific style attributes as requested.
12512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     *
12612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param context The Context that will determine this widget's theming.
12712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param attrs Specification of attributes that should deviate from the default styling.
12812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param defStyle An attribute ID within the active theme containing a reference to the
12912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     *                 default style for this widget. e.g. android.R.attr.switchStyle.
13012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
13112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public Switch(Context context, AttributeSet attrs, int defStyle) {
13212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super(context, attrs, defStyle);
13312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
13412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
13512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        Resources res = getResources();
13612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextPaint.density = res.getDisplayMetrics().density;
13712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextPaint.setCompatibilityScaling(res.getCompatibilityInfo().applicationScale);
13812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
13912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        TypedArray a = context.obtainStyledAttributes(attrs,
14012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                com.android.internal.R.styleable.Switch, defStyle, 0);
14112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
142150176d83023e3c486dba10edebb72af36b4099aChet Haase        mThumbDrawable = a.getDrawable(com.android.internal.R.styleable.Switch_thumb);
143150176d83023e3c486dba10edebb72af36b4099aChet Haase        mTrackDrawable = a.getDrawable(com.android.internal.R.styleable.Switch_track);
14412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextOn = a.getText(com.android.internal.R.styleable.Switch_textOn);
14512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextOff = a.getText(com.android.internal.R.styleable.Switch_textOff);
14612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mThumbTextPadding = a.getDimensionPixelSize(
14712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                com.android.internal.R.styleable.Switch_thumbTextPadding, 0);
14812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchMinWidth = a.getDimensionPixelSize(
14912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                com.android.internal.R.styleable.Switch_switchMinWidth, 0);
15012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchPadding = a.getDimensionPixelSize(
15112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                com.android.internal.R.styleable.Switch_switchPadding, 0);
15212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
15312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int appearance = a.getResourceId(
15412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                com.android.internal.R.styleable.Switch_switchTextAppearance, 0);
15512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (appearance != 0) {
156150176d83023e3c486dba10edebb72af36b4099aChet Haase            setSwitchTextAppearance(context, appearance);
15712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
15812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        a.recycle();
15912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
16012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        ViewConfiguration config = ViewConfiguration.get(context);
16112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTouchSlop = config.getScaledTouchSlop();
16212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mMinFlingVelocity = config.getScaledMinimumFlingVelocity();
16312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
16412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        // Refresh display with current params
165e724ee4b04d121556e9764f72f9b921a0e16392aGilles Debunne        refreshDrawableState();
16612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        setChecked(isChecked());
16712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
16812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
16912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
17012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Sets the switch text color, size, style, hint color, and highlight color
17112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * from the specified TextAppearance resource.
1726c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
1736c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_switchTextAppearance
17412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
175150176d83023e3c486dba10edebb72af36b4099aChet Haase    public void setSwitchTextAppearance(Context context, int resid) {
17612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        TypedArray appearance =
177150176d83023e3c486dba10edebb72af36b4099aChet Haase                context.obtainStyledAttributes(resid,
17812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        com.android.internal.R.styleable.TextAppearance);
17912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
18012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        ColorStateList colors;
18112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int ts;
18212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
18312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        colors = appearance.getColorStateList(com.android.internal.R.styleable.
18412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                TextAppearance_textColor);
18512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (colors != null) {
18612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mTextColors = colors;
187150176d83023e3c486dba10edebb72af36b4099aChet Haase        } else {
188150176d83023e3c486dba10edebb72af36b4099aChet Haase            // If no color set in TextAppearance, default to the view's textColor
189150176d83023e3c486dba10edebb72af36b4099aChet Haase            mTextColors = getTextColors();
19012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
19112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
19212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        ts = appearance.getDimensionPixelSize(com.android.internal.R.styleable.
19312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                TextAppearance_textSize, 0);
19412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (ts != 0) {
19512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            if (ts != mTextPaint.getTextSize()) {
19612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                mTextPaint.setTextSize(ts);
19712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                requestLayout();
19812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
19912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
20012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
20112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int typefaceIndex, styleIndex;
20212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
20312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        typefaceIndex = appearance.getInt(com.android.internal.R.styleable.
20412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                TextAppearance_typeface, -1);
20512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        styleIndex = appearance.getInt(com.android.internal.R.styleable.
20612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                TextAppearance_textStyle, -1);
20712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
20812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        setSwitchTypefaceByIndex(typefaceIndex, styleIndex);
20912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
21012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        appearance.recycle();
21112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
21212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
21312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private void setSwitchTypefaceByIndex(int typefaceIndex, int styleIndex) {
21412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        Typeface tf = null;
21512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        switch (typefaceIndex) {
21612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case SANS:
21712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                tf = Typeface.SANS_SERIF;
21812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
21912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
22012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case SERIF:
22112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                tf = Typeface.SERIF;
22212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
22312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
22412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MONOSPACE:
22512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                tf = Typeface.MONOSPACE;
22612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
22712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
22812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
22912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        setSwitchTypeface(tf, styleIndex);
23012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
23112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
23212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
23312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Sets the typeface and style in which the text should be displayed on the
23412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * switch, and turns on the fake bold and italic bits in the Paint if the
23512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Typeface that you provided does not have all the bits in the
23612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * style that you specified.
23712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
23812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void setSwitchTypeface(Typeface tf, int style) {
23912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (style > 0) {
24012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            if (tf == null) {
24112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                tf = Typeface.defaultFromStyle(style);
24212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            } else {
24312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                tf = Typeface.create(tf, style);
24412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
24512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
24612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            setSwitchTypeface(tf);
24712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            // now compute what (if any) algorithmic styling is needed
24812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            int typefaceStyle = tf != null ? tf.getStyle() : 0;
24912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            int need = style & ~typefaceStyle;
25012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mTextPaint.setFakeBoldText((need & Typeface.BOLD) != 0);
25112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mTextPaint.setTextSkewX((need & Typeface.ITALIC) != 0 ? -0.25f : 0);
25212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        } else {
25312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mTextPaint.setFakeBoldText(false);
25412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mTextPaint.setTextSkewX(0);
25512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            setSwitchTypeface(tf);
25612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
25712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
25812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
25912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
260150176d83023e3c486dba10edebb72af36b4099aChet Haase     * Sets the typeface in which the text should be displayed on the switch.
26112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Note that not all Typeface families actually have bold and italic
26212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * variants, so you may need to use
26312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * {@link #setSwitchTypeface(Typeface, int)} to get the appearance
26412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * that you actually want.
26512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     *
26612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @attr ref android.R.styleable#TextView_typeface
26712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @attr ref android.R.styleable#TextView_textStyle
26812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
26912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void setSwitchTypeface(Typeface tf) {
27012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (mTextPaint.getTypeface() != tf) {
27112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mTextPaint.setTypeface(tf);
27212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
27312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            requestLayout();
27412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            invalidate();
27512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
27612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
27712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
27812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
2796c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Set the amount of horizontal padding between the switch and the associated text.
2806c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
2816c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @param pixels Amount of padding in pixels
2826c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
2836c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_switchPadding
2846c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
2856c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public void setSwitchPadding(int pixels) {
2866c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        mSwitchPadding = pixels;
2876c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        requestLayout();
2886c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
2896c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
2906c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
2916c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Get the amount of horizontal padding between the switch and the associated text.
2926c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
2936c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @return Amount of padding in pixels
2946c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
2956c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_switchPadding
2966c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
2976c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public int getSwitchPadding() {
2986c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        return mSwitchPadding;
2996c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
3006c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
3016c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
3026c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Set the minimum width of the switch in pixels. The switch's width will be the maximum
3036c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * of this value and its measured width as determined by the switch drawables and text used.
3046c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3056c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @param pixels Minimum width of the switch in pixels
3066c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3076c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_switchMinWidth
3086c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
3096c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public void setSwitchMinWidth(int pixels) {
3106c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        mSwitchMinWidth = pixels;
3116c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        requestLayout();
3126c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
3136c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
3146c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
3156c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Get the minimum width of the switch in pixels. The switch's width will be the maximum
3166c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * of this value and its measured width as determined by the switch drawables and text used.
3176c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3186c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @return Minimum width of the switch in pixels
3196c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3206c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_switchMinWidth
3216c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
3226c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public int getSwitchMinWidth() {
3236c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        return mSwitchMinWidth;
3246c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
3256c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
3266c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
3276c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Set the horizontal padding around the text drawn on the switch itself.
3286c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3296c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @param pixels Horizontal padding for switch thumb text in pixels
3306c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3316c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_thumbTextPadding
3326c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
3336c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public void setThumbTextPadding(int pixels) {
3346c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        mThumbTextPadding = pixels;
3356c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        requestLayout();
3366c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
3376c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
3386c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
3396c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Get the horizontal padding around the text drawn on the switch itself.
3406c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3416c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @return Horizontal padding for switch thumb text in pixels
3426c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3436c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_thumbTextPadding
3446c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
3456c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public int getThumbTextPadding() {
3466c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        return mThumbTextPadding;
3476c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
3486c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
3496c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
3506c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Set the drawable used for the track that the switch slides within.
3516c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3526c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @param track Track drawable
3536c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3546c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_track
3556c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
3566c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public void setTrackDrawable(Drawable track) {
3576c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        mTrackDrawable = track;
3586c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        requestLayout();
3596c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
3606c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
3616c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
362d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     * Set the drawable used for the track that the switch slides within.
363d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     *
364dca510e026e3e75759bac84c3860dc84b83a608fAdam Powell     * @param resId Resource ID of a track drawable
365d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     *
366d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     * @attr ref android.R.styleable#Switch_track
367d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     */
368d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell    public void setTrackResource(int resId) {
369d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell        setTrackDrawable(getContext().getResources().getDrawable(resId));
370d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell    }
371d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell
372d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell    /**
3736c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Get the drawable used for the track that the switch slides within.
3746c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3756c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @return Track drawable
3766c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3776c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_track
3786c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
3796c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public Drawable getTrackDrawable() {
3806c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        return mTrackDrawable;
3816c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
3826c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
3836c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
3846c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Set the drawable used for the switch "thumb" - the piece that the user
3856c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * can physically touch and drag along the track.
3866c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3876c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @param thumb Thumb drawable
3886c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3896c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_thumb
3906c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
3916c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public void setThumbDrawable(Drawable thumb) {
3926c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        mThumbDrawable = thumb;
3936c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        requestLayout();
3946c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
3956c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
3966c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
397d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     * Set the drawable used for the switch "thumb" - the piece that the user
398d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     * can physically touch and drag along the track.
399d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     *
400dca510e026e3e75759bac84c3860dc84b83a608fAdam Powell     * @param resId Resource ID of a thumb drawable
401d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     *
402d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     * @attr ref android.R.styleable#Switch_thumb
403d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     */
404d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell    public void setThumbResource(int resId) {
405d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell        setThumbDrawable(getContext().getResources().getDrawable(resId));
406d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell    }
407d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell
408d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell    /**
4096c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Get the drawable used for the switch "thumb" - the piece that the user
4106c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * can physically touch and drag along the track.
4116c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4126c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @return Thumb drawable
4136c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4146c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_thumb
4156c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
4166c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public Drawable getThumbDrawable() {
4176c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        return mThumbDrawable;
4186c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
4196c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
4206c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
421150176d83023e3c486dba10edebb72af36b4099aChet Haase     * Returns the text displayed when the button is in the checked state.
4226c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4236c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_textOn
42412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
42512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public CharSequence getTextOn() {
42612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return mTextOn;
42712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
42812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
42912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
430150176d83023e3c486dba10edebb72af36b4099aChet Haase     * Sets the text displayed when the button is in the checked state.
4316c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4326c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_textOn
43312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
43412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void setTextOn(CharSequence textOn) {
43512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextOn = textOn;
43612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        requestLayout();
43712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
43812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
43912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
440150176d83023e3c486dba10edebb72af36b4099aChet Haase     * Returns the text displayed when the button is not in the checked state.
4416c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4426c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_textOff
44312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
44412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public CharSequence getTextOff() {
44512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return mTextOff;
44612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
44712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
44812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
449150176d83023e3c486dba10edebb72af36b4099aChet Haase     * Sets the text displayed when the button is not in the checked state.
4506c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4516c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_textOff
45212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
45312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void setTextOff(CharSequence textOff) {
45412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextOff = textOff;
45512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        requestLayout();
45612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
45712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
45812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
45912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
46012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
46112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
46212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
46312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
46412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
46512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
46612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (mOnLayout == null) {
46712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mOnLayout = makeLayout(mTextOn);
46812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
46912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (mOffLayout == null) {
47012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mOffLayout = makeLayout(mTextOff);
47112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
47212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
47312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTrackDrawable.getPadding(mTempRect);
47412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int maxTextWidth = Math.max(mOnLayout.getWidth(), mOffLayout.getWidth());
47512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int switchWidth = Math.max(mSwitchMinWidth,
47612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                maxTextWidth * 2 + mThumbTextPadding * 4 + mTempRect.left + mTempRect.right);
47712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int switchHeight = mTrackDrawable.getIntrinsicHeight();
47812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
47912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mThumbWidth = maxTextWidth + mThumbTextPadding * 2;
48012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
48112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        switch (widthMode) {
48212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MeasureSpec.AT_MOST:
48312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                widthSize = Math.min(widthSize, switchWidth);
48412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
48512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
48612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MeasureSpec.UNSPECIFIED:
48712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                widthSize = switchWidth;
48812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
48912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
49012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MeasureSpec.EXACTLY:
49112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                // Just use what we were given
49212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
49312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
49412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
49512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        switch (heightMode) {
49612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MeasureSpec.AT_MOST:
49712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                heightSize = Math.min(heightSize, switchHeight);
49812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
49912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
50012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MeasureSpec.UNSPECIFIED:
50112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                heightSize = switchHeight;
50212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
50312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
50412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MeasureSpec.EXACTLY:
50512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                // Just use what we were given
50612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
50712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
50812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
50912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchWidth = switchWidth;
51012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchHeight = switchHeight;
51112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
51212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
51312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int measuredHeight = getMeasuredHeight();
51412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (measuredHeight < switchHeight) {
515189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn            setMeasuredDimension(getMeasuredWidthAndState(), switchHeight);
51612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
51712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
51812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
51963bce03cc69be4a45230aa8bbd89dbde60681067Svetoslav Ganov    @Override
52063bce03cc69be4a45230aa8bbd89dbde60681067Svetoslav Ganov    public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
52163bce03cc69be4a45230aa8bbd89dbde60681067Svetoslav Ganov        super.onPopulateAccessibilityEvent(event);
52255249c8601e04928d4e8afb17233596a3ed4e0ceSvetoslav Ganov        CharSequence text = isChecked() ? mOnLayout.getText() : mOffLayout.getText();
52355249c8601e04928d4e8afb17233596a3ed4e0ceSvetoslav Ganov        if (!TextUtils.isEmpty(text)) {
5247650259a597dd24137420d32acc35efc44db381eSvetoslav Ganov            event.getText().add(text);
5257650259a597dd24137420d32acc35efc44db381eSvetoslav Ganov        }
52663bce03cc69be4a45230aa8bbd89dbde60681067Svetoslav Ganov    }
52763bce03cc69be4a45230aa8bbd89dbde60681067Svetoslav Ganov
52812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private Layout makeLayout(CharSequence text) {
52912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return new StaticLayout(text, mTextPaint,
53012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                (int) Math.ceil(Layout.getDesiredWidth(text, mTextPaint)),
53112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                Layout.Alignment.ALIGN_NORMAL, 1.f, 0, true);
53212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
53312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
53412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
53512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @return true if (x, y) is within the target area of the switch thumb
53612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
53712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private boolean hitThumb(float x, float y) {
53812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mThumbDrawable.getPadding(mTempRect);
53912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int thumbTop = mSwitchTop - mTouchSlop;
54012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int thumbLeft = mSwitchLeft + (int) (mThumbPosition + 0.5f) - mTouchSlop;
54112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int thumbRight = thumbLeft + mThumbWidth +
54212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                mTempRect.left + mTempRect.right + mTouchSlop;
54312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int thumbBottom = mSwitchBottom + mTouchSlop;
54412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return x > thumbLeft && x < thumbRight && y > thumbTop && y < thumbBottom;
54512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
54612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
54712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
54812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public boolean onTouchEvent(MotionEvent ev) {
54912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mVelocityTracker.addMovement(ev);
55012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int action = ev.getActionMasked();
55112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        switch (action) {
55212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MotionEvent.ACTION_DOWN: {
55312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                final float x = ev.getX();
55412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                final float y = ev.getY();
555c2ab0d665c9d1c332fbd726abf582a27cf7a6701Gilles Debunne                if (isEnabled() && hitThumb(x, y)) {
55612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    mTouchMode = TOUCH_MODE_DOWN;
55712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    mTouchX = x;
55812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    mTouchY = y;
55912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                }
56012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
56112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
56212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
56312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MotionEvent.ACTION_MOVE: {
56412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switch (mTouchMode) {
56512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    case TOUCH_MODE_IDLE:
56612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        // Didn't target the thumb, treat normally.
56712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        break;
56812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
56912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    case TOUCH_MODE_DOWN: {
57012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        final float x = ev.getX();
57112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        final float y = ev.getY();
57212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        if (Math.abs(x - mTouchX) > mTouchSlop ||
57312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                                Math.abs(y - mTouchY) > mTouchSlop) {
57412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            mTouchMode = TOUCH_MODE_DRAGGING;
57512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            getParent().requestDisallowInterceptTouchEvent(true);
57612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            mTouchX = x;
57712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            mTouchY = y;
57812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            return true;
57912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        }
58012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        break;
58112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    }
58212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
58312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    case TOUCH_MODE_DRAGGING: {
58412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        final float x = ev.getX();
58512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        final float dx = x - mTouchX;
58612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        float newPos = Math.max(0,
58712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                                Math.min(mThumbPosition + dx, getThumbScrollRange()));
58812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        if (newPos != mThumbPosition) {
58912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            mThumbPosition = newPos;
59012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            mTouchX = x;
59112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            invalidate();
59212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        }
59312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        return true;
59412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    }
59512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                }
59612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
59712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
59812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
59912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MotionEvent.ACTION_UP:
60012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MotionEvent.ACTION_CANCEL: {
60112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                if (mTouchMode == TOUCH_MODE_DRAGGING) {
60212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    stopDrag(ev);
60312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    return true;
60412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                }
60512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                mTouchMode = TOUCH_MODE_IDLE;
60612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                mVelocityTracker.clear();
60712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
60812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
60912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
61012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
61112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return super.onTouchEvent(ev);
61212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
61312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
61412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private void cancelSuperTouch(MotionEvent ev) {
61512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        MotionEvent cancel = MotionEvent.obtain(ev);
61612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        cancel.setAction(MotionEvent.ACTION_CANCEL);
61712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.onTouchEvent(cancel);
61812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        cancel.recycle();
61912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
62012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
62112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
62212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Called from onTouchEvent to end a drag operation.
62312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     *
62412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param ev Event that triggered the end of drag mode - ACTION_UP or ACTION_CANCEL
62512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
62612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private void stopDrag(MotionEvent ev) {
62712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTouchMode = TOUCH_MODE_IDLE;
628c2ab0d665c9d1c332fbd726abf582a27cf7a6701Gilles Debunne        // Up and not canceled, also checks the switch has not been disabled during the drag
629c2ab0d665c9d1c332fbd726abf582a27cf7a6701Gilles Debunne        boolean commitChange = ev.getAction() == MotionEvent.ACTION_UP && isEnabled();
63012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
63112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        cancelSuperTouch(ev);
63212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
63312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (commitChange) {
63412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            boolean newState;
63512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mVelocityTracker.computeCurrentVelocity(1000);
63612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            float xvel = mVelocityTracker.getXVelocity();
63712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            if (Math.abs(xvel) > mMinFlingVelocity) {
63801d11edc1ea2c495ba4bd6bbea8ba7bb7f597678Adam Powell                newState = xvel > 0;
63912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            } else {
64012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                newState = getTargetCheckedState();
64112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
64212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            animateThumbToCheckedState(newState);
64312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        } else {
64412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            animateThumbToCheckedState(isChecked());
64512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
64612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
64712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
64812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private void animateThumbToCheckedState(boolean newCheckedState) {
64912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        // TODO animate!
650c3eabb9b6ce7f556313c8e3870d76c5b443f1c51Joe Onorato        //float targetPos = newCheckedState ? 0 : getThumbScrollRange();
651c3eabb9b6ce7f556313c8e3870d76c5b443f1c51Joe Onorato        //mThumbPosition = targetPos;
65212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        setChecked(newCheckedState);
65312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
65412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
65512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private boolean getTargetCheckedState() {
656ec1d60369f751c2d9b60237077ceb9c03e4c0aedAdam Powell        return mThumbPosition >= getThumbScrollRange() / 2;
65712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
65812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
65912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
66012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void setChecked(boolean checked) {
66112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.setChecked(checked);
662ec1d60369f751c2d9b60237077ceb9c03e4c0aedAdam Powell        mThumbPosition = checked ? getThumbScrollRange() : 0;
663c3eabb9b6ce7f556313c8e3870d76c5b443f1c51Joe Onorato        invalidate();
66412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
66512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
66612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
66712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
66812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.onLayout(changed, left, top, right, bottom);
66912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
670ec1d60369f751c2d9b60237077ceb9c03e4c0aedAdam Powell        mThumbPosition = isChecked() ? getThumbScrollRange() : 0;
671c3eabb9b6ce7f556313c8e3870d76c5b443f1c51Joe Onorato
67212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int switchRight = getWidth() - getPaddingRight();
67312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int switchLeft = switchRight - mSwitchWidth;
67412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int switchTop = 0;
67512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int switchBottom = 0;
67612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        switch (getGravity() & Gravity.VERTICAL_GRAVITY_MASK) {
67712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            default:
67812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case Gravity.TOP:
67912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchTop = getPaddingTop();
68012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchBottom = switchTop + mSwitchHeight;
68112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
68212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
68312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case Gravity.CENTER_VERTICAL:
68412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchTop = (getPaddingTop() + getHeight() - getPaddingBottom()) / 2 -
68512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        mSwitchHeight / 2;
68612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchBottom = switchTop + mSwitchHeight;
68712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
68812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
68912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case Gravity.BOTTOM:
69012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchBottom = getHeight() - getPaddingBottom();
69112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchTop = switchBottom - mSwitchHeight;
69212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
69312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
69412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
69512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchLeft = switchLeft;
69612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchTop = switchTop;
69712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchBottom = switchBottom;
69812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchRight = switchRight;
69912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
70012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
70112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
70212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    protected void onDraw(Canvas canvas) {
70312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.onDraw(canvas);
70412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
70512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        // Draw the switch
70612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int switchLeft = mSwitchLeft;
70712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int switchTop = mSwitchTop;
70812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int switchRight = mSwitchRight;
70912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int switchBottom = mSwitchBottom;
71012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
71112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTrackDrawable.setBounds(switchLeft, switchTop, switchRight, switchBottom);
71212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTrackDrawable.draw(canvas);
71312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
71412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        canvas.save();
71512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
71612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTrackDrawable.getPadding(mTempRect);
71712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int switchInnerLeft = switchLeft + mTempRect.left;
71812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int switchInnerTop = switchTop + mTempRect.top;
71912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int switchInnerRight = switchRight - mTempRect.right;
72012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int switchInnerBottom = switchBottom - mTempRect.bottom;
72112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        canvas.clipRect(switchInnerLeft, switchTop, switchInnerRight, switchBottom);
72212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
72312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mThumbDrawable.getPadding(mTempRect);
72412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int thumbPos = (int) (mThumbPosition + 0.5f);
72512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int thumbLeft = switchInnerLeft - mTempRect.left + thumbPos;
72612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int thumbRight = switchInnerLeft + thumbPos + mThumbWidth + mTempRect.right;
72712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
72812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mThumbDrawable.setBounds(thumbLeft, switchTop, thumbRight, switchBottom);
72912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mThumbDrawable.draw(canvas);
73012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
731150176d83023e3c486dba10edebb72af36b4099aChet Haase        // mTextColors should not be null, but just in case
732150176d83023e3c486dba10edebb72af36b4099aChet Haase        if (mTextColors != null) {
733150176d83023e3c486dba10edebb72af36b4099aChet Haase            mTextPaint.setColor(mTextColors.getColorForState(getDrawableState(),
734150176d83023e3c486dba10edebb72af36b4099aChet Haase                    mTextColors.getDefaultColor()));
735150176d83023e3c486dba10edebb72af36b4099aChet Haase        }
73612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextPaint.drawableState = getDrawableState();
73712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
73812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        Layout switchText = getTargetCheckedState() ? mOnLayout : mOffLayout;
73912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
74012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        canvas.translate((thumbLeft + thumbRight) / 2 - switchText.getWidth() / 2,
74112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                (switchInnerTop + switchInnerBottom) / 2 - switchText.getHeight() / 2);
74212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        switchText.draw(canvas);
74312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
74412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        canvas.restore();
74512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
74612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
74712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
74812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public int getCompoundPaddingRight() {
74912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int padding = super.getCompoundPaddingRight() + mSwitchWidth;
75012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (!TextUtils.isEmpty(getText())) {
75112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            padding += mSwitchPadding;
75212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
75312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return padding;
75412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
75512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
75612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int getThumbScrollRange() {
75712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (mTrackDrawable == null) {
75812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            return 0;
75912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
76012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTrackDrawable.getPadding(mTempRect);
76112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return mSwitchWidth - mThumbWidth - mTempRect.left - mTempRect.right;
76212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
76312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
76412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
76512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    protected int[] onCreateDrawableState(int extraSpace) {
76612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
76712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (isChecked()) {
76812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mergeDrawableStates(drawableState, CHECKED_STATE_SET);
76912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
77012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return drawableState;
77112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
77212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
77312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
77412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    protected void drawableStateChanged() {
77512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.drawableStateChanged();
77612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
77712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int[] myDrawableState = getDrawableState();
77812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
77912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        // Set the state of the Drawable
780e724ee4b04d121556e9764f72f9b921a0e16392aGilles Debunne        // Drawable may be null when checked state is set from XML, from super constructor
781e724ee4b04d121556e9764f72f9b921a0e16392aGilles Debunne        if (mThumbDrawable != null) mThumbDrawable.setState(myDrawableState);
782e724ee4b04d121556e9764f72f9b921a0e16392aGilles Debunne        if (mTrackDrawable != null) mTrackDrawable.setState(myDrawableState);
78312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
78412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        invalidate();
78512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
78612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
78712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
78812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    protected boolean verifyDrawable(Drawable who) {
78912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return super.verifyDrawable(who) || who == mThumbDrawable || who == mTrackDrawable;
79012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
79112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
79212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
79312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void jumpDrawablesToCurrentState() {
79412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.jumpDrawablesToCurrentState();
79512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mThumbDrawable.jumpToCurrentState();
79612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTrackDrawable.jumpToCurrentState();
79712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
7988a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov
7998a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    @Override
8008a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
8018a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        super.onInitializeAccessibilityEvent(event);
8028a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        event.setClassName(Switch.class.getName());
8038a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    }
8048a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov
8058a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    @Override
8068a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
8078a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        super.onInitializeAccessibilityNodeInfo(info);
8088a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        info.setClassName(Switch.class.getName());
80978bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov        CharSequence switchText = isChecked() ? mTextOn : mTextOff;
81078bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov        if (!TextUtils.isEmpty(switchText)) {
81178bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov            CharSequence oldText = info.getText();
81278bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov            if (TextUtils.isEmpty(oldText)) {
81378bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov                info.setText(switchText);
81478bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov            } else {
81578bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov                StringBuilder newText = new StringBuilder();
81678bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov                newText.append(oldText).append(' ').append(switchText);
81778bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov                info.setText(newText);
81878bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov            }
81978bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov        }
8208a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    }
82112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell}
822