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