Home | History | Annotate | Download | only in testing
      1 /*
      2  * Copyright (C) 2016 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 
     17 package com.android.documentsui.testing;
     18 
     19 import android.annotation.IntDef;
     20 import android.graphics.Point;
     21 import android.view.KeyEvent;
     22 import android.view.MotionEvent;
     23 import android.view.MotionEvent.PointerCoords;
     24 import android.view.MotionEvent.PointerProperties;
     25 
     26 import java.lang.annotation.Retention;
     27 import java.lang.annotation.RetentionPolicy;
     28 import java.util.HashSet;
     29 import java.util.Set;
     30 
     31 /**
     32  * Handy-dandy wrapper class to facilitate the creation of MotionEvents.
     33  */
     34 public final class TestEvents {
     35 
     36     /**
     37      * Common mouse event types...for your convenience.
     38      */
     39     public static final class Mouse {
     40         public static final MotionEvent CLICK =
     41                 TestEvents.builder().mouse().primary().build();
     42         public static final MotionEvent CTRL_CLICK =
     43                 TestEvents.builder().mouse().primary().ctrl().build();
     44         public static final MotionEvent ALT_CLICK =
     45                 TestEvents.builder().mouse().primary().alt().build();
     46         public static final MotionEvent SHIFT_CLICK =
     47                 TestEvents.builder().mouse().primary().shift().build();
     48         public static final MotionEvent SECONDARY_CLICK =
     49                 TestEvents.builder().mouse().secondary().build();
     50         public static final MotionEvent TERTIARY_CLICK =
     51                 TestEvents.builder().mouse().tertiary().build();
     52     }
     53 
     54     /**
     55      * Common touch event types...for your convenience.
     56      */
     57     public static final class Touch {
     58         public static final MotionEvent TAP =
     59                 TestEvents.builder().touch().build();
     60     }
     61 
     62     static final int ACTION_UNSET = -1;
     63 
     64     // Add other actions from MotionEvent.ACTION_ as needed.
     65     @IntDef(flag = true, value = {
     66             MotionEvent.ACTION_DOWN,
     67             MotionEvent.ACTION_MOVE,
     68             MotionEvent.ACTION_UP
     69     })
     70     @Retention(RetentionPolicy.SOURCE)
     71     public @interface Action {}
     72 
     73     // Add other types from MotionEvent.TOOL_TYPE_ as needed.
     74     @IntDef(flag = true, value = {
     75             MotionEvent.TOOL_TYPE_FINGER,
     76             MotionEvent.TOOL_TYPE_MOUSE,
     77             MotionEvent.TOOL_TYPE_STYLUS,
     78             MotionEvent.TOOL_TYPE_UNKNOWN
     79     })
     80     @Retention(RetentionPolicy.SOURCE)
     81     public @interface ToolType {}
     82 
     83     @IntDef(flag = true, value = {
     84             MotionEvent.BUTTON_PRIMARY,
     85             MotionEvent.BUTTON_SECONDARY
     86     })
     87     @Retention(RetentionPolicy.SOURCE)
     88     public @interface Button {}
     89 
     90     @IntDef(flag = true, value = {
     91             KeyEvent.META_SHIFT_ON,
     92             KeyEvent.META_CTRL_ON
     93     })
     94     @Retention(RetentionPolicy.SOURCE)
     95     public @interface Key {}
     96 
     97     private static final class State {
     98         private @Action int mAction = ACTION_UNSET;
     99         private @ToolType int mToolType = MotionEvent.TOOL_TYPE_UNKNOWN;
    100         private int mPointerCount = 1;
    101         private Set<Integer> mButtons = new HashSet<>();
    102         private Set<Integer> mKeys = new HashSet<>();
    103         private Point mLocation = new Point(0, 0);
    104         private Point mRawLocation = new Point(0, 0);
    105     }
    106 
    107     public static final Builder builder() {
    108         return new Builder();
    109     }
    110 
    111     /**
    112      * Test event builder with convenience methods for common event attrs.
    113      */
    114     public static final class Builder {
    115 
    116         private State mState = new State();
    117 
    118         /**
    119          * @param action Any action specified in {@link MotionEvent}.
    120          * @return
    121          */
    122         public Builder action(int action) {
    123             mState.mAction = action;
    124             return this;
    125         }
    126 
    127         public Builder type(@ToolType int type) {
    128             mState.mToolType = type;
    129             return this;
    130         }
    131 
    132         public Builder location(int x, int y) {
    133             mState.mLocation = new Point(x, y);
    134             return this;
    135         }
    136 
    137         public Builder rawLocation(int x, int y) {
    138             mState.mRawLocation = new Point(x, y);
    139             return this;
    140         }
    141 
    142         public Builder pointerCount(int count) {
    143             mState.mPointerCount = count;
    144             return this;
    145         }
    146 
    147         /**
    148          * Adds one or more button press attributes.
    149          */
    150         public Builder pressButton(@Button int... buttons) {
    151             for (int button : buttons) {
    152                 mState.mButtons.add(button);
    153             }
    154             return this;
    155         }
    156 
    157         /**
    158          * Removes one or more button press attributes.
    159          */
    160         public Builder releaseButton(@Button int... buttons) {
    161             for (int button : buttons) {
    162                 mState.mButtons.remove(button);
    163             }
    164             return this;
    165         }
    166 
    167         /**
    168          * Adds one or more key press attributes.
    169          */
    170         public Builder pressKey(@Key int... keys) {
    171             for (int key : keys) {
    172                 mState.mKeys.add(key);
    173             }
    174             return this;
    175         }
    176 
    177         /**
    178          * Removes one or more key press attributes.
    179          */
    180         public Builder releaseKey(@Button int... keys) {
    181             for (int key : keys) {
    182                 mState.mKeys.remove(key);
    183             }
    184             return this;
    185         }
    186 
    187         public Builder touch() {
    188             type(MotionEvent.TOOL_TYPE_FINGER);
    189             return this;
    190         }
    191 
    192         public Builder mouse() {
    193             type(MotionEvent.TOOL_TYPE_MOUSE);
    194             return this;
    195         }
    196 
    197         public Builder shift() {
    198             pressKey(KeyEvent.META_SHIFT_ON);
    199             return this;
    200         }
    201 
    202         /**
    203          * Use {@link #remove(@Attribute int...)}
    204          */
    205         public Builder unshift() {
    206             releaseKey(KeyEvent.META_SHIFT_ON);
    207             return this;
    208         }
    209 
    210         public Builder ctrl() {
    211             pressKey(KeyEvent.META_CTRL_ON);
    212             return this;
    213         }
    214 
    215         public Builder alt() {
    216             pressKey(KeyEvent.META_ALT_ON);
    217             return this;
    218         }
    219 
    220         public Builder primary() {
    221             pressButton(MotionEvent.BUTTON_PRIMARY);
    222             releaseButton(MotionEvent.BUTTON_SECONDARY);
    223             releaseButton(MotionEvent.BUTTON_TERTIARY);
    224             return this;
    225         }
    226 
    227         public Builder secondary() {
    228             pressButton(MotionEvent.BUTTON_SECONDARY);
    229             releaseButton(MotionEvent.BUTTON_PRIMARY);
    230             releaseButton(MotionEvent.BUTTON_TERTIARY);
    231             return this;
    232         }
    233 
    234         public Builder tertiary() {
    235             pressButton(MotionEvent.BUTTON_TERTIARY);
    236             releaseButton(MotionEvent.BUTTON_PRIMARY);
    237             releaseButton(MotionEvent.BUTTON_SECONDARY);
    238             return this;
    239         }
    240 
    241         public MotionEvent build() {
    242 
    243             PointerProperties[] pointers = new PointerProperties[1];
    244             pointers[0] = new PointerProperties();
    245             pointers[0].id = 0;
    246             pointers[0].toolType = mState.mToolType;
    247 
    248             PointerCoords[] coords = new PointerCoords[1];
    249             coords[0] = new PointerCoords();
    250             coords[0].x = mState.mLocation.x;
    251             coords[0].y = mState.mLocation.y;
    252 
    253             int buttons = 0;
    254             for (Integer button : mState.mButtons) {
    255                 buttons |= button;
    256             }
    257 
    258             int keys = 0;
    259             for (Integer key : mState.mKeys) {
    260                 keys |= key;
    261             }
    262 
    263             return MotionEvent.obtain(
    264                     0,     // down time
    265                     1,     // event time
    266                     mState.mAction,
    267                     1,  // pointerCount,
    268                     pointers,
    269                     coords,
    270                     keys,
    271                     buttons,
    272                     1.0f,  // x precision
    273                     1.0f,  // y precision
    274                     0,     // device id
    275                     0,     // edge flags
    276                     0,     // int source,
    277                     0      // int flags
    278                     );
    279         }
    280     }
    281 }
    282