Switch.java revision aa0980afab57a6aebb06e70f60e92511708fa5af
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 *
5612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell */
5712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powellpublic class Switch extends CompoundButton {
5812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int TOUCH_MODE_IDLE = 0;
5912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int TOUCH_MODE_DOWN = 1;
6012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int TOUCH_MODE_DRAGGING = 2;
6112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
6212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    // Enum for the "typeface" XML parameter.
6312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int SANS = 1;
6412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int SERIF = 2;
6512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int MONOSPACE = 3;
6612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
6712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private Drawable mThumbDrawable;
6812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private Drawable mTrackDrawable;
6912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mThumbTextPadding;
7012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchMinWidth;
7112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchPadding;
7212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private CharSequence mTextOn;
7312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private CharSequence mTextOff;
7412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
7512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mTouchMode;
7612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mTouchSlop;
7712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private float mTouchX;
7812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private float mTouchY;
7912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private VelocityTracker mVelocityTracker = VelocityTracker.obtain();
8012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mMinFlingVelocity;
8112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
8212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private float mThumbPosition;
8312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchWidth;
8412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchHeight;
8512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mThumbWidth; // Does not include padding
8612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
8712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchLeft;
8812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchTop;
8912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchRight;
9012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int mSwitchBottom;
9112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
9212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private TextPaint mTextPaint;
9312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private ColorStateList mTextColors;
9412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private Layout mOnLayout;
9512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private Layout mOffLayout;
964c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler    private TransformationMethod2 mSwitchTransformationMethod;
9712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
98be0a4535053bbfdebd215e244b154ac810fd8edcAdam Powell    @SuppressWarnings("hiding")
9912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private final Rect mTempRect = new Rect();
10012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
10112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private static final int[] CHECKED_STATE_SET = {
10212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        R.attr.state_checked
10312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    };
10412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
10512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
10612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Construct a new Switch with default styling.
10712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     *
10812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param context The Context that will determine this widget's theming.
10912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
11012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public Switch(Context context) {
11112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        this(context, null);
11212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
11312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
11412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
11512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Construct a new Switch with default styling, overriding specific style
11612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * attributes as requested.
11712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     *
11812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param context The Context that will determine this widget's theming.
11912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param attrs Specification of attributes that should deviate from default styling.
12012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
12112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public Switch(Context context, AttributeSet attrs) {
12212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        this(context, attrs, com.android.internal.R.attr.switchStyle);
12312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
12412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
12512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
12612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Construct a new Switch with a default style determined by the given theme attribute,
12712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * overriding specific style 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 the default styling.
13112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param defStyle An attribute ID within the active theme containing a reference to the
13212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     *                 default style for this widget. e.g. android.R.attr.switchStyle.
13312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
13412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public Switch(Context context, AttributeSet attrs, int defStyle) {
13512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super(context, attrs, defStyle);
13612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
13712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
13812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        Resources res = getResources();
13912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextPaint.density = res.getDisplayMetrics().density;
14012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextPaint.setCompatibilityScaling(res.getCompatibilityInfo().applicationScale);
14112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
14212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        TypedArray a = context.obtainStyledAttributes(attrs,
14312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                com.android.internal.R.styleable.Switch, defStyle, 0);
14412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
145150176d83023e3c486dba10edebb72af36b4099aChet Haase        mThumbDrawable = a.getDrawable(com.android.internal.R.styleable.Switch_thumb);
146150176d83023e3c486dba10edebb72af36b4099aChet Haase        mTrackDrawable = a.getDrawable(com.android.internal.R.styleable.Switch_track);
14712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextOn = a.getText(com.android.internal.R.styleable.Switch_textOn);
14812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextOff = a.getText(com.android.internal.R.styleable.Switch_textOff);
14912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mThumbTextPadding = a.getDimensionPixelSize(
15012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                com.android.internal.R.styleable.Switch_thumbTextPadding, 0);
15112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchMinWidth = a.getDimensionPixelSize(
15212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                com.android.internal.R.styleable.Switch_switchMinWidth, 0);
15312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchPadding = a.getDimensionPixelSize(
15412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                com.android.internal.R.styleable.Switch_switchPadding, 0);
15512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
15612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int appearance = a.getResourceId(
15712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                com.android.internal.R.styleable.Switch_switchTextAppearance, 0);
15812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (appearance != 0) {
159150176d83023e3c486dba10edebb72af36b4099aChet Haase            setSwitchTextAppearance(context, appearance);
16012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
16112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        a.recycle();
16212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
16312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        ViewConfiguration config = ViewConfiguration.get(context);
16412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTouchSlop = config.getScaledTouchSlop();
16512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mMinFlingVelocity = config.getScaledMinimumFlingVelocity();
16612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
16712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        // Refresh display with current params
168e724ee4b04d121556e9764f72f9b921a0e16392aGilles Debunne        refreshDrawableState();
16912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        setChecked(isChecked());
17012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
17112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
17212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
17312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Sets the switch text color, size, style, hint color, and highlight color
17412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * from the specified TextAppearance resource.
1756c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
1766c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_switchTextAppearance
17712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
178150176d83023e3c486dba10edebb72af36b4099aChet Haase    public void setSwitchTextAppearance(Context context, int resid) {
17912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        TypedArray appearance =
180150176d83023e3c486dba10edebb72af36b4099aChet Haase                context.obtainStyledAttributes(resid,
18112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        com.android.internal.R.styleable.TextAppearance);
18212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
18312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        ColorStateList colors;
18412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int ts;
18512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
18612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        colors = appearance.getColorStateList(com.android.internal.R.styleable.
18712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                TextAppearance_textColor);
18812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (colors != null) {
18912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mTextColors = colors;
190150176d83023e3c486dba10edebb72af36b4099aChet Haase        } else {
191150176d83023e3c486dba10edebb72af36b4099aChet Haase            // If no color set in TextAppearance, default to the view's textColor
192150176d83023e3c486dba10edebb72af36b4099aChet Haase            mTextColors = getTextColors();
19312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
19412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
19512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        ts = appearance.getDimensionPixelSize(com.android.internal.R.styleable.
19612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                TextAppearance_textSize, 0);
19712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (ts != 0) {
19812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            if (ts != mTextPaint.getTextSize()) {
19912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                mTextPaint.setTextSize(ts);
20012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                requestLayout();
20112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
20212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
20312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
20412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int typefaceIndex, styleIndex;
20512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
20612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        typefaceIndex = appearance.getInt(com.android.internal.R.styleable.
20712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                TextAppearance_typeface, -1);
20812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        styleIndex = appearance.getInt(com.android.internal.R.styleable.
20912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                TextAppearance_textStyle, -1);
21012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
21112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        setSwitchTypefaceByIndex(typefaceIndex, styleIndex);
21212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
2134c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler        boolean allCaps = appearance.getBoolean(com.android.internal.R.styleable.
2144c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler                TextAppearance_textAllCaps, false);
2154c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler        if (allCaps) {
2164c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler            mSwitchTransformationMethod = new AllCapsTransformationMethod(getContext());
2174c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler            mSwitchTransformationMethod.setLengthChangesAllowed(true);
2184c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler        } else {
2194c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler            mSwitchTransformationMethod = null;
2204c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler        }
2214c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler
22212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        appearance.recycle();
22312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
22412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
22512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private void setSwitchTypefaceByIndex(int typefaceIndex, int styleIndex) {
22612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        Typeface tf = null;
22712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        switch (typefaceIndex) {
22812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case SANS:
22912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                tf = Typeface.SANS_SERIF;
23012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
23112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
23212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case SERIF:
23312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                tf = Typeface.SERIF;
23412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
23512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
23612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MONOSPACE:
23712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                tf = Typeface.MONOSPACE;
23812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
23912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
24012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
24112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        setSwitchTypeface(tf, styleIndex);
24212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
24312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
24412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
24512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Sets the typeface and style in which the text should be displayed on the
24612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * switch, and turns on the fake bold and italic bits in the Paint if the
24712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Typeface that you provided does not have all the bits in the
24812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * style that you specified.
24912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
25012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void setSwitchTypeface(Typeface tf, int style) {
25112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (style > 0) {
25212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            if (tf == null) {
25312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                tf = Typeface.defaultFromStyle(style);
25412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            } else {
25512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                tf = Typeface.create(tf, style);
25612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
25712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
25812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            setSwitchTypeface(tf);
25912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            // now compute what (if any) algorithmic styling is needed
26012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            int typefaceStyle = tf != null ? tf.getStyle() : 0;
26112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            int need = style & ~typefaceStyle;
26212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mTextPaint.setFakeBoldText((need & Typeface.BOLD) != 0);
26312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mTextPaint.setTextSkewX((need & Typeface.ITALIC) != 0 ? -0.25f : 0);
26412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        } else {
265aa0980afab57a6aebb06e70f60e92511708fa5afVictoria Lease            mTextPaint.setFakeBoldText(false);
26612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mTextPaint.setTextSkewX(0);
26712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            setSwitchTypeface(tf);
26812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
26912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
27012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
27112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
272150176d83023e3c486dba10edebb72af36b4099aChet Haase     * Sets the typeface in which the text should be displayed on the switch.
27312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Note that not all Typeface families actually have bold and italic
27412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * variants, so you may need to use
27512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * {@link #setSwitchTypeface(Typeface, int)} to get the appearance
27612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * that you actually want.
27712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     *
27812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @attr ref android.R.styleable#TextView_typeface
27912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @attr ref android.R.styleable#TextView_textStyle
28012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
28112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void setSwitchTypeface(Typeface tf) {
28212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (mTextPaint.getTypeface() != tf) {
28312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mTextPaint.setTypeface(tf);
28412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
28512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            requestLayout();
28612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            invalidate();
28712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
28812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
28912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
29012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
2916c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Set the amount of horizontal padding between the switch and the associated text.
2926c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
2936c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @param pixels Amount of padding in pixels
2946c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
2956c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_switchPadding
2966c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
2976c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public void setSwitchPadding(int pixels) {
2986c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        mSwitchPadding = pixels;
2996c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        requestLayout();
3006c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
3016c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
3026c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
3036c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Get the amount of horizontal padding between the switch and the associated text.
3046c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3056c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @return Amount of padding in pixels
3066c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3076c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_switchPadding
3086c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
3096c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public int getSwitchPadding() {
3106c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        return mSwitchPadding;
3116c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
3126c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
3136c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
3146c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Set the minimum width of the switch in pixels. The switch's width will be the maximum
3156c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * of this value and its measured width as determined by the switch drawables and text used.
3166c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3176c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @param pixels Minimum width of the switch in pixels
3186c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3196c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_switchMinWidth
3206c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
3216c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public void setSwitchMinWidth(int pixels) {
3226c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        mSwitchMinWidth = pixels;
3236c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        requestLayout();
3246c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
3256c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
3266c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
3276c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Get the minimum width of the switch in pixels. The switch's width will be the maximum
3286c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * of this value and its measured width as determined by the switch drawables and text used.
3296c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3306c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @return Minimum width of the switch in pixels
3316c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3326c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_switchMinWidth
3336c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
3346c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public int getSwitchMinWidth() {
3356c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        return mSwitchMinWidth;
3366c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
3376c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
3386c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
3396c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Set the horizontal padding around the text drawn on the switch itself.
3406c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3416c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @param pixels Horizontal padding for switch thumb text in pixels
3426c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3436c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_thumbTextPadding
3446c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
3456c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public void setThumbTextPadding(int pixels) {
3466c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        mThumbTextPadding = pixels;
3476c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        requestLayout();
3486c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
3496c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
3506c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
3516c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Get the horizontal padding around the text drawn on the switch itself.
3526c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3536c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @return Horizontal padding for switch thumb text in pixels
3546c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3556c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_thumbTextPadding
3566c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
3576c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public int getThumbTextPadding() {
3586c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        return mThumbTextPadding;
3596c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
3606c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
3616c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
3626c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Set the drawable used for the track that the switch slides within.
3636c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3646c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @param track Track drawable
3656c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3666c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_track
3676c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
3686c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public void setTrackDrawable(Drawable track) {
3696c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        mTrackDrawable = track;
3706c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        requestLayout();
3716c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
3726c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
3736c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
374d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     * Set the drawable used for the track that the switch slides within.
375d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     *
376dca510e026e3e75759bac84c3860dc84b83a608fAdam Powell     * @param resId Resource ID of a track drawable
377d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     *
378d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     * @attr ref android.R.styleable#Switch_track
379d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     */
380d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell    public void setTrackResource(int resId) {
381d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell        setTrackDrawable(getContext().getResources().getDrawable(resId));
382d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell    }
383d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell
384d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell    /**
3856c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Get the drawable used for the track that the switch slides within.
3866c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3876c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @return Track drawable
3886c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3896c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_track
3906c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
3916c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public Drawable getTrackDrawable() {
3926c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        return mTrackDrawable;
3936c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
3946c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
3956c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
3966c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Set the drawable used for the switch "thumb" - the piece that the user
3976c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * can physically touch and drag along the track.
3986c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
3996c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @param thumb Thumb drawable
4006c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4016c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_thumb
4026c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
4036c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public void setThumbDrawable(Drawable thumb) {
4046c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        mThumbDrawable = thumb;
4056c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        requestLayout();
4066c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
4076c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
4086c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
409d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     * Set the drawable used for the switch "thumb" - the piece that the user
410d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     * can physically touch and drag along the track.
411d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     *
412dca510e026e3e75759bac84c3860dc84b83a608fAdam Powell     * @param resId Resource ID of a thumb drawable
413d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     *
414d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     * @attr ref android.R.styleable#Switch_thumb
415d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell     */
416d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell    public void setThumbResource(int resId) {
417d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell        setThumbDrawable(getContext().getResources().getDrawable(resId));
418d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell    }
419d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell
420d9c7be6cc7d18f11731e6d7a1037cc294fde3a4bAdam Powell    /**
4216c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * Get the drawable used for the switch "thumb" - the piece that the user
4226c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * can physically touch and drag along the track.
4236c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4246c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @return Thumb drawable
4256c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4266c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_thumb
4276c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     */
4286c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    public Drawable getThumbDrawable() {
4296c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell        return mThumbDrawable;
4306c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    }
4316c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell
4326c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell    /**
433150176d83023e3c486dba10edebb72af36b4099aChet Haase     * Returns the text displayed when the button is in the checked state.
4346c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4356c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_textOn
43612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
43712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public CharSequence getTextOn() {
43812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return mTextOn;
43912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
44012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
44112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
442150176d83023e3c486dba10edebb72af36b4099aChet Haase     * Sets the text displayed when the button is in the checked state.
4436c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4446c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_textOn
44512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
44612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void setTextOn(CharSequence textOn) {
44712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextOn = textOn;
44812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        requestLayout();
44912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
45012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
45112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
452150176d83023e3c486dba10edebb72af36b4099aChet Haase     * Returns the text displayed when the button is not in the checked state.
4536c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4546c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_textOff
45512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
45612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public CharSequence getTextOff() {
45712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return mTextOff;
45812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
45912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
46012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
461150176d83023e3c486dba10edebb72af36b4099aChet Haase     * Sets the text displayed when the button is not in the checked state.
4626c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     *
4636c86e1ba41b56ccb3668dbb044fa348cd4b47d55Adam Powell     * @attr ref android.R.styleable#Switch_textOff
46412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
46512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void setTextOff(CharSequence textOff) {
46612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextOff = textOff;
46712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        requestLayout();
46812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
46912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
47012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
47112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
47212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
47312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
47412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
47512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
47612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
47712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
47812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (mOnLayout == null) {
47912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mOnLayout = makeLayout(mTextOn);
48012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
48112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (mOffLayout == null) {
48212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mOffLayout = makeLayout(mTextOff);
48312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
48412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
48512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTrackDrawable.getPadding(mTempRect);
48612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int maxTextWidth = Math.max(mOnLayout.getWidth(), mOffLayout.getWidth());
48712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int switchWidth = Math.max(mSwitchMinWidth,
48812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                maxTextWidth * 2 + mThumbTextPadding * 4 + mTempRect.left + mTempRect.right);
48912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int switchHeight = mTrackDrawable.getIntrinsicHeight();
49012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
49112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mThumbWidth = maxTextWidth + mThumbTextPadding * 2;
49212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
49312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        switch (widthMode) {
49412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MeasureSpec.AT_MOST:
49512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                widthSize = Math.min(widthSize, switchWidth);
49612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
49712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
49812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MeasureSpec.UNSPECIFIED:
49912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                widthSize = switchWidth;
50012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
50112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
50212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MeasureSpec.EXACTLY:
50312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                // Just use what we were given
50412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
50512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
50612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
50712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        switch (heightMode) {
50812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MeasureSpec.AT_MOST:
50912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                heightSize = Math.min(heightSize, switchHeight);
51012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
51112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
51212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MeasureSpec.UNSPECIFIED:
51312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                heightSize = switchHeight;
51412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
51512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
51612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MeasureSpec.EXACTLY:
51712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                // Just use what we were given
51812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
51912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
52012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
52112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchWidth = switchWidth;
52212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchHeight = switchHeight;
52312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
52412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
52512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int measuredHeight = getMeasuredHeight();
52612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (measuredHeight < switchHeight) {
527189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn            setMeasuredDimension(getMeasuredWidthAndState(), switchHeight);
52812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
52912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
53012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
53163bce03cc69be4a45230aa8bbd89dbde60681067Svetoslav Ganov    @Override
53263bce03cc69be4a45230aa8bbd89dbde60681067Svetoslav Ganov    public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
53363bce03cc69be4a45230aa8bbd89dbde60681067Svetoslav Ganov        super.onPopulateAccessibilityEvent(event);
53455249c8601e04928d4e8afb17233596a3ed4e0ceSvetoslav Ganov        CharSequence text = isChecked() ? mOnLayout.getText() : mOffLayout.getText();
53555249c8601e04928d4e8afb17233596a3ed4e0ceSvetoslav Ganov        if (!TextUtils.isEmpty(text)) {
5367650259a597dd24137420d32acc35efc44db381eSvetoslav Ganov            event.getText().add(text);
5377650259a597dd24137420d32acc35efc44db381eSvetoslav Ganov        }
53863bce03cc69be4a45230aa8bbd89dbde60681067Svetoslav Ganov    }
53963bce03cc69be4a45230aa8bbd89dbde60681067Svetoslav Ganov
54012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private Layout makeLayout(CharSequence text) {
5414c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler        final CharSequence transformed = (mSwitchTransformationMethod != null)
5424c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler                    ? mSwitchTransformationMethod.getTransformation(text, this)
5434c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler                    : text;
5444c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler
5454c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler        return new StaticLayout(transformed, mTextPaint,
5464c3308de7d51b16b1450c21787b442d84ace3984Daniel Sandler                (int) Math.ceil(Layout.getDesiredWidth(transformed, mTextPaint)),
54712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                Layout.Alignment.ALIGN_NORMAL, 1.f, 0, true);
54812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
54912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
55012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
55112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @return true if (x, y) is within the target area of the switch thumb
55212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
55312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private boolean hitThumb(float x, float y) {
55412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mThumbDrawable.getPadding(mTempRect);
55512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int thumbTop = mSwitchTop - mTouchSlop;
55612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int thumbLeft = mSwitchLeft + (int) (mThumbPosition + 0.5f) - mTouchSlop;
55712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int thumbRight = thumbLeft + mThumbWidth +
55812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                mTempRect.left + mTempRect.right + mTouchSlop;
55912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int thumbBottom = mSwitchBottom + mTouchSlop;
56012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return x > thumbLeft && x < thumbRight && y > thumbTop && y < thumbBottom;
56112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
56212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
56312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
56412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public boolean onTouchEvent(MotionEvent ev) {
56512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mVelocityTracker.addMovement(ev);
56612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int action = ev.getActionMasked();
56712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        switch (action) {
56812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MotionEvent.ACTION_DOWN: {
56912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                final float x = ev.getX();
57012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                final float y = ev.getY();
571c2ab0d665c9d1c332fbd726abf582a27cf7a6701Gilles Debunne                if (isEnabled() && hitThumb(x, y)) {
57212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    mTouchMode = TOUCH_MODE_DOWN;
57312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    mTouchX = x;
57412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    mTouchY = y;
57512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                }
57612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
57712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
57812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
57912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MotionEvent.ACTION_MOVE: {
58012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switch (mTouchMode) {
58112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    case TOUCH_MODE_IDLE:
58212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        // Didn't target the thumb, treat normally.
58312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        break;
58412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
58512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    case TOUCH_MODE_DOWN: {
58612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        final float x = ev.getX();
58712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        final float y = ev.getY();
58812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        if (Math.abs(x - mTouchX) > mTouchSlop ||
58912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                                Math.abs(y - mTouchY) > mTouchSlop) {
59012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            mTouchMode = TOUCH_MODE_DRAGGING;
59112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            getParent().requestDisallowInterceptTouchEvent(true);
59212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            mTouchX = x;
59312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            mTouchY = y;
59412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            return true;
59512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        }
59612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        break;
59712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    }
59812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
59912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    case TOUCH_MODE_DRAGGING: {
60012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        final float x = ev.getX();
60112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        final float dx = x - mTouchX;
60212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        float newPos = Math.max(0,
60312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                                Math.min(mThumbPosition + dx, getThumbScrollRange()));
60412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        if (newPos != mThumbPosition) {
60512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            mThumbPosition = newPos;
60612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            mTouchX = x;
60712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                            invalidate();
60812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        }
60912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        return true;
61012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    }
61112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                }
61212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
61312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
61412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
61512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MotionEvent.ACTION_UP:
61612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case MotionEvent.ACTION_CANCEL: {
61712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                if (mTouchMode == TOUCH_MODE_DRAGGING) {
61812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    stopDrag(ev);
61912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                    return true;
62012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                }
62112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                mTouchMode = TOUCH_MODE_IDLE;
62212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                mVelocityTracker.clear();
62312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
62412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
62512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
62612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
62712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return super.onTouchEvent(ev);
62812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
62912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
63012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private void cancelSuperTouch(MotionEvent ev) {
63112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        MotionEvent cancel = MotionEvent.obtain(ev);
63212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        cancel.setAction(MotionEvent.ACTION_CANCEL);
63312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.onTouchEvent(cancel);
63412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        cancel.recycle();
63512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
63612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
63712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    /**
63812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * Called from onTouchEvent to end a drag operation.
63912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     *
64012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     * @param ev Event that triggered the end of drag mode - ACTION_UP or ACTION_CANCEL
64112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell     */
64212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private void stopDrag(MotionEvent ev) {
64312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTouchMode = TOUCH_MODE_IDLE;
644c2ab0d665c9d1c332fbd726abf582a27cf7a6701Gilles Debunne        // Up and not canceled, also checks the switch has not been disabled during the drag
645c2ab0d665c9d1c332fbd726abf582a27cf7a6701Gilles Debunne        boolean commitChange = ev.getAction() == MotionEvent.ACTION_UP && isEnabled();
64612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
64712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        cancelSuperTouch(ev);
64812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
64912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (commitChange) {
65012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            boolean newState;
65112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mVelocityTracker.computeCurrentVelocity(1000);
65212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            float xvel = mVelocityTracker.getXVelocity();
65312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            if (Math.abs(xvel) > mMinFlingVelocity) {
65401d11edc1ea2c495ba4bd6bbea8ba7bb7f597678Adam Powell                newState = xvel > 0;
65512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            } else {
65612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                newState = getTargetCheckedState();
65712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            }
65812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            animateThumbToCheckedState(newState);
65912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        } else {
66012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            animateThumbToCheckedState(isChecked());
66112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
66212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
66312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
66412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private void animateThumbToCheckedState(boolean newCheckedState) {
66512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        // TODO animate!
666c3eabb9b6ce7f556313c8e3870d76c5b443f1c51Joe Onorato        //float targetPos = newCheckedState ? 0 : getThumbScrollRange();
667c3eabb9b6ce7f556313c8e3870d76c5b443f1c51Joe Onorato        //mThumbPosition = targetPos;
66812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        setChecked(newCheckedState);
66912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
67012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
67112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private boolean getTargetCheckedState() {
672ec1d60369f751c2d9b60237077ceb9c03e4c0aedAdam Powell        return mThumbPosition >= getThumbScrollRange() / 2;
67312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
67412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
67512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
67612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void setChecked(boolean checked) {
67712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.setChecked(checked);
678ec1d60369f751c2d9b60237077ceb9c03e4c0aedAdam Powell        mThumbPosition = checked ? getThumbScrollRange() : 0;
679c3eabb9b6ce7f556313c8e3870d76c5b443f1c51Joe Onorato        invalidate();
68012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
68112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
68212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
68312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
68412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.onLayout(changed, left, top, right, bottom);
68512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
686ec1d60369f751c2d9b60237077ceb9c03e4c0aedAdam Powell        mThumbPosition = isChecked() ? getThumbScrollRange() : 0;
687c3eabb9b6ce7f556313c8e3870d76c5b443f1c51Joe Onorato
68812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int switchRight = getWidth() - getPaddingRight();
68912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int switchLeft = switchRight - mSwitchWidth;
69012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int switchTop = 0;
69112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int switchBottom = 0;
69212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        switch (getGravity() & Gravity.VERTICAL_GRAVITY_MASK) {
69312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            default:
69412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case Gravity.TOP:
69512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchTop = getPaddingTop();
69612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchBottom = switchTop + mSwitchHeight;
69712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
69812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
69912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case Gravity.CENTER_VERTICAL:
70012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchTop = (getPaddingTop() + getHeight() - getPaddingBottom()) / 2 -
70112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                        mSwitchHeight / 2;
70212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchBottom = switchTop + mSwitchHeight;
70312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
70412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
70512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            case Gravity.BOTTOM:
70612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchBottom = getHeight() - getPaddingBottom();
70712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                switchTop = switchBottom - mSwitchHeight;
70812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                break;
70912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
71012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
71112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchLeft = switchLeft;
71212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchTop = switchTop;
71312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchBottom = switchBottom;
71412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mSwitchRight = switchRight;
71512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
71612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
71712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
71812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    protected void onDraw(Canvas canvas) {
71912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.onDraw(canvas);
72012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
72112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        // Draw the switch
72212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int switchLeft = mSwitchLeft;
72312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int switchTop = mSwitchTop;
72412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int switchRight = mSwitchRight;
72512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int switchBottom = mSwitchBottom;
72612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
72712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTrackDrawable.setBounds(switchLeft, switchTop, switchRight, switchBottom);
72812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTrackDrawable.draw(canvas);
72912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
73012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        canvas.save();
73112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
73212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTrackDrawable.getPadding(mTempRect);
73312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int switchInnerLeft = switchLeft + mTempRect.left;
73412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int switchInnerTop = switchTop + mTempRect.top;
73512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int switchInnerRight = switchRight - mTempRect.right;
73612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int switchInnerBottom = switchBottom - mTempRect.bottom;
73712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        canvas.clipRect(switchInnerLeft, switchTop, switchInnerRight, switchBottom);
73812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
73912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mThumbDrawable.getPadding(mTempRect);
74012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int thumbPos = (int) (mThumbPosition + 0.5f);
74112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int thumbLeft = switchInnerLeft - mTempRect.left + thumbPos;
74212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int thumbRight = switchInnerLeft + thumbPos + mThumbWidth + mTempRect.right;
74312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
74412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mThumbDrawable.setBounds(thumbLeft, switchTop, thumbRight, switchBottom);
74512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mThumbDrawable.draw(canvas);
74612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
747150176d83023e3c486dba10edebb72af36b4099aChet Haase        // mTextColors should not be null, but just in case
748150176d83023e3c486dba10edebb72af36b4099aChet Haase        if (mTextColors != null) {
749150176d83023e3c486dba10edebb72af36b4099aChet Haase            mTextPaint.setColor(mTextColors.getColorForState(getDrawableState(),
750150176d83023e3c486dba10edebb72af36b4099aChet Haase                    mTextColors.getDefaultColor()));
751150176d83023e3c486dba10edebb72af36b4099aChet Haase        }
75212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTextPaint.drawableState = getDrawableState();
75312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
75412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        Layout switchText = getTargetCheckedState() ? mOnLayout : mOffLayout;
75512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
75612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        canvas.translate((thumbLeft + thumbRight) / 2 - switchText.getWidth() / 2,
75712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell                (switchInnerTop + switchInnerBottom) / 2 - switchText.getHeight() / 2);
75812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        switchText.draw(canvas);
75912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
76012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        canvas.restore();
76112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
76212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
76312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
76412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public int getCompoundPaddingRight() {
76512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int padding = super.getCompoundPaddingRight() + mSwitchWidth;
76612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (!TextUtils.isEmpty(getText())) {
76712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            padding += mSwitchPadding;
76812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
76912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return padding;
77012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
77112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
77212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    private int getThumbScrollRange() {
77312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (mTrackDrawable == null) {
77412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            return 0;
77512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
77612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTrackDrawable.getPadding(mTempRect);
77712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return mSwitchWidth - mThumbWidth - mTempRect.left - mTempRect.right;
77812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
77912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
78012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
78112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    protected int[] onCreateDrawableState(int extraSpace) {
78212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
78312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        if (isChecked()) {
78412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell            mergeDrawableStates(drawableState, CHECKED_STATE_SET);
78512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        }
78612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return drawableState;
78712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
78812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
78912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
79012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    protected void drawableStateChanged() {
79112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.drawableStateChanged();
79212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
79312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        int[] myDrawableState = getDrawableState();
79412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
79512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        // Set the state of the Drawable
796e724ee4b04d121556e9764f72f9b921a0e16392aGilles Debunne        // Drawable may be null when checked state is set from XML, from super constructor
797e724ee4b04d121556e9764f72f9b921a0e16392aGilles Debunne        if (mThumbDrawable != null) mThumbDrawable.setState(myDrawableState);
798e724ee4b04d121556e9764f72f9b921a0e16392aGilles Debunne        if (mTrackDrawable != null) mTrackDrawable.setState(myDrawableState);
79912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
80012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        invalidate();
80112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
80212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
80312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
80412190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    protected boolean verifyDrawable(Drawable who) {
80512190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        return super.verifyDrawable(who) || who == mThumbDrawable || who == mTrackDrawable;
80612190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
80712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell
80812190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    @Override
80912190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    public void jumpDrawablesToCurrentState() {
81012190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        super.jumpDrawablesToCurrentState();
81112190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mThumbDrawable.jumpToCurrentState();
81212190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell        mTrackDrawable.jumpToCurrentState();
81312190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell    }
8148a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov
8158a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    @Override
8168a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
8178a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        super.onInitializeAccessibilityEvent(event);
8188a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        event.setClassName(Switch.class.getName());
8198a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    }
8208a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov
8218a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    @Override
8228a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
8238a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        super.onInitializeAccessibilityNodeInfo(info);
8248a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        info.setClassName(Switch.class.getName());
82578bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov        CharSequence switchText = isChecked() ? mTextOn : mTextOff;
82678bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov        if (!TextUtils.isEmpty(switchText)) {
82778bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov            CharSequence oldText = info.getText();
82878bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov            if (TextUtils.isEmpty(oldText)) {
82978bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov                info.setText(switchText);
83078bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov            } else {
83178bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov                StringBuilder newText = new StringBuilder();
83278bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov                newText.append(oldText).append(' ').append(switchText);
83378bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov                info.setText(newText);
83478bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov            }
83578bcc15b6c5959cc3eb9bbe2459af93451b74a22Svetoslav Ganov        }
8368a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    }
83712190b36a9da88f8db7dbd9ce16d127d76a904b7Adam Powell}
838