1/* 2 * Copyright 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package androidx.appcompat.app; 18 19import static android.support.test.espresso.Espresso.onView; 20import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom; 21 22import static androidx.appcompat.testutils.DrawerLayoutActions.openDrawer; 23 24import static org.hamcrest.CoreMatchers.equalTo; 25import static org.hamcrest.CoreMatchers.is; 26import static org.hamcrest.MatcherAssert.assertThat; 27 28import android.app.Activity; 29import android.content.Context; 30import android.support.test.InstrumentationRegistry; 31import android.support.test.filters.LargeTest; 32import android.support.test.rule.ActivityTestRule; 33import android.support.test.runner.AndroidJUnit4; 34import android.view.Gravity; 35import android.view.InputDevice; 36import android.view.MotionEvent; 37import android.view.View; 38import android.view.ViewGroup; 39 40import androidx.core.view.GravityCompat; 41import androidx.drawerlayout.widget.DrawerLayout; 42 43import org.junit.Before; 44import org.junit.Rule; 45import org.junit.Test; 46import org.junit.runner.RunWith; 47 48import java.util.concurrent.CountDownLatch; 49import java.util.concurrent.TimeUnit; 50 51@RunWith(AndroidJUnit4.class) 52public class DrawerInteractionTest { 53 54 @Rule 55 public final ActivityTestRule<DrawerInteractionActivity> mActivityTestRule = 56 new ActivityTestRule<>(DrawerInteractionActivity.class); 57 58 private TestDrawerLayout mDrawerLayout; 59 private MockView mStartDrawer; 60 private MockView mContentView; 61 62 @Before 63 public void setUp() throws Throwable { 64 final Activity activity = mActivityTestRule.getActivity(); 65 66 Context context = InstrumentationRegistry.getContext(); 67 mDrawerLayout = new TestDrawerLayout(InstrumentationRegistry.getContext()); 68 mContentView = new MockView(context); 69 mStartDrawer = new MockView(context); 70 71 mDrawerLayout.setLayoutParams(new ViewGroup.LayoutParams(100, 100)); 72 DrawerLayout.LayoutParams contentViewLayoutParams = new DrawerLayout.LayoutParams(100, 100); 73 DrawerLayout.LayoutParams drawerViewLayoutParams = new DrawerLayout.LayoutParams(50, 100); 74 75 contentViewLayoutParams.gravity = Gravity.NO_GRAVITY; 76 drawerViewLayoutParams.gravity = Gravity.START; 77 78 mContentView.setLayoutParams(contentViewLayoutParams); 79 mStartDrawer.setLayoutParams(drawerViewLayoutParams); 80 mStartDrawer.setBackgroundColor(0xFF00FF00); 81 82 mDrawerLayout.addView(mContentView); 83 mDrawerLayout.addView(mStartDrawer); 84 mDrawerLayout.setBackgroundColor(0xFFFF0000); 85 86 mDrawerLayout.expectLayouts(1); 87 mActivityTestRule.runOnUiThread(new Runnable() { 88 @Override 89 public void run() { 90 activity.setContentView(mDrawerLayout); 91 } 92 }); 93 assertThat(mDrawerLayout.waitForLayouts(2), is(true)); 94 } 95 96 // Verification that DrawerLayout blocks certain pointer motion events from getting to the 97 // content view when the drawer is open. 98 99 @Test 100 @LargeTest 101 public void ui_pointerEvent_overDrawer_receivedByDrawer() throws Throwable { 102 onView(isAssignableFrom(DrawerLayout.class)).perform(openDrawer( 103 GravityCompat.START)); 104 MotionEvent motionEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_SCROLL, 25, 50, 0); 105 motionEvent.setSource(InputDevice.SOURCE_CLASS_POINTER); 106 107 mDrawerLayout.dispatchGenericMotionEvent(motionEvent); 108 109 assertThat(mStartDrawer.mMotionEventPassedToDispatchGenericMotionEvent, 110 is(equalTo(motionEvent))); 111 } 112 113 @Test 114 @LargeTest 115 public void ui_pointerEvent_overDrawer_notReceivedByContent() throws Throwable { 116 onView(isAssignableFrom(DrawerLayout.class)).perform(openDrawer( 117 GravityCompat.START)); 118 MotionEvent motionEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_SCROLL, 25, 50, 0); 119 motionEvent.setSource(InputDevice.SOURCE_CLASS_POINTER); 120 121 mDrawerLayout.dispatchGenericMotionEvent(motionEvent); 122 123 assertThat(mContentView.mDispatchGenericMotionEventCalled, is(false)); 124 } 125 126 @Test 127 @LargeTest 128 public void ui_pointerEvent_overContentDrawerOpen_notReceivedByContent() throws Throwable { 129 onView(isAssignableFrom(DrawerLayout.class)).perform(openDrawer( 130 GravityCompat.START)); 131 MotionEvent motionEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_SCROLL, 75, 50, 0); 132 motionEvent.setSource(InputDevice.SOURCE_CLASS_POINTER); 133 134 mDrawerLayout.dispatchGenericMotionEvent(motionEvent); 135 136 assertThat(mContentView.mDispatchGenericMotionEventCalled, is(false)); 137 } 138 139 @Test 140 @LargeTest 141 public void ui_pointerEvent_overContentDrawerClosed_receivedByContent() { 142 MotionEvent motionEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_SCROLL, 75, 50, 0); 143 motionEvent.setSource(InputDevice.SOURCE_CLASS_POINTER); 144 145 mDrawerLayout.dispatchGenericMotionEvent(motionEvent); 146 147 assertThat(mContentView.mMotionEventPassedToDispatchGenericMotionEvent, 148 is(equalTo(motionEvent))); 149 } 150 151 private class TestDrawerLayout extends DrawerLayout { 152 153 CountDownLatch mLayoutCountDownLatch; 154 155 TestDrawerLayout(Context context) { 156 super(context); 157 } 158 159 public void expectLayouts(int count) { 160 mLayoutCountDownLatch = new CountDownLatch(count); 161 } 162 163 public boolean waitForLayouts(int seconds) throws InterruptedException { 164 boolean result = mLayoutCountDownLatch.await(seconds, TimeUnit.SECONDS); 165 mLayoutCountDownLatch = null; 166 return result; 167 } 168 169 @Override 170 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 171 super.onLayout(changed, left, top, right, bottom); 172 if (mLayoutCountDownLatch != null) { 173 mLayoutCountDownLatch.countDown(); 174 } 175 } 176 177 } 178 179 private class MockView extends View { 180 181 MotionEvent mMotionEventPassedToDispatchGenericMotionEvent; 182 boolean mDispatchGenericMotionEventCalled = false; 183 184 MockView(Context context) { 185 super(context); 186 } 187 188 @Override 189 public boolean dispatchGenericMotionEvent(MotionEvent event) { 190 mMotionEventPassedToDispatchGenericMotionEvent = event; 191 mDispatchGenericMotionEventCalled = true; 192 return super.dispatchGenericMotionEvent(event); 193 } 194 } 195 196 197} 198