blob: c3283d0c1214931f6da3d9ddc48791739c44b01d [file] [log] [blame]
/*
* Copyright 2018 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 androidx.appcompat.app;
import static androidx.appcompat.testutils.DrawerLayoutActions.openDrawer;
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import android.app.Activity;
import android.content.Context;
import android.view.Gravity;
import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
import androidx.test.rule.ActivityTestRule;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@RunWith(AndroidJUnit4.class)
public class DrawerInteractionTest {
@Rule
public final ActivityTestRule<DrawerInteractionActivity> mActivityTestRule =
new ActivityTestRule<>(DrawerInteractionActivity.class);
private TestDrawerLayout mDrawerLayout;
private MockView mStartDrawer;
private MockView mContentView;
@Before
public void setUp() throws Throwable {
final Activity activity = mActivityTestRule.getActivity();
Context context = ApplicationProvider.getApplicationContext();
mDrawerLayout = new TestDrawerLayout(ApplicationProvider.getApplicationContext());
mContentView = new MockView(context);
mStartDrawer = new MockView(context);
mDrawerLayout.setLayoutParams(new ViewGroup.LayoutParams(100, 100));
DrawerLayout.LayoutParams contentViewLayoutParams = new DrawerLayout.LayoutParams(100, 100);
DrawerLayout.LayoutParams drawerViewLayoutParams = new DrawerLayout.LayoutParams(50, 100);
contentViewLayoutParams.gravity = Gravity.NO_GRAVITY;
drawerViewLayoutParams.gravity = Gravity.START;
mContentView.setLayoutParams(contentViewLayoutParams);
mStartDrawer.setLayoutParams(drawerViewLayoutParams);
mStartDrawer.setBackgroundColor(0xFF00FF00);
mDrawerLayout.addView(mContentView);
mDrawerLayout.addView(mStartDrawer);
mDrawerLayout.setBackgroundColor(0xFFFF0000);
mDrawerLayout.expectLayouts(1);
mActivityTestRule.runOnUiThread(new Runnable() {
@Override
public void run() {
activity.setContentView(mDrawerLayout);
}
});
assertThat(mDrawerLayout.waitForLayouts(2), is(true));
}
// Verification that DrawerLayout blocks certain pointer motion events from getting to the
// content view when the drawer is open.
@Test
@LargeTest
public void ui_pointerEvent_overDrawer_receivedByDrawer() throws Throwable {
onView(isAssignableFrom(DrawerLayout.class)).perform(openDrawer(
GravityCompat.START));
MotionEvent motionEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_SCROLL, 25, 50, 0);
motionEvent.setSource(InputDevice.SOURCE_CLASS_POINTER);
mDrawerLayout.dispatchGenericMotionEvent(motionEvent);
assertThat(mStartDrawer.mMotionEventPassedToDispatchGenericMotionEvent,
is(equalTo(motionEvent)));
}
@Test
@LargeTest
public void ui_pointerEvent_overDrawer_notReceivedByContent() throws Throwable {
onView(isAssignableFrom(DrawerLayout.class)).perform(openDrawer(
GravityCompat.START));
MotionEvent motionEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_SCROLL, 25, 50, 0);
motionEvent.setSource(InputDevice.SOURCE_CLASS_POINTER);
mDrawerLayout.dispatchGenericMotionEvent(motionEvent);
assertThat(mContentView.mDispatchGenericMotionEventCalled, is(false));
}
@Test
@LargeTest
public void ui_pointerEvent_overContentDrawerOpen_notReceivedByContent() throws Throwable {
onView(isAssignableFrom(DrawerLayout.class)).perform(openDrawer(
GravityCompat.START));
MotionEvent motionEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_SCROLL, 75, 50, 0);
motionEvent.setSource(InputDevice.SOURCE_CLASS_POINTER);
mDrawerLayout.dispatchGenericMotionEvent(motionEvent);
assertThat(mContentView.mDispatchGenericMotionEventCalled, is(false));
}
@Test
@LargeTest
public void ui_pointerEvent_overContentDrawerClosed_receivedByContent() {
MotionEvent motionEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_SCROLL, 75, 50, 0);
motionEvent.setSource(InputDevice.SOURCE_CLASS_POINTER);
mDrawerLayout.dispatchGenericMotionEvent(motionEvent);
assertThat(mContentView.mMotionEventPassedToDispatchGenericMotionEvent,
is(equalTo(motionEvent)));
}
private class TestDrawerLayout extends DrawerLayout {
CountDownLatch mLayoutCountDownLatch;
TestDrawerLayout(Context context) {
super(context);
}
public void expectLayouts(int count) {
mLayoutCountDownLatch = new CountDownLatch(count);
}
public boolean waitForLayouts(int seconds) throws InterruptedException {
boolean result = mLayoutCountDownLatch.await(seconds, TimeUnit.SECONDS);
mLayoutCountDownLatch = null;
return result;
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (mLayoutCountDownLatch != null) {
mLayoutCountDownLatch.countDown();
}
}
}
private class MockView extends View {
MotionEvent mMotionEventPassedToDispatchGenericMotionEvent;
boolean mDispatchGenericMotionEventCalled = false;
MockView(Context context) {
super(context);
}
@Override
public boolean dispatchGenericMotionEvent(MotionEvent event) {
mMotionEventPassedToDispatchGenericMotionEvent = event;
mDispatchGenericMotionEventCalled = true;
return super.dispatchGenericMotionEvent(event);
}
}
}