blob: ade66cbe7634e8f16150cbea456830f651f8b908 [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.view.cts;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import android.app.Activity;
import android.app.Instrumentation;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.platform.test.annotations.Presubmit;
import android.util.Pair;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroupOverlay;
import android.view.cts.util.DrawingUtils;
import androidx.test.InstrumentationRegistry;
import androidx.test.annotation.UiThreadTest;
import androidx.test.filters.MediumTest;
import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.AndroidJUnit4;
import com.android.compatibility.common.util.CtsTouchUtils;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.List;
@MediumTest
@RunWith(AndroidJUnit4.class)
public class ViewGroupOverlayTest {
private Instrumentation mInstrumentation;
private Activity mActivity;
private ViewGroup mViewGroupWithOverlay;
private ViewGroupOverlay mViewGroupOverlay;
@Rule
public ActivityTestRule<ViewGroupOverlayCtsActivity> mActivityRule =
new ActivityTestRule<>(ViewGroupOverlayCtsActivity.class);
@Before
public void setup() {
mInstrumentation = InstrumentationRegistry.getInstrumentation();
mActivity = mActivityRule.getActivity();
mViewGroupWithOverlay = (ViewGroup) mActivity.findViewById(R.id.viewgroup_with_overlay);
mViewGroupOverlay = mViewGroupWithOverlay.getOverlay();
}
@Presubmit
@Test
public void testBasics() {
DrawingUtils.assertAllPixelsOfColor("Default fill", mViewGroupWithOverlay,
Color.WHITE, null);
assertNotNull("Overlay is not null", mViewGroupOverlay);
}
@UiThreadTest
@Test(expected=IllegalArgumentException.class)
public void testAddNullView() {
mViewGroupOverlay.add((View) null);
}
@UiThreadTest
@Test(expected=IllegalArgumentException.class)
public void testRemoveNullView() {
mViewGroupOverlay.remove((View) null);
}
@UiThreadTest
@Test
public void testOverlayWithOneView() {
// Add one colored view to the overlay
final View redView = new View(mActivity);
redView.setBackgroundColor(Color.RED);
redView.layout(10, 20, 30, 40);
mViewGroupOverlay.add(redView);
final List<Pair<Rect, Integer>> colorRectangles = new ArrayList<>();
colorRectangles.add(new Pair<>(new Rect(10, 20, 30, 40), Color.RED));
DrawingUtils.assertAllPixelsOfColor("Overlay with one red view",
mViewGroupWithOverlay, Color.WHITE, colorRectangles);
// Now remove that view from the overlay and test that we're back to pure white fill
mViewGroupOverlay.remove(redView);
DrawingUtils.assertAllPixelsOfColor("Back to default fill", mViewGroupWithOverlay,
Color.WHITE, null);
}
@UiThreadTest
@Test
public void testOverlayWithNonOverlappingViews() {
// Add three views to the overlay
final View redView = new View(mActivity);
redView.setBackgroundColor(Color.RED);
redView.layout(10, 20, 30, 40);
final View greenView = new View(mActivity);
greenView.setBackgroundColor(Color.GREEN);
greenView.layout(60, 30, 90, 50);
final View blueView = new View(mActivity);
blueView.setBackgroundColor(Color.BLUE);
blueView.layout(40, 60, 80, 90);
mViewGroupOverlay.add(redView);
mViewGroupOverlay.add(greenView);
mViewGroupOverlay.add(blueView);
final List<Pair<Rect, Integer>> colorRectangles = new ArrayList<>();
colorRectangles.add(new Pair<>(new Rect(10, 20, 30, 40), Color.RED));
colorRectangles.add(new Pair<>(new Rect(60, 30, 90, 50), Color.GREEN));
colorRectangles.add(new Pair<>(new Rect(40, 60, 80, 90), Color.BLUE));
DrawingUtils.assertAllPixelsOfColor("Overlay with three views", mViewGroupWithOverlay,
Color.WHITE, colorRectangles);
// Remove one of the views from the overlay
mViewGroupOverlay.remove(greenView);
colorRectangles.clear();
colorRectangles.add(new Pair<>(new Rect(10, 20, 30, 40), Color.RED));
colorRectangles.add(new Pair<>(new Rect(40, 60, 80, 90), Color.BLUE));
DrawingUtils.assertAllPixelsOfColor("Overlay with two views", mViewGroupWithOverlay,
Color.WHITE, colorRectangles);
// Clear all views from the overlay and test that we're back to pure white fill
mViewGroupOverlay.clear();
DrawingUtils.assertAllPixelsOfColor("Back to default fill", mViewGroupWithOverlay,
Color.WHITE, null);
}
@UiThreadTest
@Test
public void testOverlayWithNonOverlappingViewAndDrawable() {
// Add one view and one drawable to the overlay
final View redView = new View(mActivity);
redView.setBackgroundColor(Color.RED);
redView.layout(10, 20, 30, 40);
final Drawable greenDrawable = new ColorDrawable(Color.GREEN);
greenDrawable.setBounds(60, 30, 90, 50);
mViewGroupOverlay.add(redView);
mViewGroupOverlay.add(greenDrawable);
final List<Pair<Rect, Integer>> colorRectangles = new ArrayList<>();
colorRectangles.add(new Pair<>(new Rect(10, 20, 30, 40), Color.RED));
colorRectangles.add(new Pair<>(new Rect(60, 30, 90, 50), Color.GREEN));
DrawingUtils.assertAllPixelsOfColor("Overlay with one view and one drawable",
mViewGroupWithOverlay, Color.WHITE, colorRectangles);
// Remove the view from the overlay
mViewGroupOverlay.remove(redView);
colorRectangles.clear();
colorRectangles.add(new Pair<>(new Rect(60, 30, 90, 50), Color.GREEN));
DrawingUtils.assertAllPixelsOfColor("Overlay with one drawable", mViewGroupWithOverlay,
Color.WHITE, colorRectangles);
// Clear everything from the overlay and test that we're back to pure white fill
mViewGroupOverlay.clear();
DrawingUtils.assertAllPixelsOfColor("Back to default fill", mViewGroupWithOverlay,
Color.WHITE, null);
}
@UiThreadTest
@Test
public void testOverlayWithOverlappingViews() {
// Add two overlapping colored views to the overlay
final View redView = new View(mActivity);
redView.setBackgroundColor(Color.RED);
redView.layout(10, 20, 60, 40);
final View greenView = new View(mActivity);
greenView.setBackgroundColor(Color.GREEN);
greenView.layout(30, 20, 80, 40);
mViewGroupOverlay.add(redView);
mViewGroupOverlay.add(greenView);
// Our overlay views overlap in horizontal 30-60 range. Here we test that the
// second view is the one that is drawn last in that range.
final List<Pair<Rect, Integer>> colorRectangles = new ArrayList<>();
colorRectangles.add(new Pair<>(new Rect(10, 20, 30, 40), Color.RED));
colorRectangles.add(new Pair<>(new Rect(30, 20, 80, 40), Color.GREEN));
DrawingUtils.assertAllPixelsOfColor("Overlay with two drawables", mViewGroupWithOverlay,
Color.WHITE, colorRectangles);
// Remove the second view from the overlay
mViewGroupOverlay.remove(greenView);
colorRectangles.clear();
colorRectangles.add(new Pair<>(new Rect(10, 20, 60, 40), Color.RED));
DrawingUtils.assertAllPixelsOfColor("Overlay with one drawable", mViewGroupWithOverlay,
Color.WHITE, colorRectangles);
// Clear all views from the overlay and test that we're back to pure white fill
mViewGroupOverlay.clear();
DrawingUtils.assertAllPixelsOfColor("Back to default fill", mViewGroupWithOverlay,
Color.WHITE, null);
}
@UiThreadTest
@Test
public void testOverlayWithOverlappingViewAndDrawable() {
// Add two overlapping colored views to the overlay
final Drawable redDrawable = new ColorDrawable(Color.RED);
redDrawable.setBounds(10, 20, 60, 40);
final View greenView = new View(mActivity);
greenView.setBackgroundColor(Color.GREEN);
greenView.layout(30, 20, 80, 40);
mViewGroupOverlay.add(redDrawable);
mViewGroupOverlay.add(greenView);
// Our overlay views overlap in horizontal 30-60 range. Even though the green view was
// added after the red drawable, *all* overlay drawables are drawn after the overlay views.
// So in the overlap range we expect color red
final List<Pair<Rect, Integer>> colorRectangles = new ArrayList<>();
colorRectangles.add(new Pair<>(new Rect(10, 20, 60, 40), Color.RED));
colorRectangles.add(new Pair<>(new Rect(60, 20, 80, 40), Color.GREEN));
DrawingUtils.assertAllPixelsOfColor("Overlay with one view and one drawable",
mViewGroupWithOverlay, Color.WHITE, colorRectangles);
// Remove the drawable from the overlay
mViewGroupOverlay.remove(redDrawable);
colorRectangles.clear();
colorRectangles.add(new Pair<>(new Rect(30, 20, 80, 40), Color.GREEN));
DrawingUtils.assertAllPixelsOfColor("Overlay with one view", mViewGroupWithOverlay,
Color.WHITE, colorRectangles);
// Clear all views from the overlay and test that we're back to pure white fill
mViewGroupOverlay.clear();
DrawingUtils.assertAllPixelsOfColor("Back to default fill", mViewGroupWithOverlay,
Color.WHITE, null);
}
@Test
public void testOverlayViewNoClicks() throws Throwable {
// Add one colored view with mock click listener to the overlay
final View redView = new View(mActivity);
redView.setBackgroundColor(Color.RED);
final View.OnClickListener mockClickListener = mock(View.OnClickListener.class);
redView.setOnClickListener(mockClickListener);
redView.layout(10, 20, 30, 40);
mActivityRule.runOnUiThread(() -> mViewGroupOverlay.add(redView));
// Emulate a tap in the center of the view we've added to the overlay
CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mViewGroupWithOverlay);
// Verify that our mock listener hasn't been called
verify(mockClickListener, never()).onClick(any(View.class));
}
@UiThreadTest
@Test
public void testOverlayReparenting() {
// Find the view that we're about to add to our overlay
final View level2View = mViewGroupWithOverlay.findViewById(R.id.level2);
final View level3View = level2View.findViewById(R.id.level3);
assertTrue(level2View == level3View.getParent());
// Set the fill of this view to red
level3View.setBackgroundColor(Color.RED);
mViewGroupOverlay.add(level3View);
// At this point we expect the view that was added to the overlay to have been removed
// from its original parent
assertFalse(level2View == level3View.getParent());
// Check the expected visual appearance of our view group. We expect that the view that
// was added to the overlay to maintain its relative location inside the activity.
final List<Pair<Rect, Integer>> colorRectangles = new ArrayList<>();
colorRectangles.add(new Pair<>(new Rect(65, 60, 85, 90), Color.RED));
DrawingUtils.assertAllPixelsOfColor("Empty overlay before adding grandchild",
mViewGroupWithOverlay, Color.WHITE, colorRectangles);
}
}