CompoundButton.java revision 72c510f1c4d5cff42a3925a784027e258ac0bcdc
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.widget; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 196a394f4def305560c9b7ca3a14b3a313556db36eAlan Viveretteimport android.annotation.DrawableRes; 2094a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamyimport android.annotation.NonNull; 21911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viveretteimport android.annotation.Nullable; 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 23911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viveretteimport android.content.res.ColorStateList; 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.TypedArray; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Canvas; 2699441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikasimport android.graphics.PorterDuff; 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.drawable.Drawable; 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Parcel; 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Parcelable; 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.AttributeSet; 319668903731c272e51ce610598c052ef411c9d89fPhilip P. Moltmannimport android.util.Log; 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.Gravity; 33d4e7790fee10e21b41a1c387c2734722bda56a0bAlan Viveretteimport android.view.SoundEffectConstants; 347a36788f4a69b3ddaf8fb8e250e1a13bee7238faSteve Zeiglerimport android.view.ViewDebug; 3599441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikasimport android.view.ViewHierarchyEncoder; 36c01a873c4f68518be4698077c7eb593a6a3b9f4cFelipe Lemeimport android.view.ViewStructure; 37cf4550c3198d6b3d92cdc52707fe70d7cc0caa9fJean-Baptiste Queruimport android.view.accessibility.AccessibilityEvent; 3813774d2e38e73ef4d0f6d0db3501ba032fa6da5aSvetoslav Ganovimport android.view.accessibility.AccessibilityNodeInfo; 39640f30a7763b0a4b80c767acb84c740aac04768bFelipe Lemeimport android.view.autofill.AutofillManager; 40640f30a7763b0a4b80c767acb84c740aac04768bFelipe Lemeimport android.view.autofill.AutofillValue; 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4299441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikasimport com.android.internal.R; 4399441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p> 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A button with two states, checked and unchecked. When the button is pressed 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * or clicked, the state changes automatically. 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * </p> 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p><strong>XML attributes</strong></p> 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p> 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See {@link android.R.styleable#CompoundButton 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * CompoundButton Attributes}, {@link android.R.styleable#Button Button 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Attributes}, {@link android.R.styleable#TextView TextView Attributes}, {@link 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * android.R.styleable#View View Attributes} 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * </p> 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic abstract class CompoundButton extends Button implements Checkable { 599668903731c272e51ce610598c052ef411c9d89fPhilip P. Moltmann private static final String LOG_TAG = CompoundButton.class.getSimpleName(); 606d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mChecked; 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mBroadcasting; 63911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Drawable mButtonDrawable; 65a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette private ColorStateList mButtonTintList = null; 66b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette private PorterDuff.Mode mButtonTintMode = null; 67911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette private boolean mHasButtonTint = false; 68b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette private boolean mHasButtonTintMode = false; 69911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private OnCheckedChangeListener mOnCheckedChangeListener; 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private OnCheckedChangeListener mOnCheckedChangeWidgetListener; 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 73c01a873c4f68518be4698077c7eb593a6a3b9f4cFelipe Leme // Indicates whether the toggle state was set from resources or dynamically, so it can be used 74640f30a7763b0a4b80c767acb84c740aac04768bFelipe Leme // to sanitize autofill requests. 75c01a873c4f68518be4698077c7eb593a6a3b9f4cFelipe Leme private boolean mCheckedFromResource = false; 76c01a873c4f68518be4698077c7eb593a6a3b9f4cFelipe Leme 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int[] CHECKED_STATE_SET = { 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project R.attr.state_checked 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public CompoundButton(Context context) { 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this(context, null); 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public CompoundButton(Context context, AttributeSet attrs) { 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this(context, attrs, 0); 879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 89617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette public CompoundButton(Context context, AttributeSet attrs, int defStyleAttr) { 90617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette this(context, attrs, defStyleAttr, 0); 91617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette } 92617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette 93617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette public CompoundButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 94617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette super(context, attrs, defStyleAttr, defStyleRes); 959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 96617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette final TypedArray a = context.obtainStyledAttributes( 97617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette attrs, com.android.internal.R.styleable.CompoundButton, defStyleAttr, defStyleRes); 989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 99911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette final Drawable d = a.getDrawable(com.android.internal.R.styleable.CompoundButton_button); 1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (d != null) { 1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setButtonDrawable(d); 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 104b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette if (a.hasValue(R.styleable.CompoundButton_buttonTintMode)) { 105b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette mButtonTintMode = Drawable.parseTintMode(a.getInt( 106b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette R.styleable.CompoundButton_buttonTintMode, -1), mButtonTintMode); 107b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette mHasButtonTintMode = true; 108b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette } 1094f64c048505a432e549ccb756634ecebf28f9e80Alan Viverette 110911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette if (a.hasValue(R.styleable.CompoundButton_buttonTint)) { 111a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette mButtonTintList = a.getColorStateList(R.styleable.CompoundButton_buttonTint); 112911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette mHasButtonTint = true; 113911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette } 114911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette 115911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette final boolean checked = a.getBoolean( 116911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette com.android.internal.R.styleable.CompoundButton_checked, false); 1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setChecked(checked); 118c01a873c4f68518be4698077c7eb593a6a3b9f4cFelipe Leme mCheckedFromResource = true; 1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project a.recycle(); 121b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette 122b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette applyButtonTint(); 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1256d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme @Override 1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void toggle() { 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setChecked(!mChecked); 1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean performClick() { 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project toggle(); 133d4e7790fee10e21b41a1c387c2734722bda56a0bAlan Viverette 134d4e7790fee10e21b41a1c387c2734722bda56a0bAlan Viverette final boolean handled = super.performClick(); 135d4e7790fee10e21b41a1c387c2734722bda56a0bAlan Viverette if (!handled) { 136d4e7790fee10e21b41a1c387c2734722bda56a0bAlan Viverette // View only makes a sound effect if the onClickListener was 137d4e7790fee10e21b41a1c387c2734722bda56a0bAlan Viverette // called, so we'll need to make one here instead. 138d4e7790fee10e21b41a1c387c2734722bda56a0bAlan Viverette playSoundEffect(SoundEffectConstants.CLICK); 139d4e7790fee10e21b41a1c387c2734722bda56a0bAlan Viverette } 140d4e7790fee10e21b41a1c387c2734722bda56a0bAlan Viverette 141d4e7790fee10e21b41a1c387c2734722bda56a0bAlan Viverette return handled; 1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1447a36788f4a69b3ddaf8fb8e250e1a13bee7238faSteve Zeigler @ViewDebug.ExportedProperty 1456d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme @Override 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isChecked() { 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mChecked; 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>Changes the checked state of this button.</p> 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param checked true to check the button, false to uncheck it 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1556d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme @Override 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setChecked(boolean checked) { 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mChecked != checked) { 158c01a873c4f68518be4698077c7eb593a6a3b9f4cFelipe Leme mCheckedFromResource = false; 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mChecked = checked; 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project refreshDrawableState(); 16172c510f1c4d5cff42a3925a784027e258ac0bcdcEugene Susla notifyViewAccessibilityStateChangedIfNeeded( 16277e9a28e2faa36f127231b842476d47f9823a83aAlan Viverette AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Avoid infinite recursions if setChecked() is called from a listener 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mBroadcasting) { 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBroadcasting = true; 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mOnCheckedChangeListener != null) { 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mOnCheckedChangeListener.onCheckedChanged(this, mChecked); 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mOnCheckedChangeWidgetListener != null) { 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mOnCheckedChangeWidgetListener.onCheckedChanged(this, mChecked); 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 176640f30a7763b0a4b80c767acb84c740aac04768bFelipe Leme final AutofillManager afm = mContext.getSystemService(AutofillManager.class); 1775882c4f5d2ff552a233ba88d2445f6810dd7599bFelipe Leme if (afm != null) { 1782f8fb1f62f2840701e3e16497eb8191f38b72e0bSvet Ganov afm.notifyValueChanged(this); 1795882c4f5d2ff552a233ba88d2445f6810dd7599bFelipe Leme } 180cf4550c3198d6b3d92cdc52707fe70d7cc0caa9fJean-Baptiste Queru 18199441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas mBroadcasting = false; 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Register a callback to be invoked when the checked state of this button 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * changes. 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param listener the callback to call on checked state change 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 191acdaaea50c543276c70aaa32d6b33aa61a9f6195Jason Long public void setOnCheckedChangeListener(@Nullable OnCheckedChangeListener listener) { 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mOnCheckedChangeListener = listener; 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Register a callback to be invoked when the checked state of this button 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * changes. This callback is used for internal purpose only. 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param listener the callback to call on checked state change 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void setOnCheckedChangeWidgetListener(OnCheckedChangeListener listener) { 2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mOnCheckedChangeWidgetListener = listener; 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Interface definition for a callback to be invoked when the checked state 2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * of a compound button changed. 2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static interface OnCheckedChangeListener { 2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Called when the checked state of a compound button has changed. 2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param buttonView The compound button view whose state has changed. 2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param isChecked The new checked state of buttonView. 2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void onCheckedChanged(CompoundButton buttonView, boolean isChecked); 2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2216a394f4def305560c9b7ca3a14b3a313556db36eAlan Viverette * Sets a drawable as the compound button image given its resource 2226a394f4def305560c9b7ca3a14b3a313556db36eAlan Viverette * identifier. 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2246a394f4def305560c9b7ca3a14b3a313556db36eAlan Viverette * @param resId the resource identifier of the drawable 2256a394f4def305560c9b7ca3a14b3a313556db36eAlan Viverette * @attr ref android.R.styleable#CompoundButton_button 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2276a394f4def305560c9b7ca3a14b3a313556db36eAlan Viverette public void setButtonDrawable(@DrawableRes int resId) { 2286a394f4def305560c9b7ca3a14b3a313556db36eAlan Viverette final Drawable d; 2296a394f4def305560c9b7ca3a14b3a313556db36eAlan Viverette if (resId != 0) { 2306a394f4def305560c9b7ca3a14b3a313556db36eAlan Viverette d = getContext().getDrawable(resId); 2316a394f4def305560c9b7ca3a14b3a313556db36eAlan Viverette } else { 2326a394f4def305560c9b7ca3a14b3a313556db36eAlan Viverette d = null; 2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setButtonDrawable(d); 2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2386a394f4def305560c9b7ca3a14b3a313556db36eAlan Viverette * Sets a drawable as the compound button image. 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2406a394f4def305560c9b7ca3a14b3a313556db36eAlan Viverette * @param drawable the drawable to set 2416a394f4def305560c9b7ca3a14b3a313556db36eAlan Viverette * @attr ref android.R.styleable#CompoundButton_button 2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2436a394f4def305560c9b7ca3a14b3a313556db36eAlan Viverette public void setButtonDrawable(@Nullable Drawable drawable) { 2446a394f4def305560c9b7ca3a14b3a313556db36eAlan Viverette if (mButtonDrawable != drawable) { 2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mButtonDrawable != null) { 2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mButtonDrawable.setCallback(null); 2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project unscheduleDrawable(mButtonDrawable); 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 249911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette 2506a394f4def305560c9b7ca3a14b3a313556db36eAlan Viverette mButtonDrawable = drawable; 251911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette 2526a394f4def305560c9b7ca3a14b3a313556db36eAlan Viverette if (drawable != null) { 2536a394f4def305560c9b7ca3a14b3a313556db36eAlan Viverette drawable.setCallback(this); 2546a394f4def305560c9b7ca3a14b3a313556db36eAlan Viverette drawable.setLayoutDirection(getLayoutDirection()); 2556a394f4def305560c9b7ca3a14b3a313556db36eAlan Viverette if (drawable.isStateful()) { 2566a394f4def305560c9b7ca3a14b3a313556db36eAlan Viverette drawable.setState(getDrawableState()); 257911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette } 2586a394f4def305560c9b7ca3a14b3a313556db36eAlan Viverette drawable.setVisible(getVisibility() == VISIBLE, false); 2596a394f4def305560c9b7ca3a14b3a313556db36eAlan Viverette setMinHeight(drawable.getIntrinsicHeight()); 260911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette applyButtonTint(); 261911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette } 2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 263911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette } 2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 265911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette /** 2663380e69f5529972ff03b545353d5f1c5e2abc1b1Doris Liu * @hide 2673380e69f5529972ff03b545353d5f1c5e2abc1b1Doris Liu */ 2683380e69f5529972ff03b545353d5f1c5e2abc1b1Doris Liu @Override 2693380e69f5529972ff03b545353d5f1c5e2abc1b1Doris Liu public void onResolveDrawables(@ResolvedLayoutDir int layoutDirection) { 2703380e69f5529972ff03b545353d5f1c5e2abc1b1Doris Liu super.onResolveDrawables(layoutDirection); 2713380e69f5529972ff03b545353d5f1c5e2abc1b1Doris Liu if (mButtonDrawable != null) { 2723380e69f5529972ff03b545353d5f1c5e2abc1b1Doris Liu mButtonDrawable.setLayoutDirection(layoutDirection); 2733380e69f5529972ff03b545353d5f1c5e2abc1b1Doris Liu } 2743380e69f5529972ff03b545353d5f1c5e2abc1b1Doris Liu } 2753380e69f5529972ff03b545353d5f1c5e2abc1b1Doris Liu 2763380e69f5529972ff03b545353d5f1c5e2abc1b1Doris Liu /** 2776a394f4def305560c9b7ca3a14b3a313556db36eAlan Viverette * @return the drawable used as the compound button image 2786a394f4def305560c9b7ca3a14b3a313556db36eAlan Viverette * @see #setButtonDrawable(Drawable) 2796a394f4def305560c9b7ca3a14b3a313556db36eAlan Viverette * @see #setButtonDrawable(int) 2806a394f4def305560c9b7ca3a14b3a313556db36eAlan Viverette */ 2816a394f4def305560c9b7ca3a14b3a313556db36eAlan Viverette @Nullable 2826a394f4def305560c9b7ca3a14b3a313556db36eAlan Viverette public Drawable getButtonDrawable() { 2836a394f4def305560c9b7ca3a14b3a313556db36eAlan Viverette return mButtonDrawable; 2846a394f4def305560c9b7ca3a14b3a313556db36eAlan Viverette } 2856a394f4def305560c9b7ca3a14b3a313556db36eAlan Viverette 2866a394f4def305560c9b7ca3a14b3a313556db36eAlan Viverette /** 2874f64c048505a432e549ccb756634ecebf28f9e80Alan Viverette * Applies a tint to the button drawable. Does not modify the current tint 288b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 289911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette * <p> 290911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette * Subsequent calls to {@link #setButtonDrawable(Drawable)} will 291911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette * automatically mutate the drawable and apply the specified tint and tint 292911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette * mode using 293a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette * {@link Drawable#setTintList(ColorStateList)}. 294911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette * 295911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette * @param tint the tint to apply, may be {@code null} to clear tint 296911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette * 297911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette * @attr ref android.R.styleable#CompoundButton_buttonTint 298a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette * @see #setButtonTintList(ColorStateList) 299a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette * @see Drawable#setTintList(ColorStateList) 300911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette */ 301a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette public void setButtonTintList(@Nullable ColorStateList tint) { 302a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette mButtonTintList = tint; 303911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette mHasButtonTint = true; 304911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette 305911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette applyButtonTint(); 306911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette } 307911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette 308911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette /** 309911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette * @return the tint applied to the button drawable 310911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette * @attr ref android.R.styleable#CompoundButton_buttonTint 311a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette * @see #setButtonTintList(ColorStateList) 312911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette */ 313911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette @Nullable 314a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette public ColorStateList getButtonTintList() { 315a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette return mButtonTintList; 316911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette } 317911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette 318911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette /** 319911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette * Specifies the blending mode used to apply the tint specified by 320a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette * {@link #setButtonTintList(ColorStateList)}} to the button drawable. The 321b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette * default mode is {@link PorterDuff.Mode#SRC_IN}. 322911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette * 323911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette * @param tintMode the blending mode used to apply the tint, may be 324911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette * {@code null} to clear tint 325911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette * @attr ref android.R.styleable#CompoundButton_buttonTintMode 3264f64c048505a432e549ccb756634ecebf28f9e80Alan Viverette * @see #getButtonTintMode() 327a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette * @see Drawable#setTintMode(PorterDuff.Mode) 328911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette */ 329911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette public void setButtonTintMode(@Nullable PorterDuff.Mode tintMode) { 3304f64c048505a432e549ccb756634ecebf28f9e80Alan Viverette mButtonTintMode = tintMode; 331b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette mHasButtonTintMode = true; 3324f64c048505a432e549ccb756634ecebf28f9e80Alan Viverette 3334f64c048505a432e549ccb756634ecebf28f9e80Alan Viverette applyButtonTint(); 334911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette } 335911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette 336911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette /** 337911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette * @return the blending mode used to apply the tint to the button drawable 338911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette * @attr ref android.R.styleable#CompoundButton_buttonTintMode 3394f64c048505a432e549ccb756634ecebf28f9e80Alan Viverette * @see #setButtonTintMode(PorterDuff.Mode) 340911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette */ 341911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette @Nullable 342911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette public PorterDuff.Mode getButtonTintMode() { 343911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette return mButtonTintMode; 344911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette } 345911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette 346911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette private void applyButtonTint() { 347b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette if (mButtonDrawable != null && (mHasButtonTint || mHasButtonTintMode)) { 348911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette mButtonDrawable = mButtonDrawable.mutate(); 349b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette 350b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette if (mHasButtonTint) { 351b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette mButtonDrawable.setTintList(mButtonTintList); 352b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette } 353b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette 354b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette if (mHasButtonTintMode) { 355b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette mButtonDrawable.setTintMode(mButtonTintMode); 356b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette } 357d5133792391443521dc15f7da7de5d280e6703ddAlan Viverette 358d5133792391443521dc15f7da7de5d280e6703ddAlan Viverette // The drawable (or one of its children) may not have been 359d5133792391443521dc15f7da7de5d280e6703ddAlan Viverette // stateful before applying the tint, so let's try again. 360d5133792391443521dc15f7da7de5d280e6703ddAlan Viverette if (mButtonDrawable.isStateful()) { 361d5133792391443521dc15f7da7de5d280e6703ddAlan Viverette mButtonDrawable.setState(getDrawableState()); 362d5133792391443521dc15f7da7de5d280e6703ddAlan Viverette } 363911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette } 3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 366a7bb6fbeab933326d58aa806d8194b7b13239d34Dianne Hackborn @Override 367a7bb6fbeab933326d58aa806d8194b7b13239d34Dianne Hackborn public CharSequence getAccessibilityClassName() { 368a7bb6fbeab933326d58aa806d8194b7b13239d34Dianne Hackborn return CompoundButton.class.getName(); 369a7bb6fbeab933326d58aa806d8194b7b13239d34Dianne Hackborn } 370a7bb6fbeab933326d58aa806d8194b7b13239d34Dianne Hackborn 371a54956a0bc611b1e9b3914edc7a604b59688f6b7Alan Viverette /** @hide */ 3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 373a54956a0bc611b1e9b3914edc7a604b59688f6b7Alan Viverette public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) { 374a54956a0bc611b1e9b3914edc7a604b59688f6b7Alan Viverette super.onInitializeAccessibilityEventInternal(event); 375736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov event.setChecked(mChecked); 376cf4550c3198d6b3d92cdc52707fe70d7cc0caa9fJean-Baptiste Queru } 377cf4550c3198d6b3d92cdc52707fe70d7cc0caa9fJean-Baptiste Queru 378a54956a0bc611b1e9b3914edc7a604b59688f6b7Alan Viverette /** @hide */ 379cf4550c3198d6b3d92cdc52707fe70d7cc0caa9fJean-Baptiste Queru @Override 380a54956a0bc611b1e9b3914edc7a604b59688f6b7Alan Viverette public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) { 381a54956a0bc611b1e9b3914edc7a604b59688f6b7Alan Viverette super.onInitializeAccessibilityNodeInfoInternal(info); 3820f55cc33f658b2793a12d609a0989348077324a4Svetoslav Ganov info.setCheckable(true); 38313774d2e38e73ef4d0f6d0db3501ba032fa6da5aSvetoslav Ganov info.setChecked(mChecked); 38413774d2e38e73ef4d0f6d0db3501ba032fa6da5aSvetoslav Ganov } 38513774d2e38e73ef4d0f6d0db3501ba032fa6da5aSvetoslav Ganov 38613774d2e38e73ef4d0f6d0db3501ba032fa6da5aSvetoslav Ganov @Override 3872842679d3426295b6674dfcfb8591fad79de6cb2Fabrice Di Meglio public int getCompoundPaddingLeft() { 3882842679d3426295b6674dfcfb8591fad79de6cb2Fabrice Di Meglio int padding = super.getCompoundPaddingLeft(); 3892842679d3426295b6674dfcfb8591fad79de6cb2Fabrice Di Meglio if (!isLayoutRtl()) { 3902842679d3426295b6674dfcfb8591fad79de6cb2Fabrice Di Meglio final Drawable buttonDrawable = mButtonDrawable; 3912842679d3426295b6674dfcfb8591fad79de6cb2Fabrice Di Meglio if (buttonDrawable != null) { 3922842679d3426295b6674dfcfb8591fad79de6cb2Fabrice Di Meglio padding += buttonDrawable.getIntrinsicWidth(); 3932842679d3426295b6674dfcfb8591fad79de6cb2Fabrice Di Meglio } 3942842679d3426295b6674dfcfb8591fad79de6cb2Fabrice Di Meglio } 3952842679d3426295b6674dfcfb8591fad79de6cb2Fabrice Di Meglio return padding; 3962842679d3426295b6674dfcfb8591fad79de6cb2Fabrice Di Meglio } 3972842679d3426295b6674dfcfb8591fad79de6cb2Fabrice Di Meglio 3982842679d3426295b6674dfcfb8591fad79de6cb2Fabrice Di Meglio @Override 3992842679d3426295b6674dfcfb8591fad79de6cb2Fabrice Di Meglio public int getCompoundPaddingRight() { 4002842679d3426295b6674dfcfb8591fad79de6cb2Fabrice Di Meglio int padding = super.getCompoundPaddingRight(); 4012842679d3426295b6674dfcfb8591fad79de6cb2Fabrice Di Meglio if (isLayoutRtl()) { 4022842679d3426295b6674dfcfb8591fad79de6cb2Fabrice Di Meglio final Drawable buttonDrawable = mButtonDrawable; 4032842679d3426295b6674dfcfb8591fad79de6cb2Fabrice Di Meglio if (buttonDrawable != null) { 4042842679d3426295b6674dfcfb8591fad79de6cb2Fabrice Di Meglio padding += buttonDrawable.getIntrinsicWidth(); 4052842679d3426295b6674dfcfb8591fad79de6cb2Fabrice Di Meglio } 4062842679d3426295b6674dfcfb8591fad79de6cb2Fabrice Di Meglio } 4072842679d3426295b6674dfcfb8591fad79de6cb2Fabrice Di Meglio return padding; 4082842679d3426295b6674dfcfb8591fad79de6cb2Fabrice Di Meglio } 4092842679d3426295b6674dfcfb8591fad79de6cb2Fabrice Di Meglio 410b878ddb56ec4e755706890110d76735176ff2295Fabrice Di Meglio /** 411b878ddb56ec4e755706890110d76735176ff2295Fabrice Di Meglio * @hide 412b878ddb56ec4e755706890110d76735176ff2295Fabrice Di Meglio */ 413b878ddb56ec4e755706890110d76735176ff2295Fabrice Di Meglio @Override 414b878ddb56ec4e755706890110d76735176ff2295Fabrice Di Meglio public int getHorizontalOffsetForDrawables() { 415b878ddb56ec4e755706890110d76735176ff2295Fabrice Di Meglio final Drawable buttonDrawable = mButtonDrawable; 416b878ddb56ec4e755706890110d76735176ff2295Fabrice Di Meglio return (buttonDrawable != null) ? buttonDrawable.getIntrinsicWidth() : 0; 417b878ddb56ec4e755706890110d76735176ff2295Fabrice Di Meglio } 418b878ddb56ec4e755706890110d76735176ff2295Fabrice Di Meglio 4192842679d3426295b6674dfcfb8591fad79de6cb2Fabrice Di Meglio @Override 4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void onDraw(Canvas canvas) { 4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Drawable buttonDrawable = mButtonDrawable; 4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (buttonDrawable != null) { 4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int verticalGravity = getGravity() & Gravity.VERTICAL_GRAVITY_MASK; 4242842679d3426295b6674dfcfb8591fad79de6cb2Fabrice Di Meglio final int drawableHeight = buttonDrawable.getIntrinsicHeight(); 4252842679d3426295b6674dfcfb8591fad79de6cb2Fabrice Di Meglio final int drawableWidth = buttonDrawable.getIntrinsicWidth(); 4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 42761956606818918194a38e045a8e35e7108480e5eAlan Viverette final int top; 4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (verticalGravity) { 4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case Gravity.BOTTOM: 4302842679d3426295b6674dfcfb8591fad79de6cb2Fabrice Di Meglio top = getHeight() - drawableHeight; 4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case Gravity.CENTER_VERTICAL: 4332842679d3426295b6674dfcfb8591fad79de6cb2Fabrice Di Meglio top = (getHeight() - drawableHeight) / 2; 4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 43561956606818918194a38e045a8e35e7108480e5eAlan Viverette default: 43661956606818918194a38e045a8e35e7108480e5eAlan Viverette top = 0; 4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 43861956606818918194a38e045a8e35e7108480e5eAlan Viverette final int bottom = top + drawableHeight; 43961956606818918194a38e045a8e35e7108480e5eAlan Viverette final int left = isLayoutRtl() ? getWidth() - drawableWidth : 0; 44061956606818918194a38e045a8e35e7108480e5eAlan Viverette final int right = isLayoutRtl() ? getWidth() : drawableWidth; 4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4422842679d3426295b6674dfcfb8591fad79de6cb2Fabrice Di Meglio buttonDrawable.setBounds(left, top, right, bottom); 44361956606818918194a38e045a8e35e7108480e5eAlan Viverette 44461956606818918194a38e045a8e35e7108480e5eAlan Viverette final Drawable background = getBackground(); 445c80ad99a33ee49d0bac994c1749ff24d243c3862Alan Viverette if (background != null) { 44661956606818918194a38e045a8e35e7108480e5eAlan Viverette background.setHotspotBounds(left, top, right, bottom); 44761956606818918194a38e045a8e35e7108480e5eAlan Viverette } 44861956606818918194a38e045a8e35e7108480e5eAlan Viverette } 44961956606818918194a38e045a8e35e7108480e5eAlan Viverette 45061956606818918194a38e045a8e35e7108480e5eAlan Viverette super.onDraw(canvas); 45161956606818918194a38e045a8e35e7108480e5eAlan Viverette 45261956606818918194a38e045a8e35e7108480e5eAlan Viverette if (buttonDrawable != null) { 453b95c336d7863e6b63e2aa8682a90dd8ae213889cAlan Viverette final int scrollX = mScrollX; 454b95c336d7863e6b63e2aa8682a90dd8ae213889cAlan Viverette final int scrollY = mScrollY; 455b95c336d7863e6b63e2aa8682a90dd8ae213889cAlan Viverette if (scrollX == 0 && scrollY == 0) { 456b95c336d7863e6b63e2aa8682a90dd8ae213889cAlan Viverette buttonDrawable.draw(canvas); 457b95c336d7863e6b63e2aa8682a90dd8ae213889cAlan Viverette } else { 458b95c336d7863e6b63e2aa8682a90dd8ae213889cAlan Viverette canvas.translate(scrollX, scrollY); 459b95c336d7863e6b63e2aa8682a90dd8ae213889cAlan Viverette buttonDrawable.draw(canvas); 460b95c336d7863e6b63e2aa8682a90dd8ae213889cAlan Viverette canvas.translate(-scrollX, -scrollY); 461b95c336d7863e6b63e2aa8682a90dd8ae213889cAlan Viverette } 4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected int[] onCreateDrawableState(int extraSpace) { 4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int[] drawableState = super.onCreateDrawableState(extraSpace + 1); 4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (isChecked()) { 4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mergeDrawableStates(drawableState, CHECKED_STATE_SET); 4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return drawableState; 4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void drawableStateChanged() { 4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.drawableStateChanged(); 477ad0020f8075ecf768cb610d60dbb167d41f0fbe5Alan Viverette 478ad0020f8075ecf768cb610d60dbb167d41f0fbe5Alan Viverette final Drawable buttonDrawable = mButtonDrawable; 479ad0020f8075ecf768cb610d60dbb167d41f0fbe5Alan Viverette if (buttonDrawable != null && buttonDrawable.isStateful() 480ad0020f8075ecf768cb610d60dbb167d41f0fbe5Alan Viverette && buttonDrawable.setState(getDrawableState())) { 481ad0020f8075ecf768cb610d60dbb167d41f0fbe5Alan Viverette invalidateDrawable(buttonDrawable); 4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 485cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette @Override 4868de1494557cf1d00c1c3fce439138a28de7fbd61Alan Viverette public void drawableHotspotChanged(float x, float y) { 4878de1494557cf1d00c1c3fce439138a28de7fbd61Alan Viverette super.drawableHotspotChanged(x, y); 488cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette 489cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette if (mButtonDrawable != null) { 490cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette mButtonDrawable.setHotspot(x, y); 491cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette } 492cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette } 493cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette 4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 495f6d87ec193f17e8dad82c9994ba7a58e975d364bAlan Viverette protected boolean verifyDrawable(@NonNull Drawable who) { 4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return super.verifyDrawable(who) || who == mButtonDrawable; 4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 499e213677037f836529efcc0ac201fc61dd95481c5Dianne Hackborn @Override 500e213677037f836529efcc0ac201fc61dd95481c5Dianne Hackborn public void jumpDrawablesToCurrentState() { 501e213677037f836529efcc0ac201fc61dd95481c5Dianne Hackborn super.jumpDrawablesToCurrentState(); 502e213677037f836529efcc0ac201fc61dd95481c5Dianne Hackborn if (mButtonDrawable != null) mButtonDrawable.jumpToCurrentState(); 503e213677037f836529efcc0ac201fc61dd95481c5Dianne Hackborn } 504e213677037f836529efcc0ac201fc61dd95481c5Dianne Hackborn 5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static class SavedState extends BaseSavedState { 5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean checked; 5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Constructor called from {@link CompoundButton#onSaveInstanceState()} 5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SavedState(Parcelable superState) { 5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super(superState); 5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 51499441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas 5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Constructor called from {@link #CREATOR} 5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private SavedState(Parcel in) { 5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super(in); 5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project checked = (Boolean)in.readValue(null); 5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void writeToParcel(Parcel out, int flags) { 5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.writeToParcel(out, flags); 5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.writeValue(checked); 5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String toString() { 5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "CompoundButton.SavedState{" 5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + Integer.toHexString(System.identityHashCode(this)) 5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + " checked=" + checked + "}"; 5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5366d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme @SuppressWarnings("hiding") 5376d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme public static final Parcelable.Creator<SavedState> CREATOR = 5386d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme new Parcelable.Creator<SavedState>() { 5396d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme @Override 5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public SavedState createFromParcel(Parcel in) { 5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new SavedState(in); 5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5446d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme @Override 5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public SavedState[] newArray(int size) { 5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new SavedState[size]; 5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Parcelable onSaveInstanceState() { 5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Parcelable superState = super.onSaveInstanceState(); 5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SavedState ss = new SavedState(superState); 5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ss.checked = isChecked(); 5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return ss; 5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onRestoreInstanceState(Parcelable state) { 5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SavedState ss = (SavedState) state; 56494a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamy 5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.onRestoreInstanceState(ss.getSuperState()); 5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setChecked(ss.checked); 5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project requestLayout(); 5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 56994a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamy 57094a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamy /** @hide */ 57194a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamy @Override 57294a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamy protected void encodeProperties(@NonNull ViewHierarchyEncoder stream) { 57394a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamy super.encodeProperties(stream); 57494a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamy stream.addProperty("checked", isChecked()); 57594a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamy } 5766d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme 5770200d9ea1509089c0c03b7071aa271e3a9b35c11Felipe Leme @Override 578640f30a7763b0a4b80c767acb84c740aac04768bFelipe Leme public void onProvideAutofillStructure(ViewStructure structure, int flags) { 579640f30a7763b0a4b80c767acb84c740aac04768bFelipe Leme super.onProvideAutofillStructure(structure, flags); 580c01a873c4f68518be4698077c7eb593a6a3b9f4cFelipe Leme 581c9a19b1b274af1fdd8b811c9ce2df994f7db47a4Felipe Leme structure.setDataIsSensitive(!mCheckedFromResource); 582c01a873c4f68518be4698077c7eb593a6a3b9f4cFelipe Leme } 583c01a873c4f68518be4698077c7eb593a6a3b9f4cFelipe Leme 584c01a873c4f68518be4698077c7eb593a6a3b9f4cFelipe Leme @Override 585955e252a95785192902da7c9f5610f8e40f97803Felipe Leme public void autofill(AutofillValue value) { 586955e252a95785192902da7c9f5610f8e40f97803Felipe Leme if (!isEnabled()) return; 587bab851c7c9dfe6f3d063a1009c4d57cfa2ff005cFelipe Leme 588955e252a95785192902da7c9f5610f8e40f97803Felipe Leme if (!value.isToggle()) { 5899668903731c272e51ce610598c052ef411c9d89fPhilip P. Moltmann Log.w(LOG_TAG, value + " could not be autofilled into " + this); 590955e252a95785192902da7c9f5610f8e40f97803Felipe Leme return; 5919668903731c272e51ce610598c052ef411c9d89fPhilip P. Moltmann } 5927b7711680244108923f0dbb4ca6e35db7e659e6aPhilip P. Moltmann 593955e252a95785192902da7c9f5610f8e40f97803Felipe Leme setChecked(value.getToggleValue()); 5946d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme } 5956d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme 5966d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme @Override 5978931e303700a5adb6e013c2b5a6cec621eede968Felipe Leme public @AutofillType int getAutofillType() { 5988931e303700a5adb6e013c2b5a6cec621eede968Felipe Leme return isEnabled() ? AUTOFILL_TYPE_TOGGLE : AUTOFILL_TYPE_NONE; 5996d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme } 600bab851c7c9dfe6f3d063a1009c4d57cfa2ff005cFelipe Leme 601bab851c7c9dfe6f3d063a1009c4d57cfa2ff005cFelipe Leme @Override 602640f30a7763b0a4b80c767acb84c740aac04768bFelipe Leme public AutofillValue getAutofillValue() { 603640f30a7763b0a4b80c767acb84c740aac04768bFelipe Leme return isEnabled() ? AutofillValue.forToggle(isChecked()) : null; 604bab851c7c9dfe6f3d063a1009c4d57cfa2ff005cFelipe Leme } 6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 606