1f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev/* 2f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev * Copyright (C) 2014 The Android Open Source Project 3f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev * 4f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev * Licensed under the Apache License, Version 2.0 (the "License"); 5f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev * you may not use this file except in compliance with the License. 6f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev * You may obtain a copy of the License at 7f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev * 8f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev * http://www.apache.org/licenses/LICENSE-2.0 9f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev * 10f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev * Unless required by applicable law or agreed to in writing, software 11f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev * distributed under the License is distributed on an "AS IS" BASIS, 12f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev * See the License for the specific language governing permissions and 14f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev * limitations under the License. 15f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev */ 16f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 17f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevpackage com.google.android.apps.common.testing.ui.espresso.base; 18f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 19f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport com.google.android.apps.common.testing.testrunner.ActivityLifecycleCallback; 20f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport com.google.android.apps.common.testing.testrunner.ActivityLifecycleMonitorRegistry; 21f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport com.google.android.apps.common.testing.testrunner.Stage; 22f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport com.google.android.apps.common.testing.ui.espresso.InjectEventSecurityException; 23f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport com.google.android.apps.common.testing.ui.testapp.R; 24f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport com.google.android.apps.common.testing.ui.testapp.SendActivity; 25f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 26f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport android.app.Activity; 27f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport android.os.Build; 28f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport android.os.SystemClock; 29f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport android.test.ActivityInstrumentationTestCase2; 30f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport android.test.suitebuilder.annotation.LargeTest; 31f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport android.util.Log; 32f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport android.view.KeyCharacterMap; 33f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport android.view.KeyEvent; 34f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport android.view.MotionEvent; 35f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport android.view.View; 36f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 37f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport java.util.concurrent.CountDownLatch; 38f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport java.util.concurrent.TimeUnit; 39f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport java.util.concurrent.atomic.AtomicBoolean; 40f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 41f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev/** 42f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev * Tests for {@link EventInjector}. 43f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev */ 44f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevpublic class EventInjectorTest extends ActivityInstrumentationTestCase2<SendActivity> { 45f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev private static final String TAG = EventInjectorTest.class.getSimpleName(); 46f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev private Activity sendActivity; 47f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev private EventInjector injector; 48f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev final AtomicBoolean injectEventWorked = new AtomicBoolean(false); 49f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev final AtomicBoolean injectEventThrewSecurityException = new AtomicBoolean(false); 50f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev final CountDownLatch latch = new CountDownLatch(1); 51f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 52f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev @SuppressWarnings("deprecation") 53f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public EventInjectorTest() { 54f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev // Supporting froyo. 55f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev super("com.google.android.apps.common.testing.ui.testapp", SendActivity.class); 56f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 57f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 58f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev @Override 59f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public void setUp() throws Exception { 60f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev super.setUp(); 61f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev if (Build.VERSION.SDK_INT > 15) { 62f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev InputManagerEventInjectionStrategy strat = new InputManagerEventInjectionStrategy(); 63f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev strat.initialize(); 64f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev injector = new EventInjector(strat); 65f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } else { 66f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev WindowManagerEventInjectionStrategy strat = new WindowManagerEventInjectionStrategy(); 67f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev strat.initialize(); 68f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev injector = new EventInjector(strat); 69f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 70f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 71f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 72f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev @Override 73f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public void tearDown() throws Exception { 74f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev super.tearDown(); 75f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 76f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 77f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev @LargeTest 78f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public void testInjectKeyEventUpWithNoDown() throws Exception { 79f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev sendActivity = getActivity(); 80f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 81f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev getInstrumentation().runOnMainSync(new Runnable() { 82f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev @Override 83f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public void run() { 84f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev View view = sendActivity.findViewById(R.id.send_data_edit_text); 85f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev assertTrue(view.requestFocus()); 86f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev latch.countDown(); 87f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 88f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev }); 89f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 90f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev assertTrue("Timed out!", latch.await(10, TimeUnit.SECONDS)); 91f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev KeyCharacterMap keyCharacterMap = UiControllerImpl.getKeyCharacterMap(); 92f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev KeyEvent[] events = keyCharacterMap.getEvents("a".toCharArray()); 93f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev assertTrue(injector.injectKeyEvent(events[1])); 94f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 95f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 96f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev @LargeTest 97f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public void testInjectStaleKeyEvent() throws Exception { 98f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev sendActivity = getActivity(); 99f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 100f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev getInstrumentation().runOnMainSync(new Runnable() { 101f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev @Override 102f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public void run() { 103f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev View view = sendActivity.findViewById(R.id.send_data_edit_text); 104f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev assertTrue(view.requestFocus()); 105f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev latch.countDown(); 106f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 107f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev }); 108f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 109f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev assertTrue("Timed out!", latch.await(10, TimeUnit.SECONDS)); 110f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev assertFalse("SecurityException exception was thrown.", injectEventThrewSecurityException.get()); 111f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 112f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev KeyCharacterMap keyCharacterMap = UiControllerImpl.getKeyCharacterMap(); 113f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev KeyEvent[] events = keyCharacterMap.getEvents("a".toCharArray()); 114f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev KeyEvent event = KeyEvent.changeTimeRepeat(events[0], 1, 0); 115f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 116f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev // Stale event does not fail for API < 13. 117f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev if (Build.VERSION.SDK_INT < 13) { 118f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev assertTrue(injector.injectKeyEvent(event)); 119f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } else { 120f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev assertFalse(injector.injectKeyEvent(event)); 121f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 122f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 123f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 124f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev @LargeTest 125f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public void testInjectKeyEvent_securityException() { 126f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev KeyCharacterMap keyCharacterMap = UiControllerImpl.getKeyCharacterMap(); 127f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev KeyEvent[] events = keyCharacterMap.getEvents("a".toCharArray()); 128f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev try { 129f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev injector.injectKeyEvent(events[0]); 130f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev fail("Should have thrown a security exception!"); 131f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } catch (InjectEventSecurityException expected) { } 132f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 133f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 134f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev @LargeTest 135f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public void testInjectMotionEvent_securityException() throws Exception { 136f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev getInstrumentation().runOnMainSync(new Runnable() { 137f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev @Override 138f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public void run() { 139f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev MotionEvent down = MotionEvent.obtain(SystemClock.uptimeMillis(), 140f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev SystemClock.uptimeMillis(), 141f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev MotionEvent.ACTION_DOWN, 142f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 0, 143f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 0, 144f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 0); 145f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev try { 146f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev injector.injectMotionEvent(down); 147f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } catch (InjectEventSecurityException expected) { 148f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev injectEventThrewSecurityException.set(true); 149f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 150f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev latch.countDown(); 151f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 152f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev }); 153f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 154f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev latch.await(10, TimeUnit.SECONDS); 155f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev assertTrue(injectEventThrewSecurityException.get()); 156f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 157f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 158f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev @LargeTest 159f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public void testInjectMotionEvent_upEventFailure() throws InterruptedException { 160f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev final CountDownLatch activityStarted = new CountDownLatch(1); 161f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev ActivityLifecycleCallback callback = new ActivityLifecycleCallback() { 162f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev @Override 163f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public void onActivityLifecycleChanged(Activity activity, Stage stage) { 164f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev if (Stage.RESUMED == stage && activity instanceof SendActivity) { 165f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev activityStarted.countDown(); 166f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 167f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 168f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev }; 169f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev ActivityLifecycleMonitorRegistry 170f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev .getInstance() 171f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev .addLifecycleCallback(callback); 172f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev try { 173f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev getActivity(); 174f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev assertTrue(activityStarted.await(20, TimeUnit.SECONDS)); 175f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev final int[] xy = UiControllerImplIntegrationTest.getCoordinatesInMiddleOfSendButton( 176f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev getActivity(), getInstrumentation()); 177f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 178f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev getInstrumentation().runOnMainSync(new Runnable() { 179f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev @Override 180f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public void run() { 181f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev MotionEvent up = MotionEvent.obtain(SystemClock.uptimeMillis(), 182f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev SystemClock.uptimeMillis(), 183f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev MotionEvent.ACTION_UP, 184f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev xy[0], 185f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev xy[1], 186f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 0); 187f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 188f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev try { 189f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev injectEventWorked.set(injector.injectMotionEvent(up)); 190f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } catch (InjectEventSecurityException e) { 191f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev Log.e(TAG, "injectEvent threw a SecurityException"); 192f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 193f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev up.recycle(); 194f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev latch.countDown(); 195f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 196f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev }); 197f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 198f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev latch.await(10, TimeUnit.SECONDS); 199f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev assertFalse(injectEventWorked.get()); 200f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } finally { 201f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev ActivityLifecycleMonitorRegistry 202f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev .getInstance() 203f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev .removeLifecycleCallback(callback); 204f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 205f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 206f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 207f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev} 208