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.content.Context; 20415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.content.res.ColorStateList; 21415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.content.res.Resources; 22415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.content.res.TypedArray; 23415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.graphics.Canvas; 24415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.graphics.Paint; 25d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banesimport android.graphics.PorterDuff; 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; 31d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banesimport android.support.annotation.Nullable; 32415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.support.v4.graphics.drawable.DrawableCompat; 33415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.support.v4.view.MotionEventCompat; 34415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.support.v4.view.ViewCompat; 35415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.support.v7.appcompat.R; 364c99f0e29b0926d8e5de44b7e3980d47f052f04cChris Banesimport android.support.v7.content.res.AppCompatResources; 3766698bb15ba0f873aa1c2290cc50d6bb839a474aChris Banesimport android.support.v7.text.AllCapsTransformationMethod; 38415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.text.Layout; 39415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.text.StaticLayout; 40415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.text.TextPaint; 41415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.text.TextUtils; 42415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.text.method.TransformationMethod; 43415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.util.AttributeSet; 44415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.view.Gravity; 45415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.view.MotionEvent; 4636ba98b397a95e5d74318f7d9008fdaf604c05c2Chris Banesimport android.view.SoundEffectConstants; 47415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.view.VelocityTracker; 48415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.view.ViewConfiguration; 49415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.view.accessibility.AccessibilityEvent; 50415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.view.accessibility.AccessibilityNodeInfo; 51415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.view.animation.Animation; 52415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.view.animation.Transformation; 53415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banesimport android.widget.CompoundButton; 54415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 55415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes/** 56415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * SwitchCompat is a version of the Switch widget which on devices back to API v7. It does not 57415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * make any attempt to use the platform provided widget on those devices which it is available 58415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * normally. 59415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * <p> 60415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * A Switch is a two-state toggle switch widget that can select between two 61415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * options. The user may drag the "thumb" back and forth to choose the selected option, 62415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * or simply tap to toggle as if it were a checkbox. The {@link #setText(CharSequence) text} 63415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * property controls the text displayed in the label for the switch, whereas the 64415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * {@link #setTextOff(CharSequence) off} and {@link #setTextOn(CharSequence) on} text 65415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * controls the text on the thumb. Similarly, the 66415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * {@link #setTextAppearance(android.content.Context, int) textAppearance} and the related 67415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * setTypeface() methods control the typeface and style of label text, whereas the 68415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * {@link #setSwitchTextAppearance(android.content.Context, int) switchTextAppearance} and 69d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * the related setSwitchTypeface() methods control that of the thumb. 70d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * 71d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * <p>See the <a href="{@docRoot}guide/topics/ui/controls/togglebutton.html">Toggle Buttons</a> 72d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * guide.</p> 73d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * 74d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @attr ref android.support.v7.appcompat.R.styleable#SwitchCompat_android_textOn 75d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @attr ref android.support.v7.appcompat.R.styleable#SwitchCompat_android_textOff 76d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @attr ref android.support.v7.appcompat.R.styleable#SwitchCompat_switchMinWidth 77d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @attr ref android.support.v7.appcompat.R.styleable#SwitchCompat_switchPadding 78d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @attr ref android.support.v7.appcompat.R.styleable#SwitchCompat_switchTextAppearance 79d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @attr ref android.support.v7.appcompat.R.styleable#SwitchCompat_android_thumb 80d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @attr ref android.support.v7.appcompat.R.styleable#SwitchCompat_thumbTextPadding 81d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @attr ref android.support.v7.appcompat.R.styleable#SwitchCompat_track 82415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 83415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banespublic class SwitchCompat extends CompoundButton { 84415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private static final int THUMB_ANIMATION_DURATION = 250; 85415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 86415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private static final int TOUCH_MODE_IDLE = 0; 87415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private static final int TOUCH_MODE_DOWN = 1; 88415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private static final int TOUCH_MODE_DRAGGING = 2; 89415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 90befecd646c6b7249ee9894ee2c21a5965bb33cffChris Banes // We force the accessibility events to have a class name of Switch, since screen readers 91befecd646c6b7249ee9894ee2c21a5965bb33cffChris Banes // already know how to handle their events 92befecd646c6b7249ee9894ee2c21a5965bb33cffChris Banes private static final String ACCESSIBILITY_EVENT_CLASS_NAME = "android.widget.Switch"; 93befecd646c6b7249ee9894ee2c21a5965bb33cffChris Banes 94415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Enum for the "typeface" XML parameter. 95415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private static final int SANS = 1; 96415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private static final int SERIF = 2; 97415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private static final int MONOSPACE = 3; 98415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 99415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private Drawable mThumbDrawable; 100d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes private ColorStateList mThumbTintList = null; 101d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes private PorterDuff.Mode mThumbTintMode = null; 102d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes private boolean mHasThumbTint = false; 103d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes private boolean mHasThumbTintMode = false; 104d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes 105415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private Drawable mTrackDrawable; 106d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes private ColorStateList mTrackTintList = null; 107d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes private PorterDuff.Mode mTrackTintMode = null; 108d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes private boolean mHasTrackTint = false; 109d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes private boolean mHasTrackTintMode = false; 110d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes 111415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int mThumbTextPadding; 112415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int mSwitchMinWidth; 113415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int mSwitchPadding; 114415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private boolean mSplitTrack; 115415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private CharSequence mTextOn; 116415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private CharSequence mTextOff; 117415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private boolean mShowText; 118415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 119415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int mTouchMode; 120415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int mTouchSlop; 121415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private float mTouchX; 122415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private float mTouchY; 123415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private VelocityTracker mVelocityTracker = VelocityTracker.obtain(); 124415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int mMinFlingVelocity; 125415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 126415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private float mThumbPosition; 127415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 128415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 129415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Width required to draw the switch track and thumb. Includes padding and 130415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * optical bounds for both the track and thumb. 131415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 132415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int mSwitchWidth; 133415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 134415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 135415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Height required to draw the switch track and thumb. Includes padding and 136415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * optical bounds for both the track and thumb. 137415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 138415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int mSwitchHeight; 139415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 140415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 141415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Width of the thumb's content region. Does not include padding or 142415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * optical bounds. 143415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 144415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int mThumbWidth; 145415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 146415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** Left bound for drawing the switch track and thumb. */ 147415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int mSwitchLeft; 148415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 149415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** Top bound for drawing the switch track and thumb. */ 150415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int mSwitchTop; 151415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 152415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** Right bound for drawing the switch track and thumb. */ 153415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int mSwitchRight; 154415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 155415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** Bottom bound for drawing the switch track and thumb. */ 156415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int mSwitchBottom; 157415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 158415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private TextPaint mTextPaint; 159415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private ColorStateList mTextColors; 160415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private Layout mOnLayout; 161415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private Layout mOffLayout; 162415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private TransformationMethod mSwitchTransformationMethod; 1632c1bad7ecd5879bf0f29ce2ce1bc5bd67a3f4682Aurimas Liutikas ThumbAnimation mPositionAnimator; 164415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 165415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @SuppressWarnings("hiding") 166415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private final Rect mTempRect = new Rect(); 167415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 168415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private static final int[] CHECKED_STATE_SET = { 169415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes android.R.attr.state_checked 170415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes }; 171415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 172415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 173415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Construct a new Switch with default styling. 174415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 175415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param context The Context that will determine this widget's theming. 176415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 177415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public SwitchCompat(Context context) { 178415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes this(context, null); 179415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 180415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 181415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 182415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Construct a new Switch with default styling, overriding specific style 183415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * attributes as requested. 184415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 185415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param context The Context that will determine this widget's theming. 186415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param attrs Specification of attributes that should deviate from default styling. 187415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 188415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public SwitchCompat(Context context, AttributeSet attrs) { 189415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes this(context, attrs, R.attr.switchStyle); 190415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 191415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 192415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 193415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Construct a new Switch with a default style determined by the given theme attribute, 194415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * overriding specific style attributes as requested. 195415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 196415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param context The Context that will determine this widget's theming. 197415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param attrs Specification of attributes that should deviate from the default styling. 198415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param defStyleAttr An attribute in the current theme that contains a 199415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * reference to a style resource that supplies default values for 200415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * the view. Can be 0 to not look for defaults. 201415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 202415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public SwitchCompat(Context context, AttributeSet attrs, int defStyleAttr) { 203415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super(context, attrs, defStyleAttr); 204415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 205415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); 206415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 207415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Resources res = getResources(); 208415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextPaint.density = res.getDisplayMetrics().density; 209415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 210415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, 211415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes attrs, R.styleable.SwitchCompat, defStyleAttr, 0); 212415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbDrawable = a.getDrawable(R.styleable.SwitchCompat_android_thumb); 213414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes if (mThumbDrawable != null) { 214414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes mThumbDrawable.setCallback(this); 215414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 216415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTrackDrawable = a.getDrawable(R.styleable.SwitchCompat_track); 217414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes if (mTrackDrawable != null) { 218414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes mTrackDrawable.setCallback(this); 219414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 220415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextOn = a.getText(R.styleable.SwitchCompat_android_textOn); 221415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextOff = a.getText(R.styleable.SwitchCompat_android_textOff); 222415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mShowText = a.getBoolean(R.styleable.SwitchCompat_showText, true); 223415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbTextPadding = a.getDimensionPixelSize( 224415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes R.styleable.SwitchCompat_thumbTextPadding, 0); 225415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchMinWidth = a.getDimensionPixelSize( 226415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes R.styleable.SwitchCompat_switchMinWidth, 0); 227415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchPadding = a.getDimensionPixelSize( 228415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes R.styleable.SwitchCompat_switchPadding, 0); 229415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSplitTrack = a.getBoolean(R.styleable.SwitchCompat_splitTrack, false); 230415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 231d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes ColorStateList thumbTintList = a.getColorStateList(R.styleable.SwitchCompat_thumbTint); 232d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes if (thumbTintList != null) { 233d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes mThumbTintList = thumbTintList; 234d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes mHasThumbTint = true; 235d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes } 236d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes PorterDuff.Mode thumbTintMode = DrawableUtils.parseTintMode( 237d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes a.getInt(R.styleable.SwitchCompat_thumbTintMode, -1), null); 238d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes if (mThumbTintMode != thumbTintMode) { 239d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes mThumbTintMode = thumbTintMode; 240d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes mHasThumbTintMode = true; 241d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes } 242d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes if (mHasThumbTint || mHasThumbTintMode) { 243d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes applyThumbTint(); 244d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes } 245d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes 246d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes ColorStateList trackTintList = a.getColorStateList(R.styleable.SwitchCompat_trackTint); 247d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes if (trackTintList != null) { 248d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes mTrackTintList = trackTintList; 249d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes mHasTrackTint = true; 250d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes } 251d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes PorterDuff.Mode trackTintMode = DrawableUtils.parseTintMode( 252d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes a.getInt(R.styleable.SwitchCompat_trackTintMode, -1), null); 253d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes if (mTrackTintMode != trackTintMode) { 254d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes mTrackTintMode = trackTintMode; 255d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes mHasTrackTintMode = true; 256d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes } 257d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes if (mHasTrackTint || mHasTrackTintMode) { 258d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes applyTrackTint(); 259d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes } 260d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes 261415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int appearance = a.getResourceId( 262415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes R.styleable.SwitchCompat_switchTextAppearance, 0); 263415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (appearance != 0) { 264415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes setSwitchTextAppearance(context, appearance); 265415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 266415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 267415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes a.recycle(); 268415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 269415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final ViewConfiguration config = ViewConfiguration.get(context); 270415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTouchSlop = config.getScaledTouchSlop(); 271415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mMinFlingVelocity = config.getScaledMinimumFlingVelocity(); 272415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 273415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Refresh display with current params 274415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes refreshDrawableState(); 275415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes setChecked(isChecked()); 276415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 277415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 278415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 279415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Sets the switch text color, size, style, hint color, and highlight color 280415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * from the specified TextAppearance resource. 281d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * 282d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @attr ref android.support.v7.appcompat.R.styleable#SwitchCompat_switchTextAppearance 283415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 284415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setSwitchTextAppearance(Context context, int resid) { 285f50b0ed369ec1610a6fe0a69eb26faa48d702c5dChris Banes final TintTypedArray appearance = TintTypedArray.obtainStyledAttributes(context, resid, 286f50b0ed369ec1610a6fe0a69eb26faa48d702c5dChris Banes R.styleable.TextAppearance); 287415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 288415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes ColorStateList colors; 289415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int ts; 290415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 291320c3e9fe1e100a5a7cda5dd217d2d1152d08b3fChris Banes colors = appearance.getColorStateList(R.styleable.TextAppearance_android_textColor); 292415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (colors != null) { 293415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextColors = colors; 294415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 295415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // If no color set in TextAppearance, default to the view's textColor 296415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextColors = getTextColors(); 297415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 298415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 299320c3e9fe1e100a5a7cda5dd217d2d1152d08b3fChris Banes ts = appearance.getDimensionPixelSize(R.styleable.TextAppearance_android_textSize, 0); 300415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (ts != 0) { 301415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (ts != mTextPaint.getTextSize()) { 302415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextPaint.setTextSize(ts); 303415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes requestLayout(); 304415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 305415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 306415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 307414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes int typefaceIndex, styleIndex; 308320c3e9fe1e100a5a7cda5dd217d2d1152d08b3fChris Banes typefaceIndex = appearance.getInt(R.styleable.TextAppearance_android_typeface, -1); 309320c3e9fe1e100a5a7cda5dd217d2d1152d08b3fChris Banes styleIndex = appearance.getInt(R.styleable.TextAppearance_android_textStyle, -1); 310414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes 311414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes setSwitchTypefaceByIndex(typefaceIndex, styleIndex); 312414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes 313320c3e9fe1e100a5a7cda5dd217d2d1152d08b3fChris Banes boolean allCaps = appearance.getBoolean(R.styleable.TextAppearance_textAllCaps, false); 314415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (allCaps) { 315415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchTransformationMethod = new AllCapsTransformationMethod(getContext()); 316415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 317415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchTransformationMethod = null; 318415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 319415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 320415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes appearance.recycle(); 321415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 322415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 323414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes private void setSwitchTypefaceByIndex(int typefaceIndex, int styleIndex) { 324414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes Typeface tf = null; 325414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes switch (typefaceIndex) { 326414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes case SANS: 327414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes tf = Typeface.SANS_SERIF; 328414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes break; 329414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes 330414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes case SERIF: 331414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes tf = Typeface.SERIF; 332414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes break; 333414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes 334414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes case MONOSPACE: 335414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes tf = Typeface.MONOSPACE; 336414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes break; 337414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 338414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes 339414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes setSwitchTypeface(tf, styleIndex); 340414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 341414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes 342415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 343415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Sets the typeface and style in which the text should be displayed on the 344415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * switch, and turns on the fake bold and italic bits in the Paint if the 345415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Typeface that you provided does not have all the bits in the 346415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * style that you specified. 347415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 348415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setSwitchTypeface(Typeface tf, int style) { 349415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (style > 0) { 350415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (tf == null) { 351415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes tf = Typeface.defaultFromStyle(style); 352415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 353415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes tf = Typeface.create(tf, style); 354415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 355415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 356415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes setSwitchTypeface(tf); 357415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // now compute what (if any) algorithmic styling is needed 358415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int typefaceStyle = tf != null ? tf.getStyle() : 0; 359415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int need = style & ~typefaceStyle; 360415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextPaint.setFakeBoldText((need & Typeface.BOLD) != 0); 361415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextPaint.setTextSkewX((need & Typeface.ITALIC) != 0 ? -0.25f : 0); 362415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 363415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextPaint.setFakeBoldText(false); 364415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextPaint.setTextSkewX(0); 365415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes setSwitchTypeface(tf); 366415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 367415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 368415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 369415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 370415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Sets the typeface in which the text should be displayed on the switch. 371415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Note that not all Typeface families actually have bold and italic 372415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * variants, so you may need to use 373415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * {@link #setSwitchTypeface(Typeface, int)} to get the appearance 374415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * that you actually want. 375415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 376415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setSwitchTypeface(Typeface tf) { 377415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mTextPaint.getTypeface() != tf) { 378415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextPaint.setTypeface(tf); 379415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 380415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes requestLayout(); 381415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes invalidate(); 382415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 383415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 384415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 385415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 386415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Set the amount of horizontal padding between the switch and the associated text. 387415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 388415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param pixels Amount of padding in pixels 389d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * 390d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @attr ref android.support.v7.appcompat.R.styleable#SwitchCompat_switchPadding 391415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 392415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setSwitchPadding(int pixels) { 393415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchPadding = pixels; 394415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes requestLayout(); 395415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 396415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 397415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 398415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Get the amount of horizontal padding between the switch and the associated text. 399415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 400415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @return Amount of padding in pixels 401d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * 402d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @attr ref android.support.v7.appcompat.R.styleable#SwitchCompat_switchPadding 403415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 404415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public int getSwitchPadding() { 405415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mSwitchPadding; 406415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 407415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 408415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 409415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Set the minimum width of the switch in pixels. The switch's width will be the maximum 410415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * of this value and its measured width as determined by the switch drawables and text used. 411415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 412415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param pixels Minimum width of the switch in pixels 413d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * 414d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @attr ref android.support.v7.appcompat.R.styleable#SwitchCompat_switchMinWidth 415415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 416415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setSwitchMinWidth(int pixels) { 417415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchMinWidth = pixels; 418415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes requestLayout(); 419415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 420415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 421415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 422415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Get the minimum width of the switch in pixels. The switch's width will be the maximum 423415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * of this value and its measured width as determined by the switch drawables and text used. 424415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 425415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @return Minimum width of the switch in pixels 426d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * 427d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @attr ref android.support.v7.appcompat.R.styleable#SwitchCompat_switchMinWidth 428415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 429415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public int getSwitchMinWidth() { 430415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mSwitchMinWidth; 431415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 432415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 433415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 434415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Set the horizontal padding around the text drawn on the switch itself. 435415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 436415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param pixels Horizontal padding for switch thumb text in pixels 437d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * 438d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @attr ref android.support.v7.appcompat.R.styleable#SwitchCompat_thumbTextPadding 439415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 440415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setThumbTextPadding(int pixels) { 441415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbTextPadding = pixels; 442415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes requestLayout(); 443415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 444415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 445415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 446415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Get the horizontal padding around the text drawn on the switch itself. 447415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 448415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @return Horizontal padding for switch thumb text in pixels 449d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * 450d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @attr ref android.support.v7.appcompat.R.styleable#SwitchCompat_thumbTextPadding 451415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 452415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public int getThumbTextPadding() { 453415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mThumbTextPadding; 454415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 455415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 456415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 457415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Set the drawable used for the track that the switch slides within. 458415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 459415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param track Track drawable 460d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * 461d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @attr ref android.support.v7.appcompat.R.styleable#SwitchCompat_track 462415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 463415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setTrackDrawable(Drawable track) { 464d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes if (mTrackDrawable != null) { 465d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes mTrackDrawable.setCallback(null); 466d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes } 467415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTrackDrawable = track; 468d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes if (track != null) { 469d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes track.setCallback(this); 470d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes } 471415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes requestLayout(); 472415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 473415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 474415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 475415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Set the drawable used for the track that the switch slides within. 476415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 477415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param resId Resource ID of a track drawable 478d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * 479d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @attr ref android.support.v7.appcompat.R.styleable#SwitchCompat_track 480415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 481415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setTrackResource(int resId) { 4824c99f0e29b0926d8e5de44b7e3980d47f052f04cChris Banes setTrackDrawable(AppCompatResources.getDrawable(getContext(), resId)); 483415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 484415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 485415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 486415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Get the drawable used for the track that the switch slides within. 487415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 488415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @return Track drawable 489d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * 490d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @attr ref android.support.v7.appcompat.R.styleable#SwitchCompat_track 491415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 492415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public Drawable getTrackDrawable() { 493415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mTrackDrawable; 494415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 495415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 496415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 497d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * Applies a tint to the track drawable. Does not modify the current 498d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * tint mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 499d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * <p> 500d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * Subsequent calls to {@link #setTrackDrawable(Drawable)} will 501d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * automatically mutate the drawable and apply the specified tint and tint 502d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * mode using {@link DrawableCompat#setTintList(Drawable, ColorStateList)}. 503d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * 504d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @param tint the tint to apply, may be {@code null} to clear tint 505d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * 506d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @attr ref android.support.v7.appcompat.R.styleable#SwitchCompat_trackTint 507d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @see #getTrackTintList() 508d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes */ 509d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes public void setTrackTintList(@Nullable ColorStateList tint) { 510d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes mTrackTintList = tint; 511d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes mHasTrackTint = true; 512d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes 513d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes applyTrackTint(); 514d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes } 515d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes 516d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes /** 517d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @return the tint applied to the track drawable 518d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @attr ref android.support.v7.appcompat.R.styleable#SwitchCompat_trackTint 519d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @see #setTrackTintList(ColorStateList) 520d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes */ 521d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes @Nullable 522d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes public ColorStateList getTrackTintList() { 523d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes return mTrackTintList; 524d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes } 525d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes 526d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes /** 527d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * Specifies the blending mode used to apply the tint specified by 528d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * {@link #setTrackTintList(ColorStateList)}} to the track drawable. 529d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * The default mode is {@link PorterDuff.Mode#SRC_IN}. 530d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * 531d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @param tintMode the blending mode used to apply the tint, may be 532d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * {@code null} to clear tint 533d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @attr ref android.support.v7.appcompat.R.styleable#SwitchCompat_trackTintMode 534d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @see #getTrackTintMode() 535d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes */ 536d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes public void setTrackTintMode(@Nullable PorterDuff.Mode tintMode) { 537d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes mTrackTintMode = tintMode; 538d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes mHasTrackTintMode = true; 539d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes 540d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes applyTrackTint(); 541d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes } 542d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes 543d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes /** 544d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @return the blending mode used to apply the tint to the track 545d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * drawable 546d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @attr ref android.support.v7.appcompat.R.styleable#SwitchCompat_trackTintMode 547d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @see #setTrackTintMode(PorterDuff.Mode) 548d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes */ 549d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes @Nullable 550d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes public PorterDuff.Mode getTrackTintMode() { 551d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes return mTrackTintMode; 552d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes } 553d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes 554d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes private void applyTrackTint() { 555d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes if (mTrackDrawable != null && (mHasTrackTint || mHasTrackTintMode)) { 556d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes mTrackDrawable = mTrackDrawable.mutate(); 557d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes 558d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes if (mHasTrackTint) { 559d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes DrawableCompat.setTintList(mTrackDrawable, mTrackTintList); 560d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes } 561d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes 562d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes if (mHasTrackTintMode) { 563d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes DrawableCompat.setTintMode(mTrackDrawable, mTrackTintMode); 564d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes } 565d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes 566d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes // The drawable (or one of its children) may not have been 567d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes // stateful before applying the tint, so let's try again. 568d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes if (mTrackDrawable.isStateful()) { 569d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes mTrackDrawable.setState(getDrawableState()); 570d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes } 571d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes } 572d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes } 573d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes 574d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes /** 575415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Set the drawable used for the switch "thumb" - the piece that the user 576415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * can physically touch and drag along the track. 577415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 578415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param thumb Thumb drawable 579d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * 580d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @attr ref android.support.v7.appcompat.R.styleable#SwitchCompat_android_thumb 581415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 582415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setThumbDrawable(Drawable thumb) { 583d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes if (mThumbDrawable != null) { 584d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes mThumbDrawable.setCallback(null); 585d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes } 586415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbDrawable = thumb; 587d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes if (thumb != null) { 588d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes thumb.setCallback(this); 589d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes } 590415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes requestLayout(); 591415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 592415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 593415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 594415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Set the drawable used for the switch "thumb" - the piece that the user 595415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * can physically touch and drag along the track. 596415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 597415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param resId Resource ID of a thumb drawable 598d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * 599d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @attr ref android.support.v7.appcompat.R.styleable#SwitchCompat_android_thumb 600415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 601415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setThumbResource(int resId) { 6024c99f0e29b0926d8e5de44b7e3980d47f052f04cChris Banes setThumbDrawable(AppCompatResources.getDrawable(getContext(), resId)); 603415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 604415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 605415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 606415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Get the drawable used for the switch "thumb" - the piece that the user 607415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * can physically touch and drag along the track. 608415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 609415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @return Thumb drawable 610d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * 611d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @attr ref android.support.v7.appcompat.R.styleable#SwitchCompat_android_thumb 612415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 613415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public Drawable getThumbDrawable() { 614415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mThumbDrawable; 615415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 616415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 617415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 618d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * Applies a tint to the thumb drawable. Does not modify the current 619d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * tint mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 620d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * <p> 621d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * Subsequent calls to {@link #setThumbDrawable(Drawable)} will 622d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * automatically mutate the drawable and apply the specified tint and tint 623d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * mode using {@link DrawableCompat#setTintList(Drawable, ColorStateList)}. 624d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * 625d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @param tint the tint to apply, may be {@code null} to clear tint 626d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * 627d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @attr ref android.support.v7.appcompat.R.styleable#SwitchCompat_thumbTint 628d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @see #getThumbTintList() 629d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @see Drawable#setTintList(ColorStateList) 630d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes */ 631d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes public void setThumbTintList(@Nullable ColorStateList tint) { 632d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes mThumbTintList = tint; 633d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes mHasThumbTint = true; 634d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes 635d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes applyThumbTint(); 636d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes } 637d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes 638d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes /** 639d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @return the tint applied to the thumb drawable 640d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @attr ref android.support.v7.appcompat.R.styleable#SwitchCompat_thumbTint 641d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @see #setThumbTintList(ColorStateList) 642d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes */ 643d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes @Nullable 644d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes public ColorStateList getThumbTintList() { 645d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes return mThumbTintList; 646d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes } 647d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes 648d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes /** 649d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * Specifies the blending mode used to apply the tint specified by 650d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * {@link #setThumbTintList(ColorStateList)}} to the thumb drawable. 651d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * The default mode is {@link PorterDuff.Mode#SRC_IN}. 652d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * 653d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @param tintMode the blending mode used to apply the tint, may be 654d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * {@code null} to clear tint 655d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @attr ref android.support.v7.appcompat.R.styleable#SwitchCompat_thumbTintMode 656d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @see #getThumbTintMode() 657d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @see Drawable#setTintMode(PorterDuff.Mode) 658d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes */ 659d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes public void setThumbTintMode(@Nullable PorterDuff.Mode tintMode) { 660d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes mThumbTintMode = tintMode; 661d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes mHasThumbTintMode = true; 662d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes 663d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes applyThumbTint(); 664d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes } 665d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes 666d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes /** 667d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @return the blending mode used to apply the tint to the thumb 668d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * drawable 669d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @attr ref android.support.v7.appcompat.R.styleable#SwitchCompat_thumbTintMode 670d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @see #setThumbTintMode(PorterDuff.Mode) 671d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes */ 672d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes @Nullable 673d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes public PorterDuff.Mode getThumbTintMode() { 674d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes return mThumbTintMode; 675d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes } 676d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes 677d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes private void applyThumbTint() { 678d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes if (mThumbDrawable != null && (mHasThumbTint || mHasThumbTintMode)) { 679d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes mThumbDrawable = mThumbDrawable.mutate(); 680d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes 681d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes if (mHasThumbTint) { 682d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes DrawableCompat.setTintList(mThumbDrawable, mThumbTintList); 683d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes } 684d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes 685d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes if (mHasThumbTintMode) { 686d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes DrawableCompat.setTintMode(mThumbDrawable, mThumbTintMode); 687d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes } 688d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes 689d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes // The drawable (or one of its children) may not have been 690d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes // stateful before applying the tint, so let's try again. 691d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes if (mThumbDrawable.isStateful()) { 692d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes mThumbDrawable.setState(getDrawableState()); 693d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes } 694d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes } 695d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes } 696d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes 697d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes /** 698415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Specifies whether the track should be split by the thumb. When true, 699415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * the thumb's optical bounds will be clipped out of the track drawable, 700415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * then the thumb will be drawn into the resulting gap. 701415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 702415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param splitTrack Whether the track should be split by the thumb 703d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * 704d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @attr ref android.support.v7.appcompat.R.styleable#SwitchCompat_splitTrack 705415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 706415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setSplitTrack(boolean splitTrack) { 707415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSplitTrack = splitTrack; 708415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes invalidate(); 709415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 710415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 711415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 712415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Returns whether the track should be split by the thumb. 713d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * 714d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @attr ref android.support.v7.appcompat.R.styleable#SwitchCompat_splitTrack 715415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 716415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public boolean getSplitTrack() { 717415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mSplitTrack; 718415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 719415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 720415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 721415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Returns the text displayed when the button is in the checked state. 722d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * 723d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @attr ref android.support.v7.appcompat.R.styleable#SwitchCompat_android_textOn 724415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 725415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public CharSequence getTextOn() { 726415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mTextOn; 727415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 728415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 729415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 730415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Sets the text displayed when the button is in the checked state. 731d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * 732d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @attr ref android.support.v7.appcompat.R.styleable#SwitchCompat_android_textOn 733415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 734415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setTextOn(CharSequence textOn) { 735415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextOn = textOn; 736415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes requestLayout(); 737415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 738415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 739415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 740415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Returns the text displayed when the button is not in the checked state. 741d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * 742d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @attr ref android.support.v7.appcompat.R.styleable#SwitchCompat_android_textOff 743415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 744415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public CharSequence getTextOff() { 745415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mTextOff; 746415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 747415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 748415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 749415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Sets the text displayed when the button is not in the checked state. 750d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * 751d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @attr ref android.support.v7.appcompat.R.styleable#SwitchCompat_android_textOff 752415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 753415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setTextOff(CharSequence textOff) { 754415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextOff = textOff; 755415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes requestLayout(); 756415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 757415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 758415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 759415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Sets whether the on/off text should be displayed. 760415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 761415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param showText {@code true} to display on/off text 762d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @attr ref android.support.v7.appcompat.R.styleable#SwitchCompat_showText 763415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 764415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setShowText(boolean showText) { 765415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mShowText != showText) { 766415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mShowText = showText; 767415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes requestLayout(); 768415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 769415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 770415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 771415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 772415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @return whether the on/off text should be displayed 773d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes * @attr ref android.support.v7.appcompat.R.styleable#SwitchCompat_showText 774415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 775415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public boolean getShowText() { 776415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mShowText; 777415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 778415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 779415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 780415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 781415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mShowText) { 782415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mOnLayout == null) { 783415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mOnLayout = makeLayout(mTextOn); 784415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 785415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 786415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mOffLayout == null) { 787415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mOffLayout = makeLayout(mTextOff); 788415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 789415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 790415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 791415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Rect padding = mTempRect; 792415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int thumbWidth; 793415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int thumbHeight; 794415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mThumbDrawable != null) { 795415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Cached thumb width does not include padding. 796415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbDrawable.getPadding(padding); 797415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes thumbWidth = mThumbDrawable.getIntrinsicWidth() - padding.left - padding.right; 798415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes thumbHeight = mThumbDrawable.getIntrinsicHeight(); 799415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 800415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes thumbWidth = 0; 801415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes thumbHeight = 0; 802415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 803415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 804415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int maxTextWidth; 805415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mShowText) { 806415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes maxTextWidth = Math.max(mOnLayout.getWidth(), mOffLayout.getWidth()) 807415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes + mThumbTextPadding * 2; 808415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 809415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes maxTextWidth = 0; 810415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 811415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 812415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbWidth = Math.max(maxTextWidth, thumbWidth); 813415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 814415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int trackHeight; 815415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mTrackDrawable != null) { 816415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTrackDrawable.getPadding(padding); 817415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes trackHeight = mTrackDrawable.getIntrinsicHeight(); 818415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 819415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes padding.setEmpty(); 820415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes trackHeight = 0; 821415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 822415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 823415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Adjust left and right padding to ensure there's enough room for the 824415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // thumb's padding (when present). 825415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int paddingLeft = padding.left; 826415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int paddingRight = padding.right; 827414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes if (mThumbDrawable != null) { 828414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes final Rect inset = DrawableUtils.getOpticalBounds(mThumbDrawable); 829414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes paddingLeft = Math.max(paddingLeft, inset.left); 830414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes paddingRight = Math.max(paddingRight, inset.right); 831414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 832415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 833415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchWidth = Math.max(mSwitchMinWidth, 834415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 2 * mThumbWidth + paddingLeft + paddingRight); 835415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchHeight = Math.max(trackHeight, thumbHeight); 836415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchWidth = switchWidth; 837415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchHeight = switchHeight; 838415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 839415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.onMeasure(widthMeasureSpec, heightMeasureSpec); 840415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 841415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int measuredHeight = getMeasuredHeight(); 842415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (measuredHeight < switchHeight) { 843415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes setMeasuredDimension(ViewCompat.getMeasuredWidthAndState(this), switchHeight); 844415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 845415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 846415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 847415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 848415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 849415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.onPopulateAccessibilityEvent(event); 850415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 851415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final CharSequence text = isChecked() ? mTextOn : mTextOff; 852415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (text != null) { 853415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes event.getText().add(text); 854415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 855415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 856415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 857415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private Layout makeLayout(CharSequence text) { 858415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final CharSequence transformed = (mSwitchTransformationMethod != null) 859415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes ? mSwitchTransformationMethod.getTransformation(text, this) 860415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes : text; 861415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 862415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return new StaticLayout(transformed, mTextPaint, 8631949ae9aeaadf52ad7bd7bb74ca5419c67ea7f65Taeho Kim transformed != null ? 8641949ae9aeaadf52ad7bd7bb74ca5419c67ea7f65Taeho Kim (int) Math.ceil(Layout.getDesiredWidth(transformed, mTextPaint)) : 0, 865415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes Layout.Alignment.ALIGN_NORMAL, 1.f, 0, true); 866415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 867415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 868415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 869415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @return true if (x, y) is within the target area of the switch thumb 870415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 871415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private boolean hitThumb(float x, float y) { 872af34a5378411bd76e8fd45a2bf23d17ccc19aae1Chris Banes if (mThumbDrawable == null) { 873af34a5378411bd76e8fd45a2bf23d17ccc19aae1Chris Banes return false; 874af34a5378411bd76e8fd45a2bf23d17ccc19aae1Chris Banes } 875af34a5378411bd76e8fd45a2bf23d17ccc19aae1Chris Banes 876415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Relies on mTempRect, MUST be called first! 877415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int thumbOffset = getThumbOffset(); 878415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 879415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbDrawable.getPadding(mTempRect); 880415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int thumbTop = mSwitchTop - mTouchSlop; 881415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int thumbLeft = mSwitchLeft + thumbOffset - mTouchSlop; 882415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int thumbRight = thumbLeft + mThumbWidth + 883415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTempRect.left + mTempRect.right + mTouchSlop; 884415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int thumbBottom = mSwitchBottom + mTouchSlop; 885415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return x > thumbLeft && x < thumbRight && y > thumbTop && y < thumbBottom; 886415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 887415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 888415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 889415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public boolean onTouchEvent(MotionEvent ev) { 890415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mVelocityTracker.addMovement(ev); 891415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int action = MotionEventCompat.getActionMasked(ev); 892415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switch (action) { 893415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes case MotionEvent.ACTION_DOWN: { 894415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final float x = ev.getX(); 895415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final float y = ev.getY(); 896415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (isEnabled() && hitThumb(x, y)) { 897415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTouchMode = TOUCH_MODE_DOWN; 898415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTouchX = x; 899415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTouchY = y; 900415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 901415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes break; 902415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 903415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 904415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes case MotionEvent.ACTION_MOVE: { 905415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switch (mTouchMode) { 906415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes case TOUCH_MODE_IDLE: 907415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Didn't target the thumb, treat normally. 908415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes break; 909415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 910415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes case TOUCH_MODE_DOWN: { 911415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final float x = ev.getX(); 912415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final float y = ev.getY(); 913415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (Math.abs(x - mTouchX) > mTouchSlop || 914415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes Math.abs(y - mTouchY) > mTouchSlop) { 915415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTouchMode = TOUCH_MODE_DRAGGING; 916415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes getParent().requestDisallowInterceptTouchEvent(true); 917415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTouchX = x; 918415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTouchY = y; 919415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return true; 920415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 921415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes break; 922415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 923415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 924415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes case TOUCH_MODE_DRAGGING: { 925415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final float x = ev.getX(); 926415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int thumbScrollRange = getThumbScrollRange(); 927415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final float thumbScrollOffset = x - mTouchX; 928415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes float dPos; 929415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (thumbScrollRange != 0) { 930415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes dPos = thumbScrollOffset / thumbScrollRange; 931415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 932415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // If the thumb scroll range is empty, just use the 933415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // movement direction to snap on or off. 934415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes dPos = thumbScrollOffset > 0 ? 1 : -1; 935415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 936415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (ViewUtils.isLayoutRtl(this)) { 937415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes dPos = -dPos; 938415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 939415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final float newPos = constrain(mThumbPosition + dPos, 0, 1); 940415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (newPos != mThumbPosition) { 941415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTouchX = x; 942415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes setThumbPosition(newPos); 943415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 944415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return true; 945415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 946415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 947415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes break; 948415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 949415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 950415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes case MotionEvent.ACTION_UP: 951415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes case MotionEvent.ACTION_CANCEL: { 952415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mTouchMode == TOUCH_MODE_DRAGGING) { 953415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes stopDrag(ev); 954415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Allow super class to handle pressed state, etc. 955415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.onTouchEvent(ev); 956415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return true; 957415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 958415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTouchMode = TOUCH_MODE_IDLE; 959415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mVelocityTracker.clear(); 960415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes break; 961415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 962415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 963415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 964415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return super.onTouchEvent(ev); 965415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 966415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 967415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private void cancelSuperTouch(MotionEvent ev) { 968415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes MotionEvent cancel = MotionEvent.obtain(ev); 969415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes cancel.setAction(MotionEvent.ACTION_CANCEL); 970415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.onTouchEvent(cancel); 971415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes cancel.recycle(); 972415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 973415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 974415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 975415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Called from onTouchEvent to end a drag operation. 976415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 977415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param ev Event that triggered the end of drag mode - ACTION_UP or ACTION_CANCEL 978415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 979415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private void stopDrag(MotionEvent ev) { 980415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTouchMode = TOUCH_MODE_IDLE; 981415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 982415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Commit the change if the event is up and not canceled and the switch 983415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // has not been disabled during the drag. 984415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final boolean commitChange = ev.getAction() == MotionEvent.ACTION_UP && isEnabled(); 98536ba98b397a95e5d74318f7d9008fdaf604c05c2Chris Banes final boolean oldState = isChecked(); 986415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final boolean newState; 987415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (commitChange) { 988415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mVelocityTracker.computeCurrentVelocity(1000); 989415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final float xvel = mVelocityTracker.getXVelocity(); 990415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (Math.abs(xvel) > mMinFlingVelocity) { 991415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes newState = ViewUtils.isLayoutRtl(this) ? (xvel < 0) : (xvel > 0); 992415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 993415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes newState = getTargetCheckedState(); 994415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 995415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 99636ba98b397a95e5d74318f7d9008fdaf604c05c2Chris Banes newState = oldState; 997415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 998415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 99936ba98b397a95e5d74318f7d9008fdaf604c05c2Chris Banes if (newState != oldState) { 100036ba98b397a95e5d74318f7d9008fdaf604c05c2Chris Banes playSoundEffect(SoundEffectConstants.CLICK); 100136ba98b397a95e5d74318f7d9008fdaf604c05c2Chris Banes } 1002964d1912cc68e67fdbbe4643004a00c706bffdbaChris Banes // Always call setChecked so that the thumb is moved back to the correct edge 1003964d1912cc68e67fdbbe4643004a00c706bffdbaChris Banes setChecked(newState); 1004415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes cancelSuperTouch(ev); 1005415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1006415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 10075dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes private void animateThumbToCheckedState(final boolean newCheckedState) { 10085dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes if (mPositionAnimator != null) { 10095dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes // If there's a current animator running, cancel it 10105dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes cancelPositionAnimator(); 10115dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes } 10125dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes 10135dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes mPositionAnimator = new ThumbAnimation(mThumbPosition, newCheckedState ? 1f : 0f); 1014415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mPositionAnimator.setDuration(THUMB_ANIMATION_DURATION); 10155dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes mPositionAnimator.setAnimationListener(new Animation.AnimationListener() { 10165dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes @Override 10175dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes public void onAnimationStart(Animation animation) {} 10185dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes 10195dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes @Override 10205dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes public void onAnimationEnd(Animation animation) { 10215dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes if (mPositionAnimator == animation) { 10225dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes // If we're still the active animation, ensure the final position 10235dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes setThumbPosition(newCheckedState ? 1f : 0f); 10245dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes mPositionAnimator = null; 10255dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes } 10265dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes } 10275dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes 10285dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes @Override 10295dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes public void onAnimationRepeat(Animation animation) {} 10305dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes }); 1031415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes startAnimation(mPositionAnimator); 1032415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1033415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1034415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private void cancelPositionAnimator() { 1035415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mPositionAnimator != null) { 1036415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes clearAnimation(); 1037415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mPositionAnimator = null; 1038415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1039415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1040415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1041415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private boolean getTargetCheckedState() { 1042415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return mThumbPosition > 0.5f; 1043415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1044415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1045415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 1046415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Sets the thumb position as a decimal value between 0 (off) and 1 (on). 1047415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 1048415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @param position new position between [0,1] 1049415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 10502c1bad7ecd5879bf0f29ce2ce1bc5bd67a3f4682Aurimas Liutikas void setThumbPosition(float position) { 1051415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbPosition = position; 1052415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes invalidate(); 1053415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1054415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1055415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 1056415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void toggle() { 1057415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes setChecked(!isChecked()); 1058415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1059415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1060415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 1061415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void setChecked(boolean checked) { 1062415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.setChecked(checked); 1063415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1064415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Calling the super method may result in setChecked() getting called 1065415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // recursively with a different value, so load the REAL value... 1066415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes checked = isChecked(); 1067415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 106887638543a7f772792e77f4bb260e6dc117c52674Chris Banes if (getWindowToken() != null && ViewCompat.isLaidOut(this) && isShown()) { 1069415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes animateThumbToCheckedState(checked); 1070415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 1071415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Immediately move the thumb to the new position. 1072415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes cancelPositionAnimator(); 1073415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes setThumbPosition(checked ? 1 : 0); 1074415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1075415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1076415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1077415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 1078415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 1079415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.onLayout(changed, left, top, right, bottom); 1080415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1081415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int opticalInsetLeft = 0; 1082415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int opticalInsetRight = 0; 1083415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mThumbDrawable != null) { 1084415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Rect trackPadding = mTempRect; 1085415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mTrackDrawable != null) { 1086415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTrackDrawable.getPadding(trackPadding); 1087415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 1088415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes trackPadding.setEmpty(); 1089415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1090415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1091414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes final Rect insets = DrawableUtils.getOpticalBounds(mThumbDrawable); 1092414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes opticalInsetLeft = Math.max(0, insets.left - trackPadding.left); 1093414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes opticalInsetRight = Math.max(0, insets.right - trackPadding.right); 1094415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1095415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1096415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchRight; 1097415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchLeft; 1098415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (ViewUtils.isLayoutRtl(this)) { 1099415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchLeft = getPaddingLeft() + opticalInsetLeft; 1100415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchRight = switchLeft + mSwitchWidth - opticalInsetLeft - opticalInsetRight; 1101415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 1102415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchRight = getWidth() - getPaddingRight() - opticalInsetRight; 1103415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchLeft = switchRight - mSwitchWidth + opticalInsetLeft + opticalInsetRight; 1104415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1105415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1106415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchTop; 1107415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchBottom; 1108415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switch (getGravity() & Gravity.VERTICAL_GRAVITY_MASK) { 1109415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes default: 1110415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes case Gravity.TOP: 1111415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchTop = getPaddingTop(); 1112415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchBottom = switchTop + mSwitchHeight; 1113415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes break; 1114415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1115415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes case Gravity.CENTER_VERTICAL: 1116415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchTop = (getPaddingTop() + getHeight() - getPaddingBottom()) / 2 - 1117415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchHeight / 2; 1118415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchBottom = switchTop + mSwitchHeight; 1119415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes break; 1120415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1121415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes case Gravity.BOTTOM: 1122415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchBottom = getHeight() - getPaddingBottom(); 1123415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchTop = switchBottom - mSwitchHeight; 1124415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes break; 1125415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1126415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1127415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchLeft = switchLeft; 1128415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchTop = switchTop; 1129415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchBottom = switchBottom; 1130415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mSwitchRight = switchRight; 1131415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1132415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1133415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 1134415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void draw(Canvas c) { 1135415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Rect padding = mTempRect; 1136415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchLeft = mSwitchLeft; 1137415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchTop = mSwitchTop; 1138415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchRight = mSwitchRight; 1139415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchBottom = mSwitchBottom; 1140415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1141415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int thumbInitialLeft = switchLeft + getThumbOffset(); 1142415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1143414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes final Rect thumbInsets; 1144414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes if (mThumbDrawable != null) { 1145414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes thumbInsets = DrawableUtils.getOpticalBounds(mThumbDrawable); 1146414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } else { 1147414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes thumbInsets = DrawableUtils.INSETS_NONE; 1148414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 1149414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes 1150415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Layout the track. 1151415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mTrackDrawable != null) { 1152415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTrackDrawable.getPadding(padding); 1153415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1154415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Adjust thumb position for track padding. 1155415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes thumbInitialLeft += padding.left; 1156415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1157415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // If necessary, offset by the optical insets of the thumb asset. 1158415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int trackLeft = switchLeft; 1159415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int trackTop = switchTop; 1160415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int trackRight = switchRight; 1161415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int trackBottom = switchBottom; 11625dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes if (thumbInsets != null) { 1163414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes if (thumbInsets.left > padding.left) { 1164414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes trackLeft += thumbInsets.left - padding.left; 1165414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 1166414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes if (thumbInsets.top > padding.top) { 1167414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes trackTop += thumbInsets.top - padding.top; 1168414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 1169414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes if (thumbInsets.right > padding.right) { 1170414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes trackRight -= thumbInsets.right - padding.right; 1171414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 1172414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes if (thumbInsets.bottom > padding.bottom) { 1173414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes trackBottom -= thumbInsets.bottom - padding.bottom; 1174414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 1175414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 1176415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTrackDrawable.setBounds(trackLeft, trackTop, trackRight, trackBottom); 1177415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1178415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1179415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Layout the thumb. 1180415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mThumbDrawable != null) { 1181415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbDrawable.getPadding(padding); 1182415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1183415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int thumbLeft = thumbInitialLeft - padding.left; 1184415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int thumbRight = thumbInitialLeft + mThumbWidth + padding.right; 1185415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbDrawable.setBounds(thumbLeft, switchTop, thumbRight, switchBottom); 1186415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1187415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Drawable background = getBackground(); 1188415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (background != null) { 1189415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes DrawableCompat.setHotspotBounds(background, thumbLeft, switchTop, 1190415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes thumbRight, switchBottom); 1191415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1192415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1193415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1194415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes // Draw the background. 1195415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.draw(c); 1196415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1197415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1198415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 1199415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes protected void onDraw(Canvas canvas) { 1200415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.onDraw(canvas); 1201415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1202415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Rect padding = mTempRect; 1203415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Drawable trackDrawable = mTrackDrawable; 1204415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (trackDrawable != null) { 1205415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes trackDrawable.getPadding(padding); 1206415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 1207415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes padding.setEmpty(); 1208415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1209415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1210415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchTop = mSwitchTop; 1211415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchBottom = mSwitchBottom; 1212415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchInnerTop = switchTop + padding.top; 1213415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int switchInnerBottom = switchBottom - padding.bottom; 1214415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1215415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Drawable thumbDrawable = mThumbDrawable; 1216415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (trackDrawable != null) { 1217414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes if (mSplitTrack && thumbDrawable != null) { 1218414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes final Rect insets = DrawableUtils.getOpticalBounds(thumbDrawable); 1219414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes thumbDrawable.copyBounds(padding); 1220414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes padding.left += insets.left; 1221414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes padding.right -= insets.right; 1222414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes 1223414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes final int saveCount = canvas.save(); 1224414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes canvas.clipRect(padding, Region.Op.DIFFERENCE); 1225414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes trackDrawable.draw(canvas); 1226414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes canvas.restoreToCount(saveCount); 1227414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } else { 1228414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes trackDrawable.draw(canvas); 1229414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 1230415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1231415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1232415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int saveCount = canvas.save(); 1233415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1234415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (thumbDrawable != null) { 1235415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes thumbDrawable.draw(canvas); 1236415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1237415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1238415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Layout switchText = getTargetCheckedState() ? mOnLayout : mOffLayout; 1239415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (switchText != null) { 1240415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int drawableState[] = getDrawableState(); 1241415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mTextColors != null) { 1242415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextPaint.setColor(mTextColors.getColorForState(drawableState, 0)); 1243415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1244415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTextPaint.drawableState = drawableState; 1245415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1246415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int cX; 1247415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (thumbDrawable != null) { 1248415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Rect bounds = thumbDrawable.getBounds(); 1249415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes cX = bounds.left + bounds.right; 1250415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 1251415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes cX = getWidth(); 1252415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1253415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1254415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int left = cX / 2 - switchText.getWidth() / 2; 1255415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int top = (switchInnerTop + switchInnerBottom) / 2 - switchText.getHeight() / 2; 1256415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes canvas.translate(left, top); 1257415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes switchText.draw(canvas); 1258415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1259415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1260415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes canvas.restoreToCount(saveCount); 1261415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1262415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1263415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 1264415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public int getCompoundPaddingLeft() { 1265415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (!ViewUtils.isLayoutRtl(this)) { 1266415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return super.getCompoundPaddingLeft(); 1267415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1268415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int padding = super.getCompoundPaddingLeft() + mSwitchWidth; 1269415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (!TextUtils.isEmpty(getText())) { 1270415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes padding += mSwitchPadding; 1271415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1272415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return padding; 1273415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1274415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1275415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 1276415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public int getCompoundPaddingRight() { 1277415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (ViewUtils.isLayoutRtl(this)) { 1278415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return super.getCompoundPaddingRight(); 1279415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1280415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes int padding = super.getCompoundPaddingRight() + mSwitchWidth; 1281415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (!TextUtils.isEmpty(getText())) { 1282415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes padding += mSwitchPadding; 1283415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1284415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return padding; 1285415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1286415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1287415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 1288415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Translates thumb position to offset according to current RTL setting and 1289415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * thumb scroll range. Accounts for both track and thumb padding. 1290415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * 1291415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * @return thumb offset 1292415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 1293415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int getThumbOffset() { 1294415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final float thumbPosition; 1295415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (ViewUtils.isLayoutRtl(this)) { 1296415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes thumbPosition = 1 - mThumbPosition; 1297415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 1298415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes thumbPosition = mThumbPosition; 1299415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1300415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return (int) (thumbPosition * getThumbScrollRange() + 0.5f); 1301415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1302415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1303415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private int getThumbScrollRange() { 1304415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mTrackDrawable != null) { 1305415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final Rect padding = mTempRect; 1306415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTrackDrawable.getPadding(padding); 1307414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes 1308414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes final Rect insets; 1309414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes if (mThumbDrawable != null) { 1310414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes insets = DrawableUtils.getOpticalBounds(mThumbDrawable); 1311414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } else { 1312414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes insets = DrawableUtils.INSETS_NONE; 1313414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 1314414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes 1315414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes return mSwitchWidth - mThumbWidth - padding.left - padding.right 1316414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes - insets.left - insets.right; 1317415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 1318415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return 0; 1319415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1320415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1321415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1322415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 1323415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes protected int[] onCreateDrawableState(int extraSpace) { 1324415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes final int[] drawableState = super.onCreateDrawableState(extraSpace + 1); 1325415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (isChecked()) { 1326415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mergeDrawableStates(drawableState, CHECKED_STATE_SET); 1327415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1328415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return drawableState; 1329415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1330415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1331415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 1332415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes protected void drawableStateChanged() { 1333415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.drawableStateChanged(); 1334415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1335d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes final int[] state = getDrawableState(); 1336d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes boolean changed = false; 1337415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1338d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes final Drawable thumbDrawable = mThumbDrawable; 1339d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes if (thumbDrawable != null && thumbDrawable.isStateful()) { 1340d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes changed |= thumbDrawable.setState(state); 1341415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1342415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1343d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes final Drawable trackDrawable = mTrackDrawable; 1344d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes if (trackDrawable != null && trackDrawable.isStateful()) { 1345d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes changed |= trackDrawable.setState(state); 1346415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1347415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1348d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes if (changed) { 1349d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes invalidate(); 1350d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes } 1351415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1352415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1353415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 1354415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void drawableHotspotChanged(float x, float y) { 135536ba98b397a95e5d74318f7d9008fdaf604c05c2Chris Banes if (Build.VERSION.SDK_INT >= 21) { 135636ba98b397a95e5d74318f7d9008fdaf604c05c2Chris Banes super.drawableHotspotChanged(x, y); 135736ba98b397a95e5d74318f7d9008fdaf604c05c2Chris Banes } 1358415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1359415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mThumbDrawable != null) { 1360415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes DrawableCompat.setHotspot(mThumbDrawable, x, y); 1361415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1362415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1363415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mTrackDrawable != null) { 1364415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes DrawableCompat.setHotspot(mTrackDrawable, x, y); 1365415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1366415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1367415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1368415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 1369415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes protected boolean verifyDrawable(Drawable who) { 1370415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return super.verifyDrawable(who) || who == mThumbDrawable || who == mTrackDrawable; 1371415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1372415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1373415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 1374415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void jumpDrawablesToCurrentState() { 1375415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (Build.VERSION.SDK_INT >= 11) { 1376415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.jumpDrawablesToCurrentState(); 1377415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1378415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mThumbDrawable != null) { 1379415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mThumbDrawable.jumpToCurrentState(); 1380415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1381415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1382415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (mTrackDrawable != null) { 1383415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes mTrackDrawable.jumpToCurrentState(); 1384415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1385415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 13865dc563e669eb337639a8b0b9e4e28cd5ea08fbeaChris Banes cancelPositionAnimator(); 1387c1884ce2aebcb773378b32f98588cdc643ce68b0Chris Banes setThumbPosition(isChecked() ? 1 : 0); 1388415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1389415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1390415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1391415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 1392415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 1393415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.onInitializeAccessibilityEvent(event); 1394befecd646c6b7249ee9894ee2c21a5965bb33cffChris Banes event.setClassName(ACCESSIBILITY_EVENT_CLASS_NAME); 1395415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1396415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1397415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes @Override 1398415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 1399415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (Build.VERSION.SDK_INT >= 14) { 1400415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes super.onInitializeAccessibilityNodeInfo(info); 1401befecd646c6b7249ee9894ee2c21a5965bb33cffChris Banes info.setClassName(ACCESSIBILITY_EVENT_CLASS_NAME); 1402415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes CharSequence switchText = isChecked() ? mTextOn : mTextOff; 1403415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (!TextUtils.isEmpty(switchText)) { 1404415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes CharSequence oldText = info.getText(); 1405415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes if (TextUtils.isEmpty(oldText)) { 1406415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes info.setText(switchText); 1407415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } else { 1408415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes StringBuilder newText = new StringBuilder(); 1409415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes newText.append(oldText).append(' ').append(switchText); 1410415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes info.setText(newText); 1411415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1412415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1413415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1414415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 1415415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 1416415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes /** 1417415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes * Taken from android.util.MathUtils 1418415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes */ 1419415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes private static float constrain(float amount, float low, float high) { 1420415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes return amount < low ? low : (amount > high ? high : amount); 1421415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 14222f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes 14232f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes private class ThumbAnimation extends Animation { 14242f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes final float mStartPosition; 14252f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes final float mEndPosition; 14262f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes final float mDiff; 14272f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes 14282c1bad7ecd5879bf0f29ce2ce1bc5bd67a3f4682Aurimas Liutikas ThumbAnimation(float startPosition, float endPosition) { 14292f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes mStartPosition = startPosition; 14302f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes mEndPosition = endPosition; 14312f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes mDiff = endPosition - startPosition; 14322f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes } 14332f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes 14342f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes @Override 14352f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes protected void applyTransformation(float interpolatedTime, Transformation t) { 14362f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes setThumbPosition(mStartPosition + (mDiff * interpolatedTime)); 14372f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes } 14382f6f9480ddbe941a13c9c3da335caa1a022fa017Chris Banes } 1439415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes}