1package android.uirendering.cts.testclasses;
2
3import static org.junit.Assert.assertFalse;
4
5import android.graphics.Color;
6import android.graphics.Outline;
7import android.graphics.Path;
8import android.graphics.Rect;
9import android.support.test.filters.MediumTest;
10import android.support.test.runner.AndroidJUnit4;
11import android.uirendering.cts.R;
12import android.uirendering.cts.bitmapverifiers.BitmapVerifier;
13import android.uirendering.cts.bitmapverifiers.RectVerifier;
14import android.uirendering.cts.testclasses.view.UnclippedBlueView;
15import android.uirendering.cts.testinfrastructure.ActivityTestBase;
16import android.uirendering.cts.testinfrastructure.ViewInitializer;
17import android.view.View;
18import android.view.ViewGroup;
19import android.view.ViewOutlineProvider;
20
21import org.junit.Test;
22import org.junit.runner.RunWith;
23
24/**
25 * This tests view clipping by modifying properties of blue_padded_layout, and validating
26 * the resulting rect of content.
27 *
28 * Since the layout is blue on a white background, this is always done with a RectVerifier.
29 */
30@MediumTest
31@RunWith(AndroidJUnit4.class)
32public class ViewClippingTests extends ActivityTestBase {
33    static final Rect FULL_RECT = new Rect(0, 0, 90, 90);
34    static final Rect BOUNDS_RECT = new Rect(0, 0, 80, 80);
35    static final Rect PADDED_RECT = new Rect(15, 16, 63, 62);
36    static final Rect OUTLINE_RECT = new Rect(1, 2, 78, 79);
37    static final Rect CLIP_BOUNDS_RECT = new Rect(10, 20, 50, 60);
38
39    static final ViewInitializer BOUNDS_CLIP_INIT =
40            rootView -> ((ViewGroup)rootView).setClipChildren(true);
41
42    static final ViewInitializer PADDING_CLIP_INIT = rootView -> {
43        ViewGroup child = (ViewGroup) rootView.findViewById(R.id.child);
44        child.setClipToPadding(true);
45        child.setWillNotDraw(true);
46        child.addView(new UnclippedBlueView(rootView.getContext()));
47    };
48
49    static final ViewInitializer OUTLINE_CLIP_INIT = rootView -> {
50        View child = rootView.findViewById(R.id.child);
51        child.setOutlineProvider(new ViewOutlineProvider() {
52            @Override
53            public void getOutline(View view, Outline outline) {
54                outline.setRect(OUTLINE_RECT);
55            }
56        });
57        child.setClipToOutline(true);
58    };
59
60    static final ViewInitializer CLIP_BOUNDS_CLIP_INIT =
61            view -> view.setClipBounds(CLIP_BOUNDS_RECT);
62
63    static BitmapVerifier makeClipVerifier(Rect blueBoundsRect) {
64        // very high error tolerance, since all these tests care about is clip alignment
65        return new RectVerifier(Color.WHITE, Color.BLUE, blueBoundsRect, 75);
66    }
67
68    @Test
69    public void testSimpleUnclipped() {
70        createTest()
71                .addLayout(R.layout.blue_padded_layout, null)
72                .runWithVerifier(makeClipVerifier(FULL_RECT));
73    }
74
75    @Test
76    public void testSimpleBoundsClip() {
77        createTest()
78                .addLayout(R.layout.blue_padded_layout, BOUNDS_CLIP_INIT)
79                .runWithVerifier(makeClipVerifier(BOUNDS_RECT));
80    }
81
82    @Test
83    public void testSimpleClipBoundsClip() {
84        createTest()
85                .addLayout(R.layout.blue_padded_layout, CLIP_BOUNDS_CLIP_INIT)
86                .runWithVerifier(makeClipVerifier(CLIP_BOUNDS_RECT));
87    }
88
89    @Test
90    public void testSimplePaddingClip() {
91        createTest()
92                .addLayout(R.layout.blue_padded_layout, PADDING_CLIP_INIT)
93                .runWithVerifier(makeClipVerifier(PADDED_RECT));
94    }
95    // TODO: add tests with clip + scroll, and with interesting combinations of the above
96
97    @Test
98    public void testSimpleOutlineClip() {
99        // NOTE: Only HW is supported
100        createTest()
101                .addLayout(R.layout.blue_padded_layout, OUTLINE_CLIP_INIT, true)
102                .runWithVerifier(makeClipVerifier(OUTLINE_RECT));
103
104        // SW ignores the outline clip
105        createTest()
106                .addLayout(R.layout.blue_padded_layout, OUTLINE_CLIP_INIT, false)
107                .runWithVerifier(makeClipVerifier(FULL_RECT));
108    }
109
110    @Test
111    public void testOvalOutlineClip() {
112        // In hw this works because clipping to a non-round rect isn't supported, and is no-op'd.
113        // In sw this works because Outline clipping isn't supported.
114        createTest()
115                .addLayout(R.layout.blue_padded_layout, view -> {
116                    view.setOutlineProvider(new ViewOutlineProvider() {
117                        Path mPath = new Path();
118                        @Override
119                        public void getOutline(View view, Outline outline) {
120                            mPath.reset();
121                            mPath.addOval(0, 0, view.getWidth(), view.getHeight(),
122                                    Path.Direction.CW);
123                            outline.setConvexPath(mPath);
124                            assertFalse(outline.canClip()); // NOTE: non-round-rect, so can't clip
125                        }
126                    });
127                    view.setClipToOutline(true); // should do nothing, since non-rect clip
128                })
129                .runWithVerifier(makeClipVerifier(FULL_RECT));
130    }
131}
132