210 lines
5.9 KiB
Java
210 lines
5.9 KiB
Java
/*
|
|
* Copyright (C) 2013 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package org.godotengine.godot.input;
|
|
|
|
import android.os.Handler;
|
|
import android.os.Message;
|
|
import android.os.SystemClock;
|
|
import android.util.Log;
|
|
import android.util.SparseArray;
|
|
import android.view.InputDevice;
|
|
import android.view.MotionEvent;
|
|
|
|
import java.lang.ref.WeakReference;
|
|
import java.util.ArrayDeque;
|
|
import java.util.HashMap;
|
|
import java.util.Map;
|
|
import java.util.Queue;
|
|
|
|
public class InputManagerV9 implements InputManagerCompat {
|
|
private static final String LOG_TAG = "InputManagerV9";
|
|
private static final int MESSAGE_TEST_FOR_DISCONNECT = 101;
|
|
private static final long CHECK_ELAPSED_TIME = 3000L;
|
|
|
|
private static final int ON_DEVICE_ADDED = 0;
|
|
private static final int ON_DEVICE_CHANGED = 1;
|
|
private static final int ON_DEVICE_REMOVED = 2;
|
|
|
|
private final SparseArray<long[]> mDevices;
|
|
private final Map<InputDeviceListener, Handler> mListeners;
|
|
private final Handler mDefaultHandler;
|
|
|
|
private static class PollingMessageHandler extends Handler {
|
|
private final WeakReference<InputManagerV9> mInputManager;
|
|
|
|
PollingMessageHandler(InputManagerV9 im) {
|
|
mInputManager = new WeakReference<InputManagerV9>(im);
|
|
}
|
|
|
|
@Override
|
|
public void handleMessage(Message msg) {
|
|
super.handleMessage(msg);
|
|
switch (msg.what) {
|
|
case MESSAGE_TEST_FOR_DISCONNECT:
|
|
InputManagerV9 imv = mInputManager.get();
|
|
if (null != imv) {
|
|
long time = SystemClock.elapsedRealtime();
|
|
int size = imv.mDevices.size();
|
|
for (int i = 0; i < size; i++) {
|
|
long[] lastContact = imv.mDevices.valueAt(i);
|
|
if (null != lastContact) {
|
|
if (time - lastContact[0] > CHECK_ELAPSED_TIME) {
|
|
// check to see if the device has been
|
|
// disconnected
|
|
int id = imv.mDevices.keyAt(i);
|
|
if (null == InputDevice.getDevice(id)) {
|
|
// disconnected!
|
|
imv.notifyListeners(ON_DEVICE_REMOVED, id);
|
|
imv.mDevices.remove(id);
|
|
} else {
|
|
lastContact[0] = time;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
sendEmptyMessageDelayed(MESSAGE_TEST_FOR_DISCONNECT,
|
|
CHECK_ELAPSED_TIME);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
public InputManagerV9() {
|
|
mDevices = new SparseArray<long[]>();
|
|
mListeners = new HashMap<InputDeviceListener, Handler>();
|
|
mDefaultHandler = new PollingMessageHandler(this);
|
|
// as a side-effect, populates our collection of watched
|
|
// input devices
|
|
getInputDeviceIds();
|
|
}
|
|
|
|
@Override
|
|
public InputDevice getInputDevice(int id) {
|
|
return InputDevice.getDevice(id);
|
|
}
|
|
|
|
@Override
|
|
public int[] getInputDeviceIds() {
|
|
// add any hitherto unknown devices to our
|
|
// collection of watched input devices
|
|
int[] activeDevices = InputDevice.getDeviceIds();
|
|
long time = SystemClock.elapsedRealtime();
|
|
for (int id : activeDevices) {
|
|
long[] lastContact = mDevices.get(id);
|
|
if (null == lastContact) {
|
|
// we have a new device
|
|
mDevices.put(id, new long[] { time });
|
|
}
|
|
}
|
|
return activeDevices;
|
|
}
|
|
|
|
@Override
|
|
public void registerInputDeviceListener(InputDeviceListener listener, Handler handler) {
|
|
mListeners.remove(listener);
|
|
if (handler == null) {
|
|
handler = mDefaultHandler;
|
|
}
|
|
mListeners.put(listener, handler);
|
|
}
|
|
|
|
@Override
|
|
public void unregisterInputDeviceListener(InputDeviceListener listener) {
|
|
mListeners.remove(listener);
|
|
}
|
|
|
|
private void notifyListeners(int why, int deviceId) {
|
|
// the state of some device has changed
|
|
if (!mListeners.isEmpty()) {
|
|
// yes... this will cause an object to get created... hopefully
|
|
// it won't happen very often
|
|
for (InputDeviceListener listener : mListeners.keySet()) {
|
|
Handler handler = mListeners.get(listener);
|
|
DeviceEvent odc = DeviceEvent.getDeviceEvent(why, deviceId, listener);
|
|
handler.post(odc);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static class DeviceEvent implements Runnable {
|
|
private int mMessageType;
|
|
private int mId;
|
|
private InputDeviceListener mListener;
|
|
private static Queue<DeviceEvent> sEventQueue = new ArrayDeque<DeviceEvent>();
|
|
|
|
private DeviceEvent() {
|
|
}
|
|
|
|
static DeviceEvent getDeviceEvent(int messageType, int id,
|
|
InputDeviceListener listener) {
|
|
DeviceEvent curChanged = sEventQueue.poll();
|
|
if (null == curChanged) {
|
|
curChanged = new DeviceEvent();
|
|
}
|
|
curChanged.mMessageType = messageType;
|
|
curChanged.mId = id;
|
|
curChanged.mListener = listener;
|
|
return curChanged;
|
|
}
|
|
|
|
@Override
|
|
public void run() {
|
|
switch (mMessageType) {
|
|
case ON_DEVICE_ADDED:
|
|
mListener.onInputDeviceAdded(mId);
|
|
break;
|
|
case ON_DEVICE_CHANGED:
|
|
mListener.onInputDeviceChanged(mId);
|
|
break;
|
|
case ON_DEVICE_REMOVED:
|
|
mListener.onInputDeviceRemoved(mId);
|
|
break;
|
|
default:
|
|
Log.e(LOG_TAG, "Unknown Message Type");
|
|
break;
|
|
}
|
|
// dump this runnable back in the queue
|
|
sEventQueue.offer(this);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onGenericMotionEvent(MotionEvent event) {
|
|
// detect new devices
|
|
int id = event.getDeviceId();
|
|
long[] timeArray = mDevices.get(id);
|
|
if (null == timeArray) {
|
|
notifyListeners(ON_DEVICE_ADDED, id);
|
|
timeArray = new long[1];
|
|
mDevices.put(id, timeArray);
|
|
}
|
|
long time = SystemClock.elapsedRealtime();
|
|
timeArray[0] = time;
|
|
}
|
|
|
|
@Override
|
|
public void onPause() {
|
|
mDefaultHandler.removeMessages(MESSAGE_TEST_FOR_DISCONNECT);
|
|
}
|
|
|
|
@Override
|
|
public void onResume() {
|
|
mDefaultHandler.sendEmptyMessage(MESSAGE_TEST_FOR_DISCONNECT);
|
|
}
|
|
}
|