1 /* 2 * Copyright (C) 2017 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.server.wm; 18 19 import static android.view.InputDevice.SOURCE_CLASS_POINTER; 20 import static android.view.MotionEvent.ACTION_CANCEL; 21 import static android.view.MotionEvent.ACTION_DOWN; 22 import static android.view.MotionEvent.ACTION_MOVE; 23 import static android.view.MotionEvent.ACTION_UP; 24 import static android.view.MotionEvent.BUTTON_STYLUS_PRIMARY; 25 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG; 26 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 27 28 import android.os.Looper; 29 import android.util.Slog; 30 import android.view.InputChannel; 31 import android.view.InputDevice; 32 import android.view.InputEvent; 33 import android.view.InputEventReceiver; 34 import android.view.MotionEvent; 35 36 /** 37 * Input receiver for drag and drop 38 */ 39 class DragInputEventReceiver extends InputEventReceiver { 40 private final DragDropController mDragDropController; 41 42 // Set, if stylus button was down at the start of the drag. 43 private boolean mStylusButtonDownAtStart; 44 // Indicates the first event to check for button state. 45 private boolean mIsStartEvent = true; 46 // Set to true to ignore input events after the drag gesture is complete but the drag events 47 // are still being dispatched. 48 private boolean mMuteInput = false; 49 50 DragInputEventReceiver(InputChannel inputChannel, Looper looper, 51 DragDropController controller) { 52 super(inputChannel, looper); 53 mDragDropController = controller; 54 } 55 56 @Override 57 public void onInputEvent(InputEvent event, int displayId) { 58 boolean handled = false; 59 try { 60 if (!(event instanceof MotionEvent) 61 || (event.getSource() & SOURCE_CLASS_POINTER) == 0 62 || mMuteInput) { 63 return; 64 } 65 final MotionEvent motionEvent = (MotionEvent) event; 66 final float newX = motionEvent.getRawX(); 67 final float newY = motionEvent.getRawY(); 68 final boolean isStylusButtonDown = 69 (motionEvent.getButtonState() & BUTTON_STYLUS_PRIMARY) != 0; 70 71 if (mIsStartEvent) { 72 // First event and the button was down, check for the button being 73 // lifted in the future, if that happens we'll drop the item. 74 mStylusButtonDownAtStart = isStylusButtonDown; 75 mIsStartEvent = false; 76 } 77 78 switch (motionEvent.getAction()) { 79 case ACTION_DOWN: 80 if (DEBUG_DRAG) Slog.w(TAG_WM, "Unexpected ACTION_DOWN in drag layer"); 81 return; 82 case ACTION_MOVE: 83 if (mStylusButtonDownAtStart && !isStylusButtonDown) { 84 if (DEBUG_DRAG) { 85 Slog.d(TAG_WM, "Button no longer pressed; dropping at " + newX + "," 86 + newY); 87 } 88 mMuteInput = true; 89 } 90 break; 91 case ACTION_UP: 92 if (DEBUG_DRAG) { 93 Slog.d(TAG_WM, "Got UP on move channel; dropping at " + newX + "," + newY); 94 } 95 mMuteInput = true; 96 break; 97 case ACTION_CANCEL: 98 if (DEBUG_DRAG) Slog.d(TAG_WM, "Drag cancelled!"); 99 mMuteInput = true; 100 break; 101 default: 102 return; 103 } 104 105 mDragDropController.handleMotionEvent(!mMuteInput /* keepHandling */, newX, newY); 106 handled = true; 107 } catch (Exception e) { 108 Slog.e(TAG_WM, "Exception caught by drag handleMotion", e); 109 } finally { 110 finishInputEvent(event, handled); 111 } 112 } 113 } 114