/**
* Copyright (c) 2017-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.litho;
import java.util.List;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.support.v4.util.SparseArrayCompat;
import android.util.SparseArray;
import android.view.MotionEvent;
import android.view.View;
import com.facebook.litho.testing.testrunner.ComponentsTestRunner;
import com.facebook.litho.testing.TestDrawableComponent;
import com.facebook.litho.testing.TestViewComponent;
import com.facebook.yoga.YogaDirection;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.reflect.Whitebox;
import org.robolectric.RuntimeEnvironment;
import static android.view.View.GONE;
import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_AUTO;
import static android.view.View.INVISIBLE;
import static android.view.View.MeasureSpec.EXACTLY;
import static android.view.View.MeasureSpec.makeMeasureSpec;
import static android.view.View.VISIBLE;
import static com.facebook.litho.MountItem.FLAG_DUPLICATE_PARENT_STATE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* Tests {@link ComponentHost}
*/
@RunWith(ComponentsTestRunner.class)
public class ComponentHostTest {
private Component<?> mViewGroupHost;
private TestableComponentHost mHost;
private Component<?> mDrawableComponent;
private Component<?> mViewComponent;
private ComponentContext mContext;
@Before
public void setup() throws Exception {
mContext = new ComponentContext(RuntimeEnvironment.application);
mViewComponent = TestViewComponent.create(mContext).build();
mDrawableComponent = TestDrawableComponent.create(mContext).build();
mHost = new TestableComponentHost(mContext);
mViewGroupHost = HostComponent.create();
}
@Test
public void testParentHostMarker() {
assertEquals(0, mHost.getParentHostMarker());
mHost.setParentHostMarker(1);
assertEquals(1, mHost.getParentHostMarker());
}
@Test
public void testInvalidations() {
assertEquals(0, mHost.getInvalidationCount());
assertNull(mHost.getInvalidationRect());
Drawable d1 = new ColorDrawable();
d1.setBounds(0, 0, 1, 1);
MountItem mountItem1 = mount(0, d1);
assertEquals(1, mHost.getInvalidationCount());
assertEquals(d1.getBounds(), mHost.getInvalidationRect());
Drawable d2 = new ColorDrawable();
d2.setBounds(0, 0, 2, 2);
MountItem mountItem2 = mount(1, d2);
assertEquals(2, mHost.getInvalidationCount());
assertEquals(d2.getBounds(), mHost.getInvalidationRect());
View v1 = new View(mContext);
Rect v1Bounds = new Rect(0, 0, 10, 10);
v1.measure(
makeMeasureSpec(v1Bounds.width(), EXACTLY),
makeMeasureSpec(v1Bounds.height(), EXACTLY));
v1.layout(v1Bounds.left, v1Bounds.top, v1Bounds.right, v1Bounds.bottom);
MountItem mountItem3 = mount(2, v1);
assertEquals(3, mHost.getInvalidationCount());
assertEquals(v1Bounds, mHost.getInvalidationRect());
unmount(0, mountItem1);
assertEquals(4, mHost.getInvalidationCount());
assertEquals(d1.getBounds(), mHost.getInvalidationRect());
unmount(1, mountItem2);
assertEquals(5, mHost.getInvalidationCount());
assertEquals(d2.getBounds(), mHost.getInvalidationRect());
unmount(2, mountItem3);
assertEquals(6, mHost.getInvalidationCount());
assertEquals(v1Bounds, mHost.getInvalidationRect());
}
@Test
public void testCallbacks() {
Drawable d = new ColorDrawable();
assertNull(d.getCallback());
MountItem mountItem = mount(0, d);
assertEquals(mHost, d.getCallback());
unmount(0, mountItem);
assertNull(d.getCallback());
}
@Test
public void testGetMountItemCount() {
assertEquals(0, mHost.getMountItemCount());
MountItem mountItem1 = mount(0, new ColorDrawable());
assertEquals(1, mHost.getMountItemCount());
mount(1, new ColorDrawable());
assertEquals(2, mHost.getMountItemCount());
MountItem mountItem3 = mount(2, new View(mContext));
assertEquals(3, mHost.getMountItemCount());
unmount(0, mountItem1);
assertEquals(2, mHost.getMountItemCount());
MountItem mountItem4 = mount(1, new ColorDrawable());
assertEquals(2, mHost.getMountItemCount());
unmount(2, mountItem3);
assertEquals(1, mHost.getMountItemCount());
unmount(1, mountItem4);
assertEquals(0, mHost.getMountItemCount());
}
@Test
public void testGetMountItemAt() {
assertNull(mHost.getMountItemAt(0));
assertNull(mHost.getMountItemAt(1));
assertNull(mHost.getMountItemAt(2));
MountItem mountItem1 = mount(0, new ColorDrawable());
MountItem mountItem2 = mount(1, new View(mContext));
MountItem mountItem3 = mount(5, new ColorDrawable());
assertEquals(mountItem1, mHost.getMountItemAt(0));
assertEquals(mountItem2, mHost.getMountItemAt(1));
assertEquals(mountItem3, mHost.getMountItemAt(2));
unmount(1, mountItem2);
assertEquals(mountItem1, mHost.getMountItemAt(0));
assertEquals(mountItem3, mHost.getMountItemAt(1));
unmount(0, mountItem1);
assertEquals(mountItem3, mHost.getMountItemAt(0));
}
@Test
public void testMoveItem() {
MountItem mountItem1 = mount(1, new ColorDrawable());
MountItem mountItem2 = mount(2, new View(mContext));
assertEquals(2, mHost.getMountItemCount());
assertEquals(mountItem1, mHost.getMountItemAt(0));
assertEquals(mountItem2, mHost.getMountItemAt(1));
mHost.moveItem(mountItem2, 2, 0);
assertEquals(2, mHost.getMountItemCount());
assertEquals(mountItem2, mHost.getMountItemAt(0));
assertEquals(mountItem1, mHost.getMountItemAt(1));
mHost.moveItem(mountItem2, 0, 1);
assertEquals(1, mHost.getMountItemCount());
assertEquals(mountItem2, mHost.getMountItemAt(0));
mHost.moveItem(mountItem2, 1, 0);
assertEquals(2, mHost.getMountItemCount());
assertEquals(mountItem1, mHost.getMountItemAt(0));
assertEquals(mountItem2, mHost.getMountItemAt(1));
}
@Test
public void testMoveItemWithoutTouchables()
throws Exception {
Drawable d1 = new ColorDrawable(Color.BLACK);
MountItem mountItem1 = mount(1, d1);
Drawable d2 = new ColorDrawable(Color.BLACK);
MountItem mountItem2 = mount(2, d2);
assertEquals(2, getDrawableItemsSize());
assertEquals(mountItem1, getDrawableMountItemAt(0));
assertEquals(mountItem2, getDrawableMountItemAt(1));
mHost.moveItem(mountItem2, 2, 0);
// There are no Touchable Drawables so this call should return false and not crash.
assertFalse(mHost.onTouchEvent(MotionEvent.obtain(0, 0, 0, 0, 0, 0)));
}
@Test
public void testDrawableStateChangedOnDrawables() {
Drawable d1 = mock(ColorDrawable.class);
when(d1.getBounds()).thenReturn(new Rect());
when(d1.isStateful()).thenReturn(false);
MountItem mountItem1 = mount(0, d1);
verify(d1, never()).setState(any(int[].class));
unmount(0, mountItem1);
Drawable d2 = mock(ColorDrawable.class);
when(d2.getBounds()).thenReturn(new Rect());
when(d2.isStateful()).thenReturn(true);
mount(0, d2, FLAG_DUPLICATE_PARENT_STATE);
verify(d2, times(1)).setState(eq(mHost.getDrawableState()));
mHost.setSelected(true);
verify(d2, times(1)).setState(eq(mHost.getDrawableState()));
}
@Test
public void testMoveTouchExpansionItem() {
View view = mock(View.class);
when(view.getContext()).thenReturn(RuntimeEnvironment.application);
MountItem mountItem = mountTouchExpansionItem(0, view);
mHost.moveItem(mountItem, 0, 1);
unmount(1, mountItem);
}
@Test
public void testDuplicateParentStateOnViews() {
View v1 = mock(View.class);
mount(0, v1);
View v2 = mock(View.class);
mount(1, v2, FLAG_DUPLICATE_PARENT_STATE);
verify(v1, times(1)).setDuplicateParentStateEnabled(eq(false));
verify(v2, times(1)).setDuplicateParentStateEnabled(eq(true));
}
@Test
public void testJumpDrawablesToCurrentState() {
mHost.jumpDrawablesToCurrentState();
Drawable d1 = mock(ColorDrawable.class);
when(d1.getBounds()).thenReturn(new Rect());
mount(0, d1);
Drawable d2 = mock(ColorDrawable.class);
when(d2.getBounds()).thenReturn(new Rect());
mount(1, d2);
View v1 = mock(View.class);
mount(2, v1);
mHost.jumpDrawablesToCurrentState();
verify(d1, times(1)).jumpToCurrentState();
verify(d2, times(1)).jumpToCurrentState();
}
@Test
public void testSetVisibility() {
Drawable d1 = mock(ColorDrawable.class);
when(d1.getBounds()).thenReturn(new Rect());
mount(0, d1);
Drawable d2 = mock(ColorDrawable.class);
when(d2.getBounds()).thenReturn(new Rect());
mount(1, d2);
View v1 = mock(View.class);
mount(2, v1);
mHost.setVisibility(GONE);
mHost.setVisibility(INVISIBLE);
mHost.setVisibility(VISIBLE);
verify(d1, times(2)).setVisible(eq(true), eq(false));
verify(d1, times(2)).setVisible(eq(false), eq(false));
verify(d2, times(2)).setVisible(eq(true), eq(false));
verify(d2, times(2)).setVisible(eq(false), eq(false));
verify(v1, never()).setVisibility(anyInt());
}
@Test
public void testGetDrawables() {
Drawable d1 = new ColorDrawable();
MountItem mountItem1 = mount(0, d1);
Drawable d2 = new ColorDrawable();
mount(1, d2);
MountItem mountItem3 = mount(2, new View(mContext));
List<Drawable> drawables = mHost.getDrawables();
assertEquals(2, drawables.size());
assertEquals(d1, drawables.get(0));
assertEquals(d2, drawables.get(1));
unmount(0, mountItem1);
drawables = mHost.getDrawables();
assertEquals(1, drawables.size());
assertEquals(d2, drawables.get(0));
unmount(2, mountItem3);
drawables = mHost.getDrawables();
assertEquals(1, drawables.size());
assertEquals(d2, drawables.get(0));
}
@Test
public void testViewTag() {
assertNull(mHost.getTag());
Object tag = new Object();
mHost.setViewTag(tag);
assertEquals(tag, mHost.getTag());
mHost.setViewTag(null);
assertNull(mHost.getTag());
}
@Test
public void testViewTags() {
assertNull(mHost.getTag(1));
assertNull(mHost.getTag(2));
Object value1 = new Object();
Object value2 = new Object();
SparseArray<Object> viewTags = new SparseArray<>();
viewTags.put(1, value1);
viewTags.put(2, value2);
mHost.setViewTags(viewTags);
assertEquals(value1, mHost.getTag(1));
assertEquals(value2, mHost.getTag(2));
mHost.setViewTags(null);
assertNull(mHost.getTag(1));
assertNull(mHost.getTag(2));
}
@Test
public void testComponentClickListener() {
assertNull(mHost.getComponentClickListener());
ComponentClickListener listener = new ComponentClickListener();
mHost.setComponentClickListener(listener);
assertEquals(listener, mHost.getComponentClickListener());
mHost.setComponentClickListener(null);
assertNull(mHost.getComponentClickListener());
}
@Test
public void testComponentLongClickListener() {
assertNull(mHost.getComponentLongClickListener());
ComponentLongClickListener listener = new ComponentLongClickListener();
mHost.setComponentLongClickListener(listener);
assertEquals(listener, mHost.getComponentLongClickListener());
mHost.setComponentLongClickListener(null);
assertNull(mHost.getComponentLongClickListener());
}
@Test
public void testComponentTouchListener() {
assertNull(mHost.getComponentTouchListener());
ComponentTouchListener listener = new ComponentTouchListener();
mHost.setComponentTouchListener(listener);
assertEquals(listener, mHost.getComponentTouchListener());
mHost.setComponentTouchListener(null);
assertNull(mHost.getComponentTouchListener());
}
@Test
public void testSuppressInvalidations() {
mHost.layout(0, 0, 100, 100);
mHost.invalidate();
assertEquals(new Rect(0, 0, 100, 100), mHost.getInvalidationRect());
mHost.suppressInvalidations(true);
mHost.invalidate();
mHost.invalidate(0, 0, 5, 5);
mHost.suppressInvalidations(false);
assertEquals(new Rect(0, 0, 100, 100), mHost.getInvalidationRect());
}
@Test
public void testSuppressInvalidationsWithCoordinates() {
mHost.layout(0, 0, 100, 100);
mHost.invalidate(0, 0, 20, 20);
assertEquals(new Rect(0, 0, 20, 20), mHost.getInvalidationRect());
mHost.suppressInvalidations(true);
mHost.invalidate(0, 0, 10, 10);
mHost.invalidate(0, 0, 5, 5);
mHost.suppressInvalidations(false);
assertEquals(new Rect(0, 0, 100, 100), mHost.getInvalidationRect());
}
@Test
public void testSuppressInvalidationsWithRect() {
mHost.layout(0, 0, 100, 100);
mHost.invalidate(new Rect(0, 0, 20, 20));
assertEquals(new Rect(0, 0, 20, 20), mHost.getInvalidationRect());
mHost.suppressInvalidations(true);
mHost.invalidate(new Rect(0, 0, 10, 10));
mHost.invalidate(new Rect(0, 0, 5, 5));
mHost.suppressInvalidations(false);
assertEquals(new Rect(0, 0, 100, 100), mHost.getInvalidationRect());
}
@Test
public void testNoScrapHosts() {
assertNull(mHost.recycleHost());
}
@Test
public void testViewGroupScrapHosts() {
testScrapHostsForComponent(mViewGroupHost, ComponentHost.class);
}
@Test
public void testGetContentDescriptions() {
CharSequence hostContentDescription = "hostContentDescription";
mHost.setContentDescription(hostContentDescription);
CharSequence drawableContentDescription = "drawableContentDescription";
MountItem mountItem0 = mount(0, new ColorDrawable(), 0, drawableContentDescription);
CharSequence viewContentDescription = "viewContentDescription";
mount(1, mock(View.class), 0, viewContentDescription);
assertTrue(mHost.getContentDescriptions().contains(hostContentDescription));
assertTrue(mHost.getContentDescriptions().contains(drawableContentDescription));
assertFalse(mHost.getContentDescriptions().contains(viewContentDescription));
unmount(0, mountItem0);
assertTrue(mHost.getContentDescriptions().contains(hostContentDescription));
assertFalse(mHost.getContentDescriptions().contains(drawableContentDescription));
assertFalse(mHost.getContentDescriptions().contains(viewContentDescription));
}
@Test
public void testGetChildDrawingOrder() {
View v1 = new View(mContext);
mount(2, v1);
View v2 = new View(mContext);
MountItem mountItem2 = mount(0, v2);
assertEquals(1, mHost.getChildDrawingOrder(mHost.getChildCount(), 0));
assertEquals(0, mHost.getChildDrawingOrder(mHost.getChildCount(), 1));
View v3 = new ComponentHost(mContext);
MountItem mountItem3 = mount(1, v3);
assertEquals(1, mHost.getChildDrawingOrder(mHost.getChildCount(), 0));
assertEquals(2, mHost.getChildDrawingOrder(mHost.getChildCount(), 1));
assertEquals(0, mHost.getChildDrawingOrder(mHost.getChildCount(), 2));
mHost.unmount(1, mountItem3);
assertEquals(1, mHost.getChildDrawingOrder(mHost.getChildCount(), 0));
assertEquals(0, mHost.getChildDrawingOrder(mHost.getChildCount(), 1));
mount(1, v3);
assertEquals(1, mHost.getChildDrawingOrder(mHost.getChildCount(), 0));
assertEquals(2, mHost.getChildDrawingOrder(mHost.getChildCount(), 1));
assertEquals(0, mHost.getChildDrawingOrder(mHost.getChildCount(), 2));
mHost.unmount(0, mountItem2);
assertEquals(1, mHost.getChildDrawingOrder(mHost.getChildCount(), 0));
assertEquals(0, mHost.getChildDrawingOrder(mHost.getChildCount(), 1));
mHost.moveItem(mountItem3, 1, 3);
assertEquals(0, mHost.getChildDrawingOrder(mHost.getChildCount(), 0));
assertEquals(1, mHost.getChildDrawingOrder(mHost.getChildCount(), 1));
}
@Test
public void testDisappearingItemDrawingOrder() {
View v1 = new View(mContext);
mount(5, v1);
View v2 = new View(mContext);
mount(2, v2);
View v3 = new View(mContext);
MountItem mountItem3 = mount(4, v3);
View v4 = new View(mContext);
MountItem mountItem4 = mount(0, v4);
assertEquals(3, mHost.getChildDrawingOrder(mHost.getChildCount(), 0));
assertEquals(1, mHost.getChildDrawingOrder(mHost.getChildCount(), 1));
assertEquals(2, mHost.getChildDrawingOrder(mHost.getChildCount(), 2));
assertEquals(0, mHost.getChildDrawingOrder(mHost.getChildCount(), 3));
assertEquals(4, mHost.getMountItemCount());
assertEquals(4, mHost.getChildCount());
// mountItem3 started disappearing
mHost.startUnmountDisappearingItem(4, mountItem3);
assertEquals(3, mHost.getMountItemCount());
assertEquals(4, mHost.getChildCount());
assertEquals(3, mHost.getChildDrawingOrder(mHost.getChildCount(), 0));
assertEquals(1, mHost.getChildDrawingOrder(mHost.getChildCount(), 1));
assertEquals(0, mHost.getChildDrawingOrder(mHost.getChildCount(), 2));
assertEquals(2, mHost.getChildDrawingOrder(mHost.getChildCount(), 3));
// mountItem4 started disappearing
mHost.startUnmountDisappearingItem(0, mountItem4);
assertEquals(2, mHost.getMountItemCount());
assertEquals(4, mHost.getChildCount());
assertEquals(1, mHost.getChildDrawingOrder(mHost.getChildCount(), 0));
assertEquals(0, mHost.getChildDrawingOrder(mHost.getChildCount(), 1));
assertEquals(3, mHost.getChildDrawingOrder(mHost.getChildCount(), 2));
assertEquals(2, mHost.getChildDrawingOrder(mHost.getChildCount(), 3));
// mountItem4 finished disappearing
mHost.unmountDisappearingItem(mountItem4);
assertEquals(2, mHost.getMountItemCount());
assertEquals(3, mHost.getChildCount());
assertEquals(1, mHost.getChildDrawingOrder(mHost.getChildCount(), 0));
assertEquals(0, mHost.getChildDrawingOrder(mHost.getChildCount(), 1));
assertEquals(2, mHost.getChildDrawingOrder(mHost.getChildCount(), 2));
// mountItem3 finished disappearing
mHost.unmountDisappearingItem(mountItem3);
assertEquals(2, mHost.getMountItemCount());
assertEquals(2, mHost.getChildCount());
assertEquals(1, mHost.getChildDrawingOrder(mHost.getChildCount(), 0));
assertEquals(0, mHost.getChildDrawingOrder(mHost.getChildCount(), 1));
}
@Test
public void testDrawableItemsSize()
throws Exception {
assertEquals(0, getDrawableItemsSize());
assertEquals(0, getDrawableItemsSize());
Drawable d1 = new ColorDrawable(Color.BLACK);
MountItem m1 = mount(0, d1);
assertEquals(1, getDrawableItemsSize());
Drawable d2 = new ColorDrawable(Color.BLACK);
mount(1, d2);
assertEquals(2, getDrawableItemsSize());
unmount(0, m1);
assertEquals(1, getDrawableItemsSize());
Drawable d3 = new ColorDrawable(Color.BLACK);
MountItem m3 = mount(1, d3);
assertEquals(1, getDrawableItemsSize());
unmount(1, m3);
assertEquals(0, getDrawableItemsSize());
}
@Test
public void testGetDrawableMountItem()
throws Exception {
Drawable d1 = new ColorDrawable(Color.BLACK);
MountItem mountItem1 = mount(0, d1);
Drawable d2 = new ColorDrawable(Color.BLACK);
MountItem mountItem2 = mount(1, d2);
Drawable d3 = new ColorDrawable(Color.BLACK);
MountItem mountItem3 = mount(5, d3);
assertEquals(mountItem1, getDrawableMountItemAt(0));
assertEquals(mountItem2, getDrawableMountItemAt(1));
assertEquals(mountItem3, getDrawableMountItemAt(2));
}
private int getDrawableItemsSize()
throws Exception {
SparseArrayCompat drawableItems = Whitebox.getInternalState(mHost, "mDrawableMountItems");
return Whitebox.invokeMethod(drawableItems, "size");
}
private MountItem getDrawableMountItemAt(int index)
throws Exception {
SparseArrayCompat drawableItems = Whitebox.getInternalState(mHost, "mDrawableMountItems");
return Whitebox.invokeMethod(drawableItems, "valueAt", index);
}
private void testScrapHostsForComponent(
Component<?> component,
Class<? extends View> viewClass) {
View view = mock(viewClass);
MountItem mountItem = new MountItem();
mountItem.init(
component,
null,
view,
null,
null,
null,
0,
IMPORTANT_FOR_ACCESSIBILITY_AUTO);
mHost.mount(0, mountItem, new Rect());
assertNull(mHost.recycleHost());
assertEquals(1, mHost.getChildCount());
mHost.unmount(0, mountItem);
assertNotNull(mHost.recycleHost());
assertEquals(1, mHost.getChildCount());
assertNull(mHost.recycleHost());
when(view.getParent()).thenReturn(mHost);
mHost.mount(0, mountItem, new Rect());
assertNull(mHost.recycleHost());
assertEquals(1, mHost.getChildCount());
assertNull(mHost.recycleHost());
verify(view).setVisibility(View.GONE);
verify(view).setVisibility(View.VISIBLE);
}
private MountItem mount(int index, Object content) {
return mount(index, content, 0);
}
private MountItem mount(int index, Object content, int flags) {
return mount(index, content, flags, null);
}
private MountItem mount(int index, Object content, int flags, CharSequence contentDescription) {
MountItem mountItem = new MountItem();
NodeInfo nodeInfo = NodeInfo.acquire();
nodeInfo.setContentDescription(contentDescription);
mountItem.init(
content instanceof Drawable ? mDrawableComponent : mViewComponent,
null,
content,
nodeInfo,
null,
null,
flags,
IMPORTANT_FOR_ACCESSIBILITY_AUTO);
mHost.mount(
index,
mountItem,
content instanceof Drawable ? ((Drawable) content).getBounds() : new Rect());
return mountItem;
}
private MountItem mountTouchExpansionItem(int index, Object content) {
final MountItem viewMountItem = new MountItem();
final ViewNodeInfo viewNodeInfo = ViewNodeInfo.acquire();
viewNodeInfo.setLayoutDirection(YogaDirection.LTR);
viewMountItem.init(
mViewComponent,
null,
content,
null,
viewNodeInfo,
null,
0,
IMPORTANT_FOR_ACCESSIBILITY_AUTO);
mHost.mount(index, viewMountItem, new Rect());
return viewMountItem;
}
private void unmount(int index, MountItem mountItem) {
mHost.unmount(index, mountItem);
}
private static class TestableComponentHost extends ComponentHost {
private int mInvalidationCount = 0;
private Rect mInvalidationRect = null;
public TestableComponentHost(ComponentContext context) {
super(context);
}
public TestableComponentHost(Context context) {
super(context);
}
@Override
public void invalidate(Rect dirty) {
super.invalidate(dirty);
trackInvalidation(
dirty.left,
dirty.top,
dirty.right,
dirty.bottom);
}
@Override
public void invalidate(int l, int t, int r, int b) {
super.invalidate(l, t, r, b);
trackInvalidation(l, t, r, b);
}
@Override
public void invalidate() {
super.invalidate();
trackInvalidation(0, 0, getWidth(), getHeight());
}
@Override
public void addView(View child, int index, LayoutParams params) {
super.addView(child, index, params);
trackInvalidation(
child.getLeft(),
child.getTop(),
child.getRight(),
child.getBottom());
}
@Override
public void removeView(View child) {
super.removeView(child);
trackInvalidation(
child.getLeft(),
child.getTop(),
child.getRight(),
child.getBottom());
}
int getInvalidationCount() {
return mInvalidationCount;
}
Rect getInvalidationRect() {
return mInvalidationRect;
}
private void trackInvalidation(int l, int t, int r, int b) {
mInvalidationCount++;
mInvalidationRect = new Rect();
mInvalidationRect.set(l, t, r, b);
}
}
}