First stab at attaching native event dispatching.

Provides the basic infrastructure for a
NativeActivity's native code to get an object representing
its event stream that can be used to read input events.

Still work to do, probably some API changes, and reasonable
default key handling (so that for example back will still
work).

Change-Id: I6db891bc35dc9683181d7708eaed552b955a077e
This commit is contained in:
Dianne Hackborn
2010-06-18 18:09:33 -07:00
parent ef730e6ece
commit a95e4cb62f
19 changed files with 606 additions and 175 deletions

View File

@@ -26306,6 +26306,8 @@
deprecated="not deprecated"
visibility="public"
>
<implements name="android.view.InputConsumer.Callback">
</implements>
<implements name="android.view.SurfaceHolder.Callback">
</implements>
<constructor name="NativeActivity"
@@ -26316,6 +26318,32 @@
visibility="public"
>
</constructor>
<method name="onInputConsumerCreated"
return="void"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="consumer" type="android.view.InputConsumer">
</parameter>
</method>
<method name="onInputConsumerDestroyed"
return="void"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="consumer" type="android.view.InputConsumer">
</parameter>
</method>
<method name="surfaceChanged"
return="void"
abstract="false"
@@ -172813,6 +172841,49 @@
</parameter>
</constructor>
</class>
<class name="InputConsumer"
extends="java.lang.Object"
abstract="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
</class>
<interface name="InputConsumer.Callback"
abstract="true"
static="true"
final="false"
deprecated="not deprecated"
visibility="public"
>
<method name="onInputConsumerCreated"
return="void"
abstract="true"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="consumer" type="android.view.InputConsumer">
</parameter>
</method>
<method name="onInputConsumerDestroyed"
return="void"
abstract="true"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="consumer" type="android.view.InputConsumer">
</parameter>
</method>
</interface>
<class name="KeyCharacterMap"
extends="java.lang.Object"
abstract="false"
@@ -187266,6 +187337,19 @@
<parameter name="event" type="android.view.MotionEvent">
</parameter>
</method>
<method name="takeInputChannel"
return="void"
abstract="true"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="callback" type="android.view.InputConsumer.Callback">
</parameter>
</method>
<method name="takeKeyEvents"
return="void"
abstract="true"

View File

