SwitchCompat.java revision 66698bb15ba0f873aa1c2290cc50d6bb839a474a
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; 3566698bb15ba0f873aa1c2290cc50d6bb839a474aChris Banesimport android.support.v7.text.AllCapsTransformationMethod; 36415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.text.Layout; 37415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.text.StaticLayout; 38415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.text.TextPaint; 39415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.text.TextUtils; 40415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.text.method.TransformationMethod; 41415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.util.AttributeSet; 42415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.view.Gravity; 43415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.view.MotionEvent; 4436ba98b397a95e5d74318f7d9008fdaf604c05c2Chris Banesimport android.view.SoundEffectConstants; 45415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.view.VelocityTracker; 46415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.view.ViewConfiguration; 47415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.view.accessibility.AccessibilityEvent; 48415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.view.accessibility.AccessibilityNodeInfo; 49415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.view.animation.Animation; 50415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.view.animation.Transformation; 51415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.widget.CompoundButton; 52415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 53415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes/** 54415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * SwitchCompat is a version of the Switch widget which on devices back to API v7. It does not 55415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * make any attempt to use the platform provided widget on those devices which it is available 56415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * normally. 57415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * <p> 58415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * A Switch is a two-state toggle switch widget that can select between two 59415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * options. The user may drag the "thumb" back and forth to choose the selected option, 60415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * or simply tap to toggle as if it were a checkbox. The {@link #setText(CharSequence) text} 61415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * property controls the text displayed in the label for the switch, whereas the 62415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * {@link #setTextOff(CharSequence) off} and {@link #setTextOn(CharSequence) on} text 63415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * controls the text on the thumb. Similarly, the 64415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * {@link #setTextAppearance(android.content.Context, int) textAppearance} and the related 65415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * setTypeface() methods control the typeface and style of label text, whereas the 66415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * {@link #setSwitchTextAppearance(android.content.Context, int) switchTextAppearance} and 67415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * the related seSwitchTypeface() methods control that of the thumb. 68415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 69415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banespublic class SwitchCompat extends CompoundButton { 70415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private static final int THUMB_ANIMATION_DURATION = 250; 71415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 72415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private static final int TOUCH_MODE_IDLE = 0; 73415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private static final int TOUCH_MODE_DOWN = 1; 74415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private static final int TOUCH_MODE_DRAGGING = 2; 75415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 76befecd646c6b7249ee9894ee2c21a5965bb33cffChris Banes // We force the accessibility events to have a class name of Switch, since screen readers 77befecd646c6b7249ee9894ee2c21a5965bb33cffChris Banes // already know how to handle their events 78befecd646c6b7249ee9894ee2c21a5965bb33cffChris Banes private static final String ACCESSIBILITY_EVENT_CLASS_NAME = "android.widget.Switch"; 79befecd646c6b7249ee9894ee2c21a5965bb33cffChris Banes 80415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Enum for the "typeface" XML parameter. 81415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private static final int SANS = 1; 82415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private static final int SERIF = 2; 83415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private static final int MONOSPACE = 3; 84415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 85415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private Drawable mThumbDrawable; 86415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private Drawable mTrackDrawable; 87415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int mThumbTextPadding; 88415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int mSwitchMinWidth; 89415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int mSwitchPadding; 90415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private boolean mSplitTrack; 91415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private CharSequence mTextOn; 92415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private CharSequence mTextOff; 93415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private boolean mShowText; 94415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 95415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int mTouchMode; 96415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int mTouchSlop; 97415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private float mTouchX; 98415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private float mTouchY; 99415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private VelocityTracker mVelocityTracker = VelocityTracker.obtain(); 100415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int mMinFlingVelocity; 101415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 102415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private float mThumbPosition; 103415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 104415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 105415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Width required to draw the switch track and thumb. Includes padding and 106415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * optical bounds for both the track and thumb. 107415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 108415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int mSwitchWidth; 109415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 110415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 111415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Height required to draw the switch track and thumb. Includes padding and 112415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * optical bounds for both the track and thumb. 113415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 114415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int mSwitchHeight; 115415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 116415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 117415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Width of the thumb's content region. Does not include padding or 118415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * optical bounds. 119415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 120415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int mThumbWidth; 121415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 122415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** Left bound for drawing the switch track and thumb. */ 123415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int mSwitchLeft; 124415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 125415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** Top bound for drawing the switch track and thumb. */ 126415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int mSwitchTop; 127415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 128415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** Right bound for drawing the switch track and thumb. */ 129415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int mSwitchRight; 130415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 131415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** Bottom bound for drawing the switch track and thumb. */ 132415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int mSwitchBottom; 133415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 134415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private TextPaint mTextPaint; 135415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private ColorStateList mTextColors; 136415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private Layout mOnLayout; 137415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private Layout mOffLayout; 138415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private TransformationMethod mSwitchTransformationMethod; 1392f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes private ThumbAnimation mPositionAnimator; 140415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 141415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @SuppressWarnings("hiding") 142415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private final Rect mTempRect = new Rect(); 143415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1447e4e8b664820f773bc96e37ee1d2bbf500d64e69Chris Banes private final AppCompatDrawableManager mDrawableManager; 145415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 146415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private static final int[] CHECKED_STATE_SET = { 147415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes android.R.attr.state_checked 148415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes }; 149415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 150415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 151415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Construct a new Switch with default styling. 152415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 153415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param context The Context that will determine this widget's theming. 154415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 155415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public SwitchCompat(Context context) { 156415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes this(context, null); 157415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 158415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 159415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 160415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Construct a new Switch with default styling, overriding specific style 161415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * attributes as requested. 162415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 163415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param context The Context that will determine this widget's theming. 164415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param attrs Specification of attributes that should deviate from default styling. 165415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 166415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public SwitchCompat(Context context, AttributeSet attrs) { 167415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes this(context, attrs, R.attr.switchStyle); 168415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 169415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 170415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 171415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Construct a new Switch with a default style determined by the given theme attribute, 172415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * overriding specific style attributes as requested. 173415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 174415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param context The Context that will determine this widget's theming. 175415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param attrs Specification of attributes that should deviate from the default styling. 176415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param defStyleAttr An attribute in the current theme that contains a 177415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * reference to a style resource that supplies default values for 178415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * the view. Can be 0 to not look for defaults. 179415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 180415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public SwitchCompat(Context context, AttributeSet attrs, int defStyleAttr) { 181415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super(context, attrs, defStyleAttr); 182415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 183415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); 184415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 185415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Resources res = getResources(); 186415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextPaint.density = res.getDisplayMetrics().density; 187415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 188415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, 189415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes attrs, R.styleable.SwitchCompat, defStyleAttr, 0); 190415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbDrawable = a.getDrawable(R.styleable.SwitchCompat_android_thumb); 191414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes if (mThumbDrawable != null) { 192414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes mThumbDrawable.setCallback(this); 193414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 194415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTrackDrawable = a.getDrawable(R.styleable.SwitchCompat_track); 195414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes if (mTrackDrawable != null) { 196414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes mTrackDrawable.setCallback(this); 197414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 198415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextOn = a.getText(R.styleable.SwitchCompat_android_textOn); 199415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextOff = a.getText(R.styleable.SwitchCompat_android_textOff); 200415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mShowText = a.getBoolean(R.styleable.SwitchCompat_showText, true); 201415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbTextPadding = a.getDimensionPixelSize( 202415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes R.styleable.SwitchCompat_thumbTextPadding, 0); 203415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchMinWidth = a.getDimensionPixelSize( 204415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes R.styleable.SwitchCompat_switchMinWidth, 0); 205415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchPadding = a.getDimensionPixelSize( 206415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes R.styleable.SwitchCompat_switchPadding, 0); 207415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSplitTrack = a.getBoolean(R.styleable.SwitchCompat_splitTrack, false); 208415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 209415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int appearance = a.getResourceId( 210415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes R.styleable.SwitchCompat_switchTextAppearance, 0); 211415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (appearance != 0) { 212415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes setSwitchTextAppearance(context, appearance); 213415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 214415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 2157e4e8b664820f773bc96e37ee1d2bbf500d64e69Chris Banes mDrawableManager = AppCompatDrawableManager.get(); 216415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 217415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes a.recycle(); 218415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 219415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final ViewConfiguration config = ViewConfiguration.get(context); 220415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTouchSlop = config.getScaledTouchSlop(); 221415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mMinFlingVelocity = config.getScaledMinimumFlingVelocity(); 222415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 223415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Refresh display with current params 224415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes refreshDrawableState(); 225415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes setChecked(isChecked()); 226415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 227415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 228415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 229415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Sets the switch text color, size, style, hint color, and highlight color 230415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * from the specified TextAppearance resource. 231415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 232415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setSwitchTextAppearance(Context context, int resid) { 233320c3e9fe1e100a5a7cda5dd217d2d1152d08b3fChris Banes TypedArray appearance = context.obtainStyledAttributes(resid, R.styleable.TextAppearance); 234415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 235415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes ColorStateList colors; 236415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int ts; 237415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 238320c3e9fe1e100a5a7cda5dd217d2d1152d08b3fChris Banes colors = appearance.getColorStateList(R.styleable.TextAppearance_android_textColor); 239415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (colors != null) { 240415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextColors = colors; 241415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 242415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // If no color set in TextAppearance, default to the view's textColor 243415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextColors = getTextColors(); 244415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 245415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 246320c3e9fe1e100a5a7cda5dd217d2d1152d08b3fChris Banes ts = appearance.getDimensionPixelSize(R.styleable.TextAppearance_android_textSize, 0); 247415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (ts != 0) { 248415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (ts != mTextPaint.getTextSize()) { 249415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextPaint.setTextSize(ts); 250415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes requestLayout(); 251415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 252415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 253415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 254414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes int typefaceIndex, styleIndex; 255320c3e9fe1e100a5a7cda5dd217d2d1152d08b3fChris Banes typefaceIndex = appearance.getInt(R.styleable.TextAppearance_android_typeface, -1); 256320c3e9fe1e100a5a7cda5dd217d2d1152d08b3fChris Banes styleIndex = appearance.getInt(R.styleable.TextAppearance_android_textStyle, -1); 257414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes 258414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes setSwitchTypefaceByIndex(typefaceIndex, styleIndex); 259414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes 260320c3e9fe1e100a5a7cda5dd217d2d1152d08b3fChris Banes boolean allCaps = appearance.getBoolean(R.styleable.TextAppearance_textAllCaps, false); 261415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (allCaps) { 262415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchTransformationMethod = new AllCapsTransformationMethod(getContext()); 263415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 264415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchTransformationMethod = null; 265415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 266415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 267415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes appearance.recycle(); 268415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 269415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 270414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes private void setSwitchTypefaceByIndex(int typefaceIndex, int styleIndex) { 271414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes Typeface tf = null; 272414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes switch (typefaceIndex) { 273414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes case SANS: 274414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes tf = Typeface.SANS_SERIF; 275414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes break; 276414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes 277414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes case SERIF: 278414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes tf = Typeface.SERIF; 279414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes break; 280414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes 281414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes case MONOSPACE: 282414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes tf = Typeface.MONOSPACE; 283414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes break; 284414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 285414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes 286414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes setSwitchTypeface(tf, styleIndex); 287414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 288414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes 289415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 290415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Sets the typeface and style in which the text should be displayed on the 291415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * switch, and turns on the fake bold and italic bits in the Paint if the 292415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Typeface that you provided does not have all the bits in the 293415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * style that you specified. 294415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 295415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setSwitchTypeface(Typeface tf, int style) { 296415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (style > 0) { 297415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (tf == null) { 298415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes tf = Typeface.defaultFromStyle(style); 299415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 300415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes tf = Typeface.create(tf, style); 301415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 302415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 303415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes setSwitchTypeface(tf); 304415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // now compute what (if any) algorithmic styling is needed 305415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int typefaceStyle = tf != null ? tf.getStyle() : 0; 306415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int need = style & ~typefaceStyle; 307415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextPaint.setFakeBoldText((need & Typeface.BOLD) != 0); 308415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextPaint.setTextSkewX((need & Typeface.ITALIC) != 0 ? -0.25f : 0); 309415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 310415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextPaint.setFakeBoldText(false); 311415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextPaint.setTextSkewX(0); 312415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes setSwitchTypeface(tf); 313415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 314415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 315415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 316415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 317415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Sets the typeface in which the text should be displayed on the switch. 318415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Note that not all Typeface families actually have bold and italic 319415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * variants, so you may need to use 320415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * {@link #setSwitchTypeface(Typeface, int)} to get the appearance 321415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * that you actually want. 322415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 323415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setSwitchTypeface(Typeface tf) { 324415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mTextPaint.getTypeface() != tf) { 325415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextPaint.setTypeface(tf); 326415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 327415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes requestLayout(); 328415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes invalidate(); 329415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 330415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 331415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 332415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 333415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Set the amount of horizontal padding between the switch and the associated text. 334415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 335415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param pixels Amount of padding in pixels 336415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 337415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setSwitchPadding(int pixels) { 338415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchPadding = pixels; 339415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes requestLayout(); 340415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 341415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 342415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 343415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Get the amount of horizontal padding between the switch and the associated text. 344415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 345415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @return Amount of padding in pixels 346415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 347415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public int getSwitchPadding() { 348415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mSwitchPadding; 349415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 350415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 351415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 352415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Set the minimum width of the switch in pixels. The switch's width will be the maximum 353415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * of this value and its measured width as determined by the switch drawables and text used. 354415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 355415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param pixels Minimum width of the switch in pixels 356415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 357415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setSwitchMinWidth(int pixels) { 358415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchMinWidth = pixels; 359415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes requestLayout(); 360415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 361415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 362415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 363415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Get the minimum width of the switch in pixels. The switch's width will be the maximum 364415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * of this value and its measured width as determined by the switch drawables and text used. 365415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 366415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @return Minimum width of the switch in pixels 367415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 368415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public int getSwitchMinWidth() { 369415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mSwitchMinWidth; 370415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 371415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 372415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 373415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Set the horizontal padding around the text drawn on the switch itself. 374415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 375415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param pixels Horizontal padding for switch thumb text in pixels 376415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 377415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setThumbTextPadding(int pixels) { 378415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbTextPadding = pixels; 379415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes requestLayout(); 380415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 381415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 382415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 383415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Get the horizontal padding around the text drawn on the switch itself. 384415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 385415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @return Horizontal padding for switch thumb text in pixels 386415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 387415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public int getThumbTextPadding() { 388415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mThumbTextPadding; 389415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 390415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 391415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 392415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Set the drawable used for the track that the switch slides within. 393415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 394415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param track Track drawable 395415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 396415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setTrackDrawable(Drawable track) { 397415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTrackDrawable = track; 398415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes requestLayout(); 399415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 400415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 401415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 402415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Set the drawable used for the track that the switch slides within. 403415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 404415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param resId Resource ID of a track drawable 405415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 406415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setTrackResource(int resId) { 4077e4e8b664820f773bc96e37ee1d2bbf500d64e69Chris Banes setTrackDrawable(mDrawableManager.getDrawable(getContext(), resId)); 408415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 409415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 410415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 411415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Get the drawable used for the track that the switch slides within. 412415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 413415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @return Track drawable 414415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 415415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public Drawable getTrackDrawable() { 416415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mTrackDrawable; 417415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 418415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 419415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 420415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Set the drawable used for the switch "thumb" - the piece that the user 421415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * can physically touch and drag along the track. 422415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 423415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param thumb Thumb drawable 424415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 425415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setThumbDrawable(Drawable thumb) { 426415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbDrawable = thumb; 427415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes requestLayout(); 428415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 429415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 430415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 431415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Set the drawable used for the switch "thumb" - the piece that the user 432415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * can physically touch and drag along the track. 433415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 434415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param resId Resource ID of a thumb drawable 435415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 436415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setThumbResource(int resId) { 4377e4e8b664820f773bc96e37ee1d2bbf500d64e69Chris Banes setThumbDrawable(mDrawableManager.getDrawable(getContext(), resId)); 438415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 439415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 440415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 441415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Get the drawable used for the switch "thumb" - the piece that the user 442415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * can physically touch and drag along the track. 443415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 444415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @return Thumb drawable 445415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 446415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public Drawable getThumbDrawable() { 447415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mThumbDrawable; 448415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 449415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 450415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 451415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Specifies whether the track should be split by the thumb. When true, 452415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * the thumb's optical bounds will be clipped out of the track drawable, 453415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * then the thumb will be drawn into the resulting gap. 454415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 455415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param splitTrack Whether the track should be split by the thumb 456415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 457415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setSplitTrack(boolean splitTrack) { 458415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSplitTrack = splitTrack; 459415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes invalidate(); 460415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 461415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 462415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 463415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Returns whether the track should be split by the thumb. 464415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 465415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public boolean getSplitTrack() { 466415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mSplitTrack; 467415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 468415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 469415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 470415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Returns the text displayed when the button is in the checked state. 471415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 472415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public CharSequence getTextOn() { 473415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mTextOn; 474415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 475415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 476415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 477415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Sets the text displayed when the button is in the checked state. 478415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 479415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setTextOn(CharSequence textOn) { 480415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextOn = textOn; 481415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes requestLayout(); 482415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 483415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 484415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 485415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Returns the text displayed when the button is not in the checked state. 486415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 487415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public CharSequence getTextOff() { 488415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mTextOff; 489415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 490415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 491415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 492415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Sets the text displayed when the button is not in the checked state. 493415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 494415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setTextOff(CharSequence textOff) { 495415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextOff = textOff; 496415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes requestLayout(); 497415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 498415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 499415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 500415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Sets whether the on/off text should be displayed. 501415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 502415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param showText {@code true} to display on/off text 503415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 504415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setShowText(boolean showText) { 505415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mShowText != showText) { 506415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mShowText = showText; 507415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes requestLayout(); 508415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 509415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 510415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 511415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 512415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @return whether the on/off text should be displayed 513415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 514415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public boolean getShowText() { 515415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mShowText; 516415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 517415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 518415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 519415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 520415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mShowText) { 521415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mOnLayout == null) { 522415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mOnLayout = makeLayout(mTextOn); 523415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 524415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 525415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mOffLayout == null) { 526415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mOffLayout = makeLayout(mTextOff); 527415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 528415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 529415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 530415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Rect padding = mTempRect; 531415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int thumbWidth; 532415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int thumbHeight; 533415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mThumbDrawable != null) { 534415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Cached thumb width does not include padding. 535415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbDrawable.getPadding(padding); 536415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes thumbWidth = mThumbDrawable.getIntrinsicWidth() - padding.left - padding.right; 537415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes thumbHeight = mThumbDrawable.getIntrinsicHeight(); 538415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 539415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes thumbWidth = 0; 540415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes thumbHeight = 0; 541415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 542415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 543415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int maxTextWidth; 544415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mShowText) { 545415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes maxTextWidth = Math.max(mOnLayout.getWidth(), mOffLayout.getWidth()) 546415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes + mThumbTextPadding * 2; 547415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 548415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes maxTextWidth = 0; 549415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 550415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 551415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbWidth = Math.max(maxTextWidth, thumbWidth); 552415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 553415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int trackHeight; 554415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mTrackDrawable != null) { 555415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTrackDrawable.getPadding(padding); 556415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes trackHeight = mTrackDrawable.getIntrinsicHeight(); 557415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 558415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes padding.setEmpty(); 559415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes trackHeight = 0; 560415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 561415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 562415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Adjust left and right padding to ensure there's enough room for the 563415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // thumb's padding (when present). 564415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int paddingLeft = padding.left; 565415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int paddingRight = padding.right; 566414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes if (mThumbDrawable != null) { 567414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes final Rect inset = DrawableUtils.getOpticalBounds(mThumbDrawable); 568414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes paddingLeft = Math.max(paddingLeft, inset.left); 569414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes paddingRight = Math.max(paddingRight, inset.right); 570414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 571415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 572415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchWidth = Math.max(mSwitchMinWidth, 573415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 2 * mThumbWidth + paddingLeft + paddingRight); 574415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchHeight = Math.max(trackHeight, thumbHeight); 575415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchWidth = switchWidth; 576415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchHeight = switchHeight; 577415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 578415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.onMeasure(widthMeasureSpec, heightMeasureSpec); 579415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 580415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int measuredHeight = getMeasuredHeight(); 581415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (measuredHeight < switchHeight) { 582415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes setMeasuredDimension(ViewCompat.getMeasuredWidthAndState(this), switchHeight); 583415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 584415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 585415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 586415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) 587415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 588415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 589415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.onPopulateAccessibilityEvent(event); 590415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 591415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final CharSequence text = isChecked() ? mTextOn : mTextOff; 592415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (text != null) { 593415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes event.getText().add(text); 594415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 595415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 596415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 597415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private Layout makeLayout(CharSequence text) { 598415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final CharSequence transformed = (mSwitchTransformationMethod != null) 599415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes ? mSwitchTransformationMethod.getTransformation(text, this) 600415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes : text; 601415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 602415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return new StaticLayout(transformed, mTextPaint, 6031949ae9aeaadf52ad7bd7bb74ca5419c67ea7f65Taeho Kim transformed != null ? 6041949ae9aeaadf52ad7bd7bb74ca5419c67ea7f65Taeho Kim (int) Math.ceil(Layout.getDesiredWidth(transformed, mTextPaint)) : 0, 605415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes Layout.Alignment.ALIGN_NORMAL, 1.f, 0, true); 606415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 607415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 608415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 609415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @return true if (x, y) is within the target area of the switch thumb 610415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 611415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private boolean hitThumb(float x, float y) { 612af34a5378411bd76e8fd45a2bf23d17ccc19aae1Chris Banes if (mThumbDrawable == null) { 613af34a5378411bd76e8fd45a2bf23d17ccc19aae1Chris Banes return false; 614af34a5378411bd76e8fd45a2bf23d17ccc19aae1Chris Banes } 615af34a5378411bd76e8fd45a2bf23d17ccc19aae1Chris Banes 616415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Relies on mTempRect, MUST be called first! 617415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int thumbOffset = getThumbOffset(); 618415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 619415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbDrawable.getPadding(mTempRect); 620415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int thumbTop = mSwitchTop - mTouchSlop; 621415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int thumbLeft = mSwitchLeft + thumbOffset - mTouchSlop; 622415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int thumbRight = thumbLeft + mThumbWidth + 623415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTempRect.left + mTempRect.right + mTouchSlop; 624415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int thumbBottom = mSwitchBottom + mTouchSlop; 625415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return x > thumbLeft && x < thumbRight && y > thumbTop && y < thumbBottom; 626415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 627415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 628415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 629415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public boolean onTouchEvent(MotionEvent ev) { 630415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mVelocityTracker.addMovement(ev); 631415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int action = MotionEventCompat.getActionMasked(ev); 632415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switch (action) { 633415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes case MotionEvent.ACTION_DOWN: { 634415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final float x = ev.getX(); 635415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final float y = ev.getY(); 636415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (isEnabled() && hitThumb(x, y)) { 637415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTouchMode = TOUCH_MODE_DOWN; 638415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTouchX = x; 639415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTouchY = y; 640415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 641415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes break; 642415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 643415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 644415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes case MotionEvent.ACTION_MOVE: { 645415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switch (mTouchMode) { 646415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes case TOUCH_MODE_IDLE: 647415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Didn't target the thumb, treat normally. 648415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes break; 649415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 650415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes case TOUCH_MODE_DOWN: { 651415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final float x = ev.getX(); 652415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final float y = ev.getY(); 653415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (Math.abs(x - mTouchX) > mTouchSlop || 654415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes Math.abs(y - mTouchY) > mTouchSlop) { 655415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTouchMode = TOUCH_MODE_DRAGGING; 656415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes getParent().requestDisallowInterceptTouchEvent(true); 657415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTouchX = x; 658415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTouchY = y; 659415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return true; 660415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 661415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes break; 662415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 663415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 664415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes case TOUCH_MODE_DRAGGING: { 665415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final float x = ev.getX(); 666415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int thumbScrollRange = getThumbScrollRange(); 667415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final float thumbScrollOffset = x - mTouchX; 668415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes float dPos; 669415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (thumbScrollRange != 0) { 670415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes dPos = thumbScrollOffset / thumbScrollRange; 671415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 672415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // If the thumb scroll range is empty, just use the 673415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // movement direction to snap on or off. 674415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes dPos = thumbScrollOffset > 0 ? 1 : -1; 675415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 676415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (ViewUtils.isLayoutRtl(this)) { 677415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes dPos = -dPos; 678415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 679415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final float newPos = constrain(mThumbPosition + dPos, 0, 1); 680415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (newPos != mThumbPosition) { 681415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTouchX = x; 682415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes setThumbPosition(newPos); 683415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 684415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return true; 685415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 686415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 687415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes break; 688415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 689415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 690415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes case MotionEvent.ACTION_UP: 691415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes case MotionEvent.ACTION_CANCEL: { 692415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mTouchMode == TOUCH_MODE_DRAGGING) { 693415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes stopDrag(ev); 694415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Allow super class to handle pressed state, etc. 695415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.onTouchEvent(ev); 696415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return true; 697415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 698415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTouchMode = TOUCH_MODE_IDLE; 699415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mVelocityTracker.clear(); 700415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes break; 701415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 702415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 703415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 704415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return super.onTouchEvent(ev); 705415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 706415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 707415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private void cancelSuperTouch(MotionEvent ev) { 708415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes MotionEvent cancel = MotionEvent.obtain(ev); 709415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes cancel.setAction(MotionEvent.ACTION_CANCEL); 710415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.onTouchEvent(cancel); 711415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes cancel.recycle(); 712415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 713415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 714415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 715415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Called from onTouchEvent to end a drag operation. 716415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 717415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param ev Event that triggered the end of drag mode - ACTION_UP or ACTION_CANCEL 718415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 719415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private void stopDrag(MotionEvent ev) { 720415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTouchMode = TOUCH_MODE_IDLE; 721415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 722415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Commit the change if the event is up and not canceled and the switch 723415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // has not been disabled during the drag. 724415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final boolean commitChange = ev.getAction() == MotionEvent.ACTION_UP && isEnabled(); 72536ba98b397a95e5d74318f7d9008fdaf604c05c2Chris Banes final boolean oldState = isChecked(); 726415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final boolean newState; 727415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (commitChange) { 728415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mVelocityTracker.computeCurrentVelocity(1000); 729415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final float xvel = mVelocityTracker.getXVelocity(); 730415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (Math.abs(xvel) > mMinFlingVelocity) { 731415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes newState = ViewUtils.isLayoutRtl(this) ? (xvel < 0) : (xvel > 0); 732415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 733415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes newState = getTargetCheckedState(); 734415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 735415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 73636ba98b397a95e5d74318f7d9008fdaf604c05c2Chris Banes newState = oldState; 737415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 738415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 73936ba98b397a95e5d74318f7d9008fdaf604c05c2Chris Banes if (newState != oldState) { 74036ba98b397a95e5d74318f7d9008fdaf604c05c2Chris Banes playSoundEffect(SoundEffectConstants.CLICK); 74136ba98b397a95e5d74318f7d9008fdaf604c05c2Chris Banes } 742964d1912cc68e67fdbbe4643004a00c706bffdbaChris Banes // Always call setChecked so that the thumb is moved back to the correct edge 743964d1912cc68e67fdbbe4643004a00c706bffdbaChris Banes setChecked(newState); 744415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes cancelSuperTouch(ev); 745415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 746415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 7475dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes private void animateThumbToCheckedState(final boolean newCheckedState) { 7485dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes if (mPositionAnimator != null) { 7495dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes // If there's a current animator running, cancel it 7505dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes cancelPositionAnimator(); 7515dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes } 7525dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes 7535dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes mPositionAnimator = new ThumbAnimation(mThumbPosition, newCheckedState ? 1f : 0f); 754415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mPositionAnimator.setDuration(THUMB_ANIMATION_DURATION); 7555dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes mPositionAnimator.setAnimationListener(new Animation.AnimationListener() { 7565dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes @Override 7575dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes public void onAnimationStart(Animation animation) {} 7585dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes 7595dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes @Override 7605dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes public void onAnimationEnd(Animation animation) { 7615dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes if (mPositionAnimator == animation) { 7625dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes // If we're still the active animation, ensure the final position 7635dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes setThumbPosition(newCheckedState ? 1f : 0f); 7645dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes mPositionAnimator = null; 7655dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes } 7665dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes } 7675dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes 7685dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes @Override 7695dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes public void onAnimationRepeat(Animation animation) {} 7705dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes }); 771415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes startAnimation(mPositionAnimator); 772415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 773415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 774415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private void cancelPositionAnimator() { 775415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mPositionAnimator != null) { 776415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes clearAnimation(); 777415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mPositionAnimator = null; 778415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 779415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 780415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 781415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private boolean getTargetCheckedState() { 782415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mThumbPosition > 0.5f; 783415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 784415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 785415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 786415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Sets the thumb position as a decimal value between 0 (off) and 1 (on). 787415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 788415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param position new position between [0,1] 789415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 790415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private void setThumbPosition(float position) { 791415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbPosition = position; 792415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes invalidate(); 793415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 794415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 795415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 796415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void toggle() { 797415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes setChecked(!isChecked()); 798415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 799415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 800415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 801415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setChecked(boolean checked) { 802415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.setChecked(checked); 803415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 804415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Calling the super method may result in setChecked() getting called 805415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // recursively with a different value, so load the REAL value... 806415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes checked = isChecked(); 807415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 80887638543a7f772792e77f4bb260e6dc117c52674Chris Banes if (getWindowToken() != null && ViewCompat.isLaidOut(this) && isShown()) { 809415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes animateThumbToCheckedState(checked); 810415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 811415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Immediately move the thumb to the new position. 812415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes cancelPositionAnimator(); 813415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes setThumbPosition(checked ? 1 : 0); 814415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 815415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 816415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 817415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 818415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 819415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.onLayout(changed, left, top, right, bottom); 820415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 821415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int opticalInsetLeft = 0; 822415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int opticalInsetRight = 0; 823415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mThumbDrawable != null) { 824415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Rect trackPadding = mTempRect; 825415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mTrackDrawable != null) { 826415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTrackDrawable.getPadding(trackPadding); 827415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 828415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes trackPadding.setEmpty(); 829415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 830415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 831414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes final Rect insets = DrawableUtils.getOpticalBounds(mThumbDrawable); 832414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes opticalInsetLeft = Math.max(0, insets.left - trackPadding.left); 833414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes opticalInsetRight = Math.max(0, insets.right - trackPadding.right); 834415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 835415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 836415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchRight; 837415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchLeft; 838415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (ViewUtils.isLayoutRtl(this)) { 839415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchLeft = getPaddingLeft() + opticalInsetLeft; 840415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchRight = switchLeft + mSwitchWidth - opticalInsetLeft - opticalInsetRight; 841415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 842415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchRight = getWidth() - getPaddingRight() - opticalInsetRight; 843415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchLeft = switchRight - mSwitchWidth + opticalInsetLeft + opticalInsetRight; 844415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 845415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 846415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchTop; 847415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchBottom; 848415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switch (getGravity() & Gravity.VERTICAL_GRAVITY_MASK) { 849415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes default: 850415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes case Gravity.TOP: 851415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchTop = getPaddingTop(); 852415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchBottom = switchTop + mSwitchHeight; 853415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes break; 854415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 855415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes case Gravity.CENTER_VERTICAL: 856415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchTop = (getPaddingTop() + getHeight() - getPaddingBottom()) / 2 - 857415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchHeight / 2; 858415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchBottom = switchTop + mSwitchHeight; 859415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes break; 860415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 861415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes case Gravity.BOTTOM: 862415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchBottom = getHeight() - getPaddingBottom(); 863415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchTop = switchBottom - mSwitchHeight; 864415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes break; 865415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 866415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 867415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchLeft = switchLeft; 868415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchTop = switchTop; 869415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchBottom = switchBottom; 870415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchRight = switchRight; 871415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 872415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 873415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 874415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void draw(Canvas c) { 875415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Rect padding = mTempRect; 876415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchLeft = mSwitchLeft; 877415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchTop = mSwitchTop; 878415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchRight = mSwitchRight; 879415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchBottom = mSwitchBottom; 880415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 881415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int thumbInitialLeft = switchLeft + getThumbOffset(); 882415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 883414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes final Rect thumbInsets; 884414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes if (mThumbDrawable != null) { 885414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes thumbInsets = DrawableUtils.getOpticalBounds(mThumbDrawable); 886414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } else { 887414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes thumbInsets = DrawableUtils.INSETS_NONE; 888414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 889414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes 890415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Layout the track. 891415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mTrackDrawable != null) { 892415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTrackDrawable.getPadding(padding); 893415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 894415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Adjust thumb position for track padding. 895415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes thumbInitialLeft += padding.left; 896415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 897415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // If necessary, offset by the optical insets of the thumb asset. 898415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int trackLeft = switchLeft; 899415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int trackTop = switchTop; 900415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int trackRight = switchRight; 901415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int trackBottom = switchBottom; 9025dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes if (thumbInsets != null) { 903414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes if (thumbInsets.left > padding.left) { 904414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes trackLeft += thumbInsets.left - padding.left; 905414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 906414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes if (thumbInsets.top > padding.top) { 907414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes trackTop += thumbInsets.top - padding.top; 908414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 909414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes if (thumbInsets.right > padding.right) { 910414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes trackRight -= thumbInsets.right - padding.right; 911414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 912414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes if (thumbInsets.bottom > padding.bottom) { 913414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes trackBottom -= thumbInsets.bottom - padding.bottom; 914414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 915414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 916415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTrackDrawable.setBounds(trackLeft, trackTop, trackRight, trackBottom); 917415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 918415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 919415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Layout the thumb. 920415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mThumbDrawable != null) { 921415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbDrawable.getPadding(padding); 922415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 923415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int thumbLeft = thumbInitialLeft - padding.left; 924415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int thumbRight = thumbInitialLeft + mThumbWidth + padding.right; 925415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbDrawable.setBounds(thumbLeft, switchTop, thumbRight, switchBottom); 926415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 927415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Drawable background = getBackground(); 928415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (background != null) { 929415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes DrawableCompat.setHotspotBounds(background, thumbLeft, switchTop, 930415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes thumbRight, switchBottom); 931415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 932415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 933415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 934415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Draw the background. 935415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.draw(c); 936415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 937415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 938415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 939415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes protected void onDraw(Canvas canvas) { 940415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.onDraw(canvas); 941415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 942415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Rect padding = mTempRect; 943415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Drawable trackDrawable = mTrackDrawable; 944415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (trackDrawable != null) { 945415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes trackDrawable.getPadding(padding); 946415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 947415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes padding.setEmpty(); 948415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 949415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 950415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchTop = mSwitchTop; 951415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchBottom = mSwitchBottom; 952415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchInnerTop = switchTop + padding.top; 953415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchInnerBottom = switchBottom - padding.bottom; 954415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 955415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Drawable thumbDrawable = mThumbDrawable; 956415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (trackDrawable != null) { 957414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes if (mSplitTrack && thumbDrawable != null) { 958414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes final Rect insets = DrawableUtils.getOpticalBounds(thumbDrawable); 959414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes thumbDrawable.copyBounds(padding); 960414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes padding.left += insets.left; 961414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes padding.right -= insets.right; 962414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes 963414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes final int saveCount = canvas.save(); 964414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes canvas.clipRect(padding, Region.Op.DIFFERENCE); 965414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes trackDrawable.draw(canvas); 966414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes canvas.restoreToCount(saveCount); 967414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } else { 968414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes trackDrawable.draw(canvas); 969414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 970415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 971415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 972415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int saveCount = canvas.save(); 973415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 974415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (thumbDrawable != null) { 975415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes thumbDrawable.draw(canvas); 976415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 977415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 978415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Layout switchText = getTargetCheckedState() ? mOnLayout : mOffLayout; 979415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (switchText != null) { 980415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int drawableState[] = getDrawableState(); 981415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mTextColors != null) { 982415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextPaint.setColor(mTextColors.getColorForState(drawableState, 0)); 983415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 984415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextPaint.drawableState = drawableState; 985415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 986415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int cX; 987415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (thumbDrawable != null) { 988415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Rect bounds = thumbDrawable.getBounds(); 989415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes cX = bounds.left + bounds.right; 990415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 991415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes cX = getWidth(); 992415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 993415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 994415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int left = cX / 2 - switchText.getWidth() / 2; 995415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int top = (switchInnerTop + switchInnerBottom) / 2 - switchText.getHeight() / 2; 996415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes canvas.translate(left, top); 997415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchText.draw(canvas); 998415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 999415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1000415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes canvas.restoreToCount(saveCount); 1001415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1002415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1003415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 1004415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public int getCompoundPaddingLeft() { 1005415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (!ViewUtils.isLayoutRtl(this)) { 1006415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return super.getCompoundPaddingLeft(); 1007415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1008415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int padding = super.getCompoundPaddingLeft() + mSwitchWidth; 1009415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (!TextUtils.isEmpty(getText())) { 1010415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes padding += mSwitchPadding; 1011415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1012415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return padding; 1013415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1014415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1015415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 1016415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public int getCompoundPaddingRight() { 1017415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (ViewUtils.isLayoutRtl(this)) { 1018415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return super.getCompoundPaddingRight(); 1019415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1020415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int padding = super.getCompoundPaddingRight() + mSwitchWidth; 1021415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (!TextUtils.isEmpty(getText())) { 1022415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes padding += mSwitchPadding; 1023415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1024415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return padding; 1025415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1026415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1027415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 1028415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Translates thumb position to offset according to current RTL setting and 1029415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * thumb scroll range. Accounts for both track and thumb padding. 1030415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 1031415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @return thumb offset 1032415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 1033415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int getThumbOffset() { 1034415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final float thumbPosition; 1035415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (ViewUtils.isLayoutRtl(this)) { 1036415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes thumbPosition = 1 - mThumbPosition; 1037415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 1038415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes thumbPosition = mThumbPosition; 1039415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1040415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return (int) (thumbPosition * getThumbScrollRange() + 0.5f); 1041415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1042415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1043415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int getThumbScrollRange() { 1044415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mTrackDrawable != null) { 1045415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Rect padding = mTempRect; 1046415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTrackDrawable.getPadding(padding); 1047414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes 1048414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes final Rect insets; 1049414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes if (mThumbDrawable != null) { 1050414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes insets = DrawableUtils.getOpticalBounds(mThumbDrawable); 1051414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } else { 1052414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes insets = DrawableUtils.INSETS_NONE; 1053414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 1054414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes 1055414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes return mSwitchWidth - mThumbWidth - padding.left - padding.right 1056414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes - insets.left - insets.right; 1057415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 1058415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return 0; 1059415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1060415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1061415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1062415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 1063415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes protected int[] onCreateDrawableState(int extraSpace) { 1064415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int[] drawableState = super.onCreateDrawableState(extraSpace + 1); 1065415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (isChecked()) { 1066415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mergeDrawableStates(drawableState, CHECKED_STATE_SET); 1067415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1068415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return drawableState; 1069415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1070415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1071415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 1072415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes protected void drawableStateChanged() { 1073415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.drawableStateChanged(); 1074415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1075415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int[] myDrawableState = getDrawableState(); 1076415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1077415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mThumbDrawable != null) { 1078415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbDrawable.setState(myDrawableState); 1079415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1080415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1081415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mTrackDrawable != null) { 1082415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTrackDrawable.setState(myDrawableState); 1083415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1084415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1085415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes invalidate(); 1086415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1087415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1088415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 1089415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void drawableHotspotChanged(float x, float y) { 109036ba98b397a95e5d74318f7d9008fdaf604c05c2Chris Banes if (Build.VERSION.SDK_INT >= 21) { 109136ba98b397a95e5d74318f7d9008fdaf604c05c2Chris Banes super.drawableHotspotChanged(x, y); 109236ba98b397a95e5d74318f7d9008fdaf604c05c2Chris Banes } 1093415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1094415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mThumbDrawable != null) { 1095415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes DrawableCompat.setHotspot(mThumbDrawable, x, y); 1096415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1097415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1098415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mTrackDrawable != null) { 1099415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes DrawableCompat.setHotspot(mTrackDrawable, x, y); 1100415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1101415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1102415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1103415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 1104415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes protected boolean verifyDrawable(Drawable who) { 1105415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return super.verifyDrawable(who) || who == mThumbDrawable || who == mTrackDrawable; 1106415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1107415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1108415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 1109415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void jumpDrawablesToCurrentState() { 1110415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (Build.VERSION.SDK_INT >= 11) { 1111415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.jumpDrawablesToCurrentState(); 1112415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1113415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mThumbDrawable != null) { 1114415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbDrawable.jumpToCurrentState(); 1115415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1116415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1117415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mTrackDrawable != null) { 1118415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTrackDrawable.jumpToCurrentState(); 1119415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1120415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 11215dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes cancelPositionAnimator(); 1122415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1123415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1124415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1125415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) 1126415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 1127415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 1128415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.onInitializeAccessibilityEvent(event); 1129befecd646c6b7249ee9894ee2c21a5965bb33cffChris Banes event.setClassName(ACCESSIBILITY_EVENT_CLASS_NAME); 1130415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1131415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1132415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 1133415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 1134415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (Build.VERSION.SDK_INT >= 14) { 1135415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.onInitializeAccessibilityNodeInfo(info); 1136befecd646c6b7249ee9894ee2c21a5965bb33cffChris Banes info.setClassName(ACCESSIBILITY_EVENT_CLASS_NAME); 1137415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes CharSequence switchText = isChecked() ? mTextOn : mTextOff; 1138415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (!TextUtils.isEmpty(switchText)) { 1139415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes CharSequence oldText = info.getText(); 1140415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (TextUtils.isEmpty(oldText)) { 1141415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes info.setText(switchText); 1142415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 1143415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes StringBuilder newText = new StringBuilder(); 1144415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes newText.append(oldText).append(' ').append(switchText); 1145415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes info.setText(newText); 1146415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1147415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1148415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1149415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1150415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1151415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 1152415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Taken from android.util.MathUtils 1153415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 1154415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private static float constrain(float amount, float low, float high) { 1155415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return amount < low ? low : (amount > high ? high : amount); 1156415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 11572f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes 11582f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes private class ThumbAnimation extends Animation { 11592f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes final float mStartPosition; 11602f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes final float mEndPosition; 11612f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes final float mDiff; 11622f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes 11632f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes private ThumbAnimation(float startPosition, float endPosition) { 11642f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes mStartPosition = startPosition; 11652f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes mEndPosition = endPosition; 11662f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes mDiff = endPosition - startPosition; 11672f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes } 11682f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes 11692f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes @Override 11702f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes protected void applyTransformation(float interpolatedTime, Transformation t) { 11712f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes setThumbPosition(mStartPosition + (mDiff * interpolatedTime)); 11722f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes } 11732f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes } 1174415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes}