1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.widget.cts; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertFalse; 21 import static org.junit.Assert.assertNotNull; 22 import static org.junit.Assert.assertNull; 23 import static org.junit.Assert.assertSame; 24 import static org.junit.Assert.assertTrue; 25 import static org.mockito.Matchers.any; 26 import static org.mockito.Mockito.mock; 27 import static org.mockito.Mockito.never; 28 import static org.mockito.Mockito.reset; 29 import static org.mockito.Mockito.spy; 30 import static org.mockito.Mockito.times; 31 import static org.mockito.Mockito.verify; 32 import static org.mockito.Mockito.verifyZeroInteractions; 33 34 import android.app.Activity; 35 import android.app.Instrumentation; 36 import android.content.Context; 37 import android.content.res.ColorStateList; 38 import android.graphics.Canvas; 39 import android.graphics.Color; 40 import android.graphics.PorterDuff; 41 import android.graphics.Rect; 42 import android.graphics.drawable.ColorDrawable; 43 import android.graphics.drawable.Drawable; 44 import android.os.Parcelable; 45 import android.support.test.InstrumentationRegistry; 46 import android.support.test.annotation.UiThreadTest; 47 import android.support.test.filters.SmallTest; 48 import android.support.test.rule.ActivityTestRule; 49 import android.support.test.runner.AndroidJUnit4; 50 import android.util.AttributeSet; 51 import android.util.StateSet; 52 import android.util.Xml; 53 import android.view.Gravity; 54 import android.view.View; 55 import android.widget.CompoundButton; 56 import android.widget.cts.util.TestUtils; 57 58 import org.junit.Before; 59 import org.junit.Rule; 60 import org.junit.Test; 61 import org.junit.runner.RunWith; 62 import org.xmlpull.v1.XmlPullParser; 63 64 /** 65 * Test {@link CompoundButton}. 66 */ 67 @SmallTest 68 @RunWith(AndroidJUnit4.class) 69 public class CompoundButtonTest { 70 private Instrumentation mInstrumentation; 71 private Activity mActivity; 72 private CompoundButton mCompoundButton; 73 74 @Rule 75 public ActivityTestRule<CompoundButtonCtsActivity> mActivityRule = 76 new ActivityTestRule<>(CompoundButtonCtsActivity.class); 77 78 @Before 79 public void setup() { 80 mInstrumentation = InstrumentationRegistry.getInstrumentation(); 81 mActivity = mActivityRule.getActivity(); 82 mCompoundButton = (CompoundButton) mActivity.findViewById(R.id.compound_button); 83 } 84 85 @Test 86 public void testConstructor() { 87 XmlPullParser parser = mActivity.getResources().getXml(R.layout.compoundbutton_layout); 88 AttributeSet mAttrSet = Xml.asAttributeSet(parser); 89 90 new MockCompoundButton(mActivity, mAttrSet, 0); 91 new MockCompoundButton(mActivity, mAttrSet); 92 new MockCompoundButton(mActivity); 93 } 94 95 @Test(expected=NullPointerException.class) 96 public void testConstructorWithNullContext1() { 97 new MockCompoundButton(null); 98 } 99 100 @Test(expected=NullPointerException.class) 101 public void testConstructorWithNullContext2() { 102 new MockCompoundButton(null, null); 103 } 104 105 @Test(expected=NullPointerException.class) 106 public void testConstructorWithNullContext3() { 107 new MockCompoundButton(null, null, -1); 108 } 109 110 @UiThreadTest 111 @Test 112 public void testAccessChecked() { 113 CompoundButton.OnCheckedChangeListener mockCheckedChangeListener = 114 mock(CompoundButton.OnCheckedChangeListener.class); 115 mCompoundButton.setOnCheckedChangeListener(mockCheckedChangeListener); 116 assertFalse(mCompoundButton.isChecked()); 117 verifyZeroInteractions(mockCheckedChangeListener); 118 119 mCompoundButton.setChecked(true); 120 assertTrue(mCompoundButton.isChecked()); 121 verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mCompoundButton, true); 122 123 reset(mockCheckedChangeListener); 124 mCompoundButton.setChecked(true); 125 assertTrue(mCompoundButton.isChecked()); 126 verifyZeroInteractions(mockCheckedChangeListener); 127 128 mCompoundButton.setChecked(false); 129 assertFalse(mCompoundButton.isChecked()); 130 verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mCompoundButton, false); 131 } 132 133 @UiThreadTest 134 @Test 135 public void testSetOnCheckedChangeListener() { 136 CompoundButton.OnCheckedChangeListener mockCheckedChangeListener = 137 mock(CompoundButton.OnCheckedChangeListener.class); 138 mCompoundButton.setOnCheckedChangeListener(mockCheckedChangeListener); 139 assertFalse(mCompoundButton.isChecked()); 140 verifyZeroInteractions(mockCheckedChangeListener); 141 142 mCompoundButton.setChecked(true); 143 verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mCompoundButton, true); 144 145 // set null 146 mCompoundButton.setOnCheckedChangeListener(null); 147 reset(mockCheckedChangeListener); 148 mCompoundButton.setChecked(false); 149 verifyZeroInteractions(mockCheckedChangeListener); 150 } 151 152 @UiThreadTest 153 @Test 154 public void testToggle() { 155 assertFalse(mCompoundButton.isChecked()); 156 157 mCompoundButton.toggle(); 158 assertTrue(mCompoundButton.isChecked()); 159 160 mCompoundButton.toggle(); 161 assertFalse(mCompoundButton.isChecked()); 162 163 mCompoundButton.setChecked(true); 164 mCompoundButton.toggle(); 165 assertFalse(mCompoundButton.isChecked()); 166 } 167 168 @UiThreadTest 169 @Test 170 public void testPerformClick() { 171 assertFalse(mCompoundButton.isChecked()); 172 173 // performClick without OnClickListener will return false. 174 assertFalse(mCompoundButton.performClick()); 175 assertTrue(mCompoundButton.isChecked()); 176 177 assertFalse(mCompoundButton.performClick()); 178 assertFalse(mCompoundButton.isChecked()); 179 180 // performClick with OnClickListener will return true. 181 mCompoundButton.setOnClickListener((view) -> {}); 182 assertTrue(mCompoundButton.performClick()); 183 assertTrue(mCompoundButton.isChecked()); 184 185 assertTrue(mCompoundButton.performClick()); 186 assertFalse(mCompoundButton.isChecked()); 187 } 188 189 @UiThreadTest 190 @Test 191 public void testDrawableStateChanged() { 192 MockCompoundButton compoundButton = new MockCompoundButton(mActivity); 193 assertFalse(compoundButton.isChecked()); 194 // drawableStateChanged without any drawables. 195 compoundButton.drawableStateChanged(); 196 197 // drawableStateChanged when CheckMarkDrawable is not null. 198 Drawable drawable = mActivity.getDrawable(R.drawable.statelistdrawable); 199 compoundButton.setButtonDrawable(drawable); 200 drawable.setState(null); 201 assertNull(drawable.getState()); 202 203 compoundButton.drawableStateChanged(); 204 assertNotNull(drawable.getState()); 205 assertSame(compoundButton.getDrawableState(), drawable.getState()); 206 } 207 208 @UiThreadTest 209 @Test 210 public void testSetButtonDrawableByDrawable() { 211 // set null drawable 212 mCompoundButton.setButtonDrawable(null); 213 assertNull(mCompoundButton.getButtonDrawable()); 214 215 // set drawable when button is GONE 216 mCompoundButton.setVisibility(View.GONE); 217 Drawable firstDrawable = mActivity.getDrawable(R.drawable.scenery); 218 firstDrawable.setVisible(true, false); 219 assertEquals(StateSet.WILD_CARD, firstDrawable.getState()); 220 221 mCompoundButton.setButtonDrawable(firstDrawable); 222 assertSame(firstDrawable, mCompoundButton.getButtonDrawable()); 223 assertFalse(firstDrawable.isVisible()); 224 225 // update drawable when button is VISIBLE 226 mCompoundButton.setVisibility(View.VISIBLE); 227 Drawable secondDrawable = mActivity.getDrawable(R.drawable.pass); 228 secondDrawable.setVisible(true, false); 229 assertEquals(StateSet.WILD_CARD, secondDrawable.getState()); 230 231 mCompoundButton.setButtonDrawable(secondDrawable); 232 assertSame(secondDrawable, mCompoundButton.getButtonDrawable()); 233 assertTrue(secondDrawable.isVisible()); 234 // the firstDrawable is not active. 235 assertFalse(firstDrawable.isVisible()); 236 } 237 238 @UiThreadTest 239 @Test 240 public void testSetButtonDrawableById() { 241 // resId is 0 242 mCompoundButton.setButtonDrawable(0); 243 244 // set drawable 245 mCompoundButton.setButtonDrawable(R.drawable.scenery); 246 247 // set the same drawable again 248 mCompoundButton.setButtonDrawable(R.drawable.scenery); 249 250 // update drawable 251 mCompoundButton.setButtonDrawable(R.drawable.pass); 252 } 253 254 @Test 255 public void testOnCreateDrawableState() { 256 // compoundButton is not checked, append 0 to state array. 257 MockCompoundButton compoundButton = new MockCompoundButton(mActivity); 258 int[] state = compoundButton.onCreateDrawableState(0); 259 assertEquals(0, state[state.length - 1]); 260 261 // compoundButton is checked, append R.attr.state_checked to state array. 262 compoundButton.setChecked(true); 263 int[] checkedState = compoundButton.onCreateDrawableState(0); 264 assertEquals(state[0], checkedState[0]); 265 assertEquals(android.R.attr.state_checked, 266 checkedState[checkedState.length - 1]); 267 268 // compoundButton is not checked again. 269 compoundButton.setChecked(false); 270 state = compoundButton.onCreateDrawableState(0); 271 assertEquals(0, state[state.length - 1]); 272 } 273 274 @Test 275 public void testOnDraw() { 276 int viewHeight; 277 int drawableWidth; 278 int drawableHeight; 279 Rect bounds; 280 Drawable drawable; 281 Canvas canvas = new Canvas(android.graphics.Bitmap.createBitmap(100, 100, 282 android.graphics.Bitmap.Config.ARGB_8888)); 283 MockCompoundButton compoundButton; 284 285 // onDraw when there is no drawable 286 compoundButton = new MockCompoundButton(mActivity); 287 compoundButton.onDraw(canvas); 288 289 // onDraw when Gravity.TOP, it's default. 290 compoundButton = new MockCompoundButton(mActivity); 291 drawable = mActivity.getDrawable(R.drawable.scenery); 292 compoundButton.setButtonDrawable(drawable); 293 viewHeight = compoundButton.getHeight(); 294 drawableWidth = drawable.getIntrinsicWidth(); 295 drawableHeight = drawable.getIntrinsicHeight(); 296 297 compoundButton.onDraw(canvas); 298 bounds = drawable.copyBounds(); 299 assertEquals(0, bounds.left); 300 assertEquals(drawableWidth, bounds.right); 301 assertEquals(0, bounds.top); 302 assertEquals(drawableHeight, bounds.bottom); 303 304 // onDraw when Gravity.BOTTOM 305 compoundButton.setGravity(Gravity.BOTTOM); 306 compoundButton.onDraw(canvas); 307 bounds = drawable.copyBounds(); 308 assertEquals(0, bounds.left); 309 assertEquals(drawableWidth, bounds.right); 310 assertEquals(viewHeight - drawableHeight, bounds.top); 311 assertEquals(viewHeight, bounds.bottom); 312 313 // onDraw when Gravity.CENTER_VERTICAL 314 compoundButton.setGravity(Gravity.CENTER_VERTICAL); 315 compoundButton.onDraw(canvas); 316 bounds = drawable.copyBounds(); 317 assertEquals(0, bounds.left); 318 assertEquals(drawableWidth, bounds.right); 319 assertEquals( (viewHeight - drawableHeight) / 2, bounds.top); 320 assertEquals( (viewHeight - drawableHeight) / 2 + drawableHeight, bounds.bottom); 321 } 322 323 @UiThreadTest 324 @Test 325 public void testAccessInstanceState() { 326 Parcelable state; 327 328 assertFalse(mCompoundButton.isChecked()); 329 assertFalse(mCompoundButton.getFreezesText()); 330 331 state = mCompoundButton.onSaveInstanceState(); 332 assertNotNull(state); 333 assertFalse(mCompoundButton.getFreezesText()); 334 335 mCompoundButton.setChecked(true); 336 337 mCompoundButton.onRestoreInstanceState(state); 338 assertFalse(mCompoundButton.isChecked()); 339 assertTrue(mCompoundButton.isLayoutRequested()); 340 } 341 342 @Test 343 public void testVerifyDrawable() { 344 MockCompoundButton compoundButton = new MockCompoundButton(mActivity); 345 Drawable drawable = mActivity.getDrawable(R.drawable.scenery); 346 347 assertTrue(compoundButton.verifyDrawable(null)); 348 assertFalse(compoundButton.verifyDrawable(drawable)); 349 350 compoundButton.setButtonDrawable(drawable); 351 assertTrue(compoundButton.verifyDrawable(null)); 352 assertTrue(compoundButton.verifyDrawable(drawable)); 353 } 354 355 @UiThreadTest 356 @Test 357 public void testButtonTint() { 358 CompoundButton tintedButton = (CompoundButton) mActivity.findViewById(R.id.button_tint); 359 360 assertEquals("Button tint inflated correctly", 361 Color.WHITE, tintedButton.getButtonTintList().getDefaultColor()); 362 assertEquals("Button tint mode inflated correctly", 363 PorterDuff.Mode.SRC_OVER, tintedButton.getButtonTintMode()); 364 365 Drawable mockDrawable = spy(new ColorDrawable(Color.GREEN)); 366 367 mCompoundButton.setButtonDrawable(mockDrawable); 368 // No button tint applied by default 369 verify(mockDrawable, never()).setTintList(any(ColorStateList.class)); 370 371 mCompoundButton.setButtonTintList(ColorStateList.valueOf(Color.WHITE)); 372 // Button tint applied when setButtonTintList() called after setButton() 373 verify(mockDrawable, times(1)).setTintList(TestUtils.colorStateListOf(Color.WHITE)); 374 375 reset(mockDrawable); 376 mCompoundButton.setButtonDrawable(null); 377 mCompoundButton.setButtonDrawable(mockDrawable); 378 // Button tint applied when setButtonTintList() called before setButton() 379 verify(mockDrawable, times(1)).setTintList(TestUtils.colorStateListOf(Color.WHITE)); 380 } 381 382 public static final class MockCompoundButton extends CompoundButton { 383 public MockCompoundButton(Context context) { 384 super(context); 385 } 386 387 public MockCompoundButton(Context context, AttributeSet attrs) { 388 super(context, attrs, 0); 389 } 390 391 public MockCompoundButton(Context context, AttributeSet attrs, int defStyle) { 392 super(context, attrs, defStyle); 393 } 394 395 @Override 396 protected void drawableStateChanged() { 397 super.drawableStateChanged(); 398 } 399 400 @Override 401 protected void onDraw(Canvas canvas) { 402 super.onDraw(canvas); 403 } 404 405 @Override 406 protected int[] onCreateDrawableState(int extraSpace) { 407 return super.onCreateDrawableState(extraSpace); 408 } 409 410 @Override 411 protected boolean verifyDrawable(Drawable who) { 412 return super.verifyDrawable(who); 413 } 414 } 415 } 416