| /* |
| * Copyright (C) 2016 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 com.android.documentsui.testing; |
| |
| import androidx.annotation.IntDef; |
| import android.graphics.Point; |
| import android.view.KeyEvent; |
| import android.view.MotionEvent; |
| import android.view.MotionEvent.PointerCoords; |
| import android.view.MotionEvent.PointerProperties; |
| |
| import java.lang.annotation.Retention; |
| import java.lang.annotation.RetentionPolicy; |
| import java.util.HashSet; |
| import java.util.Set; |
| |
| /** |
| * Handy-dandy wrapper class to facilitate the creation of MotionEvents. |
| */ |
| public final class TestEvents { |
| |
| /** |
| * Common mouse event types...for your convenience. |
| */ |
| public static final class Mouse { |
| public static final MotionEvent CLICK = |
| TestEvents.builder().mouse().primary().build(); |
| public static final MotionEvent CTRL_CLICK = |
| TestEvents.builder().mouse().primary().ctrl().build(); |
| public static final MotionEvent ALT_CLICK = |
| TestEvents.builder().mouse().primary().alt().build(); |
| public static final MotionEvent SHIFT_CLICK = |
| TestEvents.builder().mouse().primary().shift().build(); |
| public static final MotionEvent SECONDARY_CLICK = |
| TestEvents.builder().mouse().secondary().build(); |
| public static final MotionEvent TERTIARY_CLICK = |
| TestEvents.builder().mouse().tertiary().build(); |
| } |
| |
| /** |
| * Common touch event types...for your convenience. |
| */ |
| public static final class Touch { |
| public static final MotionEvent TAP = |
| TestEvents.builder().touch().build(); |
| } |
| |
| static final int ACTION_UNSET = -1; |
| |
| // Add other actions from MotionEvent.ACTION_ as needed. |
| @IntDef(flag = true, value = { |
| MotionEvent.ACTION_DOWN, |
| MotionEvent.ACTION_MOVE, |
| MotionEvent.ACTION_UP |
| }) |
| @Retention(RetentionPolicy.SOURCE) |
| public @interface Action {} |
| |
| // Add other types from MotionEvent.TOOL_TYPE_ as needed. |
| @IntDef(flag = true, value = { |
| MotionEvent.TOOL_TYPE_FINGER, |
| MotionEvent.TOOL_TYPE_MOUSE, |
| MotionEvent.TOOL_TYPE_STYLUS, |
| MotionEvent.TOOL_TYPE_UNKNOWN |
| }) |
| @Retention(RetentionPolicy.SOURCE) |
| public @interface ToolType {} |
| |
| @IntDef(flag = true, value = { |
| MotionEvent.BUTTON_PRIMARY, |
| MotionEvent.BUTTON_SECONDARY |
| }) |
| @Retention(RetentionPolicy.SOURCE) |
| public @interface Button {} |
| |
| @IntDef(flag = true, value = { |
| KeyEvent.META_SHIFT_ON, |
| KeyEvent.META_CTRL_ON |
| }) |
| @Retention(RetentionPolicy.SOURCE) |
| public @interface Key {} |
| |
| private static final class State { |
| private @Action int mAction = ACTION_UNSET; |
| private @ToolType int mToolType = MotionEvent.TOOL_TYPE_UNKNOWN; |
| private int mPointerCount = 1; |
| private Set<Integer> mButtons = new HashSet<>(); |
| private Set<Integer> mKeys = new HashSet<>(); |
| private Point mLocation = new Point(0, 0); |
| private Point mRawLocation = new Point(0, 0); |
| } |
| |
| public static final Builder builder() { |
| return new Builder(); |
| } |
| |
| /** |
| * Test event builder with convenience methods for common event attrs. |
| */ |
| public static final class Builder { |
| |
| private State mState = new State(); |
| |
| /** |
| * @param action Any action specified in {@link MotionEvent}. |
| * @return |
| */ |
| public Builder action(int action) { |
| mState.mAction = action; |
| return this; |
| } |
| |
| public Builder type(@ToolType int type) { |
| mState.mToolType = type; |
| return this; |
| } |
| |
| public Builder location(int x, int y) { |
| mState.mLocation = new Point(x, y); |
| return this; |
| } |
| |
| public Builder rawLocation(int x, int y) { |
| mState.mRawLocation = new Point(x, y); |
| return this; |
| } |
| |
| public Builder pointerCount(int count) { |
| mState.mPointerCount = count; |
| return this; |
| } |
| |
| /** |
| * Adds one or more button press attributes. |
| */ |
| public Builder pressButton(@Button int... buttons) { |
| for (int button : buttons) { |
| mState.mButtons.add(button); |
| } |
| return this; |
| } |
| |
| /** |
| * Removes one or more button press attributes. |
| */ |
| public Builder releaseButton(@Button int... buttons) { |
| for (int button : buttons) { |
| mState.mButtons.remove(button); |
| } |
| return this; |
| } |
| |
| /** |
| * Adds one or more key press attributes. |
| */ |
| public Builder pressKey(@Key int... keys) { |
| for (int key : keys) { |
| mState.mKeys.add(key); |
| } |
| return this; |
| } |
| |
| /** |
| * Removes one or more key press attributes. |
| */ |
| public Builder releaseKey(@Button int... keys) { |
| for (int key : keys) { |
| mState.mKeys.remove(key); |
| } |
| return this; |
| } |
| |
| public Builder touch() { |
| type(MotionEvent.TOOL_TYPE_FINGER); |
| return this; |
| } |
| |
| public Builder mouse() { |
| type(MotionEvent.TOOL_TYPE_MOUSE); |
| return this; |
| } |
| |
| public Builder shift() { |
| pressKey(KeyEvent.META_SHIFT_ON); |
| return this; |
| } |
| |
| /** |
| * Use {@link #remove(@Attribute int...)} |
| */ |
| public Builder unshift() { |
| releaseKey(KeyEvent.META_SHIFT_ON); |
| return this; |
| } |
| |
| public Builder ctrl() { |
| pressKey(KeyEvent.META_CTRL_ON); |
| return this; |
| } |
| |
| public Builder alt() { |
| pressKey(KeyEvent.META_ALT_ON); |
| return this; |
| } |
| |
| public Builder primary() { |
| pressButton(MotionEvent.BUTTON_PRIMARY); |
| releaseButton(MotionEvent.BUTTON_SECONDARY); |
| releaseButton(MotionEvent.BUTTON_TERTIARY); |
| return this; |
| } |
| |
| public Builder secondary() { |
| pressButton(MotionEvent.BUTTON_SECONDARY); |
| releaseButton(MotionEvent.BUTTON_PRIMARY); |
| releaseButton(MotionEvent.BUTTON_TERTIARY); |
| return this; |
| } |
| |
| public Builder tertiary() { |
| pressButton(MotionEvent.BUTTON_TERTIARY); |
| releaseButton(MotionEvent.BUTTON_PRIMARY); |
| releaseButton(MotionEvent.BUTTON_SECONDARY); |
| return this; |
| } |
| |
| public MotionEvent build() { |
| |
| PointerProperties[] pointers = new PointerProperties[1]; |
| pointers[0] = new PointerProperties(); |
| pointers[0].id = 0; |
| pointers[0].toolType = mState.mToolType; |
| |
| PointerCoords[] coords = new PointerCoords[1]; |
| coords[0] = new PointerCoords(); |
| coords[0].x = mState.mLocation.x; |
| coords[0].y = mState.mLocation.y; |
| |
| int buttons = 0; |
| for (Integer button : mState.mButtons) { |
| buttons |= button; |
| } |
| |
| int keys = 0; |
| for (Integer key : mState.mKeys) { |
| keys |= key; |
| } |
| |
| return MotionEvent.obtain( |
| 0, // down time |
| 1, // event time |
| mState.mAction, |
| 1, // pointerCount, |
| pointers, |
| coords, |
| keys, |
| buttons, |
| 1.0f, // x precision |
| 1.0f, // y precision |
| 0, // device id |
| 0, // edge flags |
| 0, // int source, |
| 0 // int flags |
| ); |
| } |
| } |
| } |