Implement default key handling for native code.
The native code now maintains a list of all keys that may use default handling. If the app finishes one of these keys without handling it, the key will be passed back off to Java for default treatment. Change-Id: I6a842a0d728eeafa4de7142fae573f8c11099e18
This commit is contained in:
@@ -39,7 +39,6 @@ import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.RemoteException;
|
||||
import android.text.Selection;
|
||||
import android.text.SpannableStringBuilder;
|
||||
|
||||
@@ -6,9 +6,13 @@ import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.Looper;
|
||||
import android.os.MessageQueue;
|
||||
import android.view.InputChannel;
|
||||
import android.view.InputQueue;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.View;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@@ -22,7 +26,12 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback,
|
||||
|
||||
private int mNativeHandle;
|
||||
|
||||
private native int loadNativeCode(String path);
|
||||
private InputQueue mCurInputQueue;
|
||||
private SurfaceHolder mCurSurfaceHolder;
|
||||
|
||||
private boolean mDestroyed;
|
||||
|
||||
private native int loadNativeCode(String path, MessageQueue queue);
|
||||
private native void unloadNativeCode(int handle);
|
||||
|
||||
private native void onStartNative(int handle);
|
||||
@@ -78,7 +87,7 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback,
|
||||
throw new IllegalArgumentException("Unable to find native library: " + libname);
|
||||
}
|
||||
|
||||
mNativeHandle = loadNativeCode(path);
|
||||
mNativeHandle = loadNativeCode(path, Looper.myQueue());
|
||||
if (mNativeHandle == 0) {
|
||||
throw new IllegalArgumentException("Unable to load native library: " + path);
|
||||
}
|
||||
@@ -87,6 +96,15 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback,
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
mDestroyed = true;
|
||||
if (mCurSurfaceHolder != null) {
|
||||
onSurfaceDestroyedNative(mNativeHandle, mCurSurfaceHolder);
|
||||
mCurSurfaceHolder = null;
|
||||
}
|
||||
if (mCurInputQueue != null) {
|
||||
onInputChannelDestroyedNative(mNativeHandle, mCurInputQueue.getInputChannel());
|
||||
mCurInputQueue = null;
|
||||
}
|
||||
unloadNativeCode(mNativeHandle);
|
||||
super.onDestroy();
|
||||
}
|
||||
@@ -124,32 +142,58 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback,
|
||||
@Override
|
||||
public void onLowMemory() {
|
||||
super.onLowMemory();
|
||||
onLowMemoryNative(mNativeHandle);
|
||||
if (!mDestroyed) {
|
||||
onLowMemoryNative(mNativeHandle);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWindowFocusChanged(boolean hasFocus) {
|
||||
super.onWindowFocusChanged(hasFocus);
|
||||
onWindowFocusChangedNative(mNativeHandle, hasFocus);
|
||||
if (!mDestroyed) {
|
||||
onWindowFocusChangedNative(mNativeHandle, hasFocus);
|
||||
}
|
||||
}
|
||||
|
||||
public void surfaceCreated(SurfaceHolder holder) {
|
||||
onSurfaceCreatedNative(mNativeHandle, holder);
|
||||
if (!mDestroyed) {
|
||||
mCurSurfaceHolder = holder;
|
||||
onSurfaceCreatedNative(mNativeHandle, holder);
|
||||
}
|
||||
}
|
||||
|
||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
||||
onSurfaceChangedNative(mNativeHandle, holder, format, width, height);
|
||||
if (!mDestroyed) {
|
||||
mCurSurfaceHolder = holder;
|
||||
onSurfaceChangedNative(mNativeHandle, holder, format, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||
onSurfaceDestroyedNative(mNativeHandle, holder);
|
||||
mCurSurfaceHolder = null;
|
||||
if (!mDestroyed) {
|
||||
onSurfaceDestroyedNative(mNativeHandle, holder);
|
||||
}
|
||||
}
|
||||
|
||||
public void onInputQueueCreated(InputQueue queue) {
|
||||
onInputChannelCreatedNative(mNativeHandle, queue.getInputChannel());
|
||||
if (!mDestroyed) {
|
||||
mCurInputQueue = queue;
|
||||
onInputChannelCreatedNative(mNativeHandle, queue.getInputChannel());
|
||||
}
|
||||
}
|
||||
|
||||
public void onInputQueueDestroyed(InputQueue queue) {
|
||||
onInputChannelDestroyedNative(mNativeHandle, queue.getInputChannel());
|
||||
mCurInputQueue = null;
|
||||
if (!mDestroyed) {
|
||||
onInputChannelDestroyedNative(mNativeHandle, queue.getInputChannel());
|
||||
}
|
||||
}
|
||||
|
||||
void dispatchUnhandledKeyEvent(KeyEvent event) {
|
||||
View decor = getWindow().getDecorView();
|
||||
if (decor != null) {
|
||||
decor.dispatchKeyEvent(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -676,33 +676,12 @@ public class KeyEvent implements Parcelable {
|
||||
* TODO: should the dpad keys be here? arguably, because they also shouldn't be menu shortcuts
|
||||
*/
|
||||
public final boolean isSystem() {
|
||||
switch (mKeyCode) {
|
||||
case KEYCODE_MENU:
|
||||
case KEYCODE_SOFT_RIGHT:
|
||||
case KEYCODE_HOME:
|
||||
case KEYCODE_BACK:
|
||||
case KEYCODE_CALL:
|
||||
case KEYCODE_ENDCALL:
|
||||
case KEYCODE_VOLUME_UP:
|
||||
case KEYCODE_VOLUME_DOWN:
|
||||
case KEYCODE_MUTE:
|
||||
case KEYCODE_POWER:
|
||||
case KEYCODE_HEADSETHOOK:
|
||||
case KEYCODE_MEDIA_PLAY_PAUSE:
|
||||
case KEYCODE_MEDIA_STOP:
|
||||
case KEYCODE_MEDIA_NEXT:
|
||||
case KEYCODE_MEDIA_PREVIOUS:
|
||||
case KEYCODE_MEDIA_REWIND:
|
||||
case KEYCODE_MEDIA_FAST_FORWARD:
|
||||
case KEYCODE_CAMERA:
|
||||
case KEYCODE_FOCUS:
|
||||
case KEYCODE_SEARCH:
|
||||
case KEYCODE_PICTSYMBOLS:
|
||||
case KEYCODE_SWITCH_CHARSET:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return native_isSystemKey(mKeyCode);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public final boolean hasDefaultAction() {
|
||||
return native_hasDefaultAction(mKeyCode);
|
||||
}
|
||||
|
||||
|
||||
@@ -1226,4 +1205,7 @@ public class KeyEvent implements Parcelable {
|
||||
mDownTime = in.readLong();
|
||||
mEventTime = in.readLong();
|
||||
}
|
||||
|
||||
private native boolean native_isSystemKey(int keyCode);
|
||||
private native boolean native_hasDefaultAction(int keyCode);
|
||||
}
|
||||
|
||||
@@ -17,17 +17,63 @@
|
||||
#define LOG_TAG "NativeActivity"
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include "JNIHelp.h"
|
||||
#include "android_view_InputChannel.h"
|
||||
#include <poll.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include <android_runtime/AndroidRuntime.h>
|
||||
#include <android/native_activity.h>
|
||||
#include <ui/InputTransport.h>
|
||||
#include <utils/PollLoop.h>
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include "JNIHelp.h"
|
||||
#include "android_os_MessageQueue.h"
|
||||
#include "android_view_InputChannel.h"
|
||||
#include "android_view_KeyEvent.h"
|
||||
|
||||
namespace android
|
||||
{
|
||||
|
||||
static struct {
|
||||
jclass clazz;
|
||||
|
||||
jmethodID dispatchUnhandledKeyEvent;
|
||||
} gNativeActivityClassInfo;
|
||||
|
||||
struct MyInputQueue : AInputQueue {
|
||||
explicit MyInputQueue(const android::sp<android::InputChannel>& channel, int workWrite)
|
||||
: AInputQueue(channel), mWorkWrite(workWrite) {
|
||||
}
|
||||
|
||||
virtual void doDefaultKey(android::KeyEvent* keyEvent) {
|
||||
mLock.lock();
|
||||
LOGI("Default key: pending=%d write=%d\n", mPendingKeys.size(), mWorkWrite);
|
||||
if (mPendingKeys.size() <= 0 && mWorkWrite >= 0) {
|
||||
int8_t cmd = 1;
|
||||
write(mWorkWrite, &cmd, sizeof(cmd));
|
||||
}
|
||||
mPendingKeys.add(keyEvent);
|
||||
mLock.unlock();
|
||||
}
|
||||
|
||||
KeyEvent* getNextEvent() {
|
||||
KeyEvent* event = NULL;
|
||||
|
||||
mLock.lock();
|
||||
if (mPendingKeys.size() > 0) {
|
||||
event = mPendingKeys[0];
|
||||
mPendingKeys.removeAt(0);
|
||||
}
|
||||
mLock.unlock();
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
int mWorkWrite;
|
||||
|
||||
Mutex mLock;
|
||||
Vector<KeyEvent*> mPendingKeys;
|
||||
};
|
||||
|
||||
struct NativeCode {
|
||||
NativeCode(void* _dlhandle, ANativeActivity_createFunc* _createFunc) {
|
||||
memset(&activity, sizeof(activity), 0);
|
||||
@@ -37,14 +83,26 @@ struct NativeCode {
|
||||
surface = NULL;
|
||||
inputChannel = NULL;
|
||||
nativeInputQueue = NULL;
|
||||
mainWorkRead = mainWorkWrite = -1;
|
||||
}
|
||||
|
||||
~NativeCode() {
|
||||
if (activity.env != NULL && activity.clazz != NULL) {
|
||||
activity.env->DeleteGlobalRef(activity.clazz);
|
||||
}
|
||||
if (pollLoop != NULL && mainWorkRead >= 0) {
|
||||
pollLoop->removeCallback(mainWorkRead);
|
||||
}
|
||||
if (nativeInputQueue != NULL) {
|
||||
nativeInputQueue->mWorkWrite = -1;
|
||||
}
|
||||
setSurface(NULL);
|
||||
setInputChannel(NULL);
|
||||
if (callbacks.onDestroy != NULL) {
|
||||
callbacks.onDestroy(&activity);
|
||||
}
|
||||
if (mainWorkRead >= 0) close(mainWorkRead);
|
||||
if (mainWorkWrite >= 0) close(mainWorkWrite);
|
||||
if (dlhandle != NULL) {
|
||||
dlclose(dlhandle);
|
||||
}
|
||||
@@ -73,7 +131,7 @@ struct NativeCode {
|
||||
sp<InputChannel> ic =
|
||||
android_view_InputChannel_getInputChannel(activity.env, _channel);
|
||||
if (ic != NULL) {
|
||||
nativeInputQueue = new AInputQueue(ic);
|
||||
nativeInputQueue = new MyInputQueue(ic, mainWorkWrite);
|
||||
if (nativeInputQueue->getConsumer().initialize() != android::OK) {
|
||||
delete nativeInputQueue;
|
||||
nativeInputQueue = NULL;
|
||||
@@ -94,11 +152,36 @@ struct NativeCode {
|
||||
|
||||
jobject surface;
|
||||
jobject inputChannel;
|
||||
struct AInputQueue* nativeInputQueue;
|
||||
struct MyInputQueue* nativeInputQueue;
|
||||
|
||||
// These are used to wake up the main thread to process work.
|
||||
int mainWorkRead;
|
||||
int mainWorkWrite;
|
||||
sp<PollLoop> pollLoop;
|
||||
};
|
||||
|
||||
static bool mainWorkCallback(int fd, int events, void* data) {
|
||||
NativeCode* code = (NativeCode*)data;
|
||||
if ((events & POLLIN) != 0) {
|
||||
KeyEvent* keyEvent;
|
||||
while ((keyEvent=code->nativeInputQueue->getNextEvent()) != NULL) {
|
||||
jobject inputEventObj = android_view_KeyEvent_fromNative(
|
||||
code->activity.env, keyEvent);
|
||||
code->activity.env->CallVoidMethod(code->activity.clazz,
|
||||
gNativeActivityClassInfo.dispatchUnhandledKeyEvent, inputEventObj);
|
||||
int32_t res = code->nativeInputQueue->getConsumer().sendFinishedSignal();
|
||||
if (res != OK) {
|
||||
LOGW("Failed to send finished signal on channel '%s'. status=%d",
|
||||
code->nativeInputQueue->getConsumer().getChannel()->getName().string(), res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static jint
|
||||
loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path)
|
||||
loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jobject messageQueue)
|
||||
{
|
||||
const char* pathStr = env->GetStringUTFChars(path, NULL);
|
||||
NativeCode* code = NULL;
|
||||
@@ -115,6 +198,24 @@ loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path)
|
||||
delete code;
|
||||
return 0;
|
||||
}
|
||||
|
||||
code->pollLoop = android_os_MessageQueue_getPollLoop(env, messageQueue);
|
||||
if (code->pollLoop == NULL) {
|
||||
LOGW("Unable to retrieve MessageQueue's PollLoop");
|
||||
delete code;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int msgpipe[2];
|
||||
if (pipe(msgpipe)) {
|
||||
LOGW("could not create pipe: %s", strerror(errno));
|
||||
delete code;
|
||||
return 0;
|
||||
}
|
||||
code->mainWorkRead = msgpipe[0];
|
||||
code->mainWorkWrite = msgpipe[1];
|
||||
code->pollLoop->setCallback(code->mainWorkRead, POLLIN, mainWorkCallback, code);
|
||||
|
||||
code->activity.callbacks = &code->callbacks;
|
||||
if (env->GetJavaVM(&code->activity.vm) < 0) {
|
||||
LOGW("NativeActivity GetJavaVM failed");
|
||||
@@ -122,7 +223,7 @@ loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path)
|
||||
return 0;
|
||||
}
|
||||
code->activity.env = env;
|
||||
code->activity.clazz = clazz;
|
||||
code->activity.clazz = env->NewGlobalRef(clazz);
|
||||
code->createActivityFunc(&code->activity, NULL, 0);
|
||||
}
|
||||
|
||||
@@ -288,7 +389,7 @@ onInputChannelDestroyed_native(JNIEnv* env, jobject clazz, jint handle, jobject
|
||||
}
|
||||
|
||||
static const JNINativeMethod g_methods[] = {
|
||||
{ "loadNativeCode", "(Ljava/lang/String;)I", (void*)loadNativeCode_native },
|
||||
{ "loadNativeCode", "(Ljava/lang/String;Landroid/os/MessageQueue;)I", (void*)loadNativeCode_native },
|
||||
{ "unloadNativeCode", "(I)V", (void*)unloadNativeCode_native },
|
||||
{ "onStartNative", "(I)V", (void*)onStart_native },
|
||||
{ "onResumeNative", "(I)V", (void*)onResume_native },
|
||||
@@ -306,15 +407,25 @@ static const JNINativeMethod g_methods[] = {
|
||||
|
||||
static const char* const kNativeActivityPathName = "android/app/NativeActivity";
|
||||
|
||||
#define FIND_CLASS(var, className) \
|
||||
var = env->FindClass(className); \
|
||||
LOG_FATAL_IF(! var, "Unable to find class " className); \
|
||||
var = jclass(env->NewGlobalRef(var));
|
||||
|
||||
#define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
|
||||
var = env->GetMethodID(clazz, methodName, fieldDescriptor); \
|
||||
LOG_FATAL_IF(! var, "Unable to find method" methodName);
|
||||
|
||||
int register_android_app_NativeActivity(JNIEnv* env)
|
||||
{
|
||||
//LOGD("register_android_app_NativeActivity");
|
||||
|
||||
jclass clazz;
|
||||
|
||||
clazz = env->FindClass(kNativeActivityPathName);
|
||||
LOG_FATAL_IF(clazz == NULL, "Unable to find class android.app.NativeActivity");
|
||||
|
||||
FIND_CLASS(gNativeActivityClassInfo.clazz, kNativeActivityPathName);
|
||||
|
||||
GET_METHOD_ID(gNativeActivityClassInfo.dispatchUnhandledKeyEvent,
|
||||
gNativeActivityClassInfo.clazz,
|
||||
"dispatchUnhandledKeyEvent", "(Landroid/view/KeyEvent;)V");
|
||||
|
||||
return AndroidRuntime::registerNativeMethods(
|
||||
env, kNativeActivityPathName,
|
||||
g_methods, NELEM(g_methods));
|
||||
|
||||
@@ -76,8 +76,23 @@ void android_view_KeyEvent_toNative(JNIEnv* env, jobject eventObj, int32_t natur
|
||||
milliseconds_to_nanoseconds(eventTime));
|
||||
}
|
||||
|
||||
static jboolean native_isSystemKey(JNIEnv* env, jobject clazz, jint keyCode) {
|
||||
return KeyEvent::isSystemKey(keyCode);
|
||||
}
|
||||
|
||||
static jboolean native_hasDefaultAction(JNIEnv* env, jobject clazz, jint keyCode) {
|
||||
return KeyEvent::hasDefaultAction(keyCode);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static const JNINativeMethod g_methods[] = {
|
||||
{ "native_isSystemKey", "(I)Z", (void*)native_isSystemKey },
|
||||
{ "native_hasDefaultAction", "(I)Z", (void*)native_hasDefaultAction },
|
||||
};
|
||||
|
||||
static const char* const kKeyEventPathName = "android/view/KeyEvent";
|
||||
|
||||
#define FIND_CLASS(var, className) \
|
||||
var = env->FindClass(className); \
|
||||
LOG_FATAL_IF(! var, "Unable to find class " className); \
|
||||
@@ -92,8 +107,8 @@ void android_view_KeyEvent_toNative(JNIEnv* env, jobject eventObj, int32_t natur
|
||||
LOG_FATAL_IF(! var, "Unable to find field " fieldName);
|
||||
|
||||
int register_android_view_KeyEvent(JNIEnv* env) {
|
||||
FIND_CLASS(gKeyEventClassInfo.clazz, "android/view/KeyEvent");
|
||||
|
||||
FIND_CLASS(gKeyEventClassInfo.clazz, kKeyEventPathName);
|
||||
|
||||
GET_METHOD_ID(gKeyEventClassInfo.ctor, gKeyEventClassInfo.clazz,
|
||||
"<init>", "(JJIIIIIII)V");
|
||||
|
||||
@@ -118,7 +133,9 @@ int register_android_view_KeyEvent(JNIEnv* env) {
|
||||
GET_FIELD_ID(gKeyEventClassInfo.mCharacters, gKeyEventClassInfo.clazz,
|
||||
"mCharacters", "Ljava/lang/String;");
|
||||
|
||||
return 0;
|
||||
return AndroidRuntime::registerNativeMethods(
|
||||
env, kKeyEventPathName,
|
||||
g_methods, NELEM(g_methods));
|
||||
}
|
||||
|
||||
} // namespace android
|
||||
|
||||
@@ -145,7 +145,7 @@ public:
|
||||
inline int32_t getDeviceId() const { return mDeviceId; }
|
||||
|
||||
inline int32_t getNature() const { return mNature; }
|
||||
|
||||
|
||||
protected:
|
||||
void initialize(int32_t deviceId, int32_t nature);
|
||||
|
||||
@@ -179,6 +179,14 @@ public:
|
||||
|
||||
inline nsecs_t getEventTime() const { return mEventTime; }
|
||||
|
||||
// Return true if this event may have a default action implementation.
|
||||
static bool hasDefaultAction(int32_t keyCode);
|
||||
bool hasDefaultAction() const;
|
||||
|
||||
// Return true if this event represents a system key.
|
||||
static bool isSystemKey(int32_t keyCode);
|
||||
bool isSystemKey() const;
|
||||
|
||||
void initialize(
|
||||
int32_t deviceId,
|
||||
int32_t nature,
|
||||
|
||||
@@ -339,12 +339,14 @@ public:
|
||||
explicit AInputQueue(const android::sp<android::InputChannel>& channel);
|
||||
|
||||
/* Destroys the consumer and releases its input channel. */
|
||||
~AInputQueue();
|
||||
virtual ~AInputQueue();
|
||||
|
||||
inline android::InputConsumer& getConsumer() { return mConsumer; }
|
||||
|
||||
android::status_t consume(android::InputEvent** event);
|
||||
|
||||
virtual void doDefaultKey(android::KeyEvent* keyEvent) = 0;
|
||||
|
||||
private:
|
||||
android::InputConsumer mConsumer;
|
||||
android::PreallocatedInputEventFactory mInputEventFactory;
|
||||
|
||||
@@ -20,6 +20,70 @@ void InputEvent::initialize(int32_t deviceId, int32_t nature) {
|
||||
|
||||
// class KeyEvent
|
||||
|
||||
bool KeyEvent::hasDefaultAction(int32_t keyCode) {
|
||||
switch (keyCode) {
|
||||
case KEYCODE_HOME:
|
||||
case KEYCODE_BACK:
|
||||
case KEYCODE_CALL:
|
||||
case KEYCODE_ENDCALL:
|
||||
case KEYCODE_VOLUME_UP:
|
||||
case KEYCODE_VOLUME_DOWN:
|
||||
case KEYCODE_POWER:
|
||||
case KEYCODE_CAMERA:
|
||||
case KEYCODE_HEADSETHOOK:
|
||||
case KEYCODE_MENU:
|
||||
case KEYCODE_NOTIFICATION:
|
||||
case KEYCODE_FOCUS:
|
||||
case KEYCODE_SEARCH:
|
||||
case KEYCODE_MEDIA_PLAY_PAUSE:
|
||||
case KEYCODE_MEDIA_STOP:
|
||||
case KEYCODE_MEDIA_NEXT:
|
||||
case KEYCODE_MEDIA_PREVIOUS:
|
||||
case KEYCODE_MEDIA_REWIND:
|
||||
case KEYCODE_MEDIA_FAST_FORWARD:
|
||||
case KEYCODE_MUTE:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool KeyEvent::hasDefaultAction() const {
|
||||
return hasDefaultAction(getKeyCode());
|
||||
}
|
||||
|
||||
bool KeyEvent::isSystemKey(int32_t keyCode) {
|
||||
switch (keyCode) {
|
||||
case KEYCODE_MENU:
|
||||
case KEYCODE_SOFT_RIGHT:
|
||||
case KEYCODE_HOME:
|
||||
case KEYCODE_BACK:
|
||||
case KEYCODE_CALL:
|
||||
case KEYCODE_ENDCALL:
|
||||
case KEYCODE_VOLUME_UP:
|
||||
case KEYCODE_VOLUME_DOWN:
|
||||
case KEYCODE_MUTE:
|
||||
case KEYCODE_POWER:
|
||||
case KEYCODE_HEADSETHOOK:
|
||||
case KEYCODE_MEDIA_PLAY_PAUSE:
|
||||
case KEYCODE_MEDIA_STOP:
|
||||
case KEYCODE_MEDIA_NEXT:
|
||||
case KEYCODE_MEDIA_PREVIOUS:
|
||||
case KEYCODE_MEDIA_REWIND:
|
||||
case KEYCODE_MEDIA_FAST_FORWARD:
|
||||
case KEYCODE_CAMERA:
|
||||
case KEYCODE_FOCUS:
|
||||
case KEYCODE_SEARCH:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool KeyEvent::isSystemKey() const {
|
||||
return isSystemKey(getKeyCode());
|
||||
}
|
||||
|
||||
void KeyEvent::initialize(
|
||||
int32_t deviceId,
|
||||
int32_t nature,
|
||||
|
||||
@@ -225,6 +225,15 @@ int32_t AInputQueue_getEvent(AInputQueue* queue, AInputEvent** outEvent) {
|
||||
|
||||
void AInputQueue_finishEvent(AInputQueue* queue, AInputEvent* event,
|
||||
int handled) {
|
||||
if (!handled && ((InputEvent*)event)->getType() == INPUT_EVENT_TYPE_KEY
|
||||
&& ((KeyEvent*)event)->hasDefaultAction()) {
|
||||
// The app didn't handle this, but it may have a default action
|
||||
// associated with it. We need to hand this back to Java to be
|
||||
// executed.
|
||||
queue->doDefaultKey((KeyEvent*)event);
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t res = queue->getConsumer().sendFinishedSignal();
|
||||
if (res != android::OK) {
|
||||
LOGW("Failed to send finished signal on channel '%s'. status=%d",
|
||||
|
||||
Reference in New Issue
Block a user