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.selection; 18 19 import static android.support.v4.util.Preconditions.checkArgument; 20 21 import android.support.v7.widget.RecyclerView; 22 import android.support.v7.widget.RecyclerView.OnItemTouchListener; 23 import android.view.GestureDetector; 24 import android.view.MotionEvent; 25 26 /** 27 * A class responsible for routing MotionEvents to tool-type specific handlers, 28 * and if not handled by a handler, on to a {@link GestureDetector} for further 29 * processing. 30 * 31 * <p>TouchEventRouter takes its name from 32 * {@link RecyclerView#addOnItemTouchListener(OnItemTouchListener)}. Despite "Touch" 33 * being in the name, it receives MotionEvents for all types of tools. 34 */ 35 public final class TouchEventRouter implements OnItemTouchListener { 36 37 private final GestureDetector mDetector; 38 private final ToolHandlerRegistry<OnItemTouchListener> mDelegates; 39 40 public TouchEventRouter(GestureDetector detector, OnItemTouchListener defaultDelegate) { 41 checkArgument(detector != null); 42 checkArgument(defaultDelegate != null); 43 44 mDetector = detector; 45 mDelegates = new ToolHandlerRegistry<>(defaultDelegate); 46 } 47 48 public TouchEventRouter(GestureDetector detector) { 49 this( 50 detector, 51 // Default listener does nothing. 52 new OnItemTouchListener() { 53 @Override 54 public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { 55 return false; 56 } 57 58 @Override 59 public void onTouchEvent(RecyclerView rv, MotionEvent e) { 60 } 61 62 @Override 63 public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { 64 } 65 }); 66 } 67 68 /** 69 * @param toolType See MotionEvent for details on available types. 70 * @param delegate An {@link OnItemTouchListener} to receive events 71 * of {@code toolType}. 72 */ 73 public void register(int toolType, OnItemTouchListener delegate) { 74 checkArgument(delegate != null); 75 mDelegates.set(toolType, delegate); 76 } 77 78 @Override 79 public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { 80 boolean handled = mDelegates.get(e).onInterceptTouchEvent(rv, e); 81 82 // Forward all events to UserInputHandler. 83 // This is necessary since UserInputHandler needs to always see the first DOWN event. Or 84 // else all future UP events will be tossed. 85 handled |= mDetector.onTouchEvent(e); 86 87 return handled; 88 } 89 90 @Override 91 public void onTouchEvent(RecyclerView rv, MotionEvent e) { 92 mDelegates.get(e).onTouchEvent(rv, e); 93 94 // Note: even though this event is being handled as part of gestures such as drag and band, 95 // continue forwarding to the GestureDetector. The detector needs to see the entire cluster 96 // of events in order to properly interpret other gestures, such as long press. 97 mDetector.onTouchEvent(e); 98 } 99 100 @Override 101 public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {} 102 } 103