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.graphics.drawable.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.assertSame; 23 import static org.junit.Assert.assertTrue; 24 import static org.junit.Assert.fail; 25 import static org.mockito.Matchers.any; 26 import static org.mockito.Matchers.anyBoolean; 27 import static org.mockito.Matchers.anyInt; 28 import static org.mockito.Matchers.anyLong; 29 import static org.mockito.Mockito.atLeastOnce; 30 import static org.mockito.Mockito.doNothing; 31 import static org.mockito.Mockito.mock; 32 import static org.mockito.Mockito.never; 33 import static org.mockito.Mockito.reset; 34 import static org.mockito.Mockito.spy; 35 import static org.mockito.Mockito.times; 36 import static org.mockito.Mockito.verify; 37 38 import android.content.Context; 39 import android.content.res.Resources; 40 import android.content.res.XmlResourceParser; 41 import android.graphics.Canvas; 42 import android.graphics.Color; 43 import android.graphics.ColorFilter; 44 import android.graphics.Rect; 45 import android.graphics.cts.R; 46 import android.graphics.drawable.BitmapDrawable; 47 import android.graphics.drawable.ColorDrawable; 48 import android.graphics.drawable.Drawable; 49 import android.graphics.drawable.Drawable.ConstantState; 50 import android.graphics.drawable.ScaleDrawable; 51 import android.support.test.InstrumentationRegistry; 52 import android.support.test.filters.SmallTest; 53 import android.support.test.runner.AndroidJUnit4; 54 import android.util.AttributeSet; 55 import android.util.StateSet; 56 import android.view.Gravity; 57 58 import org.junit.Before; 59 import org.junit.Test; 60 import org.junit.runner.RunWith; 61 import org.xmlpull.v1.XmlPullParserException; 62 63 import java.io.IOException; 64 import java.util.Arrays; 65 66 @SmallTest 67 @RunWith(AndroidJUnit4.class) 68 public class ScaleDrawableTest { 69 private Context mContext; 70 71 @Before 72 public void setup() { 73 mContext = InstrumentationRegistry.getTargetContext(); 74 } 75 76 @SuppressWarnings("deprecation") 77 @Test 78 public void testConstructor() { 79 Drawable d = new BitmapDrawable(); 80 ScaleDrawable scaleDrawable = new ScaleDrawable(d, Gravity.CENTER, 100, 200); 81 assertSame(d, scaleDrawable.getDrawable()); 82 83 new ScaleDrawable(null, -1, Float.MAX_VALUE, Float.MIN_VALUE); 84 } 85 86 @SuppressWarnings("deprecation") 87 @Test 88 public void testInvalidateDrawable() { 89 ScaleDrawable scaleDrawable = new ScaleDrawable(new BitmapDrawable(), 90 Gravity.CENTER, 100, 200); 91 92 Drawable.Callback callback = mock(Drawable.Callback.class); 93 scaleDrawable.setCallback(callback); 94 scaleDrawable.invalidateDrawable(null); 95 verify(callback, times(1)).invalidateDrawable(any()); 96 97 reset(callback); 98 scaleDrawable.invalidateDrawable(new BitmapDrawable()); 99 verify(callback, times(1)).invalidateDrawable(any()); 100 101 reset(callback); 102 scaleDrawable.setCallback(null); 103 scaleDrawable.invalidateDrawable(null); 104 verify(callback, never()).invalidateDrawable(any()); 105 } 106 107 @SuppressWarnings("deprecation") 108 @Test 109 public void testScheduleDrawable() { 110 ScaleDrawable scaleDrawable = new ScaleDrawable(new BitmapDrawable(), 111 Gravity.CENTER, 100, 200); 112 113 Drawable.Callback callback = mock(Drawable.Callback.class); 114 scaleDrawable.setCallback(callback); 115 scaleDrawable.scheduleDrawable(null, null, 0); 116 verify(callback, times(1)).scheduleDrawable(any(), any(), anyLong()); 117 118 reset(callback); 119 scaleDrawable.scheduleDrawable(new BitmapDrawable(), () -> {}, 1000L); 120 verify(callback, times(1)).scheduleDrawable(any(), any(), anyLong()); 121 122 reset(callback); 123 scaleDrawable.setCallback(null); 124 scaleDrawable.scheduleDrawable(null, null, 0); 125 verify(callback, never()).scheduleDrawable(any(), any(), anyLong()); 126 } 127 128 @SuppressWarnings("deprecation") 129 @Test 130 public void testUnscheduleDrawable() { 131 ScaleDrawable scaleDrawable = new ScaleDrawable(new BitmapDrawable(), 132 Gravity.CENTER, 100, 200); 133 134 Drawable.Callback callback = mock(Drawable.Callback.class); 135 scaleDrawable.setCallback(callback); 136 scaleDrawable.unscheduleDrawable(null, null); 137 verify(callback, times(1)).unscheduleDrawable(any(), any()); 138 139 reset(callback); 140 scaleDrawable.unscheduleDrawable(new BitmapDrawable(), () -> {}); 141 verify(callback, times(1)).unscheduleDrawable(any(), any()); 142 143 reset(callback); 144 scaleDrawable.setCallback(null); 145 scaleDrawable.unscheduleDrawable(null, null); 146 verify(callback, never()).unscheduleDrawable(any(), any()); 147 } 148 149 @Test 150 public void testDraw() { 151 Drawable mockDrawable = spy(new ColorDrawable(Color.RED)); 152 ScaleDrawable scaleDrawable = new ScaleDrawable(mockDrawable, Gravity.CENTER, 100, 200); 153 154 scaleDrawable.draw(new Canvas()); 155 verify(mockDrawable, never()).draw(any()); 156 157 // this method will call the contained drawable's draw method 158 // if the contained drawable's level doesn't equal 0. 159 mockDrawable.setLevel(1); 160 scaleDrawable.draw(new Canvas()); 161 verify(mockDrawable, times(1)).draw(any()); 162 163 reset(mockDrawable); 164 doNothing().when(mockDrawable).draw(any()); 165 scaleDrawable.draw(null); 166 verify(mockDrawable, times(1)).draw(any()); 167 } 168 169 @Test 170 public void testGetChangingConfigurations() { 171 final int SUPER_CONFIG = 1; 172 final int CONTAINED_DRAWABLE_CONFIG = 2; 173 174 Drawable mockDrawable = new ColorDrawable(Color.YELLOW); 175 ScaleDrawable scaleDrawable = new ScaleDrawable(mockDrawable, Gravity.CENTER, 100, 200); 176 177 assertEquals(0, scaleDrawable.getChangingConfigurations()); 178 179 mockDrawable.setChangingConfigurations(CONTAINED_DRAWABLE_CONFIG); 180 assertEquals(CONTAINED_DRAWABLE_CONFIG, scaleDrawable.getChangingConfigurations()); 181 182 scaleDrawable.setChangingConfigurations(SUPER_CONFIG); 183 assertEquals(SUPER_CONFIG | CONTAINED_DRAWABLE_CONFIG, 184 scaleDrawable.getChangingConfigurations()); 185 } 186 187 @Test 188 public void testGetPadding() { 189 Drawable mockDrawable = spy(new ColorDrawable(Color.RED)); 190 ScaleDrawable scaleDrawable = new ScaleDrawable(mockDrawable, Gravity.CENTER, 100, 200); 191 192 // this method will call contained drawable's getPadding method. 193 scaleDrawable.getPadding(new Rect()); 194 verify(mockDrawable, times(1)).getPadding(any()); 195 } 196 197 @Test(expected=NullPointerException.class) 198 public void testGetPaddingNull() { 199 Drawable mockDrawable = new ColorDrawable(Color.YELLOW); 200 ScaleDrawable scaleDrawable = new ScaleDrawable(mockDrawable, Gravity.CENTER, 100, 200); 201 202 scaleDrawable.getPadding(null); 203 } 204 205 @Test 206 public void testSetVisible() { 207 Drawable mockDrawable = spy(new ColorDrawable(Color.RED)); 208 ScaleDrawable scaleDrawable = new ScaleDrawable(mockDrawable, Gravity.CENTER, 100, 200); 209 assertTrue(scaleDrawable.isVisible()); 210 211 assertTrue(scaleDrawable.setVisible(false, false)); 212 assertFalse(scaleDrawable.isVisible()); 213 verify(mockDrawable, atLeastOnce()).setVisible(anyBoolean(), anyBoolean()); 214 215 reset(mockDrawable); 216 assertFalse(scaleDrawable.setVisible(false, false)); 217 assertFalse(scaleDrawable.isVisible()); 218 verify(mockDrawable, times(1)).setVisible(anyBoolean(), anyBoolean()); 219 220 reset(mockDrawable); 221 assertTrue(scaleDrawable.setVisible(true, false)); 222 assertTrue(scaleDrawable.isVisible()); 223 verify(mockDrawable, times(1)).setVisible(anyBoolean(), anyBoolean()); 224 } 225 226 @Test 227 public void testSetAlpha() { 228 Drawable mockDrawable = spy(new ColorDrawable(Color.RED)); 229 ScaleDrawable scaleDrawable = new ScaleDrawable(mockDrawable, Gravity.CENTER, 100, 200); 230 231 // this method will call contained drawable's setAlpha method. 232 scaleDrawable.setAlpha(100); 233 verify(mockDrawable, times(1)).setAlpha(anyInt()); 234 235 reset(mockDrawable); 236 scaleDrawable.setAlpha(Integer.MAX_VALUE); 237 verify(mockDrawable, times(1)).setAlpha(anyInt()); 238 239 reset(mockDrawable); 240 scaleDrawable.setAlpha(-1); 241 verify(mockDrawable, times(1)).setAlpha(anyInt()); 242 } 243 244 @Test 245 public void testSetColorFilter() { 246 Drawable mockDrawable = spy(new ColorDrawable(Color.RED)); 247 ScaleDrawable scaleDrawable = new ScaleDrawable(mockDrawable, Gravity.CENTER, 100, 200); 248 249 // this method will call contained drawable's setColorFilter method. 250 scaleDrawable.setColorFilter(new ColorFilter()); 251 verify(mockDrawable, times(1)).setColorFilter(any()); 252 253 reset(mockDrawable); 254 scaleDrawable.setColorFilter(null); 255 verify(mockDrawable, times(1)).setColorFilter(any()); 256 } 257 258 @Test 259 public void testGetOpacity() { 260 Drawable mockDrawable = spy(new ColorDrawable(Color.RED)); 261 ScaleDrawable scaleDrawable = new ScaleDrawable(mockDrawable, Gravity.CENTER, 100, 200); 262 263 // This method will call contained drawable's getOpacity method. 264 scaleDrawable.setLevel(1); 265 scaleDrawable.getOpacity(); 266 verify(mockDrawable, times(1)).getOpacity(); 267 } 268 269 @Test 270 public void testIsStateful() { 271 Drawable mockDrawable = spy(new ColorDrawable(Color.RED)); 272 ScaleDrawable scaleDrawable = new ScaleDrawable(mockDrawable, Gravity.CENTER, 100, 200); 273 274 // this method will call contained drawable's isStateful method. 275 scaleDrawable.isStateful(); 276 verify(mockDrawable, times(1)).isStateful(); 277 } 278 279 @Test 280 public void testOnStateChange() { 281 Drawable d = new MockDrawable(); 282 MockScaleDrawable scaleDrawable = new MockScaleDrawable(d, Gravity.CENTER, 100, 200); 283 assertEquals("initial child state is empty", d.getState(), StateSet.WILD_CARD); 284 285 int[] state = new int[] {1, 2, 3}; 286 assertFalse("child did not change", scaleDrawable.onStateChange(state)); 287 assertEquals("child state did not change", d.getState(), StateSet.WILD_CARD); 288 289 d = mContext.getDrawable(R.drawable.statelistdrawable); 290 scaleDrawable = new MockScaleDrawable(d, Gravity.CENTER, 100, 200); 291 assertEquals("initial child state is empty", d.getState(), StateSet.WILD_CARD); 292 scaleDrawable.onStateChange(state); 293 assertTrue("child state changed", Arrays.equals(state, d.getState())); 294 295 // input null as param 296 scaleDrawable.onStateChange(null); 297 // expected, no Exception thrown out, test success 298 } 299 300 @Test 301 public void testInitialLevel() throws XmlPullParserException, IOException { 302 ScaleDrawable dr = new ScaleDrawable(null, Gravity.CENTER, 1, 1); 303 Resources res = mContext.getResources(); 304 XmlResourceParser parser = res.getXml(R.xml.scaledrawable_level); 305 AttributeSet attrs = DrawableTestUtils.getAttributeSet(parser, "scale_allattrs"); 306 307 // Ensure that initial level is loaded from XML. 308 dr.inflate(res, parser, attrs); 309 assertEquals(5000, dr.getLevel()); 310 311 dr.setLevel(0); 312 assertEquals(0, dr.getLevel()); 313 314 // Ensure that initial level is propagated to constant state clones. 315 ScaleDrawable clone = (ScaleDrawable) dr.getConstantState().newDrawable(res); 316 assertEquals(5000, clone.getLevel()); 317 318 // Ensure that current level is not tied to constant state. 319 dr.setLevel(1000); 320 assertEquals(1000, dr.getLevel()); 321 assertEquals(5000, clone.getLevel()); 322 } 323 324 @Test 325 public void testOnLevelChange() { 326 MockDrawable mockDrawable = new MockDrawable(); 327 MockScaleDrawable mockScaleDrawable = new MockScaleDrawable( 328 mockDrawable, Gravity.CENTER, 100, 200); 329 330 assertTrue(mockScaleDrawable.onLevelChange(0)); 331 assertFalse(mockDrawable.hasCalledOnLevelChange()); 332 assertTrue(mockScaleDrawable.hasCalledOnBoundsChange()); 333 334 mockDrawable.reset(); 335 mockScaleDrawable.reset(); 336 assertTrue(mockScaleDrawable.onLevelChange(Integer.MIN_VALUE)); 337 assertTrue(mockDrawable.hasCalledOnLevelChange()); 338 assertTrue(mockScaleDrawable.hasCalledOnBoundsChange()); 339 } 340 341 @Test 342 public void testOnBoundsChange() { 343 Drawable mockDrawable = new ColorDrawable(Color.YELLOW); 344 float scaleWidth = 0.3f; 345 float scaleHeight = 0.3f; 346 MockScaleDrawable mockScaleDrawable = new MockScaleDrawable( 347 mockDrawable, Gravity.LEFT, scaleWidth, scaleHeight); 348 Rect bounds = new Rect(2, 2, 26, 32); 349 mockDrawable.setBounds(bounds); 350 mockScaleDrawable.onBoundsChange(bounds); 351 Rect expected = new Rect(); 352 Gravity.apply(Gravity.LEFT, bounds.width() - (int) (bounds.width() * scaleWidth), 353 bounds.height() - (int) (bounds.height() * scaleHeight), bounds, expected); 354 assertEquals(expected.left, mockDrawable.getBounds().left); 355 assertEquals(expected.top, mockDrawable.getBounds().top); 356 assertEquals(expected.right, mockDrawable.getBounds().right); 357 assertEquals(expected.bottom, mockDrawable.getBounds().bottom); 358 359 scaleWidth = 0.6f; 360 scaleHeight = 0.7f; 361 int level = 4000; 362 mockScaleDrawable = new MockScaleDrawable( 363 mockDrawable, Gravity.BOTTOM | Gravity.RIGHT, scaleWidth, scaleHeight); 364 mockDrawable.setBounds(bounds); 365 mockScaleDrawable.setLevel(level); 366 mockScaleDrawable.onBoundsChange(bounds); 367 Gravity.apply(Gravity.BOTTOM | Gravity.RIGHT, 368 bounds.width() - (int) (bounds.width() * scaleWidth * (10000 - level) / 10000), 369 bounds.height() - (int) (bounds.height() * scaleHeight * (10000 - level) / 10000), 370 bounds, expected); 371 assertEquals(expected.left, mockDrawable.getBounds().left); 372 assertEquals(expected.top, mockDrawable.getBounds().top); 373 assertEquals(expected.right, mockDrawable.getBounds().right); 374 assertEquals(expected.bottom, mockDrawable.getBounds().bottom); 375 376 scaleWidth = 0f; 377 scaleHeight = -0.3f; 378 mockScaleDrawable = new MockScaleDrawable( 379 mockDrawable, Gravity.BOTTOM | Gravity.RIGHT, scaleWidth, scaleHeight); 380 mockDrawable.setBounds(bounds); 381 mockScaleDrawable.onBoundsChange(bounds); 382 assertEquals(bounds.left, mockDrawable.getBounds().left); 383 assertEquals(bounds.top, mockDrawable.getBounds().top); 384 assertEquals(bounds.right, mockDrawable.getBounds().right); 385 assertEquals(bounds.bottom, mockDrawable.getBounds().bottom); 386 387 scaleWidth = 1f; 388 scaleHeight = 1.7f; 389 mockScaleDrawable = new MockScaleDrawable( 390 mockDrawable, Gravity.BOTTOM | Gravity.RIGHT, scaleWidth, scaleHeight); 391 mockDrawable.setBounds(bounds); 392 mockScaleDrawable.onBoundsChange(bounds); 393 assertEquals(bounds.left, mockDrawable.getBounds().left); 394 assertEquals(bounds.top, mockDrawable.getBounds().top); 395 assertEquals(bounds.right, mockDrawable.getBounds().right); 396 assertEquals(bounds.bottom, mockDrawable.getBounds().bottom); 397 } 398 399 @Test 400 public void testGetIntrinsicWidth() { 401 Drawable mockDrawable = spy(new ColorDrawable(Color.RED)); 402 ScaleDrawable scaleDrawable = new ScaleDrawable(mockDrawable, Gravity.CENTER, 100, 200); 403 404 // this method will call contained drawable's getIntrinsicWidth method. 405 scaleDrawable.getIntrinsicWidth(); 406 verify(mockDrawable, times(1)).getIntrinsicWidth(); 407 } 408 409 @Test 410 public void testGetIntrinsicHeight() { 411 Drawable mockDrawable = spy(new ColorDrawable(Color.RED)); 412 ScaleDrawable scaleDrawable = new ScaleDrawable(mockDrawable, Gravity.CENTER, 100, 200); 413 414 // this method will call contained drawable's getIntrinsicHeight method. 415 scaleDrawable.getIntrinsicHeight(); 416 verify(mockDrawable, times(1)).getIntrinsicHeight(); 417 } 418 419 @SuppressWarnings("deprecation") 420 @Test 421 public void testGetConstantState() { 422 ScaleDrawable scaleDrawable = new ScaleDrawable(new BitmapDrawable(), 423 Gravity.CENTER, 100, 200); 424 425 ConstantState constantState = scaleDrawable.getConstantState(); 426 assertNotNull(constantState); 427 assertEquals(0, constantState.getChangingConfigurations()); 428 429 scaleDrawable.setChangingConfigurations(1); 430 constantState = scaleDrawable.getConstantState(); 431 assertNotNull(constantState); 432 assertEquals(1, constantState.getChangingConfigurations()); 433 } 434 435 @SuppressWarnings("deprecation") 436 @Test 437 public void testInflate() throws XmlPullParserException, IOException { 438 ScaleDrawable scaleDrawable = new ScaleDrawable(new BitmapDrawable(), 439 Gravity.RIGHT, 100, 200); 440 441 Resources res = mContext.getResources(); 442 XmlResourceParser parser = res.getXml(R.xml.scaledrawable); 443 AttributeSet attrs = DrawableTestUtils.getAttributeSet(parser, "scale_allattrs"); 444 scaleDrawable.inflate(res, parser, attrs); 445 final int bitmapSize = Math.round(48f * res.getDisplayMetrics().density); 446 assertEquals(bitmapSize, scaleDrawable.getIntrinsicWidth()); 447 assertEquals(bitmapSize, scaleDrawable.getIntrinsicHeight()); 448 449 parser = res.getXml(R.xml.scaledrawable); 450 attrs = DrawableTestUtils.getAttributeSet(parser, "scale_nodrawable"); 451 try { 452 Drawable.createFromXmlInner(res, parser, attrs); 453 fail("Should throw XmlPullParserException if missing drawable"); 454 } catch (XmlPullParserException e) { 455 } 456 457 try { 458 Drawable.createFromXmlInner(null, parser, attrs); 459 fail("Should throw NullPointerException if resource is null"); 460 } catch (NullPointerException e) { 461 } 462 463 try { 464 Drawable.createFromXmlInner(res, null, attrs); 465 fail("Should throw NullPointerException if parser is null"); 466 } catch (NullPointerException e) { 467 } 468 469 try { 470 Drawable.createFromXmlInner(res, parser, null); 471 fail("Should throw NullPointerException if attribute set is null"); 472 } catch (NullPointerException e) { 473 } 474 } 475 476 @Test 477 public void testMutate() { 478 ScaleDrawable d1 = (ScaleDrawable) mContext.getDrawable(R.drawable.scaledrawable); 479 ScaleDrawable d2 = (ScaleDrawable) mContext.getDrawable(R.drawable.scaledrawable); 480 ScaleDrawable d3 = (ScaleDrawable) mContext.getDrawable(R.drawable.scaledrawable); 481 int restoreAlpha = d1.getAlpha(); 482 483 try { 484 // verify bad behavior - modify before mutate pollutes other drawables 485 d1.setAlpha(100); 486 assertEquals(100, ((BitmapDrawable) d1.getDrawable()).getPaint().getAlpha()); 487 assertEquals(100, ((BitmapDrawable) d2.getDrawable()).getPaint().getAlpha()); 488 assertEquals(100, ((BitmapDrawable) d3.getDrawable()).getPaint().getAlpha()); 489 490 d1.mutate(); 491 d1.setAlpha(200); 492 assertEquals(200, ((BitmapDrawable) d1.getDrawable()).getPaint().getAlpha()); 493 assertEquals(100, ((BitmapDrawable) d2.getDrawable()).getPaint().getAlpha()); 494 assertEquals(100, ((BitmapDrawable) d3.getDrawable()).getPaint().getAlpha()); 495 496 d2.setAlpha(50); 497 assertEquals(200, ((BitmapDrawable) d1.getDrawable()).getPaint().getAlpha()); 498 assertEquals(50, ((BitmapDrawable) d2.getDrawable()).getPaint().getAlpha()); 499 assertEquals(50, ((BitmapDrawable) d3.getDrawable()).getPaint().getAlpha()); 500 } finally { 501 // restore externally visible state, since other tests may use the drawable 502 mContext.getDrawable(R.drawable.scaledrawable).setAlpha(restoreAlpha); 503 } 504 } 505 506 // Since Mockito can't mock or spy on protected methods, we have a custom extension 507 // of Drawable to track calls to protected methods. This class also has empty implementations 508 // of the base abstract methods. 509 private static class MockDrawable extends Drawable { 510 private boolean mCalledOnLevelChange = false; 511 512 @Override 513 public void draw(Canvas canvas) { 514 } 515 516 @Override 517 public int getOpacity() { 518 return 0; 519 } 520 521 @Override 522 public void setAlpha(int alpha) { 523 } 524 525 @Override 526 public void setColorFilter(ColorFilter cf) { 527 } 528 529 @Override 530 protected boolean onLevelChange(int level) { 531 mCalledOnLevelChange = true; 532 return super.onLevelChange(level); 533 } 534 535 public boolean hasCalledOnLevelChange() { 536 return mCalledOnLevelChange; 537 } 538 539 public void reset() { 540 mCalledOnLevelChange = false; 541 } 542 } 543 544 private static class MockScaleDrawable extends ScaleDrawable { 545 private boolean mCalledOnBoundsChange = false; 546 547 MockScaleDrawable() { 548 super(null, Gravity.CENTER, 100, 200); 549 } 550 551 public MockScaleDrawable(Drawable drawable, int gravity, 552 float scaleWidth, float scaleHeight) { 553 super(drawable, gravity, scaleWidth, scaleHeight); 554 } 555 556 @Override 557 protected boolean onStateChange(int[] state) { 558 return super.onStateChange(state); 559 } 560 561 @Override 562 protected boolean onLevelChange(int level) { 563 return super.onLevelChange(level); 564 } 565 566 @Override 567 protected void onBoundsChange(Rect bounds) { 568 mCalledOnBoundsChange = true; 569 super.onBoundsChange(bounds); 570 } 571 572 public boolean hasCalledOnBoundsChange() { 573 return mCalledOnBoundsChange; 574 } 575 576 public void reset() { 577 mCalledOnBoundsChange = false; 578 } 579 } 580 } 581