13f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik/*
23f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik * Copyright (C) 2016 The Android Open Source Project
33f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik *
43f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik * Licensed under the Apache License, Version 2.0 (the "License");
53f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik * you may not use this file except in compliance with the License.
63f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik * You may obtain a copy of the License at
73f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik *
83f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik *      http://www.apache.org/licenses/LICENSE-2.0
93f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik *
103f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik * Unless required by applicable law or agreed to in writing, software
113f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik * distributed under the License is distributed on an "AS IS" BASIS,
123f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik * See the License for the specific language governing permissions and
143f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik * limitations under the License.
153f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik */
163f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
173f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craikpackage android.view;
183f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
193f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craikimport static junit.framework.Assert.assertFalse;
203f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
213f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craikimport static org.junit.Assert.assertEquals;
223f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craikimport static org.junit.Assert.assertTrue;
233f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
243f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craikimport android.app.Activity;
253f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craikimport android.content.Context;
263f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craikimport android.graphics.Rect;
273f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craikimport android.support.test.InstrumentationRegistry;
283f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craikimport android.support.test.annotation.UiThreadTest;
293f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craikimport android.support.test.filters.LargeTest;
303f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craikimport android.support.test.rule.ActivityTestRule;
313f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craikimport android.support.test.runner.AndroidJUnit4;
323f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craikimport android.widget.FrameLayout;
333f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
343f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craikimport com.android.compatibility.common.util.WidgetTestUtils;
353f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
363f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craikimport org.junit.After;
373f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craikimport org.junit.Before;
383f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craikimport org.junit.Rule;
393f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craikimport org.junit.Test;
403f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craikimport org.junit.runner.RunWith;
413f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
423f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik/**
433f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik * Test of invalidates, drawing, and the flags that support them
443f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik */
453f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik@LargeTest
463f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik@RunWith(AndroidJUnit4.class)
473f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craikpublic class ViewInvalidateTest {
483f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    @Rule
493f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    public ActivityTestRule<Activity> mActivityRule = new ActivityTestRule<>(Activity.class);
503f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
513f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    private static final int INVAL_TEST_FLAG_MASK = View.PFLAG_DIRTY
523f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik            | View.PFLAG_DIRTY_OPAQUE
533f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik            | View.PFLAG_DRAWN
543f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik            | View.PFLAG_DRAWING_CACHE_VALID
553f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik            | View.PFLAG_INVALIDATED
563f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik            | View.PFLAG_DRAW_ANIMATION;
573f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
583f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    @Before
593f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    public void setup() throws Throwable {
603f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        // separate runnable to initialize, so ref is safe to pass to runOnMainAndDrawSync
613f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        mActivityRule.runOnUiThread(() -> {
623f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik            mParent = new FrameLayout(getContext());
633f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik            mChild = new View(getContext());
643f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        });
653f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
663f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        // attached view is drawn once
673f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mParent, () -> {
683f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik            mParent.addView(mChild);
693f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik            getActivity().setContentView(mParent);
703f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
713f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik            // 'invalidated', but not yet drawn
723f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik            validateInvalFlags(mChild, View.PFLAG_INVALIDATED);
733f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        });
743f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    }
753f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
763f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    @After
773f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    public void teardown() {
783f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        // ensure we don't share views between tests
793f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        mParent = null;
803f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        mChild = null;
813f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    }
823f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
833f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    Context getContext() {
843f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        return InstrumentationRegistry.getTargetContext();
853f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    }
863f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
873f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    Activity getActivity() {
883f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        return mActivityRule.getActivity();
893f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    }
903f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
913f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    private ViewGroup mParent;
923f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    private View mChild;
933f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
943f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    private static void validateInvalFlags(View view, int... expectedFlagArray) {
953f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        int expectedFlags = 0;
963f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        for (int expectedFlag : expectedFlagArray) {
973f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik            expectedFlags |= expectedFlag;
983f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        }
993f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
1003f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        final int observedFlags = view.mPrivateFlags & INVAL_TEST_FLAG_MASK;
1013f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        assertEquals(String.format("expect %x, observed %x", expectedFlags, observedFlags),
1023f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                expectedFlags, observedFlags);
1033f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    }
1043f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
1053f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    private static ViewRootImpl getViewRoot(View view) {
1063f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        ViewParent parent = view.getParent();
1073f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        while (parent != null) {
1083f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik            if (parent instanceof ViewRootImpl) {
1093f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                return (ViewRootImpl) parent;
1103f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik            }
1113f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik            parent = parent.getParent();
1123f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        }
1133f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        return null;
1143f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    }
1153f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
1163f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    @UiThreadTest
1173f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    @Test
1183f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    public void testInvalidate_behavior() throws Throwable {
1193f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        validateInvalFlags(mChild,
1203f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                View.PFLAG_DRAWING_CACHE_VALID,
1213f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                View.PFLAG_DRAWN);
1223f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        validateInvalFlags(mParent,
1233f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                View.PFLAG_DRAWING_CACHE_VALID,
1243f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                View.PFLAG_DRAWN);
1253f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        assertFalse(getViewRoot(mParent).mTraversalScheduled);
1263f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
1273f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        mChild.invalidate();
1283f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
1293f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        // no longer drawn, is now invalidated
1303f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        validateInvalFlags(mChild,
1313f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                View.PFLAG_DIRTY,
1323f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                View.PFLAG_INVALIDATED);
1333f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
1343f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        // parent drawing cache no longer valid, marked dirty
1353f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        validateInvalFlags(mParent,
1363f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                View.PFLAG_DRAWN,
1373f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                View.PFLAG_DIRTY);
1383f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        assertTrue(getViewRoot(mParent).mTraversalScheduled);
1393f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    }
1403f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
1413f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    @UiThreadTest
1423f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    @Test
1433f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    public void testInvalidate_false() {
1443f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        // Invalidate makes it invalid
1453f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        validateInvalFlags(mChild,
1463f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                View.PFLAG_DRAWING_CACHE_VALID,
1473f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                View.PFLAG_DRAWN);
1483f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
1493f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        mChild.invalidate(/*don't invalidate cache*/ false);
1503f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
1513f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        // drawn is cleared, dirty set, nothing else changed
1523f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        validateInvalFlags(mChild,
1533f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                View.PFLAG_DRAWING_CACHE_VALID,
1543f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                View.PFLAG_DIRTY);
1553f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    }
1563f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
1573f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    @Test
1583f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    public void testInvalidate_simple() throws Throwable {
1593f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        // simple invalidate, which marks the view invalid
1603f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mParent, () -> {
1613f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik            validateInvalFlags(mChild,
1623f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                    View.PFLAG_DRAWING_CACHE_VALID,
1633f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                    View.PFLAG_DRAWN);
1643f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
1653f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik            mChild.invalidate();
1663f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
1673f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik            validateInvalFlags(mChild,
1683f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                    View.PFLAG_DIRTY,
1693f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                    View.PFLAG_INVALIDATED);
1703f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        });
1713f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
1723f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        // after draw pass, view has drawn, no longer invalid
1733f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        mActivityRule.runOnUiThread(() -> {
1743f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik            validateInvalFlags(mChild,
1753f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                    View.PFLAG_DRAWING_CACHE_VALID,
1763f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                    View.PFLAG_DRAWN);
1773f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        });
1783f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    }
1793f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
1803f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    @UiThreadTest
1813f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    @Test
1823f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    public void testInvalidate_manualUpdateDisplayList() {
1833f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        // Invalidate makes it invalid
1843f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        validateInvalFlags(mChild,
1853f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                View.PFLAG_DRAWING_CACHE_VALID,
1863f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                View.PFLAG_DRAWN);
1873f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
1883f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        mChild.invalidate();
1893f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        validateInvalFlags(mChild,
1903f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                View.PFLAG_DIRTY,
1913f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                View.PFLAG_INVALIDATED);
1923f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
1933f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        // updateDisplayListIfDirty makes it valid again, but invalidate still set,
1943f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        // since it's cleared by View#draw(canvas, parent, drawtime)
1953f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        mChild.updateDisplayListIfDirty();
1963f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik            validateInvalFlags(mChild,
1973f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                    View.PFLAG_DRAWING_CACHE_VALID,
1983f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                    View.PFLAG_DRAWN,
1993f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                    View.PFLAG_INVALIDATED);
2003f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    }
2013f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
2023f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    @UiThreadTest
2033f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    @Test
2043f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    public void testInvalidateChild_simple() {
2053f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        validateInvalFlags(mParent,
2063f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                View.PFLAG_DRAWING_CACHE_VALID,
2073f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                View.PFLAG_DRAWN);
2083f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        assertFalse(getViewRoot(mParent).mTraversalScheduled);
2093f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
2103f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        mParent.invalidateChild(mChild, new Rect(0, 0, 1, 1));
2113f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
2123f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        validateInvalFlags(mParent,
2133f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                View.PFLAG_DIRTY,
2143f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                View.PFLAG_DRAWN);
2153f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        assertTrue(getViewRoot(mParent).mTraversalScheduled);
2163f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    }
2173f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
2183f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    @Test
2193f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    public void testInvalidateChild_childHardwareLayer() throws Throwable {
2203f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mParent, () -> {
2213f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik            // do in runnable, so tree won't be dirty
2229de95db4f28f88c37b1443d20b308ce02407fd74Chris Craik            mParent.setLayerType(View.LAYER_TYPE_HARDWARE, null);
2239de95db4f28f88c37b1443d20b308ce02407fd74Chris Craik        });
2249de95db4f28f88c37b1443d20b308ce02407fd74Chris Craik
2259de95db4f28f88c37b1443d20b308ce02407fd74Chris Craik        mActivityRule.runOnUiThread(() -> {
2269de95db4f28f88c37b1443d20b308ce02407fd74Chris Craik            validateInvalFlags(mParent,
2279de95db4f28f88c37b1443d20b308ce02407fd74Chris Craik                    View.PFLAG_DRAWING_CACHE_VALID,
2289de95db4f28f88c37b1443d20b308ce02407fd74Chris Craik                    View.PFLAG_DRAWN);
2299de95db4f28f88c37b1443d20b308ce02407fd74Chris Craik
2309de95db4f28f88c37b1443d20b308ce02407fd74Chris Craik            mParent.invalidateChild(mChild, new Rect(0, 0, 1, 1));
2319de95db4f28f88c37b1443d20b308ce02407fd74Chris Craik
2329de95db4f28f88c37b1443d20b308ce02407fd74Chris Craik            validateInvalFlags(mParent,
2339de95db4f28f88c37b1443d20b308ce02407fd74Chris Craik                    View.PFLAG_DIRTY,
2349de95db4f28f88c37b1443d20b308ce02407fd74Chris Craik                    View.PFLAG_DRAWN); // Note: note invalidated, since HW damage handled in native
2359de95db4f28f88c37b1443d20b308ce02407fd74Chris Craik        });
2369de95db4f28f88c37b1443d20b308ce02407fd74Chris Craik    }
2379de95db4f28f88c37b1443d20b308ce02407fd74Chris Craik
2389de95db4f28f88c37b1443d20b308ce02407fd74Chris Craik    @Test
2399de95db4f28f88c37b1443d20b308ce02407fd74Chris Craik    public void testInvalidateChild_childSoftwareLayer() throws Throwable {
2409de95db4f28f88c37b1443d20b308ce02407fd74Chris Craik        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mParent, () -> {
2419de95db4f28f88c37b1443d20b308ce02407fd74Chris Craik            // do in runnable, so tree won't be dirty
2429de95db4f28f88c37b1443d20b308ce02407fd74Chris Craik            mParent.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
2433f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        });
2443f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
2453f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        mActivityRule.runOnUiThread(() -> {
2463f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik            validateInvalFlags(mParent,
2473f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                    View.PFLAG_DRAWING_CACHE_VALID,
2483f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                    View.PFLAG_DRAWN);
2493f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
2503f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik            mParent.invalidateChild(mChild, new Rect(0, 0, 1, 1));
2513f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
2523f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik            validateInvalFlags(mParent,
2533f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                    View.PFLAG_DIRTY,
2543f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                    View.PFLAG_DRAWN,
2559de95db4f28f88c37b1443d20b308ce02407fd74Chris Craik                    View.PFLAG_INVALIDATED); // Note: invalidated, since SW damage handled here
2563f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        });
2573f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    }
2583f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
2593f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    @UiThreadTest
2603f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    @Test
2613f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    public void testInvalidateChild_legacyAnimation() throws Throwable {
2623f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        mChild.mPrivateFlags |= View.PFLAG_DRAW_ANIMATION;
2633f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
2643f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        validateInvalFlags(mChild,
2653f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                View.PFLAG_DRAW_ANIMATION,
2663f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                View.PFLAG_DRAWING_CACHE_VALID,
2673f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                View.PFLAG_DRAWN);
2683f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        validateInvalFlags(mParent,
2693f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                View.PFLAG_DRAWING_CACHE_VALID,
2703f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                View.PFLAG_DRAWN);
2713f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        assertFalse(getViewRoot(mParent).mIsAnimating);
2723f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
2733f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        mParent.invalidateChild(mChild, new Rect(0, 0, 1, 1));
2743f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik
2753f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        validateInvalFlags(mChild,
2763f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                View.PFLAG_DRAW_ANIMATION,
2773f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                View.PFLAG_DRAWING_CACHE_VALID,
2783f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                View.PFLAG_DRAWN);
2793f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        validateInvalFlags(mParent,
2803f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                View.PFLAG_DIRTY,
2813f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                View.PFLAG_DRAW_ANIMATION, // carried up to parent
2823f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik                View.PFLAG_DRAWN);
2833f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik        assertTrue(getViewRoot(mParent).mIsAnimating);
2843f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik    }
2853f06c6de08b9e0c7ab1fd1774783ca355e994f06Chris Craik}
286