@@ -6,6 +6,8 @@ import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.view.InputChannel;
import android.view.InputConsumer;
import android.view.SurfaceHolder;
import java.io.File;
@@ -14,7 +16,8 @@ import java.io.File;
* Convenience for implementing an activity that will be implemented
* purely in native code. That is, a game (or game-like thing).
*/
public class NativeActivity extends Activity implements SurfaceHolder.Callback {
public class NativeActivity extends Activity implements SurfaceHolder.Callback,
InputConsumer.Callback {
public static final String META_DATA_LIB_NAME = "android.app.lib_name";
private int mNativeHandle;
@@ -33,6 +36,8 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback {
private native void onSurfaceChangedNative(int handle, SurfaceHolder holder,
int format, int width, int height);
private native void onSurfaceDestroyedNative(int handle, SurfaceHolder holder);
private native void onInputChannelCreatedNative(int handle, InputChannel channel);
private native void onInputChannelDestroyedNative(int handle, InputChannel channel);
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -40,6 +45,7 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback {
ActivityInfo ai;
getWindow().takeSurface(this);
getWindow().takeInputChannel(this);
try {
ai = getPackageManager().getActivityInfo(
@@ -138,4 +144,12 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback {
public void surfaceDestroyed(SurfaceHolder holder) {
onSurfaceDestroyedNative(mNativeHandle, holder);
}
public void onInputConsumerCreated(InputConsumer consumer) {
onInputChannelCreatedNative(mNativeHandle, consumer.getInputChannel());
}
public void onInputConsumerDestroyed(InputConsumer consumer) {
onInputChannelDestroyedNative(mNativeHandle, consumer.getInputChannel());
}
}

View File

@@ -22,8 +22,9 @@ import android.util.Slog;
/**
* An input channel specifies the file descriptors used to send input events to
* a window in another process. It is Parcelable so that it can be transmitted
* to the ViewRoot through a Binder transaction as part of registering the Window.
* a window in another process. It is Parcelable so that it can be sent
* to the process that is to receive events. Only one thread should be reading
* from an InputChannel at a time.
* @hide
*/
public final class InputChannel implements Parcelable {

View File

@@ -0,0 +1,39 @@
/*
* Copyright (C) 2010 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 android.view;
/**
* Handle for consuming raw input events.
*/
public class InputConsumer {
public static interface Callback {
void onInputConsumerCreated(InputConsumer consumer);
void onInputConsumerDestroyed(InputConsumer consumer);
}
final InputChannel mChannel;
/** @hide */
public InputConsumer(InputChannel channel) {
mChannel = channel;
}
/** @hide */
public InputChannel getInputChannel() {
return mChannel;
}
}

View File

@@ -154,7 +154,9 @@ public final class ViewRoot extends Handler implements ViewParent,
final View.AttachInfo mAttachInfo;
InputChannel mInputChannel;
InputConsumer.Callback mInputConsumerCallback;
InputConsumer mInputConsumer;
final Rect mTempRect; // used in the transaction to not thrash the heap.
final Rect mVisRect; // used to retrieve visible rect of focused view.
@@ -555,8 +557,17 @@ public final class ViewRoot extends Handler implements ViewParent,
}
if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
InputQueue.registerInputChannel(mInputChannel, mInputHandler,
Looper.myQueue());
if (view instanceof RootViewSurfaceTaker) {
mInputConsumerCallback =
((RootViewSurfaceTaker)view).willYouTakeTheInputConsumer();
}
if (mInputConsumerCallback != null) {
mInputConsumer = new InputConsumer(mInputChannel);
mInputConsumerCallback.onInputConsumerCreated(mInputConsumer);
} else {
InputQueue.registerInputChannel(mInputChannel, mInputHandler,
Looper.myQueue());
}
}
view.assignParent(this);
@@ -1736,7 +1747,12 @@ public final class ViewRoot extends Handler implements ViewParent,
if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
if (mInputChannel != null) {
InputQueue.unregisterInputChannel(mInputChannel);
if (mInputConsumerCallback != null) {
mInputConsumerCallback.onInputConsumerDestroyed(mInputConsumer);
mInputConsumerCallback = null;
} else {
InputQueue.unregisterInputChannel(mInputChannel);
}
mInputChannel.dispose();
mInputChannel = null;
}

View File

@@ -480,6 +480,13 @@ public abstract class Window {
*/
public abstract void takeSurface(SurfaceHolder.Callback callback);
/**
* Take ownership of this window's InputChannel. The window will no
* longer read and dispatch input events from the channel; it is your
* responsibility to do so.
*/
public abstract void takeInputChannel(InputConsumer.Callback callback);
/**
* Return whether this window is being displayed with a floating style
* (based on the {@link android.R.attr#windowIsFloating} attribute in

View File

@@ -1,5 +1,6 @@
package com.android.internal.view;
import android.view.InputConsumer;
import android.view.SurfaceHolder;
/** hahahah */
@@ -8,4 +9,5 @@ public interface RootViewSurfaceTaker {
void setSurfaceType(int type);
void setSurfaceFormat(int format);
void setSurfaceKeepScreenOn(boolean keepOn);
InputConsumer.Callback willYouTakeTheInputConsumer();
}

View File

@@ -18,8 +18,10 @@
#include <utils/Log.h>
#include "JNIHelp.h"
#include "android_view_InputChannel.h"
#include <android_runtime/AndroidRuntime.h>
#include <android/native_activity.h>
#include <ui/InputTransport.h>
#include <dlfcn.h>
@@ -33,9 +35,13 @@ struct NativeCode {
dlhandle = _dlhandle;
createActivityFunc = _createFunc;
surface = NULL;
inputChannel = NULL;
nativeInputQueue = NULL;
}
~NativeCode() {
setSurface(NULL);
setInputChannel(NULL);
if (callbacks.onDestroy != NULL) {
callbacks.onDestroy(&activity);
}
@@ -55,6 +61,31 @@ struct NativeCode {
}
}
status_t setInputChannel(jobject _channel) {
if (inputChannel != NULL) {
delete nativeInputQueue;
activity.env->DeleteGlobalRef(inputChannel);
}
inputChannel = NULL;
nativeInputQueue = NULL;
if (_channel != NULL) {
inputChannel = activity.env->NewGlobalRef(_channel);
sp<InputChannel> ic =
android_view_InputChannel_getInputChannel(activity.env, _channel);
if (ic != NULL) {
nativeInputQueue = new input_queue_t(ic);
if (nativeInputQueue->getConsumer().initialize() != android::OK) {
delete nativeInputQueue;
nativeInputQueue = NULL;
return UNKNOWN_ERROR;
}
} else {
return UNKNOWN_ERROR;
}
}
return OK;
}
android_activity_t activity;
android_activity_callbacks_t callbacks;
@@ -62,6 +93,8 @@ struct NativeCode {
android_activity_create_t* createActivityFunc;
jobject surface;
jobject inputChannel;
struct input_queue_t* nativeInputQueue;
};
static jint
@@ -217,6 +250,38 @@ onSurfaceDestroyed_native(JNIEnv* env, jobject clazz, jint handle, jobject surfa
}
}
static void
onInputChannelCreated_native(JNIEnv* env, jobject clazz, jint handle, jobject channel)
{
if (handle != 0) {
NativeCode* code = (NativeCode*)handle;
status_t err = code->setInputChannel(channel);
if (err != OK) {
jniThrowException(env, "java/lang/IllegalStateException",
"Error setting input channel");
return;
}
if (code->callbacks.onInputQueueCreated != NULL) {
code->callbacks.onInputQueueCreated(&code->activity,
code->nativeInputQueue);
}
}
}
static void
onInputChannelDestroyed_native(JNIEnv* env, jobject clazz, jint handle, jobject channel)
{
if (handle != 0) {
NativeCode* code = (NativeCode*)handle;
if (code->nativeInputQueue != NULL
&& code->callbacks.onInputQueueDestroyed != NULL) {
code->callbacks.onInputQueueDestroyed(&code->activity,
code->nativeInputQueue);
}
code->setInputChannel(NULL);
}
}
static const JNINativeMethod g_methods[] = {
{ "loadNativeCode", "(Ljava/lang/String;)I", (void*)loadNativeCode_native },
{ "unloadNativeCode", "(I)V", (void*)unloadNativeCode_native },
@@ -230,6 +295,8 @@ static const JNINativeMethod g_methods[] = {
{ "onSurfaceCreatedNative", "(ILandroid/view/SurfaceHolder;)V", (void*)onSurfaceCreated_native },
{ "onSurfaceChangedNative", "(ILandroid/view/SurfaceHolder;III)V", (void*)onSurfaceChanged_native },
{ "onSurfaceDestroyedNative", "(ILandroid/view/SurfaceHolder;)V", (void*)onSurfaceDestroyed_native },
{ "onInputChannelCreatedNative", "(ILandroid/view/InputChannel;)V", (void*)onInputChannelCreated_native },
{ "onInputChannelDestroyedNative", "(ILandroid/view/InputChannel;)V", (void*)onInputChannelDestroyed_native },
};
static const char* const kNativeActivityPathName = "android/app/NativeActivity";
@@ -248,4 +315,4 @@ int register_android_app_NativeActivity(JNIEnv* env)
g_methods, NELEM(g_methods));
}
}
} // namespace android

View File

@@ -19,9 +19,9 @@
#include "jni.h"
namespace android {
#include <ui/InputTransport.h>
class InputChannel;
namespace android {
typedef void (*InputChannelObjDisposeCallback)(JNIEnv* env, jobject inputChannelObj,
const sp<InputChannel>& inputChannel, void* data);

View File

@@ -40,6 +40,11 @@ enum {
*/
#define MAX_POINTERS 10
/*
* Declare a concrete type for the NDK's input event forward declaration.
*/
struct input_event_t { };
namespace android {
/*
@@ -128,8 +133,6 @@ struct PointerCoords {
/*
* Input events.
*/
struct input_event_t { };
class InputEvent : public input_event_t {
public:
virtual ~InputEvent() { }

View File

@@ -330,4 +330,24 @@ private:
} // namespace android
/*
* NDK input queue API.
*/
struct input_queue_t {
public:
/* Creates a consumer associated with an input channel. */
explicit input_queue_t(const android::sp<android::InputChannel>& channel);
/* Destroys the consumer and releases its input channel. */
~input_queue_t();
inline android::InputConsumer& getConsumer() { return mConsumer; }
android::status_t consume(android::InputEvent** event);
private:
android::InputConsumer mConsumer;
android::PreallocatedInputEventFactory mInputEventFactory;
};
#endif // _UI_INPUT_TRANSPORT_H

View File

@@ -88,166 +88,3 @@ void MotionEvent::offsetLocation(float xOffset, float yOffset) {
}
} // namespace android
// NDK APIs
using android::InputEvent;
using android::KeyEvent;
using android::MotionEvent;
int32_t input_event_get_type(const input_event_t* event) {
return reinterpret_cast<const InputEvent*>(event)->getType();
}
int32_t input_event_get_device_id(const input_event_t* event) {
return reinterpret_cast<const InputEvent*>(event)->getDeviceId();
}
int32_t input_event_get_nature(const input_event_t* event) {
return reinterpret_cast<const InputEvent*>(event)->getNature();
}
int32_t key_event_get_action(const input_event_t* key_event) {
return reinterpret_cast<const KeyEvent*>(key_event)->getAction();
}
int32_t key_event_get_flags(const input_event_t* key_event) {
return reinterpret_cast<const KeyEvent*>(key_event)->getFlags();
}
int32_t key_event_get_key_code(const input_event_t* key_event) {
return reinterpret_cast<const KeyEvent*>(key_event)->getKeyCode();
}
int32_t key_event_get_scan_code(const input_event_t* key_event) {
return reinterpret_cast<const KeyEvent*>(key_event)->getScanCode();
}
int32_t key_event_get_meta_state(const input_event_t* key_event) {
return reinterpret_cast<const KeyEvent*>(key_event)->getMetaState();
}
int32_t key_event_get_repeat_count(const input_event_t* key_event) {
return reinterpret_cast<const KeyEvent*>(key_event)->getRepeatCount();
}
int64_t key_event_get_down_time(const input_event_t* key_event) {
return reinterpret_cast<const KeyEvent*>(key_event)->getDownTime();
}
int64_t key_event_get_event_time(const input_event_t* key_event) {
return reinterpret_cast<const KeyEvent*>(key_event)->getEventTime();
}
int32_t motion_event_get_action(const input_event_t* motion_event) {
return reinterpret_cast<const MotionEvent*>(motion_event)->getAction();
}
int32_t motion_event_get_meta_state(const input_event_t* motion_event) {
return reinterpret_cast<const MotionEvent*>(motion_event)->getMetaState();
}
int32_t motion_event_get_edge_flags(const input_event_t* motion_event) {
return reinterpret_cast<const MotionEvent*>(motion_event)->getEdgeFlags();
}
int64_t motion_event_get_down_time(const input_event_t* motion_event) {
return reinterpret_cast<const MotionEvent*>(motion_event)->getDownTime();
}
int64_t motion_event_get_event_time(const input_event_t* motion_event) {
return reinterpret_cast<const MotionEvent*>(motion_event)->getEventTime();
}
float motion_event_get_x_offset(const input_event_t* motion_event) {
return reinterpret_cast<const MotionEvent*>(motion_event)->getXOffset();
}
float motion_event_get_y_offset(const input_event_t* motion_event) {
return reinterpret_cast<const MotionEvent*>(motion_event)->getYOffset();
}
float motion_event_get_x_precision(const input_event_t* motion_event) {
return reinterpret_cast<const MotionEvent*>(motion_event)->getXPrecision();
}
float motion_event_get_y_precision(const input_event_t* motion_event) {
return reinterpret_cast<const MotionEvent*>(motion_event)->getYPrecision();
}
size_t motion_event_get_pointer_count(const input_event_t* motion_event) {
return reinterpret_cast<const MotionEvent*>(motion_event)->getPointerCount();
}
int32_t motion_event_get_pointer_id(const input_event_t* motion_event, size_t pointer_index) {
return reinterpret_cast<const MotionEvent*>(motion_event)->getPointerId(pointer_index);
}
float motion_event_get_raw_x(const input_event_t* motion_event, size_t pointer_index) {
return reinterpret_cast<const MotionEvent*>(motion_event)->getRawX(pointer_index);
}
float motion_event_get_raw_y(const input_event_t* motion_event, size_t pointer_index) {
return reinterpret_cast<const MotionEvent*>(motion_event)->getRawY(pointer_index);
}
float motion_event_get_x(const input_event_t* motion_event, size_t pointer_index) {
return reinterpret_cast<const MotionEvent*>(motion_event)->getX(pointer_index);
}
float motion_event_get_y(const input_event_t* motion_event, size_t pointer_index) {
return reinterpret_cast<const MotionEvent*>(motion_event)->getY(pointer_index);
}
float motion_event_get_pressure(const input_event_t* motion_event, size_t pointer_index) {
return reinterpret_cast<const MotionEvent*>(motion_event)->getPressure(pointer_index);
}
float motion_event_get_size(const input_event_t* motion_event, size_t pointer_index) {
return reinterpret_cast<const MotionEvent*>(motion_event)->getSize(pointer_index);
}
size_t motion_event_get_history_size(const input_event_t* motion_event) {
return reinterpret_cast<const MotionEvent*>(motion_event)->getHistorySize();
}
int64_t motion_event_get_historical_event_time(input_event_t* motion_event,
size_t history_index) {
return reinterpret_cast<const MotionEvent*>(motion_event)->getHistoricalEventTime(
history_index);
}
float motion_event_get_historical_raw_x(input_event_t* motion_event, size_t pointer_index,
size_t history_index) {
return reinterpret_cast<const MotionEvent*>(motion_event)->getHistoricalRawX(
pointer_index, history_index);
}
float motion_event_get_historical_raw_y(input_event_t* motion_event, size_t pointer_index,
size_t history_index) {
return reinterpret_cast<const MotionEvent*>(motion_event)->getHistoricalRawY(
pointer_index, history_index);
}
float motion_event_get_historical_x(input_event_t* motion_event, size_t pointer_index,
size_t history_index) {
return reinterpret_cast<const MotionEvent*>(motion_event)->getHistoricalX(
pointer_index, history_index);
}
float motion_event_get_historical_y(input_event_t* motion_event, size_t pointer_index,
size_t history_index) {
return reinterpret_cast<const MotionEvent*>(motion_event)->getHistoricalY(
pointer_index, history_index);
}
float motion_event_get_historical_pressure(input_event_t* motion_event, size_t pointer_index,
size_t history_index) {
return reinterpret_cast<const MotionEvent*>(motion_event)->getHistoricalPressure(
pointer_index, history_index);
}
float motion_event_get_historical_size(input_event_t* motion_event, size_t pointer_index,
size_t history_index) {
return reinterpret_cast<const MotionEvent*>(motion_event)->getHistoricalSize(
pointer_index, history_index);
}

View File

@@ -686,3 +686,22 @@ void InputConsumer::populateMotionEvent(MotionEvent* motionEvent) const {
}
} // namespace android
// --- input_queue_t ---
using android::InputEvent;
using android::InputChannel;
using android::InputConsumer;
using android::sp;
using android::status_t;
input_queue_t::input_queue_t(const sp<InputChannel>& channel) :
mConsumer(channel) {
}
input_queue_t::~input_queue_t() {
}
status_t input_queue_t::consume(InputEvent** event) {
return mConsumer.consume(&mInputEventFactory, event);
}

26
native/android/Android.mk Normal file
View File

@@ -0,0 +1,26 @@
BASE_PATH := $(call my-dir)
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
# our source files
#
LOCAL_SRC_FILES:= \
activity.cpp \
input.cpp
LOCAL_SHARED_LIBRARIES := \
libandroid_runtime \
libcutils \
libutils \
libbinder \
libui
LOCAL_C_INCLUDES += \
frameworks/base/native/include \
frameworks/base/core/jni/android \
dalvik/libnativehelper/include/nativehelper
LOCAL_MODULE:= libandroid
include $(BUILD_SHARED_LIBRARY)

View File

233
native/android/input.cpp Normal file
View File

@@ -0,0 +1,233 @@
/*
* Copyright (C) 2009 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.
*/
#define LOG_TAG "input"
#include <utils/Log.h>
#include <android/input.h>
#include <ui/Input.h>
#include <ui/InputTransport.h>
#include <poll.h>
using android::InputEvent;
using android::KeyEvent;
using android::MotionEvent;
int32_t input_event_get_type(const input_event_t* event) {
return static_cast<const InputEvent*>(event)->getType();
}
int32_t input_event_get_device_id(const input_event_t* event) {
return static_cast<const InputEvent*>(event)->getDeviceId();
}
int32_t input_event_get_nature(const input_event_t* event) {
return static_cast<const InputEvent*>(event)->getNature();
}
int32_t key_event_get_action(const input_event_t* key_event) {
return static_cast<const KeyEvent*>(key_event)->getAction();
}
int32_t key_event_get_flags(const input_event_t* key_event) {
return static_cast<const KeyEvent*>(key_event)->getFlags();
}
int32_t key_event_get_key_code(const input_event_t* key_event) {
return static_cast<const KeyEvent*>(key_event)->getKeyCode();
}
int32_t key_event_get_scan_code(const input_event_t* key_event) {
return static_cast<const KeyEvent*>(key_event)->getScanCode();
}
int32_t key_event_get_meta_state(const input_event_t* key_event) {
return static_cast<const KeyEvent*>(key_event)->getMetaState();
}
int32_t key_event_get_repeat_count(const input_event_t* key_event) {
return static_cast<const KeyEvent*>(key_event)->getRepeatCount();
}
int64_t key_event_get_down_time(const input_event_t* key_event) {
return static_cast<const KeyEvent*>(key_event)->getDownTime();
}
int64_t key_event_get_event_time(const input_event_t* key_event) {
return static_cast<const KeyEvent*>(key_event)->getEventTime();
}
int32_t motion_event_get_action(const input_event_t* motion_event) {
return static_cast<const MotionEvent*>(motion_event)->getAction();
}
int32_t motion_event_get_meta_state(const input_event_t* motion_event) {
return static_cast<const MotionEvent*>(motion_event)->getMetaState();
}
int32_t motion_event_get_edge_flags(const input_event_t* motion_event) {
return reinterpret_cast<const MotionEvent*>(motion_event)->getEdgeFlags();
}
int64_t motion_event_get_down_time(const input_event_t* motion_event) {
return static_cast<const MotionEvent*>(motion_event)->getDownTime();
}
int64_t motion_event_get_event_time(const input_event_t* motion_event) {
return static_cast<const MotionEvent*>(motion_event)->getEventTime();
}
float motion_event_get_x_offset(const input_event_t* motion_event) {
return static_cast<const MotionEvent*>(motion_event)->getXOffset();
}
float motion_event_get_y_offset(const input_event_t* motion_event) {
return static_cast<const MotionEvent*>(motion_event)->getYOffset();
}
float motion_event_get_x_precision(const input_event_t* motion_event) {
return static_cast<const MotionEvent*>(motion_event)->getXPrecision();
}
float motion_event_get_y_precision(const input_event_t* motion_event) {
return static_cast<const MotionEvent*>(motion_event)->getYPrecision();
}
size_t motion_event_get_pointer_count(const input_event_t* motion_event) {
return static_cast<const MotionEvent*>(motion_event)->getPointerCount();
}
int32_t motion_event_get_pointer_id(const input_event_t* motion_event, size_t pointer_index) {
return static_cast<const MotionEvent*>(motion_event)->getPointerId(pointer_index);
}
float motion_event_get_raw_x(const input_event_t* motion_event, size_t pointer_index) {
return static_cast<const MotionEvent*>(motion_event)->getRawX(pointer_index);
}
float motion_event_get_raw_y(const input_event_t* motion_event, size_t pointer_index) {
return static_cast<const MotionEvent*>(motion_event)->getRawY(pointer_index);
}
float motion_event_get_x(const input_event_t* motion_event, size_t pointer_index) {
return static_cast<const MotionEvent*>(motion_event)->getX(pointer_index);
}
float motion_event_get_y(const input_event_t* motion_event, size_t pointer_index) {
return static_cast<const MotionEvent*>(motion_event)->getY(pointer_index);
}
float motion_event_get_pressure(const input_event_t* motion_event, size_t pointer_index) {
return static_cast<const MotionEvent*>(motion_event)->getPressure(pointer_index);
}
float motion_event_get_size(const input_event_t* motion_event, size_t pointer_index) {
return static_cast<const MotionEvent*>(motion_event)->getSize(pointer_index);
}
size_t motion_event_get_history_size(const input_event_t* motion_event) {
return static_cast<const MotionEvent*>(motion_event)->getHistorySize();
}
int64_t motion_event_get_historical_event_time(input_event_t* motion_event,
size_t history_index) {
return static_cast<const MotionEvent*>(motion_event)->getHistoricalEventTime(
history_index);
}
float motion_event_get_historical_raw_x(input_event_t* motion_event, size_t pointer_index,
size_t history_index) {
return static_cast<const MotionEvent*>(motion_event)->getHistoricalRawX(
pointer_index, history_index);
}
float motion_event_get_historical_raw_y(input_event_t* motion_event, size_t pointer_index,
size_t history_index) {
return static_cast<const MotionEvent*>(motion_event)->getHistoricalRawY(
pointer_index, history_index);
}
float motion_event_get_historical_x(input_event_t* motion_event, size_t pointer_index,
size_t history_index) {
return static_cast<const MotionEvent*>(motion_event)->getHistoricalX(
pointer_index, history_index);
}
float motion_event_get_historical_y(input_event_t* motion_event, size_t pointer_index,
size_t history_index) {
return static_cast<const MotionEvent*>(motion_event)->getHistoricalY(
pointer_index, history_index);
}
float motion_event_get_historical_pressure(input_event_t* motion_event, size_t pointer_index,
size_t history_index) {
return static_cast<const MotionEvent*>(motion_event)->getHistoricalPressure(
pointer_index, history_index);
}
float motion_event_get_historical_size(input_event_t* motion_event, size_t pointer_index,
size_t history_index) {
return static_cast<const MotionEvent*>(motion_event)->getHistoricalSize(
pointer_index, history_index);
}
int input_queue_get_fd(input_queue_t* queue) {
return queue->getConsumer().getChannel()->getReceivePipeFd();
}
int input_queue_has_events(input_queue_t* queue) {
struct pollfd pfd;
pfd.fd = queue->getConsumer().getChannel()->getReceivePipeFd();
pfd.events = POLLIN;
pfd.revents = 0;
int nfd = poll(&pfd, 1, 0);
if (nfd <= 0) return nfd;
return pfd.revents == POLLIN ? 1 : -1;
}
int32_t input_queue_get_event(input_queue_t* queue, input_event_t** outEvent) {
*outEvent = NULL;
int32_t res = queue->getConsumer().receiveDispatchSignal();
if (res != android::OK) {
LOGE("channel '%s' ~ Failed to receive dispatch signal. status=%d",
queue->getConsumer().getChannel()->getName().string(), res);
return -1;
}
InputEvent* myEvent = NULL;
res = queue->consume(&myEvent);
if (res != android::OK) {
LOGW("channel '%s' ~ Failed to consume input event. status=%d",
queue->getConsumer().getChannel()->getName().string(), res);
queue->getConsumer().sendFinishedSignal();
return -1;
}
*outEvent = myEvent;
return 0;
}
void input_queue_finish_event(input_queue_t* queue, input_event_t* event,
int handled) {
int32_t res = queue->getConsumer().sendFinishedSignal();
if (res != android::OK) {
LOGW("Failed to send finished signal on channel '%s'. status=%d",
queue->getConsumer().getChannel()->getName().string(), res);
}
}

View File

@@ -523,6 +523,42 @@ float motion_event_get_historical_pressure(input_event_t* motion_event, size_t p
float motion_event_get_historical_size(input_event_t* motion_event, size_t pointer_index,
size_t history_index);
/*
* Input queue
*
* An input queue is the facility through which you retrieve input
* events.
*/
struct input_queue_t;
typedef struct input_queue_t input_queue_t;
/*
* Return a file descriptor for the queue, which you
* can use to determine if there are events available. This
* is typically used with select() or poll() to multiplex
* with other kinds of events.
*/
int input_queue_get_fd(input_queue_t* queue);
/*
* Returns true if there are one or more events available in the
* input queue. Returns 1 if the queue has events; 0 if
* it does not have events; and a negative value if there is an error.
*/
int input_queue_has_events(input_queue_t* queue);
/*
* Returns the next available event from the queue. Returns a negative
* value if no events are available or an error has occurred.
*/
int32_t input_queue_get_event(input_queue_t* queue, input_event_t** outEvent);
/*
* Report that dispatching has finished with the given event.
* This must be called after receiving an event with input_queue_get_event().
*/
void input_queue_finish_event(input_queue_t* queue, input_event_t* event, int handled);
#ifdef __cplusplus
}
#endif

View File

@@ -23,6 +23,8 @@
#include <jni.h>
#include <android/input.h>
#ifdef __cplusplus
extern "C" {
#endif
@@ -144,6 +146,19 @@ typedef struct android_activity_callbacks_t {
* returning from here.
*/
void (*onSurfaceDestroyed)(android_activity_t* activity, android_surface_t* surface);
/**
* The input queue for this native activity's window has been created.
* You can use the given input queue to start retrieving input events.
*/
void (*onInputQueueCreated)(android_activity_t* activity, input_queue_t* queue);
/**
* The input queue for this native activity's window is being destroyed.
* You should no longer try to reference this object upon returning from this
* function.
*/
void (*onInputQueueDestroyed)(android_activity_t* activity, input_queue_t* queue);
/**
* The system is running low on memory. Use this callback to release

View File

@@ -56,6 +56,7 @@ import android.util.Log;
import android.util.SparseArray;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
import android.view.InputConsumer;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@@ -70,6 +71,7 @@ import android.view.ViewManager;
import android.view.VolumePanel;
import android.view.Window;
import android.view.WindowManager;
import android.view.InputConsumer.Callback;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.animation.Animation;
@@ -108,6 +110,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
SurfaceHolder.Callback mTakeSurfaceCallback;
BaseSurfaceHolder mSurfaceHolder;
InputConsumer.Callback mTakeInputChannelCallback;
private boolean mIsFloating;
private LayoutInflater mLayoutInflater;
@@ -251,6 +255,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
mTakeSurfaceCallback = callback;
}
public void takeInputChannel(InputConsumer.Callback callback) {
mTakeInputChannelCallback = callback;
}
@Override
public boolean isFloating() {
return mIsFloating;
@@ -2037,6 +2045,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
return mFeatureId < 0 ? mTakeSurfaceCallback : null;
}
public InputConsumer.Callback willYouTakeTheInputConsumer() {
return mFeatureId < 0 ? mTakeInputChannelCallback : null;
}
public void setSurfaceType(int type) {
PhoneWindow.this.setType(type);
}