SwitchCompat.java revision 5dc563e669eb337639a8b0b9e4e28cd5ea08fbea
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.annotation.TargetApi; 20415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.content.Context; 21415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.content.res.ColorStateList; 22415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.content.res.Resources; 23415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.content.res.TypedArray; 24415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.graphics.Canvas; 25415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.graphics.Paint; 26415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.graphics.Rect; 27414f52397a88d52a783a31d4c098bc3bec632b8dChris Banesimport android.graphics.Region; 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; 36414f52397a88d52a783a31d4c098bc3bec632b8dChris Banesimport android.support.v7.internal.widget.DrawableUtils; 37415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.support.v7.internal.widget.TintManager; 38415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.support.v7.internal.widget.TintTypedArray; 39415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.support.v7.internal.widget.ViewUtils; 40415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.text.Layout; 41415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.text.StaticLayout; 42415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.text.TextPaint; 43415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.text.TextUtils; 44415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.text.method.TransformationMethod; 45415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.util.AttributeSet; 46415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.view.Gravity; 47415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.view.MotionEvent; 4836ba98b397a95e5d74318f7d9008fdaf604c05c2Chris Banesimport android.view.SoundEffectConstants; 49415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.view.VelocityTracker; 50415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.view.ViewConfiguration; 51415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.view.accessibility.AccessibilityEvent; 52415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.view.accessibility.AccessibilityNodeInfo; 53415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.view.animation.Animation; 54415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.view.animation.Transformation; 55415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.widget.CompoundButton; 56415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 57415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes/** 58415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * SwitchCompat is a version of the Switch widget which on devices back to API v7. It does not 59415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * make any attempt to use the platform provided widget on those devices which it is available 60415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * normally. 61415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * <p> 62415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * A Switch is a two-state toggle switch widget that can select between two 63415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * options. The user may drag the "thumb" back and forth to choose the selected option, 64415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * or simply tap to toggle as if it were a checkbox. The {@link #setText(CharSequence) text} 65415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * property controls the text displayed in the label for the switch, whereas the 66415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * {@link #setTextOff(CharSequence) off} and {@link #setTextOn(CharSequence) on} text 67415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * controls the text on the thumb. Similarly, the 68415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * {@link #setTextAppearance(android.content.Context, int) textAppearance} and the related 69415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * setTypeface() methods control the typeface and style of label text, whereas the 70415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * {@link #setSwitchTextAppearance(android.content.Context, int) switchTextAppearance} and 71415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * the related seSwitchTypeface() methods control that of the thumb. 72415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 73415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banespublic class SwitchCompat extends CompoundButton { 74415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private static final int THUMB_ANIMATION_DURATION = 250; 75415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 76415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private static final int TOUCH_MODE_IDLE = 0; 77415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private static final int TOUCH_MODE_DOWN = 1; 78415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private static final int TOUCH_MODE_DRAGGING = 2; 79415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 80befecd646c6b7249ee9894ee2c21a5965bb33cffChris Banes // We force the accessibility events to have a class name of Switch, since screen readers 81befecd646c6b7249ee9894ee2c21a5965bb33cffChris Banes // already know how to handle their events 82befecd646c6b7249ee9894ee2c21a5965bb33cffChris Banes private static final String ACCESSIBILITY_EVENT_CLASS_NAME = "android.widget.Switch"; 83befecd646c6b7249ee9894ee2c21a5965bb33cffChris 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; 1432f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes private ThumbAnimation 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); 195414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes if (mThumbDrawable != null) { 196414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes mThumbDrawable.setCallback(this); 197414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 198415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTrackDrawable = a.getDrawable(R.styleable.SwitchCompat_track); 199414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes if (mTrackDrawable != null) { 200414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes mTrackDrawable.setCallback(this); 201414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 202415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextOn = a.getText(R.styleable.SwitchCompat_android_textOn); 203415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextOff = a.getText(R.styleable.SwitchCompat_android_textOff); 204415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mShowText = a.getBoolean(R.styleable.SwitchCompat_showText, true); 205415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbTextPadding = a.getDimensionPixelSize( 206415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes R.styleable.SwitchCompat_thumbTextPadding, 0); 207415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchMinWidth = a.getDimensionPixelSize( 208415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes R.styleable.SwitchCompat_switchMinWidth, 0); 209415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchPadding = a.getDimensionPixelSize( 210415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes R.styleable.SwitchCompat_switchPadding, 0); 211415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSplitTrack = a.getBoolean(R.styleable.SwitchCompat_splitTrack, false); 212415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 213415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int appearance = a.getResourceId( 214415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes R.styleable.SwitchCompat_switchTextAppearance, 0); 215415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (appearance != 0) { 216415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes setSwitchTextAppearance(context, appearance); 217415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 218415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 219415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTintManager = a.getTintManager(); 220415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 221415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes a.recycle(); 222415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 223415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final ViewConfiguration config = ViewConfiguration.get(context); 224415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTouchSlop = config.getScaledTouchSlop(); 225415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mMinFlingVelocity = config.getScaledMinimumFlingVelocity(); 226415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 227415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Refresh display with current params 228415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes refreshDrawableState(); 229415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes setChecked(isChecked()); 230415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 231415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 232415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 233415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Sets the switch text color, size, style, hint color, and highlight color 234415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * from the specified TextAppearance resource. 235415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 236415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setSwitchTextAppearance(Context context, int resid) { 237320c3e9fe1e100a5a7cda5dd217d2d1152d08b3fChris Banes TypedArray appearance = context.obtainStyledAttributes(resid, R.styleable.TextAppearance); 238415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 239415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes ColorStateList colors; 240415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int ts; 241415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 242320c3e9fe1e100a5a7cda5dd217d2d1152d08b3fChris Banes colors = appearance.getColorStateList(R.styleable.TextAppearance_android_textColor); 243415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (colors != null) { 244415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextColors = colors; 245415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 246415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // If no color set in TextAppearance, default to the view's textColor 247415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextColors = getTextColors(); 248415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 249415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 250320c3e9fe1e100a5a7cda5dd217d2d1152d08b3fChris Banes ts = appearance.getDimensionPixelSize(R.styleable.TextAppearance_android_textSize, 0); 251415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (ts != 0) { 252415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (ts != mTextPaint.getTextSize()) { 253415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextPaint.setTextSize(ts); 254415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes requestLayout(); 255415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 256415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 257415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 258414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes int typefaceIndex, styleIndex; 259320c3e9fe1e100a5a7cda5dd217d2d1152d08b3fChris Banes typefaceIndex = appearance.getInt(R.styleable.TextAppearance_android_typeface, -1); 260320c3e9fe1e100a5a7cda5dd217d2d1152d08b3fChris Banes styleIndex = appearance.getInt(R.styleable.TextAppearance_android_textStyle, -1); 261414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes 262414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes setSwitchTypefaceByIndex(typefaceIndex, styleIndex); 263414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes 264320c3e9fe1e100a5a7cda5dd217d2d1152d08b3fChris Banes boolean allCaps = appearance.getBoolean(R.styleable.TextAppearance_textAllCaps, false); 265415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (allCaps) { 266415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchTransformationMethod = new AllCapsTransformationMethod(getContext()); 267415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 268415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchTransformationMethod = null; 269415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 270415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 271415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes appearance.recycle(); 272415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 273415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 274414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes private void setSwitchTypefaceByIndex(int typefaceIndex, int styleIndex) { 275414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes Typeface tf = null; 276414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes switch (typefaceIndex) { 277414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes case SANS: 278414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes tf = Typeface.SANS_SERIF; 279414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes break; 280414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes 281414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes case SERIF: 282414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes tf = Typeface.SERIF; 283414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes break; 284414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes 285414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes case MONOSPACE: 286414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes tf = Typeface.MONOSPACE; 287414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes break; 288414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 289414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes 290414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes setSwitchTypeface(tf, styleIndex); 291414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 292414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes 293415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 294415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Sets the typeface and style in which the text should be displayed on the 295415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * switch, and turns on the fake bold and italic bits in the Paint if the 296415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Typeface that you provided does not have all the bits in the 297415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * style that you specified. 298415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 299415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setSwitchTypeface(Typeface tf, int style) { 300415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (style > 0) { 301415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (tf == null) { 302415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes tf = Typeface.defaultFromStyle(style); 303415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 304415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes tf = Typeface.create(tf, style); 305415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 306415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 307415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes setSwitchTypeface(tf); 308415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // now compute what (if any) algorithmic styling is needed 309415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int typefaceStyle = tf != null ? tf.getStyle() : 0; 310415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int need = style & ~typefaceStyle; 311415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextPaint.setFakeBoldText((need & Typeface.BOLD) != 0); 312415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextPaint.setTextSkewX((need & Typeface.ITALIC) != 0 ? -0.25f : 0); 313415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 314415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextPaint.setFakeBoldText(false); 315415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextPaint.setTextSkewX(0); 316415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes setSwitchTypeface(tf); 317415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 318415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 319415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 320415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 321415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Sets the typeface in which the text should be displayed on the switch. 322415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Note that not all Typeface families actually have bold and italic 323415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * variants, so you may need to use 324415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * {@link #setSwitchTypeface(Typeface, int)} to get the appearance 325415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * that you actually want. 326415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 327415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setSwitchTypeface(Typeface tf) { 328415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mTextPaint.getTypeface() != tf) { 329415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextPaint.setTypeface(tf); 330415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 331415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes requestLayout(); 332415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes invalidate(); 333415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 334415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 335415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 336415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 337415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Set the amount of horizontal padding between the switch and the associated text. 338415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 339415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param pixels Amount of padding in pixels 340415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 341415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setSwitchPadding(int pixels) { 342415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchPadding = pixels; 343415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes requestLayout(); 344415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 345415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 346415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 347415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Get the amount of horizontal padding between the switch and the associated text. 348415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 349415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @return Amount of padding in pixels 350415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 351415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public int getSwitchPadding() { 352415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mSwitchPadding; 353415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 354415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 355415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 356415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Set the minimum width of the switch in pixels. The switch's width will be the maximum 357415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * of this value and its measured width as determined by the switch drawables and text used. 358415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 359415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param pixels Minimum width of the switch in pixels 360415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 361415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setSwitchMinWidth(int pixels) { 362415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchMinWidth = pixels; 363415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes requestLayout(); 364415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 365415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 366415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 367415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Get the minimum width of the switch in pixels. The switch's width will be the maximum 368415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * of this value and its measured width as determined by the switch drawables and text used. 369415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 370415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @return Minimum width of the switch in pixels 371415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 372415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public int getSwitchMinWidth() { 373415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mSwitchMinWidth; 374415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 375415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 376415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 377415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Set the horizontal padding around the text drawn on the switch itself. 378415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 379415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param pixels Horizontal padding for switch thumb text in pixels 380415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 381415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setThumbTextPadding(int pixels) { 382415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbTextPadding = pixels; 383415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes requestLayout(); 384415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 385415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 386415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 387415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Get the horizontal padding around the text drawn on the switch itself. 388415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 389415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @return Horizontal padding for switch thumb text in pixels 390415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 391415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public int getThumbTextPadding() { 392415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mThumbTextPadding; 393415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 394415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 395415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 396415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Set the drawable used for the track that the switch slides within. 397415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 398415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param track Track drawable 399415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 400415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setTrackDrawable(Drawable track) { 401415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTrackDrawable = track; 402415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes requestLayout(); 403415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 404415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 405415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 406415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Set the drawable used for the track that the switch slides within. 407415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 408415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param resId Resource ID of a track drawable 409415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 410415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setTrackResource(int resId) { 411415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes setTrackDrawable(mTintManager.getDrawable(resId)); 412415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 413415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 414415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 415415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Get the drawable used for the track that the switch slides within. 416415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 417415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @return Track drawable 418415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 419415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public Drawable getTrackDrawable() { 420415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mTrackDrawable; 421415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 422415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 423415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 424415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Set the drawable used for the switch "thumb" - the piece that the user 425415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * can physically touch and drag along the track. 426415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 427415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param thumb Thumb drawable 428415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 429415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setThumbDrawable(Drawable thumb) { 430415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbDrawable = thumb; 431415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes requestLayout(); 432415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 433415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 434415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 435415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Set the drawable used for the switch "thumb" - the piece that the user 436415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * can physically touch and drag along the track. 437415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 438415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param resId Resource ID of a thumb drawable 439415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 440415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setThumbResource(int resId) { 441415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes setThumbDrawable(mTintManager.getDrawable(resId)); 442415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 443415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 444415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 445415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Get the drawable used for the switch "thumb" - the piece that the user 446415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * can physically touch and drag along the track. 447415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 448415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @return Thumb drawable 449415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 450415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public Drawable getThumbDrawable() { 451415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mThumbDrawable; 452415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 453415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 454415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 455415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Specifies whether the track should be split by the thumb. When true, 456415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * the thumb's optical bounds will be clipped out of the track drawable, 457415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * then the thumb will be drawn into the resulting gap. 458415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 459415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param splitTrack Whether the track should be split by the thumb 460415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 461415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setSplitTrack(boolean splitTrack) { 462415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSplitTrack = splitTrack; 463415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes invalidate(); 464415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 465415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 466415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 467415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Returns whether the track should be split by the thumb. 468415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 469415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public boolean getSplitTrack() { 470415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mSplitTrack; 471415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 472415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 473415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 474415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Returns the text displayed when the button is in the checked state. 475415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 476415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public CharSequence getTextOn() { 477415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mTextOn; 478415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 479415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 480415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 481415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Sets the text displayed when the button is in the checked state. 482415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 483415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setTextOn(CharSequence textOn) { 484415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextOn = textOn; 485415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes requestLayout(); 486415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 487415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 488415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 489415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Returns the text displayed when the button is not in the checked state. 490415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 491415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public CharSequence getTextOff() { 492415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mTextOff; 493415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 494415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 495415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 496415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Sets the text displayed when the button is not in the checked state. 497415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 498415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setTextOff(CharSequence textOff) { 499415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextOff = textOff; 500415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes requestLayout(); 501415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 502415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 503415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 504415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Sets whether the on/off text should be displayed. 505415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 506415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param showText {@code true} to display on/off text 507415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 508415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setShowText(boolean showText) { 509415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mShowText != showText) { 510415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mShowText = showText; 511415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes requestLayout(); 512415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 513415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 514415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 515415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 516415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @return whether the on/off text should be displayed 517415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 518415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public boolean getShowText() { 519415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mShowText; 520415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 521415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 522415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 523415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 524415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mShowText) { 525415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mOnLayout == null) { 526415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mOnLayout = makeLayout(mTextOn); 527415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 528415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 529415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mOffLayout == null) { 530415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mOffLayout = makeLayout(mTextOff); 531415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 532415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 533415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 534415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Rect padding = mTempRect; 535415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int thumbWidth; 536415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int thumbHeight; 537415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mThumbDrawable != null) { 538415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Cached thumb width does not include padding. 539415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbDrawable.getPadding(padding); 540415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes thumbWidth = mThumbDrawable.getIntrinsicWidth() - padding.left - padding.right; 541415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes thumbHeight = mThumbDrawable.getIntrinsicHeight(); 542415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 543415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes thumbWidth = 0; 544415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes thumbHeight = 0; 545415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 546415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 547415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int maxTextWidth; 548415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mShowText) { 549415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes maxTextWidth = Math.max(mOnLayout.getWidth(), mOffLayout.getWidth()) 550415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes + mThumbTextPadding * 2; 551415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 552415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes maxTextWidth = 0; 553415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 554415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 555415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbWidth = Math.max(maxTextWidth, thumbWidth); 556415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 557415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int trackHeight; 558415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mTrackDrawable != null) { 559415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTrackDrawable.getPadding(padding); 560415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes trackHeight = mTrackDrawable.getIntrinsicHeight(); 561415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 562415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes padding.setEmpty(); 563415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes trackHeight = 0; 564415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 565415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 566415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Adjust left and right padding to ensure there's enough room for the 567415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // thumb's padding (when present). 568415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int paddingLeft = padding.left; 569415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int paddingRight = padding.right; 570414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes if (mThumbDrawable != null) { 571414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes final Rect inset = DrawableUtils.getOpticalBounds(mThumbDrawable); 572414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes paddingLeft = Math.max(paddingLeft, inset.left); 573414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes paddingRight = Math.max(paddingRight, inset.right); 574414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 575415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 576415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchWidth = Math.max(mSwitchMinWidth, 577415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 2 * mThumbWidth + paddingLeft + paddingRight); 578415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchHeight = Math.max(trackHeight, thumbHeight); 579415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchWidth = switchWidth; 580415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchHeight = switchHeight; 581415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 582415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.onMeasure(widthMeasureSpec, heightMeasureSpec); 583415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 584415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int measuredHeight = getMeasuredHeight(); 585415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (measuredHeight < switchHeight) { 586415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes setMeasuredDimension(ViewCompat.getMeasuredWidthAndState(this), switchHeight); 587415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 588415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 589415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 590415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) 591415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 592415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 593415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.onPopulateAccessibilityEvent(event); 594415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 595415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final CharSequence text = isChecked() ? mTextOn : mTextOff; 596415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (text != null) { 597415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes event.getText().add(text); 598415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 599415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 600415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 601415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private Layout makeLayout(CharSequence text) { 602415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final CharSequence transformed = (mSwitchTransformationMethod != null) 603415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes ? mSwitchTransformationMethod.getTransformation(text, this) 604415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes : text; 605415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 606415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return new StaticLayout(transformed, mTextPaint, 6071949ae9aeaadf52ad7bd7bb74ca5419c67ea7f65Taeho Kim transformed != null ? 6081949ae9aeaadf52ad7bd7bb74ca5419c67ea7f65Taeho Kim (int) Math.ceil(Layout.getDesiredWidth(transformed, mTextPaint)) : 0, 609415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes Layout.Alignment.ALIGN_NORMAL, 1.f, 0, true); 610415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 611415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 612415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 613415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @return true if (x, y) is within the target area of the switch thumb 614415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 615415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private boolean hitThumb(float x, float y) { 616af34a5378411bd76e8fd45a2bf23d17ccc19aae1Chris Banes if (mThumbDrawable == null) { 617af34a5378411bd76e8fd45a2bf23d17ccc19aae1Chris Banes return false; 618af34a5378411bd76e8fd45a2bf23d17ccc19aae1Chris Banes } 619af34a5378411bd76e8fd45a2bf23d17ccc19aae1Chris Banes 620415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Relies on mTempRect, MUST be called first! 621415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int thumbOffset = getThumbOffset(); 622415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 623415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbDrawable.getPadding(mTempRect); 624415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int thumbTop = mSwitchTop - mTouchSlop; 625415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int thumbLeft = mSwitchLeft + thumbOffset - mTouchSlop; 626415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int thumbRight = thumbLeft + mThumbWidth + 627415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTempRect.left + mTempRect.right + mTouchSlop; 628415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int thumbBottom = mSwitchBottom + mTouchSlop; 629415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return x > thumbLeft && x < thumbRight && y > thumbTop && y < thumbBottom; 630415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 631415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 632415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 633415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public boolean onTouchEvent(MotionEvent ev) { 634415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mVelocityTracker.addMovement(ev); 635415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int action = MotionEventCompat.getActionMasked(ev); 636415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switch (action) { 637415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes case MotionEvent.ACTION_DOWN: { 638415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final float x = ev.getX(); 639415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final float y = ev.getY(); 640415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (isEnabled() && hitThumb(x, y)) { 641415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTouchMode = TOUCH_MODE_DOWN; 642415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTouchX = x; 643415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTouchY = y; 644415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 645415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes break; 646415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 647415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 648415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes case MotionEvent.ACTION_MOVE: { 649415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switch (mTouchMode) { 650415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes case TOUCH_MODE_IDLE: 651415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Didn't target the thumb, treat normally. 652415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes break; 653415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 654415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes case TOUCH_MODE_DOWN: { 655415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final float x = ev.getX(); 656415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final float y = ev.getY(); 657415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (Math.abs(x - mTouchX) > mTouchSlop || 658415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes Math.abs(y - mTouchY) > mTouchSlop) { 659415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTouchMode = TOUCH_MODE_DRAGGING; 660415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes getParent().requestDisallowInterceptTouchEvent(true); 661415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTouchX = x; 662415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTouchY = y; 663415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return true; 664415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 665415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes break; 666415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 667415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 668415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes case TOUCH_MODE_DRAGGING: { 669415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final float x = ev.getX(); 670415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int thumbScrollRange = getThumbScrollRange(); 671415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final float thumbScrollOffset = x - mTouchX; 672415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes float dPos; 673415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (thumbScrollRange != 0) { 674415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes dPos = thumbScrollOffset / thumbScrollRange; 675415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 676415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // If the thumb scroll range is empty, just use the 677415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // movement direction to snap on or off. 678415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes dPos = thumbScrollOffset > 0 ? 1 : -1; 679415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 680415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (ViewUtils.isLayoutRtl(this)) { 681415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes dPos = -dPos; 682415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 683415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final float newPos = constrain(mThumbPosition + dPos, 0, 1); 684415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (newPos != mThumbPosition) { 685415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTouchX = x; 686415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes setThumbPosition(newPos); 687415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 688415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return true; 689415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 690415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 691415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes break; 692415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 693415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 694415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes case MotionEvent.ACTION_UP: 695415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes case MotionEvent.ACTION_CANCEL: { 696415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mTouchMode == TOUCH_MODE_DRAGGING) { 697415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes stopDrag(ev); 698415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Allow super class to handle pressed state, etc. 699415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.onTouchEvent(ev); 700415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return true; 701415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 702415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTouchMode = TOUCH_MODE_IDLE; 703415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mVelocityTracker.clear(); 704415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes break; 705415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 706415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 707415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 708415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return super.onTouchEvent(ev); 709415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 710415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 711415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private void cancelSuperTouch(MotionEvent ev) { 712415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes MotionEvent cancel = MotionEvent.obtain(ev); 713415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes cancel.setAction(MotionEvent.ACTION_CANCEL); 714415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.onTouchEvent(cancel); 715415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes cancel.recycle(); 716415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 717415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 718415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 719415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Called from onTouchEvent to end a drag operation. 720415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 721415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param ev Event that triggered the end of drag mode - ACTION_UP or ACTION_CANCEL 722415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 723415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private void stopDrag(MotionEvent ev) { 724415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTouchMode = TOUCH_MODE_IDLE; 725415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 726415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Commit the change if the event is up and not canceled and the switch 727415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // has not been disabled during the drag. 728415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final boolean commitChange = ev.getAction() == MotionEvent.ACTION_UP && isEnabled(); 72936ba98b397a95e5d74318f7d9008fdaf604c05c2Chris Banes final boolean oldState = isChecked(); 730415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final boolean newState; 731415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (commitChange) { 732415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mVelocityTracker.computeCurrentVelocity(1000); 733415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final float xvel = mVelocityTracker.getXVelocity(); 734415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (Math.abs(xvel) > mMinFlingVelocity) { 735415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes newState = ViewUtils.isLayoutRtl(this) ? (xvel < 0) : (xvel > 0); 736415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 737415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes newState = getTargetCheckedState(); 738415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 739415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 74036ba98b397a95e5d74318f7d9008fdaf604c05c2Chris Banes newState = oldState; 741415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 742415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 74336ba98b397a95e5d74318f7d9008fdaf604c05c2Chris Banes if (newState != oldState) { 74436ba98b397a95e5d74318f7d9008fdaf604c05c2Chris Banes playSoundEffect(SoundEffectConstants.CLICK); 74536ba98b397a95e5d74318f7d9008fdaf604c05c2Chris Banes } 746964d1912cc68e67fdbbe4643004a00c706bffdbaChris Banes // Always call setChecked so that the thumb is moved back to the correct edge 747964d1912cc68e67fdbbe4643004a00c706bffdbaChris Banes setChecked(newState); 748415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes cancelSuperTouch(ev); 749415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 750415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 7515dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes private void animateThumbToCheckedState(final boolean newCheckedState) { 7525dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes if (mPositionAnimator != null) { 7535dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes // If there's a current animator running, cancel it 7545dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes cancelPositionAnimator(); 7555dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes } 7565dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes 7575dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes mPositionAnimator = new ThumbAnimation(mThumbPosition, newCheckedState ? 1f : 0f); 758415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mPositionAnimator.setDuration(THUMB_ANIMATION_DURATION); 7595dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes mPositionAnimator.setAnimationListener(new Animation.AnimationListener() { 7605dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes @Override 7615dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes public void onAnimationStart(Animation animation) {} 7625dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes 7635dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes @Override 7645dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes public void onAnimationEnd(Animation animation) { 7655dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes if (mPositionAnimator == animation) { 7665dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes // If we're still the active animation, ensure the final position 7675dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes setThumbPosition(newCheckedState ? 1f : 0f); 7685dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes mPositionAnimator = null; 7695dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes } 7705dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes } 7715dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes 7725dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes @Override 7735dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes public void onAnimationRepeat(Animation animation) {} 7745dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes }); 775415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes startAnimation(mPositionAnimator); 776415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 777415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 778415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private void cancelPositionAnimator() { 779415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mPositionAnimator != null) { 780415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes clearAnimation(); 781415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mPositionAnimator = null; 782415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 783415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 784415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 785415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private boolean getTargetCheckedState() { 786415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mThumbPosition > 0.5f; 787415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 788415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 789415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 790415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Sets the thumb position as a decimal value between 0 (off) and 1 (on). 791415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 792415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param position new position between [0,1] 793415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 794415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private void setThumbPosition(float position) { 795415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbPosition = position; 796415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes invalidate(); 797415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 798415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 799415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 800415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void toggle() { 801415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes setChecked(!isChecked()); 802415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 803415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 804415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 805415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setChecked(boolean checked) { 806415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.setChecked(checked); 807415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 808415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Calling the super method may result in setChecked() getting called 809415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // recursively with a different value, so load the REAL value... 810415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes checked = isChecked(); 811415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 81287638543a7f772792e77f4bb260e6dc117c52674Chris Banes if (getWindowToken() != null && ViewCompat.isLaidOut(this) && isShown()) { 813415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes animateThumbToCheckedState(checked); 814415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 815415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Immediately move the thumb to the new position. 816415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes cancelPositionAnimator(); 817415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes setThumbPosition(checked ? 1 : 0); 818415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 819415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 820415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 821415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 822415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 823415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.onLayout(changed, left, top, right, bottom); 824415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 825415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int opticalInsetLeft = 0; 826415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int opticalInsetRight = 0; 827415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mThumbDrawable != null) { 828415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Rect trackPadding = mTempRect; 829415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mTrackDrawable != null) { 830415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTrackDrawable.getPadding(trackPadding); 831415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 832415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes trackPadding.setEmpty(); 833415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 834415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 835414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes final Rect insets = DrawableUtils.getOpticalBounds(mThumbDrawable); 836414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes opticalInsetLeft = Math.max(0, insets.left - trackPadding.left); 837414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes opticalInsetRight = Math.max(0, insets.right - trackPadding.right); 838415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 839415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 840415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchRight; 841415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchLeft; 842415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (ViewUtils.isLayoutRtl(this)) { 843415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchLeft = getPaddingLeft() + opticalInsetLeft; 844415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchRight = switchLeft + mSwitchWidth - opticalInsetLeft - opticalInsetRight; 845415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 846415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchRight = getWidth() - getPaddingRight() - opticalInsetRight; 847415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchLeft = switchRight - mSwitchWidth + opticalInsetLeft + opticalInsetRight; 848415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 849415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 850415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchTop; 851415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchBottom; 852415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switch (getGravity() & Gravity.VERTICAL_GRAVITY_MASK) { 853415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes default: 854415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes case Gravity.TOP: 855415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchTop = getPaddingTop(); 856415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchBottom = switchTop + mSwitchHeight; 857415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes break; 858415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 859415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes case Gravity.CENTER_VERTICAL: 860415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchTop = (getPaddingTop() + getHeight() - getPaddingBottom()) / 2 - 861415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchHeight / 2; 862415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchBottom = switchTop + mSwitchHeight; 863415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes break; 864415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 865415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes case Gravity.BOTTOM: 866415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchBottom = getHeight() - getPaddingBottom(); 867415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchTop = switchBottom - mSwitchHeight; 868415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes break; 869415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 870415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 871415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchLeft = switchLeft; 872415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchTop = switchTop; 873415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchBottom = switchBottom; 874415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchRight = switchRight; 875415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 876415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 877415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 878415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void draw(Canvas c) { 879415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Rect padding = mTempRect; 880415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchLeft = mSwitchLeft; 881415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchTop = mSwitchTop; 882415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchRight = mSwitchRight; 883415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchBottom = mSwitchBottom; 884415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 885415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int thumbInitialLeft = switchLeft + getThumbOffset(); 886415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 887414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes final Rect thumbInsets; 888414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes if (mThumbDrawable != null) { 889414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes thumbInsets = DrawableUtils.getOpticalBounds(mThumbDrawable); 890414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } else { 891414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes thumbInsets = DrawableUtils.INSETS_NONE; 892414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 893414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes 894415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Layout the track. 895415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mTrackDrawable != null) { 896415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTrackDrawable.getPadding(padding); 897415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 898415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Adjust thumb position for track padding. 899415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes thumbInitialLeft += padding.left; 900415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 901415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // If necessary, offset by the optical insets of the thumb asset. 902415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int trackLeft = switchLeft; 903415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int trackTop = switchTop; 904415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int trackRight = switchRight; 905415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int trackBottom = switchBottom; 9065dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes if (thumbInsets != null) { 907414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes if (thumbInsets.left > padding.left) { 908414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes trackLeft += thumbInsets.left - padding.left; 909414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 910414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes if (thumbInsets.top > padding.top) { 911414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes trackTop += thumbInsets.top - padding.top; 912414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 913414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes if (thumbInsets.right > padding.right) { 914414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes trackRight -= thumbInsets.right - padding.right; 915414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 916414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes if (thumbInsets.bottom > padding.bottom) { 917414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes trackBottom -= thumbInsets.bottom - padding.bottom; 918414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 919414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 920415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTrackDrawable.setBounds(trackLeft, trackTop, trackRight, trackBottom); 921415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 922415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 923415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Layout the thumb. 924415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mThumbDrawable != null) { 925415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbDrawable.getPadding(padding); 926415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 927415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int thumbLeft = thumbInitialLeft - padding.left; 928415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int thumbRight = thumbInitialLeft + mThumbWidth + padding.right; 929415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbDrawable.setBounds(thumbLeft, switchTop, thumbRight, switchBottom); 930415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 931415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Drawable background = getBackground(); 932415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (background != null) { 933415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes DrawableCompat.setHotspotBounds(background, thumbLeft, switchTop, 934415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes thumbRight, switchBottom); 935415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 936415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 937415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 938415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Draw the background. 939415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.draw(c); 940415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 941415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 942415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 943415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes protected void onDraw(Canvas canvas) { 944415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.onDraw(canvas); 945415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 946415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Rect padding = mTempRect; 947415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Drawable trackDrawable = mTrackDrawable; 948415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (trackDrawable != null) { 949415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes trackDrawable.getPadding(padding); 950415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 951415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes padding.setEmpty(); 952415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 953415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 954415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchTop = mSwitchTop; 955415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchBottom = mSwitchBottom; 956415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchInnerTop = switchTop + padding.top; 957415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchInnerBottom = switchBottom - padding.bottom; 958415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 959415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Drawable thumbDrawable = mThumbDrawable; 960415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (trackDrawable != null) { 961414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes if (mSplitTrack && thumbDrawable != null) { 962414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes final Rect insets = DrawableUtils.getOpticalBounds(thumbDrawable); 963414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes thumbDrawable.copyBounds(padding); 964414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes padding.left += insets.left; 965414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes padding.right -= insets.right; 966414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes 967414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes final int saveCount = canvas.save(); 968414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes canvas.clipRect(padding, Region.Op.DIFFERENCE); 969414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes trackDrawable.draw(canvas); 970414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes canvas.restoreToCount(saveCount); 971414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } else { 972414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes trackDrawable.draw(canvas); 973414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 974415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 975415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 976415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int saveCount = canvas.save(); 977415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 978415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (thumbDrawable != null) { 979415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes thumbDrawable.draw(canvas); 980415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 981415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 982415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Layout switchText = getTargetCheckedState() ? mOnLayout : mOffLayout; 983415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (switchText != null) { 984415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int drawableState[] = getDrawableState(); 985415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mTextColors != null) { 986415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextPaint.setColor(mTextColors.getColorForState(drawableState, 0)); 987415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 988415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextPaint.drawableState = drawableState; 989415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 990415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int cX; 991415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (thumbDrawable != null) { 992415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Rect bounds = thumbDrawable.getBounds(); 993415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes cX = bounds.left + bounds.right; 994415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 995415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes cX = getWidth(); 996415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 997415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 998415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int left = cX / 2 - switchText.getWidth() / 2; 999415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int top = (switchInnerTop + switchInnerBottom) / 2 - switchText.getHeight() / 2; 1000415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes canvas.translate(left, top); 1001415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchText.draw(canvas); 1002415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1003415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1004415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes canvas.restoreToCount(saveCount); 1005415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1006415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1007415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 1008415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public int getCompoundPaddingLeft() { 1009415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (!ViewUtils.isLayoutRtl(this)) { 1010415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return super.getCompoundPaddingLeft(); 1011415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1012415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int padding = super.getCompoundPaddingLeft() + mSwitchWidth; 1013415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (!TextUtils.isEmpty(getText())) { 1014415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes padding += mSwitchPadding; 1015415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1016415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return padding; 1017415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1018415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1019415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 1020415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public int getCompoundPaddingRight() { 1021415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (ViewUtils.isLayoutRtl(this)) { 1022415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return super.getCompoundPaddingRight(); 1023415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1024415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int padding = super.getCompoundPaddingRight() + mSwitchWidth; 1025415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (!TextUtils.isEmpty(getText())) { 1026415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes padding += mSwitchPadding; 1027415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1028415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return padding; 1029415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1030415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1031415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 1032415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Translates thumb position to offset according to current RTL setting and 1033415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * thumb scroll range. Accounts for both track and thumb padding. 1034415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 1035415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @return thumb offset 1036415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 1037415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int getThumbOffset() { 1038415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final float thumbPosition; 1039415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (ViewUtils.isLayoutRtl(this)) { 1040415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes thumbPosition = 1 - mThumbPosition; 1041415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 1042415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes thumbPosition = mThumbPosition; 1043415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1044415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return (int) (thumbPosition * getThumbScrollRange() + 0.5f); 1045415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1046415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1047415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int getThumbScrollRange() { 1048415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mTrackDrawable != null) { 1049415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Rect padding = mTempRect; 1050415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTrackDrawable.getPadding(padding); 1051414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes 1052414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes final Rect insets; 1053414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes if (mThumbDrawable != null) { 1054414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes insets = DrawableUtils.getOpticalBounds(mThumbDrawable); 1055414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } else { 1056414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes insets = DrawableUtils.INSETS_NONE; 1057414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 1058414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes 1059414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes return mSwitchWidth - mThumbWidth - padding.left - padding.right 1060414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes - insets.left - insets.right; 1061415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 1062415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return 0; 1063415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1064415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1065415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1066415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 1067415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes protected int[] onCreateDrawableState(int extraSpace) { 1068415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int[] drawableState = super.onCreateDrawableState(extraSpace + 1); 1069415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (isChecked()) { 1070415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mergeDrawableStates(drawableState, CHECKED_STATE_SET); 1071415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1072415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return drawableState; 1073415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1074415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1075415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 1076415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes protected void drawableStateChanged() { 1077415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.drawableStateChanged(); 1078415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1079415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int[] myDrawableState = getDrawableState(); 1080415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1081415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mThumbDrawable != null) { 1082415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbDrawable.setState(myDrawableState); 1083415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1084415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1085415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mTrackDrawable != null) { 1086415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTrackDrawable.setState(myDrawableState); 1087415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1088415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1089415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes invalidate(); 1090415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1091415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1092415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 1093415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void drawableHotspotChanged(float x, float y) { 109436ba98b397a95e5d74318f7d9008fdaf604c05c2Chris Banes if (Build.VERSION.SDK_INT >= 21) { 109536ba98b397a95e5d74318f7d9008fdaf604c05c2Chris Banes super.drawableHotspotChanged(x, y); 109636ba98b397a95e5d74318f7d9008fdaf604c05c2Chris Banes } 1097415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1098415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mThumbDrawable != null) { 1099415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes DrawableCompat.setHotspot(mThumbDrawable, x, y); 1100415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1101415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1102415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mTrackDrawable != null) { 1103415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes DrawableCompat.setHotspot(mTrackDrawable, x, y); 1104415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1105415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1106415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1107415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 1108415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes protected boolean verifyDrawable(Drawable who) { 1109415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return super.verifyDrawable(who) || who == mThumbDrawable || who == mTrackDrawable; 1110415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1111415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1112415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 1113415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void jumpDrawablesToCurrentState() { 1114415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (Build.VERSION.SDK_INT >= 11) { 1115415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.jumpDrawablesToCurrentState(); 1116415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1117415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mThumbDrawable != null) { 1118415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbDrawable.jumpToCurrentState(); 1119415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1120415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1121415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mTrackDrawable != null) { 1122415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTrackDrawable.jumpToCurrentState(); 1123415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1124415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 11255dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes cancelPositionAnimator(); 1126415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1127415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1128415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1129415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) 1130415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 1131415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 1132415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.onInitializeAccessibilityEvent(event); 1133befecd646c6b7249ee9894ee2c21a5965bb33cffChris Banes event.setClassName(ACCESSIBILITY_EVENT_CLASS_NAME); 1134415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1135415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1136415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 1137415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 1138415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (Build.VERSION.SDK_INT >= 14) { 1139415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.onInitializeAccessibilityNodeInfo(info); 1140befecd646c6b7249ee9894ee2c21a5965bb33cffChris Banes info.setClassName(ACCESSIBILITY_EVENT_CLASS_NAME); 1141415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes CharSequence switchText = isChecked() ? mTextOn : mTextOff; 1142415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (!TextUtils.isEmpty(switchText)) { 1143415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes CharSequence oldText = info.getText(); 1144415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (TextUtils.isEmpty(oldText)) { 1145415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes info.setText(switchText); 1146415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 1147415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes StringBuilder newText = new StringBuilder(); 1148415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes newText.append(oldText).append(' ').append(switchText); 1149415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes info.setText(newText); 1150415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1151415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1152415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1153415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1154415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1155415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 1156415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Taken from android.util.MathUtils 1157415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 1158415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private static float constrain(float amount, float low, float high) { 1159415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return amount < low ? low : (amount > high ? high : amount); 1160415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 11612f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes 11622f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes private class ThumbAnimation extends Animation { 11632f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes final float mStartPosition; 11642f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes final float mEndPosition; 11652f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes final float mDiff; 11662f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes 11672f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes private ThumbAnimation(float startPosition, float endPosition) { 11682f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes mStartPosition = startPosition; 11692f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes mEndPosition = endPosition; 11702f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes mDiff = endPosition - startPosition; 11712f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes } 11722f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes 11732f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes @Override 11742f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes protected void applyTransformation(float interpolatedTime, Transformation t) { 11752f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes setThumbPosition(mStartPosition + (mDiff * interpolatedTime)); 11762f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes } 11772f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes } 1178415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes}