1 /* 2 * Copyright (C) 2013 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 android.view.InputChannel; 20 import android.view.InputDevice; 21 import android.view.InputEvent; 22 import android.view.InputEventReceiver; 23 import android.view.MotionEvent; 24 import android.view.WindowManagerPolicyConstants.PointerEventListener; 25 26 import com.android.server.UiThread; 27 28 import java.util.ArrayList; 29 30 public class PointerEventDispatcher extends InputEventReceiver { 31 private final InputChannel mInputChannel; 32 private final ArrayList<PointerEventListener> mListeners = new ArrayList<>(); 33 private PointerEventListener[] mListenersArray = new PointerEventListener[0]; 34 PointerEventDispatcher(InputChannel inputChannel)35 public PointerEventDispatcher(InputChannel inputChannel) { 36 super(inputChannel, UiThread.getHandler().getLooper()); 37 mInputChannel = inputChannel; 38 } 39 40 @Override onInputEvent(InputEvent event)41 public void onInputEvent(InputEvent event) { 42 try { 43 if (event instanceof MotionEvent 44 && (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) { 45 final MotionEvent motionEvent = (MotionEvent) event; 46 PointerEventListener[] listeners; 47 synchronized (mListeners) { 48 if (mListenersArray == null) { 49 mListenersArray = new PointerEventListener[mListeners.size()]; 50 mListeners.toArray(mListenersArray); 51 } 52 listeners = mListenersArray; 53 } 54 for (int i = 0; i < listeners.length; ++i) { 55 listeners[i].onPointerEvent(motionEvent); 56 } 57 } 58 } finally { 59 finishInputEvent(event, false); 60 } 61 } 62 63 /** 64 * Add the specified listener to the list. 65 * @param listener The listener to add. 66 */ registerInputEventListener(PointerEventListener listener)67 public void registerInputEventListener(PointerEventListener listener) { 68 synchronized (mListeners) { 69 if (mListeners.contains(listener)) { 70 throw new IllegalStateException("registerInputEventListener: trying to register" + 71 listener + " twice."); 72 } 73 mListeners.add(listener); 74 mListenersArray = null; 75 } 76 } 77 78 /** 79 * Remove the specified listener from the list. 80 * @param listener The listener to remove. 81 */ unregisterInputEventListener(PointerEventListener listener)82 public void unregisterInputEventListener(PointerEventListener listener) { 83 synchronized (mListeners) { 84 if (!mListeners.contains(listener)) { 85 throw new IllegalStateException("registerInputEventListener: " + listener + 86 " not registered."); 87 } 88 mListeners.remove(listener); 89 mListenersArray = null; 90 } 91 } 92 93 /** Dispose the associated input channel and clean up the listeners. */ 94 @Override dispose()95 public void dispose() { 96 super.dispose(); 97 mInputChannel.dispose(); 98 synchronized (mListeners) { 99 mListeners.clear(); 100 mListenersArray = null; 101 } 102 } 103 } 104