• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.support.v7.widget.RecyclerView;
22 import android.text.TextUtils;
23 import android.view.KeyEvent;
24 import android.view.MotionEvent;
25 
26 import com.android.documentsui.base.Events.InputEvent;
27 import com.android.documentsui.dirlist.DocumentDetails;
28 
29 import java.lang.annotation.Retention;
30 import java.lang.annotation.RetentionPolicy;
31 import java.util.HashSet;
32 import java.util.Set;
33 
34 /**
35  * Events and DocDetails are closely related. For the pursposes of this test
36  * we coalesce the two in a single, handy-dandy test class.
37  */
38 public class TestEvent implements InputEvent {
39     private static final int ACTION_UNSET = -1;
40 
41     // Add other actions from MotionEvent.ACTION_ as needed.
42     @IntDef(flag = true, value = {
43             MotionEvent.ACTION_DOWN,
44             MotionEvent.ACTION_MOVE,
45             MotionEvent.ACTION_UP
46     })
47     @Retention(RetentionPolicy.SOURCE)
48     public @interface Action {}
49 
50     // Add other types from MotionEvent.TOOL_TYPE_ as needed.
51     @IntDef(flag = true, value = {
52             MotionEvent.TOOL_TYPE_FINGER,
53             MotionEvent.TOOL_TYPE_MOUSE,
54             MotionEvent.TOOL_TYPE_STYLUS,
55             MotionEvent.TOOL_TYPE_UNKNOWN
56     })
57     @Retention(RetentionPolicy.SOURCE)
58     public @interface ToolType {}
59 
60     @IntDef(flag = true, value = {
61             MotionEvent.BUTTON_PRIMARY,
62             MotionEvent.BUTTON_SECONDARY
63     })
64     @Retention(RetentionPolicy.SOURCE)
65     public @interface Button {}
66 
67     @IntDef(flag = true, value = {
68             KeyEvent.META_SHIFT_ON,
69             KeyEvent.META_CTRL_ON
70     })
71     @Retention(RetentionPolicy.SOURCE)
72     public @interface Key {}
73 
74     private @Action int mAction;
75     private @ToolType int mToolType;
76     private int mPointerCount;
77     private Set<Integer> mButtons;
78     private Set<Integer> mKeys;
79     private Point mLocation;
80     private Point mRawLocation;
81     private Details mDetails;
82 
TestEvent()83     private TestEvent() {
84         mAction = ACTION_UNSET;  // somebody has to set this, else we'll barf later.
85         mToolType = MotionEvent.TOOL_TYPE_UNKNOWN;
86         mButtons = new HashSet<>();
87         mKeys = new HashSet<>();
88         mLocation = new Point(0, 0);
89         mRawLocation = new Point(0, 0);
90         mDetails = new Details();
91         mPointerCount = 0;
92     }
93 
TestEvent(TestEvent source)94     private TestEvent(TestEvent source) {
95         assert(source.mAction != ACTION_UNSET);
96         mAction = source.mAction;
97         mToolType = source.mToolType;
98         mButtons = source.mButtons;
99         mKeys = source.mKeys;
100         mLocation = source.mLocation;
101         mRawLocation = source.mRawLocation;
102         mDetails = new Details(source.mDetails);
103         mPointerCount = source.mPointerCount;
104     }
105 
106     @Override
getOrigin()107     public Point getOrigin() {
108         return mLocation;
109     }
110 
111     @Override
getX()112     public float getX() {
113         return mLocation.x;
114     }
115 
116     @Override
getY()117     public float getY() {
118         return mLocation.y;
119     }
120 
121     @Override
getRawX()122     public float getRawX() {
123         return mRawLocation.x;
124     }
125 
126     @Override
getRawY()127     public float getRawY() {
128         return mRawLocation.y;
129     }
130 
131     @Override
getPointerCount()132     public int getPointerCount() {
133         return mPointerCount;
134     }
135 
136     @Override
isMouseEvent()137     public boolean isMouseEvent() {
138         return mToolType == MotionEvent.TOOL_TYPE_MOUSE;
139     }
140 
141     @Override
isPrimaryButtonPressed()142     public boolean isPrimaryButtonPressed() {
143         return mButtons.contains(MotionEvent.BUTTON_PRIMARY);
144     }
145 
146     @Override
isSecondaryButtonPressed()147     public boolean isSecondaryButtonPressed() {
148         return mButtons.contains(MotionEvent.BUTTON_SECONDARY);
149     }
150 
151     @Override
isTertiaryButtonPressed()152     public boolean isTertiaryButtonPressed() {
153         return mButtons.contains(MotionEvent.BUTTON_TERTIARY);
154     }
155 
156     @Override
isShiftKeyDown()157     public boolean isShiftKeyDown() {
158         return mKeys.contains(KeyEvent.META_SHIFT_ON);
159     }
160 
161     @Override
isCtrlKeyDown()162     public boolean isCtrlKeyDown() {
163         return mKeys.contains(KeyEvent.META_CTRL_ON);
164     }
165 
166     @Override
isAltKeyDown()167     public boolean isAltKeyDown() {
168         return mKeys.contains(KeyEvent.META_ALT_ON);
169     }
170 
171     @Override
isActionDown()172     public boolean isActionDown() {
173         return mAction == MotionEvent.ACTION_DOWN;
174     }
175 
176     @Override
isActionUp()177     public boolean isActionUp() {
178         return mAction == MotionEvent.ACTION_UP;
179     }
180 
181     @Override
isMultiPointerActionDown()182     public boolean isMultiPointerActionDown() {
183         return mAction == MotionEvent.ACTION_POINTER_DOWN;
184     }
185 
186     @Override
isMultiPointerActionUp()187     public boolean isMultiPointerActionUp() {
188         return mAction == MotionEvent.ACTION_POINTER_UP;
189     }
190 
191     @Override
isActionMove()192     public boolean isActionMove() {
193         return mAction == MotionEvent.ACTION_MOVE;
194     }
195 
196     @Override
isActionCancel()197     public boolean isActionCancel() {
198         return mAction == MotionEvent.ACTION_CANCEL;
199     }
200 
201     @Override
isOverItem()202     public boolean isOverItem() {
203         return mDetails.isOverItem();
204     }
205 
206     @Override
isOverDocIcon()207     public boolean isOverDocIcon() {
208         return mDetails.isOverDocIcon(this);
209     }
210 
211     @Override
isOverDragHotspot()212     public boolean isOverDragHotspot() {
213         return isOverItem() && mDetails.isInDragHotspot(this);
214     }
215 
216     @Override
isOverModelItem()217     public boolean isOverModelItem() {
218         if (isOverItem()) {
219             DocumentDetails doc = getDocumentDetails();
220             return doc != null && doc.hasModelId();
221         }
222         return false;
223     }
224 
225     @Override
isTouchpadScroll()226     public boolean isTouchpadScroll() {
227         return isMouseEvent() && mButtons.isEmpty() && isActionMove();
228     }
229 
230     @Override
getItemPosition()231     public int getItemPosition() {
232         return mDetails.mPosition;
233     }
234 
235     @Override
getDocumentDetails()236     public DocumentDetails getDocumentDetails() {
237         return mDetails;
238     }
239 
240     @Override
close()241     public void close() {}
242 
243     @Override
hashCode()244     public int hashCode() {
245         return mDetails.hashCode();
246     }
247 
248     @Override
equals(Object o)249     public boolean equals(Object o) {
250       if (this == o) {
251           return true;
252       }
253 
254       if (!(o instanceof TestEvent)) {
255           return false;
256       }
257 
258       TestEvent other = (TestEvent) o;
259       return mAction == other.mAction
260               && mToolType == other.mToolType
261               && mButtons.equals(other.mButtons)
262               && mKeys.equals(other.mKeys)
263               && mLocation.equals(other.mLocation)
264               && mRawLocation.equals(other.mRawLocation)
265               && mDetails.equals(other.mDetails);
266     }
267 
268     private static final class Details implements DocumentDetails {
269 
270         private int mPosition;
271         private String mModelId;
272         private boolean mInSelectionHotspot;
273         private boolean mInDragHotspot;
274         private boolean mOverDocIcon;
275 
Details()276         public Details() {
277            mPosition = Integer.MIN_VALUE;
278         }
279 
Details(Details source)280         public Details(Details source) {
281             mPosition = source.mPosition;
282             mModelId = source.mModelId;
283             mInSelectionHotspot = source.mInSelectionHotspot;
284             mInDragHotspot = source.mInDragHotspot;
285             mOverDocIcon = source.mOverDocIcon;
286         }
287 
288 
isOverItem()289         private boolean isOverItem() {
290             return mPosition != Integer.MIN_VALUE && mPosition != RecyclerView.NO_POSITION;
291         }
292 
293         @Override
hasModelId()294         public boolean hasModelId() {
295             return !TextUtils.isEmpty(mModelId);
296         }
297 
298         @Override
getModelId()299         public String getModelId() {
300             return mModelId;
301         }
302 
303         @Override
getAdapterPosition()304         public int getAdapterPosition() {
305             return mPosition;
306         }
307 
308         @Override
isInSelectionHotspot(InputEvent event)309         public boolean isInSelectionHotspot(InputEvent event) {
310             return mInSelectionHotspot;
311         }
312 
313         @Override
isInDragHotspot(InputEvent event)314         public boolean isInDragHotspot(InputEvent event) {
315             return mInDragHotspot;
316         }
317 
318         @Override
isOverDocIcon(InputEvent event)319         public boolean isOverDocIcon(InputEvent event) {
320             return mOverDocIcon;
321         }
322 
323         @Override
hashCode()324         public int hashCode() {
325             return mModelId != null ? mModelId.hashCode() : ACTION_UNSET;
326         }
327 
328         @Override
equals(Object o)329         public boolean equals(Object o) {
330           if (this == o) {
331               return true;
332           }
333 
334           if (!(o instanceof Details)) {
335               return false;
336           }
337 
338           Details other = (Details) o;
339           return mPosition == other.mPosition
340                   && mModelId == other.mModelId;
341         }
342     }
343 
builder()344     public static final Builder builder() {
345         return new Builder();
346     }
347 
348     /**
349      * Test event builder with convenience methods for common event attrs.
350      */
351     public static final class Builder {
352 
353         private TestEvent mState = new TestEvent();
354 
Builder()355         public Builder() {
356         }
357 
Builder(TestEvent state)358         public Builder(TestEvent state) {
359             mState = new TestEvent(state);
360         }
361 
362         /**
363          * @param action Any action specified in {@link MotionEvent}.
364          * @return
365          */
action(int action)366         public Builder action(int action) {
367             mState.mAction = action;
368             return this;
369         }
370 
type(@oolType int type)371         public Builder type(@ToolType int type) {
372             mState.mToolType = type;
373             return this;
374         }
375 
location(int x, int y)376         public Builder location(int x, int y) {
377             mState.mLocation = new Point(x, y);
378             return this;
379         }
380 
rawLocation(int x, int y)381         public Builder rawLocation(int x, int y) {
382             mState.mRawLocation = new Point(x, y);
383             return this;
384         }
385 
pointerCount(int count)386         public Builder pointerCount(int count) {
387             mState.mPointerCount = count;
388             return this;
389         }
390 
391         /**
392          * Adds one or more button press attributes.
393          */
pressButton(@utton int... buttons)394         public Builder pressButton(@Button int... buttons) {
395             for (int button : buttons) {
396                 mState.mButtons.add(button);
397             }
398             return this;
399         }
400 
401         /**
402          * Removes one or more button press attributes.
403          */
releaseButton(@utton int... buttons)404         public Builder releaseButton(@Button int... buttons) {
405             for (int button : buttons) {
406                 mState.mButtons.remove(button);
407             }
408             return this;
409         }
410 
411         /**
412          * Adds one or more key press attributes.
413          */
pressKey(@ey int... keys)414         public Builder pressKey(@Key int... keys) {
415             for (int key : keys) {
416                 mState.mKeys.add(key);
417             }
418             return this;
419         }
420 
421         /**
422          * Removes one or more key press attributes.
423          */
releaseKey(@utton int... keys)424         public Builder releaseKey(@Button int... keys) {
425             for (int key : keys) {
426                 mState.mKeys.remove(key);
427             }
428             return this;
429         }
430 
at(int position)431         public Builder at(int position) {
432             mState.mDetails.mPosition = position;  // this is both "adapter position" and "item position".
433             mState.mDetails.mModelId = String.valueOf(position);
434             return this;
435         }
436 
inSelectionHotspot()437         public Builder inSelectionHotspot() {
438             mState.mDetails.mInSelectionHotspot = true;
439             return this;
440         }
441 
inDragHotspot()442         public Builder inDragHotspot() {
443             mState.mDetails.mInDragHotspot = true;
444             return this;
445         }
446 
notInDragHotspot()447         public Builder notInDragHotspot() {
448             mState.mDetails.mInDragHotspot = false;
449             return this;
450         }
451 
overDocIcon()452         public Builder overDocIcon() {
453             mState.mDetails.mOverDocIcon = true;
454             return this;
455         }
456 
notOverDocIcon()457         public Builder notOverDocIcon() {
458             mState.mDetails.mOverDocIcon = false;
459             return this;
460         }
461 
touch()462         public Builder touch() {
463             type(MotionEvent.TOOL_TYPE_FINGER);
464             return this;
465         }
466 
mouse()467         public Builder mouse() {
468             type(MotionEvent.TOOL_TYPE_MOUSE);
469             return this;
470         }
471 
shift()472         public Builder shift() {
473             pressKey(KeyEvent.META_SHIFT_ON);
474             return this;
475         }
476 
477         /**
478          * Use {@link #remove(@Attribute int...)}
479          */
480         @Deprecated
unshift()481         public Builder unshift() {
482             releaseKey(KeyEvent.META_SHIFT_ON);
483             return this;
484         }
485 
ctrl()486         public Builder ctrl() {
487             pressKey(KeyEvent.META_CTRL_ON);
488             return this;
489         }
490 
alt()491         public Builder alt() {
492             pressKey(KeyEvent.META_ALT_ON);
493             return this;
494         }
495 
primary()496         public Builder primary() {
497             pressButton(MotionEvent.BUTTON_PRIMARY);
498             releaseButton(MotionEvent.BUTTON_SECONDARY);
499             releaseButton(MotionEvent.BUTTON_TERTIARY);
500             return this;
501         }
502 
secondary()503         public Builder secondary() {
504             pressButton(MotionEvent.BUTTON_SECONDARY);
505             releaseButton(MotionEvent.BUTTON_PRIMARY);
506             releaseButton(MotionEvent.BUTTON_TERTIARY);
507             return this;
508         }
509 
tertiary()510         public Builder tertiary() {
511             pressButton(MotionEvent.BUTTON_TERTIARY);
512             releaseButton(MotionEvent.BUTTON_PRIMARY);
513             releaseButton(MotionEvent.BUTTON_SECONDARY);
514             return this;
515         }
516 
reset()517         public Builder reset() {
518             mState = new TestEvent();
519             return this;
520         }
521 
522         @Override
clone()523         public Builder clone() {
524             return new Builder(build());
525         }
526 
build()527         public TestEvent build() {
528             // Return a copy, so nobody can mess w/ our internal state.
529             return new TestEvent(mState);
530         }
531     }
532 }
533