188cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi/* 288cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi * Copyright (C) 2015 The Android Open Source Project 388cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi * 488cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi * Licensed under the Apache License, Version 2.0 (the "License"); 588cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi * you may not use this file except in compliance with the License. 688cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi * You may obtain a copy of the License at 788cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi * 888cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi * http://www.apache.org/licenses/LICENSE-2.0 988cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi * 1088cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi * Unless required by applicable law or agreed to in writing, software 1188cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi * distributed under the License is distributed on an "AS IS" BASIS, 1288cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1388cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi * See the License for the specific language governing permissions and 1488cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi * limitations under the License 1588cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi */ 1688cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi 1788cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagipackage android.widget.espresso; 1888cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi 19a0b3c068810b2bc4ed61d9ad35e9660aa247d2f6Keisuke Kuroyanagiimport static com.android.internal.util.Preconditions.checkNotNull; 20a0b3c068810b2bc4ed61d9ad35e9660aa247d2f6Keisuke Kuroyanagi 21a0b3c068810b2bc4ed61d9ad35e9660aa247d2f6Keisuke Kuroyanagiimport java.lang.annotation.Retention; 22a0b3c068810b2bc4ed61d9ad35e9660aa247d2f6Keisuke Kuroyanagiimport java.lang.annotation.RetentionPolicy; 23a0b3c068810b2bc4ed61d9ad35e9660aa247d2f6Keisuke Kuroyanagi 24a0b3c068810b2bc4ed61d9ad35e9660aa247d2f6Keisuke Kuroyanagiimport android.annotation.IntDef; 2588cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagiimport android.support.test.espresso.InjectEventSecurityException; 2688cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagiimport android.support.test.espresso.UiController; 2788cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagiimport android.view.InputDevice; 2888cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagiimport android.view.KeyEvent; 2988cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagiimport android.view.MotionEvent; 3088cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi 3188cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi/** 3288cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi * Class to wrap an UiController to overwrite source of motion events to SOURCE_MOUSE. 3388cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi * Note that this doesn't change the tool type. 3488cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi */ 35a0b3c068810b2bc4ed61d9ad35e9660aa247d2f6Keisuke Kuroyanagipublic final class MouseUiController implements UiController { 36a0b3c068810b2bc4ed61d9ad35e9660aa247d2f6Keisuke Kuroyanagi @Retention(RetentionPolicy.SOURCE) 37a0b3c068810b2bc4ed61d9ad35e9660aa247d2f6Keisuke Kuroyanagi @IntDef({MotionEvent.BUTTON_PRIMARY, MotionEvent.BUTTON_SECONDARY, MotionEvent.BUTTON_TERTIARY}) 38a0b3c068810b2bc4ed61d9ad35e9660aa247d2f6Keisuke Kuroyanagi public @interface MouseButton {} 39a0b3c068810b2bc4ed61d9ad35e9660aa247d2f6Keisuke Kuroyanagi 4088cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi private final UiController mUiController; 41a0b3c068810b2bc4ed61d9ad35e9660aa247d2f6Keisuke Kuroyanagi @MouseButton 42a0b3c068810b2bc4ed61d9ad35e9660aa247d2f6Keisuke Kuroyanagi private final int mButton; 4388cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi 4488cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi public MouseUiController(UiController uiController) { 45a0b3c068810b2bc4ed61d9ad35e9660aa247d2f6Keisuke Kuroyanagi this(uiController, MotionEvent.BUTTON_PRIMARY); 46a0b3c068810b2bc4ed61d9ad35e9660aa247d2f6Keisuke Kuroyanagi } 47a0b3c068810b2bc4ed61d9ad35e9660aa247d2f6Keisuke Kuroyanagi 48a0b3c068810b2bc4ed61d9ad35e9660aa247d2f6Keisuke Kuroyanagi /** 49a0b3c068810b2bc4ed61d9ad35e9660aa247d2f6Keisuke Kuroyanagi * Constructs MouseUiController. 50a0b3c068810b2bc4ed61d9ad35e9660aa247d2f6Keisuke Kuroyanagi * 51a0b3c068810b2bc4ed61d9ad35e9660aa247d2f6Keisuke Kuroyanagi * @param uiController the uiController to wrap 52a0b3c068810b2bc4ed61d9ad35e9660aa247d2f6Keisuke Kuroyanagi * @param button the button to be used for generating input events. 53a0b3c068810b2bc4ed61d9ad35e9660aa247d2f6Keisuke Kuroyanagi */ 54a0b3c068810b2bc4ed61d9ad35e9660aa247d2f6Keisuke Kuroyanagi public MouseUiController(UiController uiController, @MouseButton int button) { 55a0b3c068810b2bc4ed61d9ad35e9660aa247d2f6Keisuke Kuroyanagi mUiController = checkNotNull(uiController); 56a0b3c068810b2bc4ed61d9ad35e9660aa247d2f6Keisuke Kuroyanagi mButton = button; 5788cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi } 5888cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi 5988cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi @Override 6088cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi public boolean injectKeyEvent(KeyEvent event) throws InjectEventSecurityException { 6188cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi return mUiController.injectKeyEvent(event); 6288cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi } 6388cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi 6488cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi @Override 6588cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi public boolean injectMotionEvent(MotionEvent event) throws InjectEventSecurityException { 66a0b3c068810b2bc4ed61d9ad35e9660aa247d2f6Keisuke Kuroyanagi // Modify the event to mimic mouse event. 6788cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi event.setSource(InputDevice.SOURCE_MOUSE); 68a0b3c068810b2bc4ed61d9ad35e9660aa247d2f6Keisuke Kuroyanagi if (event.getActionMasked() != MotionEvent.ACTION_UP) { 69a0b3c068810b2bc4ed61d9ad35e9660aa247d2f6Keisuke Kuroyanagi event.setButtonState(mButton); 70a0b3c068810b2bc4ed61d9ad35e9660aa247d2f6Keisuke Kuroyanagi } 7188cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi return mUiController.injectMotionEvent(event); 7288cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi } 7388cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi 7488cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi @Override 7588cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi public boolean injectString(String str) throws InjectEventSecurityException { 7688cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi return mUiController.injectString(str); 7788cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi } 7888cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi 7988cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi @Override 8088cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi public void loopMainThreadForAtLeast(long millisDelay) { 8188cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi mUiController.loopMainThreadForAtLeast(millisDelay); 8288cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi } 8388cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi 8488cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi @Override 8588cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi public void loopMainThreadUntilIdle() { 8688cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi mUiController.loopMainThreadUntilIdle(); 8788cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi } 8888cabede9bc74ade7d0124cde3d40fadb6c97a85Keisuke Kuroyanagi} 89