1415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes/* 2415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Copyright (C) 2014 The Android Open Source Project 3415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 4415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Licensed under the Apache License, Version 2.0 (the "License"); 5415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * you may not use this file except in compliance with the License. 6415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * You may obtain a copy of the License at 7415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 8415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * http://www.apache.org/licenses/LICENSE-2.0 9415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 10415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Unless required by applicable law or agreed to in writing, software 11415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * distributed under the License is distributed on an "AS IS" BASIS, 12415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * See the License for the specific language governing permissions and 14415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * limitations under the License. 15415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 16415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 17415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banespackage android.support.v7.widget; 18415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 19415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.animation.ObjectAnimator; 20415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.annotation.TargetApi; 21415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.content.Context; 22415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.content.res.ColorStateList; 23415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.content.res.Resources; 24415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.content.res.TypedArray; 25415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.graphics.Canvas; 26415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.graphics.Paint; 27415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.graphics.Rect; 28415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.graphics.Typeface; 29415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.graphics.drawable.Drawable; 30415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.os.Build; 31415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.support.v4.graphics.drawable.DrawableCompat; 32415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.support.v4.view.MotionEventCompat; 33415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.support.v4.view.ViewCompat; 34415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.support.v7.appcompat.R; 35415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.support.v7.internal.text.AllCapsTransformationMethod; 36415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.support.v7.internal.widget.TintManager; 37415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.support.v7.internal.widget.TintTypedArray; 38415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.support.v7.internal.widget.ViewUtils; 39415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.text.Layout; 40415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.text.StaticLayout; 41415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.text.TextPaint; 42415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.text.TextUtils; 43415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.text.method.TransformationMethod; 44415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.util.AttributeSet; 45415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.view.Gravity; 46415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.view.MotionEvent; 47415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.view.VelocityTracker; 48415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.view.ViewConfiguration; 49415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.view.accessibility.AccessibilityEvent; 50415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.view.accessibility.AccessibilityNodeInfo; 51415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.view.animation.Animation; 52415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.view.animation.Transformation; 53415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.widget.CompoundButton; 54415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 55415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes/** 56415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * SwitchCompat is a version of the Switch widget which on devices back to API v7. It does not 57415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * make any attempt to use the platform provided widget on those devices which it is available 58415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * normally. 59415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * <p> 60415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * A Switch is a two-state toggle switch widget that can select between two 61415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * options. The user may drag the "thumb" back and forth to choose the selected option, 62415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * or simply tap to toggle as if it were a checkbox. The {@link #setText(CharSequence) text} 63415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * property controls the text displayed in the label for the switch, whereas the 64415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * {@link #setTextOff(CharSequence) off} and {@link #setTextOn(CharSequence) on} text 65415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * controls the text on the thumb. Similarly, the 66415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * {@link #setTextAppearance(android.content.Context, int) textAppearance} and the related 67415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * setTypeface() methods control the typeface and style of label text, whereas the 68415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * {@link #setSwitchTextAppearance(android.content.Context, int) switchTextAppearance} and 69415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * the related seSwitchTypeface() methods control that of the thumb. 70415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 71415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banespublic class SwitchCompat extends CompoundButton { 72415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private static final int THUMB_ANIMATION_DURATION = 250; 73415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 74415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private static final int TOUCH_MODE_IDLE = 0; 75415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private static final int TOUCH_MODE_DOWN = 1; 76415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private static final int TOUCH_MODE_DRAGGING = 2; 77415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 78415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private static final int[] TEXT_APPEARANCE_ATTRS = { 79415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes android.R.attr.textColor, 80415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes android.R.attr.textSize, 81415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes R.attr.textAllCaps 82415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes }; 83415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 84415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Enum for the "typeface" XML parameter. 85415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private static final int SANS = 1; 86415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private static final int SERIF = 2; 87415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private static final int MONOSPACE = 3; 88415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 89415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private Drawable mThumbDrawable; 90415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private Drawable mTrackDrawable; 91415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int mThumbTextPadding; 92415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int mSwitchMinWidth; 93415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int mSwitchPadding; 94415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private boolean mSplitTrack; 95415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private CharSequence mTextOn; 96415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private CharSequence mTextOff; 97415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private boolean mShowText; 98415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 99415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int mTouchMode; 100415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int mTouchSlop; 101415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private float mTouchX; 102415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private float mTouchY; 103415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private VelocityTracker mVelocityTracker = VelocityTracker.obtain(); 104415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int mMinFlingVelocity; 105415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 106415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private float mThumbPosition; 107415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 108415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 109415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Width required to draw the switch track and thumb. Includes padding and 110415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * optical bounds for both the track and thumb. 111415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 112415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int mSwitchWidth; 113415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 114415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 115415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Height required to draw the switch track and thumb. Includes padding and 116415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * optical bounds for both the track and thumb. 117415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 118415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int mSwitchHeight; 119415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 120415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 121415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Width of the thumb's content region. Does not include padding or 122415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * optical bounds. 123415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 124415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int mThumbWidth; 125415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 126415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** Left bound for drawing the switch track and thumb. */ 127415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int mSwitchLeft; 128415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 129415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** Top bound for drawing the switch track and thumb. */ 130415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int mSwitchTop; 131415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 132415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** Right bound for drawing the switch track and thumb. */ 133415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int mSwitchRight; 134415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 135415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** Bottom bound for drawing the switch track and thumb. */ 136415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int mSwitchBottom; 137415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 138415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private TextPaint mTextPaint; 139415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private ColorStateList mTextColors; 140415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private Layout mOnLayout; 141415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private Layout mOffLayout; 142415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private TransformationMethod mSwitchTransformationMethod; 143415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private Animation mPositionAnimator; 144415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 145415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @SuppressWarnings("hiding") 146415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private final Rect mTempRect = new Rect(); 147415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 148415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private final TintManager mTintManager; 149415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 150415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private static final int[] CHECKED_STATE_SET = { 151415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes android.R.attr.state_checked 152415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes }; 153415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 154415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 155415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Construct a new Switch with default styling. 156415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 157415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param context The Context that will determine this widget's theming. 158415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 159415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public SwitchCompat(Context context) { 160415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes this(context, null); 161415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 162415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 163415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 164415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Construct a new Switch with default styling, overriding specific style 165415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * attributes as requested. 166415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 167415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param context The Context that will determine this widget's theming. 168415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param attrs Specification of attributes that should deviate from default styling. 169415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 170415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public SwitchCompat(Context context, AttributeSet attrs) { 171415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes this(context, attrs, R.attr.switchStyle); 172415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 173415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 174415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 175415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Construct a new Switch with a default style determined by the given theme attribute, 176415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * overriding specific style attributes as requested. 177415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 178415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param context The Context that will determine this widget's theming. 179415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param attrs Specification of attributes that should deviate from the default styling. 180415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param defStyleAttr An attribute in the current theme that contains a 181415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * reference to a style resource that supplies default values for 182415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * the view. Can be 0 to not look for defaults. 183415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 184415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public SwitchCompat(Context context, AttributeSet attrs, int defStyleAttr) { 185415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super(context, attrs, defStyleAttr); 186415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 187415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); 188415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 189415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Resources res = getResources(); 190415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextPaint.density = res.getDisplayMetrics().density; 191415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 192415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, 193415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes attrs, R.styleable.SwitchCompat, defStyleAttr, 0); 194415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbDrawable = a.getDrawable(R.styleable.SwitchCompat_android_thumb); 195415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTrackDrawable = a.getDrawable(R.styleable.SwitchCompat_track); 196415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextOn = a.getText(R.styleable.SwitchCompat_android_textOn); 197415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextOff = a.getText(R.styleable.SwitchCompat_android_textOff); 198415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mShowText = a.getBoolean(R.styleable.SwitchCompat_showText, true); 199415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbTextPadding = a.getDimensionPixelSize( 200415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes R.styleable.SwitchCompat_thumbTextPadding, 0); 201415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchMinWidth = a.getDimensionPixelSize( 202415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes R.styleable.SwitchCompat_switchMinWidth, 0); 203415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchPadding = a.getDimensionPixelSize( 204415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes R.styleable.SwitchCompat_switchPadding, 0); 205415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSplitTrack = a.getBoolean(R.styleable.SwitchCompat_splitTrack, false); 206415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 207415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int appearance = a.getResourceId( 208415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes R.styleable.SwitchCompat_switchTextAppearance, 0); 209415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (appearance != 0) { 210415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes setSwitchTextAppearance(context, appearance); 211415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 212415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 213415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTintManager = a.getTintManager(); 214415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 215415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes a.recycle(); 216415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 217415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final ViewConfiguration config = ViewConfiguration.get(context); 218415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTouchSlop = config.getScaledTouchSlop(); 219415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mMinFlingVelocity = config.getScaledMinimumFlingVelocity(); 220415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 221415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Refresh display with current params 222415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes refreshDrawableState(); 223415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes setChecked(isChecked()); 224415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 225415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 226415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 227415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Sets the switch text color, size, style, hint color, and highlight color 228415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * from the specified TextAppearance resource. 229415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 230415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setSwitchTextAppearance(Context context, int resid) { 231415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes TypedArray appearance = context.obtainStyledAttributes(resid, TEXT_APPEARANCE_ATTRS); 232415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 233415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes ColorStateList colors; 234415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int ts; 235415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 236415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes colors = appearance.getColorStateList(0); 237415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (colors != null) { 238415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextColors = colors; 239415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 240415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // If no color set in TextAppearance, default to the view's textColor 241415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextColors = getTextColors(); 242415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 243415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 244415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes ts = appearance.getDimensionPixelSize(1, 0); 245415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (ts != 0) { 246415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (ts != mTextPaint.getTextSize()) { 247415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextPaint.setTextSize(ts); 248415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes requestLayout(); 249415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 250415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 251415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 252415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes boolean allCaps = appearance.getBoolean(2, false); 253415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (allCaps) { 254415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchTransformationMethod = new AllCapsTransformationMethod(getContext()); 255415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 256415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchTransformationMethod = null; 257415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 258415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 259415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes appearance.recycle(); 260415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 261415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 262415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 263415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Sets the typeface and style in which the text should be displayed on the 264415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * switch, and turns on the fake bold and italic bits in the Paint if the 265415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Typeface that you provided does not have all the bits in the 266415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * style that you specified. 267415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 268415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setSwitchTypeface(Typeface tf, int style) { 269415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (style > 0) { 270415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (tf == null) { 271415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes tf = Typeface.defaultFromStyle(style); 272415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 273415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes tf = Typeface.create(tf, style); 274415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 275415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 276415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes setSwitchTypeface(tf); 277415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // now compute what (if any) algorithmic styling is needed 278415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int typefaceStyle = tf != null ? tf.getStyle() : 0; 279415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int need = style & ~typefaceStyle; 280415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextPaint.setFakeBoldText((need & Typeface.BOLD) != 0); 281415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextPaint.setTextSkewX((need & Typeface.ITALIC) != 0 ? -0.25f : 0); 282415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 283415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextPaint.setFakeBoldText(false); 284415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextPaint.setTextSkewX(0); 285415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes setSwitchTypeface(tf); 286415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 287415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 288415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 289415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 290415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Sets the typeface in which the text should be displayed on the switch. 291415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Note that not all Typeface families actually have bold and italic 292415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * variants, so you may need to use 293415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * {@link #setSwitchTypeface(Typeface, int)} to get the appearance 294415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * that you actually want. 295415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 296415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setSwitchTypeface(Typeface tf) { 297415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mTextPaint.getTypeface() != tf) { 298415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextPaint.setTypeface(tf); 299415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 300415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes requestLayout(); 301415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes invalidate(); 302415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 303415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 304415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 305415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 306415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Set the amount of horizontal padding between the switch and the associated text. 307415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 308415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param pixels Amount of padding in pixels 309415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 310415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setSwitchPadding(int pixels) { 311415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchPadding = pixels; 312415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes requestLayout(); 313415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 314415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 315415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 316415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Get the amount of horizontal padding between the switch and the associated text. 317415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 318415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @return Amount of padding in pixels 319415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 320415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public int getSwitchPadding() { 321415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mSwitchPadding; 322415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 323415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 324415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 325415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Set the minimum width of the switch in pixels. The switch's width will be the maximum 326415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * of this value and its measured width as determined by the switch drawables and text used. 327415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 328415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param pixels Minimum width of the switch in pixels 329415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 330415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setSwitchMinWidth(int pixels) { 331415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchMinWidth = pixels; 332415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes requestLayout(); 333415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 334415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 335415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 336415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Get the minimum width of the switch in pixels. The switch's width will be the maximum 337415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * of this value and its measured width as determined by the switch drawables and text used. 338415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 339415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @return Minimum width of the switch in pixels 340415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 341415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public int getSwitchMinWidth() { 342415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mSwitchMinWidth; 343415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 344415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 345415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 346415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Set the horizontal padding around the text drawn on the switch itself. 347415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 348415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param pixels Horizontal padding for switch thumb text in pixels 349415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 350415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setThumbTextPadding(int pixels) { 351415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbTextPadding = pixels; 352415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes requestLayout(); 353415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 354415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 355415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 356415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Get the horizontal padding around the text drawn on the switch itself. 357415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 358415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @return Horizontal padding for switch thumb text in pixels 359415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 360415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public int getThumbTextPadding() { 361415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mThumbTextPadding; 362415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 363415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 364415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 365415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Set the drawable used for the track that the switch slides within. 366415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 367415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param track Track drawable 368415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 369415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setTrackDrawable(Drawable track) { 370415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTrackDrawable = track; 371415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes requestLayout(); 372415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 373415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 374415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 375415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Set the drawable used for the track that the switch slides within. 376415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 377415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param resId Resource ID of a track drawable 378415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 379415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setTrackResource(int resId) { 380415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes setTrackDrawable(mTintManager.getDrawable(resId)); 381415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 382415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 383415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 384415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Get the drawable used for the track that the switch slides within. 385415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 386415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @return Track drawable 387415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 388415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public Drawable getTrackDrawable() { 389415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mTrackDrawable; 390415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 391415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 392415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 393415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Set the drawable used for the switch "thumb" - the piece that the user 394415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * can physically touch and drag along the track. 395415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 396415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param thumb Thumb drawable 397415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 398415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setThumbDrawable(Drawable thumb) { 399415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbDrawable = thumb; 400415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes requestLayout(); 401415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 402415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 403415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 404415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Set the drawable used for the switch "thumb" - the piece that the user 405415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * can physically touch and drag along the track. 406415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 407415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param resId Resource ID of a thumb drawable 408415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 409415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setThumbResource(int resId) { 410415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes setThumbDrawable(mTintManager.getDrawable(resId)); 411415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 412415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 413415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 414415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Get the drawable used for the switch "thumb" - the piece that the user 415415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * can physically touch and drag along the track. 416415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 417415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @return Thumb drawable 418415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 419415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public Drawable getThumbDrawable() { 420415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mThumbDrawable; 421415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 422415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 423415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 424415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Specifies whether the track should be split by the thumb. When true, 425415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * the thumb's optical bounds will be clipped out of the track drawable, 426415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * then the thumb will be drawn into the resulting gap. 427415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 428415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param splitTrack Whether the track should be split by the thumb 429415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 430415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setSplitTrack(boolean splitTrack) { 431415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSplitTrack = splitTrack; 432415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes invalidate(); 433415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 434415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 435415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 436415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Returns whether the track should be split by the thumb. 437415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 438415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public boolean getSplitTrack() { 439415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mSplitTrack; 440415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 441415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 442415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 443415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Returns the text displayed when the button is in the checked state. 444415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 445415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public CharSequence getTextOn() { 446415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mTextOn; 447415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 448415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 449415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 450415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Sets the text displayed when the button is in the checked state. 451415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 452415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setTextOn(CharSequence textOn) { 453415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextOn = textOn; 454415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes requestLayout(); 455415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 456415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 457415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 458415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Returns the text displayed when the button is not in the checked state. 459415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 460415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public CharSequence getTextOff() { 461415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mTextOff; 462415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 463415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 464415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 465415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Sets the text displayed when the button is not in the checked state. 466415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 467415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setTextOff(CharSequence textOff) { 468415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextOff = textOff; 469415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes requestLayout(); 470415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 471415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 472415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 473415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Sets whether the on/off text should be displayed. 474415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 475415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param showText {@code true} to display on/off text 476415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 477415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setShowText(boolean showText) { 478415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mShowText != showText) { 479415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mShowText = showText; 480415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes requestLayout(); 481415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 482415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 483415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 484415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 485415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @return whether the on/off text should be displayed 486415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 487415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public boolean getShowText() { 488415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mShowText; 489415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 490415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 491415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 492415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 493415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mShowText) { 494415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mOnLayout == null) { 495415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mOnLayout = makeLayout(mTextOn); 496415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 497415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 498415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mOffLayout == null) { 499415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mOffLayout = makeLayout(mTextOff); 500415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 501415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 502415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 503415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Rect padding = mTempRect; 504415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int thumbWidth; 505415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int thumbHeight; 506415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mThumbDrawable != null) { 507415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Cached thumb width does not include padding. 508415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbDrawable.getPadding(padding); 509415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes thumbWidth = mThumbDrawable.getIntrinsicWidth() - padding.left - padding.right; 510415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes thumbHeight = mThumbDrawable.getIntrinsicHeight(); 511415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 512415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes thumbWidth = 0; 513415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes thumbHeight = 0; 514415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 515415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 516415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int maxTextWidth; 517415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mShowText) { 518415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes maxTextWidth = Math.max(mOnLayout.getWidth(), mOffLayout.getWidth()) 519415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes + mThumbTextPadding * 2; 520415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 521415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes maxTextWidth = 0; 522415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 523415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 524415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbWidth = Math.max(maxTextWidth, thumbWidth); 525415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 526415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int trackHeight; 527415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mTrackDrawable != null) { 528415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTrackDrawable.getPadding(padding); 529415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes trackHeight = mTrackDrawable.getIntrinsicHeight(); 530415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 531415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes padding.setEmpty(); 532415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes trackHeight = 0; 533415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 534415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 535415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Adjust left and right padding to ensure there's enough room for the 536415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // thumb's padding (when present). 537415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int paddingLeft = padding.left; 538415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int paddingRight = padding.right; 539415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 540415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchWidth = Math.max(mSwitchMinWidth, 541415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 2 * mThumbWidth + paddingLeft + paddingRight); 542415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchHeight = Math.max(trackHeight, thumbHeight); 543415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchWidth = switchWidth; 544415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchHeight = switchHeight; 545415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 546415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.onMeasure(widthMeasureSpec, heightMeasureSpec); 547415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 548415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int measuredHeight = getMeasuredHeight(); 549415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (measuredHeight < switchHeight) { 550415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes setMeasuredDimension(ViewCompat.getMeasuredWidthAndState(this), switchHeight); 551415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 552415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 553415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 554415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) 555415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 556415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 557415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.onPopulateAccessibilityEvent(event); 558415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 559415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final CharSequence text = isChecked() ? mTextOn : mTextOff; 560415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (text != null) { 561415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes event.getText().add(text); 562415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 563415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 564415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 565415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private Layout makeLayout(CharSequence text) { 566415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final CharSequence transformed = (mSwitchTransformationMethod != null) 567415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes ? mSwitchTransformationMethod.getTransformation(text, this) 568415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes : text; 569415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 570415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return new StaticLayout(transformed, mTextPaint, 571415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes (int) Math.ceil(Layout.getDesiredWidth(transformed, mTextPaint)), 572415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes Layout.Alignment.ALIGN_NORMAL, 1.f, 0, true); 573415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 574415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 575415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 576415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @return true if (x, y) is within the target area of the switch thumb 577415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 578415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private boolean hitThumb(float x, float y) { 579415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Relies on mTempRect, MUST be called first! 580415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int thumbOffset = getThumbOffset(); 581415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 582415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbDrawable.getPadding(mTempRect); 583415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int thumbTop = mSwitchTop - mTouchSlop; 584415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int thumbLeft = mSwitchLeft + thumbOffset - mTouchSlop; 585415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int thumbRight = thumbLeft + mThumbWidth + 586415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTempRect.left + mTempRect.right + mTouchSlop; 587415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int thumbBottom = mSwitchBottom + mTouchSlop; 588415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return x > thumbLeft && x < thumbRight && y > thumbTop && y < thumbBottom; 589415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 590415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 591415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 592415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public boolean onTouchEvent(MotionEvent ev) { 593415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mVelocityTracker.addMovement(ev); 594415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int action = MotionEventCompat.getActionMasked(ev); 595415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switch (action) { 596415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes case MotionEvent.ACTION_DOWN: { 597415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final float x = ev.getX(); 598415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final float y = ev.getY(); 599415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (isEnabled() && hitThumb(x, y)) { 600415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTouchMode = TOUCH_MODE_DOWN; 601415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTouchX = x; 602415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTouchY = y; 603415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 604415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes break; 605415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 606415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 607415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes case MotionEvent.ACTION_MOVE: { 608415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switch (mTouchMode) { 609415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes case TOUCH_MODE_IDLE: 610415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Didn't target the thumb, treat normally. 611415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes break; 612415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 613415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes case TOUCH_MODE_DOWN: { 614415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final float x = ev.getX(); 615415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final float y = ev.getY(); 616415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (Math.abs(x - mTouchX) > mTouchSlop || 617415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes Math.abs(y - mTouchY) > mTouchSlop) { 618415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTouchMode = TOUCH_MODE_DRAGGING; 619415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes getParent().requestDisallowInterceptTouchEvent(true); 620415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTouchX = x; 621415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTouchY = y; 622415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return true; 623415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 624415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes break; 625415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 626415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 627415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes case TOUCH_MODE_DRAGGING: { 628415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final float x = ev.getX(); 629415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int thumbScrollRange = getThumbScrollRange(); 630415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final float thumbScrollOffset = x - mTouchX; 631415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes float dPos; 632415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (thumbScrollRange != 0) { 633415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes dPos = thumbScrollOffset / thumbScrollRange; 634415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 635415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // If the thumb scroll range is empty, just use the 636415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // movement direction to snap on or off. 637415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes dPos = thumbScrollOffset > 0 ? 1 : -1; 638415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 639415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (ViewUtils.isLayoutRtl(this)) { 640415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes dPos = -dPos; 641415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 642415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final float newPos = constrain(mThumbPosition + dPos, 0, 1); 643415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (newPos != mThumbPosition) { 644415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTouchX = x; 645415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes setThumbPosition(newPos); 646415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 647415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return true; 648415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 649415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 650415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes break; 651415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 652415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 653415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes case MotionEvent.ACTION_UP: 654415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes case MotionEvent.ACTION_CANCEL: { 655415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mTouchMode == TOUCH_MODE_DRAGGING) { 656415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes stopDrag(ev); 657415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Allow super class to handle pressed state, etc. 658415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.onTouchEvent(ev); 659415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return true; 660415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 661415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTouchMode = TOUCH_MODE_IDLE; 662415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mVelocityTracker.clear(); 663415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes break; 664415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 665415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 666415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 667415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return super.onTouchEvent(ev); 668415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 669415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 670415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private void cancelSuperTouch(MotionEvent ev) { 671415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes MotionEvent cancel = MotionEvent.obtain(ev); 672415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes cancel.setAction(MotionEvent.ACTION_CANCEL); 673415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.onTouchEvent(cancel); 674415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes cancel.recycle(); 675415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 676415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 677415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 678415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Called from onTouchEvent to end a drag operation. 679415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 680415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param ev Event that triggered the end of drag mode - ACTION_UP or ACTION_CANCEL 681415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 682415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private void stopDrag(MotionEvent ev) { 683415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTouchMode = TOUCH_MODE_IDLE; 684415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 685415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Commit the change if the event is up and not canceled and the switch 686415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // has not been disabled during the drag. 687415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final boolean commitChange = ev.getAction() == MotionEvent.ACTION_UP && isEnabled(); 688415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final boolean newState; 689415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (commitChange) { 690415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mVelocityTracker.computeCurrentVelocity(1000); 691415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final float xvel = mVelocityTracker.getXVelocity(); 692415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (Math.abs(xvel) > mMinFlingVelocity) { 693415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes newState = ViewUtils.isLayoutRtl(this) ? (xvel < 0) : (xvel > 0); 694415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 695415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes newState = getTargetCheckedState(); 696415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 697415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 698415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes newState = isChecked(); 699415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 700415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 701415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes setChecked(newState); 702415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes cancelSuperTouch(ev); 703415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 704415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 705415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private void animateThumbToCheckedState(boolean newCheckedState) { 706415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final float startPosition = mThumbPosition; 707415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final float targetPosition = newCheckedState ? 1 : 0; 708415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final float diff = targetPosition - startPosition; 709415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 710415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mPositionAnimator = new Animation() { 711415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 712415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes protected void applyTransformation(float interpolatedTime, Transformation t) { 713415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes setThumbPosition(startPosition + (diff * interpolatedTime)); 714415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 715415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes }; 716415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mPositionAnimator.setDuration(THUMB_ANIMATION_DURATION); 717415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes startAnimation(mPositionAnimator); 718415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 719415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 720415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private void cancelPositionAnimator() { 721415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mPositionAnimator != null) { 722415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes clearAnimation(); 723415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mPositionAnimator = null; 724415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 725415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 726415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 727415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private boolean getTargetCheckedState() { 728415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mThumbPosition > 0.5f; 729415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 730415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 731415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 732415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Sets the thumb position as a decimal value between 0 (off) and 1 (on). 733415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 734415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param position new position between [0,1] 735415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 736415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private void setThumbPosition(float position) { 737415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbPosition = position; 738415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes invalidate(); 739415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 740415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 741415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 742415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void toggle() { 743415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes setChecked(!isChecked()); 744415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 745415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 746415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 747415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setChecked(boolean checked) { 748415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.setChecked(checked); 749415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 750415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Calling the super method may result in setChecked() getting called 751415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // recursively with a different value, so load the REAL value... 752415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes checked = isChecked(); 753415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 754415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (getWindowToken() != null) { 755415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes animateThumbToCheckedState(checked); 756415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 757415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Immediately move the thumb to the new position. 758415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes cancelPositionAnimator(); 759415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes setThumbPosition(checked ? 1 : 0); 760415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 761415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 762415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 763415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 764415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 765415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.onLayout(changed, left, top, right, bottom); 766415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 767415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int opticalInsetLeft = 0; 768415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int opticalInsetRight = 0; 769415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mThumbDrawable != null) { 770415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Rect trackPadding = mTempRect; 771415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mTrackDrawable != null) { 772415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTrackDrawable.getPadding(trackPadding); 773415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 774415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes trackPadding.setEmpty(); 775415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 776415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 777415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes opticalInsetLeft = 0; 778415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes opticalInsetRight = 0; 779415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 780415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 781415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchRight; 782415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchLeft; 783415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (ViewUtils.isLayoutRtl(this)) { 784415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchLeft = getPaddingLeft() + opticalInsetLeft; 785415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchRight = switchLeft + mSwitchWidth - opticalInsetLeft - opticalInsetRight; 786415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 787415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchRight = getWidth() - getPaddingRight() - opticalInsetRight; 788415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchLeft = switchRight - mSwitchWidth + opticalInsetLeft + opticalInsetRight; 789415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 790415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 791415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchTop; 792415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchBottom; 793415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switch (getGravity() & Gravity.VERTICAL_GRAVITY_MASK) { 794415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes default: 795415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes case Gravity.TOP: 796415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchTop = getPaddingTop(); 797415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchBottom = switchTop + mSwitchHeight; 798415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes break; 799415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 800415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes case Gravity.CENTER_VERTICAL: 801415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchTop = (getPaddingTop() + getHeight() - getPaddingBottom()) / 2 - 802415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchHeight / 2; 803415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchBottom = switchTop + mSwitchHeight; 804415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes break; 805415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 806415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes case Gravity.BOTTOM: 807415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchBottom = getHeight() - getPaddingBottom(); 808415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchTop = switchBottom - mSwitchHeight; 809415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes break; 810415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 811415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 812415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchLeft = switchLeft; 813415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchTop = switchTop; 814415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchBottom = switchBottom; 815415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchRight = switchRight; 816415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 817415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 818415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 819415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void draw(Canvas c) { 820415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Rect padding = mTempRect; 821415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchLeft = mSwitchLeft; 822415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchTop = mSwitchTop; 823415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchRight = mSwitchRight; 824415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchBottom = mSwitchBottom; 825415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 826415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int thumbInitialLeft = switchLeft + getThumbOffset(); 827415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 828415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Layout the track. 829415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mTrackDrawable != null) { 830415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTrackDrawable.getPadding(padding); 831415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 832415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Adjust thumb position for track padding. 833415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes thumbInitialLeft += padding.left; 834415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 835415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // If necessary, offset by the optical insets of the thumb asset. 836415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int trackLeft = switchLeft; 837415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int trackTop = switchTop; 838415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int trackRight = switchRight; 839415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int trackBottom = switchBottom; 840415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTrackDrawable.setBounds(trackLeft, trackTop, trackRight, trackBottom); 841415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 842415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 843415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Layout the thumb. 844415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mThumbDrawable != null) { 845415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbDrawable.getPadding(padding); 846415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 847415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int thumbLeft = thumbInitialLeft - padding.left; 848415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int thumbRight = thumbInitialLeft + mThumbWidth + padding.right; 849415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbDrawable.setBounds(thumbLeft, switchTop, thumbRight, switchBottom); 850415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 851415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Drawable background = getBackground(); 852415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (background != null) { 853415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes DrawableCompat.setHotspotBounds(background, thumbLeft, switchTop, 854415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes thumbRight, switchBottom); 855415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 856415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 857415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 858415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Draw the background. 859415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.draw(c); 860415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 861415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 862415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 863415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes protected void onDraw(Canvas canvas) { 864415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.onDraw(canvas); 865415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 866415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Rect padding = mTempRect; 867415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Drawable trackDrawable = mTrackDrawable; 868415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (trackDrawable != null) { 869415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes trackDrawable.getPadding(padding); 870415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 871415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes padding.setEmpty(); 872415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 873415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 874415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchTop = mSwitchTop; 875415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchBottom = mSwitchBottom; 876415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchInnerTop = switchTop + padding.top; 877415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchInnerBottom = switchBottom - padding.bottom; 878415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 879415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Drawable thumbDrawable = mThumbDrawable; 880415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (trackDrawable != null) { 881415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes trackDrawable.draw(canvas); 882415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 883415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 884415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int saveCount = canvas.save(); 885415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 886415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (thumbDrawable != null) { 887415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes thumbDrawable.draw(canvas); 888415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 889415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 890415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Layout switchText = getTargetCheckedState() ? mOnLayout : mOffLayout; 891415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (switchText != null) { 892415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int drawableState[] = getDrawableState(); 893415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mTextColors != null) { 894415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextPaint.setColor(mTextColors.getColorForState(drawableState, 0)); 895415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 896415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextPaint.drawableState = drawableState; 897415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 898415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int cX; 899415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (thumbDrawable != null) { 900415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Rect bounds = thumbDrawable.getBounds(); 901415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes cX = bounds.left + bounds.right; 902415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 903415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes cX = getWidth(); 904415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 905415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 906415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int left = cX / 2 - switchText.getWidth() / 2; 907415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int top = (switchInnerTop + switchInnerBottom) / 2 - switchText.getHeight() / 2; 908415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes canvas.translate(left, top); 909415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchText.draw(canvas); 910415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 911415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 912415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes canvas.restoreToCount(saveCount); 913415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 914415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 915415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 916415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public int getCompoundPaddingLeft() { 917415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (!ViewUtils.isLayoutRtl(this)) { 918415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return super.getCompoundPaddingLeft(); 919415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 920415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int padding = super.getCompoundPaddingLeft() + mSwitchWidth; 921415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (!TextUtils.isEmpty(getText())) { 922415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes padding += mSwitchPadding; 923415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 924415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return padding; 925415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 926415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 927415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 928415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public int getCompoundPaddingRight() { 929415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (ViewUtils.isLayoutRtl(this)) { 930415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return super.getCompoundPaddingRight(); 931415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 932415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int padding = super.getCompoundPaddingRight() + mSwitchWidth; 933415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (!TextUtils.isEmpty(getText())) { 934415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes padding += mSwitchPadding; 935415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 936415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return padding; 937415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 938415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 939415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 940415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Translates thumb position to offset according to current RTL setting and 941415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * thumb scroll range. Accounts for both track and thumb padding. 942415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 943415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @return thumb offset 944415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 945415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int getThumbOffset() { 946415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final float thumbPosition; 947415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (ViewUtils.isLayoutRtl(this)) { 948415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes thumbPosition = 1 - mThumbPosition; 949415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 950415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes thumbPosition = mThumbPosition; 951415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 952415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return (int) (thumbPosition * getThumbScrollRange() + 0.5f); 953415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 954415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 955415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int getThumbScrollRange() { 956415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mTrackDrawable != null) { 957415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Rect padding = mTempRect; 958415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTrackDrawable.getPadding(padding); 959415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mSwitchWidth - mThumbWidth - padding.left - padding.right; 960415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 961415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return 0; 962415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 963415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 964415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 965415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 966415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes protected int[] onCreateDrawableState(int extraSpace) { 967415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int[] drawableState = super.onCreateDrawableState(extraSpace + 1); 968415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (isChecked()) { 969415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mergeDrawableStates(drawableState, CHECKED_STATE_SET); 970415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 971415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return drawableState; 972415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 973415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 974415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 975415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes protected void drawableStateChanged() { 976415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.drawableStateChanged(); 977415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 978415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int[] myDrawableState = getDrawableState(); 979415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 980415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mThumbDrawable != null) { 981415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbDrawable.setState(myDrawableState); 982415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 983415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 984415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mTrackDrawable != null) { 985415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTrackDrawable.setState(myDrawableState); 986415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 987415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 988415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes invalidate(); 989415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 990415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 991415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 992415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void drawableHotspotChanged(float x, float y) { 993415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.drawableHotspotChanged(x, y); 994415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 995415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mThumbDrawable != null) { 996415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes DrawableCompat.setHotspot(mThumbDrawable, x, y); 997415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 998415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 999415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mTrackDrawable != null) { 1000415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes DrawableCompat.setHotspot(mTrackDrawable, x, y); 1001415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1002415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1003415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1004415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 1005415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes protected boolean verifyDrawable(Drawable who) { 1006415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return super.verifyDrawable(who) || who == mThumbDrawable || who == mTrackDrawable; 1007415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1008415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1009415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 1010415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void jumpDrawablesToCurrentState() { 1011415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (Build.VERSION.SDK_INT >= 11) { 1012415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.jumpDrawablesToCurrentState(); 1013415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1014415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mThumbDrawable != null) { 1015415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbDrawable.jumpToCurrentState(); 1016415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1017415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1018415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mTrackDrawable != null) { 1019415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTrackDrawable.jumpToCurrentState(); 1020415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1021415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1022415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mPositionAnimator != null && mPositionAnimator.hasStarted() && 1023415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes !mPositionAnimator.hasEnded()) { 1024415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes clearAnimation(); 1025415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mPositionAnimator = null; 1026415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1027415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1028415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1029415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1030415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) 1031415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 1032415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 1033415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.onInitializeAccessibilityEvent(event); 1034415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes event.setClassName(SwitchCompat.class.getName()); 1035415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1036415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1037415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 1038415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 1039415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (Build.VERSION.SDK_INT >= 14) { 1040415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.onInitializeAccessibilityNodeInfo(info); 1041415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes info.setClassName(SwitchCompat.class.getName()); 1042415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes CharSequence switchText = isChecked() ? mTextOn : mTextOff; 1043415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (!TextUtils.isEmpty(switchText)) { 1044415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes CharSequence oldText = info.getText(); 1045415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (TextUtils.isEmpty(oldText)) { 1046415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes info.setText(switchText); 1047415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 1048415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes StringBuilder newText = new StringBuilder(); 1049415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes newText.append(oldText).append(' ').append(switchText); 1050415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes info.setText(newText); 1051415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1052415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1053415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1054415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1055415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1056415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 1057415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Taken from android.util.MathUtils 1058415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 1059415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private static float constrain(float amount, float low, float high) { 1060415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return amount < low ? low : (amount > high ? high : amount); 1061415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1062415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes}