Loading core/java/android/app/Activity.java +0 −1 Original line number Original line Diff line number Diff line Loading @@ -39,7 +39,6 @@ import android.os.Build; import android.os.Bundle; import android.os.Bundle; import android.os.Handler; import android.os.Handler; import android.os.IBinder; import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; import android.os.RemoteException; import android.text.Selection; import android.text.Selection; import android.text.SpannableStringBuilder; import android.text.SpannableStringBuilder; Loading core/java/android/app/NativeActivity.java +53 −9 Original line number Original line Diff line number Diff line Loading @@ -6,9 +6,13 @@ import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager; import android.os.Bundle; import android.os.Bundle; import android.os.Looper; import android.os.MessageQueue; import android.view.InputChannel; import android.view.InputChannel; import android.view.InputQueue; import android.view.InputQueue; import android.view.KeyEvent; import android.view.SurfaceHolder; import android.view.SurfaceHolder; import android.view.View; import java.io.File; import java.io.File; Loading @@ -22,7 +26,12 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback, private int mNativeHandle; 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 unloadNativeCode(int handle); private native void onStartNative(int handle); private native void onStartNative(int handle); Loading Loading @@ -78,7 +87,7 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback, throw new IllegalArgumentException("Unable to find native library: " + libname); throw new IllegalArgumentException("Unable to find native library: " + libname); } } mNativeHandle = loadNativeCode(path); mNativeHandle = loadNativeCode(path, Looper.myQueue()); if (mNativeHandle == 0) { if (mNativeHandle == 0) { throw new IllegalArgumentException("Unable to load native library: " + path); throw new IllegalArgumentException("Unable to load native library: " + path); } } Loading @@ -87,6 +96,15 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback, @Override @Override protected void onDestroy() { protected void onDestroy() { mDestroyed = true; if (mCurSurfaceHolder != null) { onSurfaceDestroyedNative(mNativeHandle, mCurSurfaceHolder); mCurSurfaceHolder = null; } if (mCurInputQueue != null) { onInputChannelDestroyedNative(mNativeHandle, mCurInputQueue.getInputChannel()); mCurInputQueue = null; } unloadNativeCode(mNativeHandle); unloadNativeCode(mNativeHandle); super.onDestroy(); super.onDestroy(); } } Loading Loading @@ -124,32 +142,58 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback, @Override @Override public void onLowMemory() { public void onLowMemory() { super.onLowMemory(); super.onLowMemory(); if (!mDestroyed) { onLowMemoryNative(mNativeHandle); onLowMemoryNative(mNativeHandle); } } } @Override @Override public void onWindowFocusChanged(boolean hasFocus) { public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); super.onWindowFocusChanged(hasFocus); if (!mDestroyed) { onWindowFocusChangedNative(mNativeHandle, hasFocus); onWindowFocusChangedNative(mNativeHandle, hasFocus); } } } public void surfaceCreated(SurfaceHolder holder) { public void surfaceCreated(SurfaceHolder holder) { if (!mDestroyed) { mCurSurfaceHolder = holder; onSurfaceCreatedNative(mNativeHandle, holder); onSurfaceCreatedNative(mNativeHandle, holder); } } } public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { if (!mDestroyed) { mCurSurfaceHolder = holder; onSurfaceChangedNative(mNativeHandle, holder, format, width, height); onSurfaceChangedNative(mNativeHandle, holder, format, width, height); } } } public void surfaceDestroyed(SurfaceHolder holder) { public void surfaceDestroyed(SurfaceHolder holder) { mCurSurfaceHolder = null; if (!mDestroyed) { onSurfaceDestroyedNative(mNativeHandle, holder); onSurfaceDestroyedNative(mNativeHandle, holder); } } } public void onInputQueueCreated(InputQueue queue) { public void onInputQueueCreated(InputQueue queue) { if (!mDestroyed) { mCurInputQueue = queue; onInputChannelCreatedNative(mNativeHandle, queue.getInputChannel()); onInputChannelCreatedNative(mNativeHandle, queue.getInputChannel()); } } } public void onInputQueueDestroyed(InputQueue queue) { public void onInputQueueDestroyed(InputQueue queue) { mCurInputQueue = null; if (!mDestroyed) { onInputChannelDestroyedNative(mNativeHandle, queue.getInputChannel()); onInputChannelDestroyedNative(mNativeHandle, queue.getInputChannel()); } } } } void dispatchUnhandledKeyEvent(KeyEvent event) { View decor = getWindow().getDecorView(); if (decor != null) { decor.dispatchKeyEvent(event); } } } core/java/android/view/KeyEvent.java +9 −27 Original line number Original line Diff line number Diff line Loading @@ -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 * TODO: should the dpad keys be here? arguably, because they also shouldn't be menu shortcuts */ */ public final boolean isSystem() { public final boolean isSystem() { switch (mKeyCode) { return native_isSystemKey(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; } } /** @hide */ public final boolean hasDefaultAction() { return native_hasDefaultAction(mKeyCode); } } Loading Loading @@ -1226,4 +1205,7 @@ public class KeyEvent implements Parcelable { mDownTime = in.readLong(); mDownTime = in.readLong(); mEventTime = in.readLong(); mEventTime = in.readLong(); } } private native boolean native_isSystemKey(int keyCode); private native boolean native_hasDefaultAction(int keyCode); } } core/jni/android_app_NativeActivity.cpp +124 −13 Original line number Original line Diff line number Diff line Loading @@ -17,17 +17,63 @@ #define LOG_TAG "NativeActivity" #define LOG_TAG "NativeActivity" #include <utils/Log.h> #include <utils/Log.h> #include "JNIHelp.h" #include <poll.h> #include "android_view_InputChannel.h" #include <dlfcn.h> #include <android_runtime/AndroidRuntime.h> #include <android_runtime/AndroidRuntime.h> #include <android/native_activity.h> #include <android/native_activity.h> #include <ui/InputTransport.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 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 { struct NativeCode { NativeCode(void* _dlhandle, ANativeActivity_createFunc* _createFunc) { NativeCode(void* _dlhandle, ANativeActivity_createFunc* _createFunc) { memset(&activity, sizeof(activity), 0); memset(&activity, sizeof(activity), 0); Loading @@ -37,14 +83,26 @@ struct NativeCode { surface = NULL; surface = NULL; inputChannel = NULL; inputChannel = NULL; nativeInputQueue = NULL; nativeInputQueue = NULL; mainWorkRead = mainWorkWrite = -1; } } ~NativeCode() { ~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); setSurface(NULL); setInputChannel(NULL); setInputChannel(NULL); if (callbacks.onDestroy != NULL) { if (callbacks.onDestroy != NULL) { callbacks.onDestroy(&activity); callbacks.onDestroy(&activity); } } if (mainWorkRead >= 0) close(mainWorkRead); if (mainWorkWrite >= 0) close(mainWorkWrite); if (dlhandle != NULL) { if (dlhandle != NULL) { dlclose(dlhandle); dlclose(dlhandle); } } Loading Loading @@ -73,7 +131,7 @@ struct NativeCode { sp<InputChannel> ic = sp<InputChannel> ic = android_view_InputChannel_getInputChannel(activity.env, _channel); android_view_InputChannel_getInputChannel(activity.env, _channel); if (ic != NULL) { if (ic != NULL) { nativeInputQueue = new AInputQueue(ic); nativeInputQueue = new MyInputQueue(ic, mainWorkWrite); if (nativeInputQueue->getConsumer().initialize() != android::OK) { if (nativeInputQueue->getConsumer().initialize() != android::OK) { delete nativeInputQueue; delete nativeInputQueue; nativeInputQueue = NULL; nativeInputQueue = NULL; Loading @@ -94,11 +152,36 @@ struct NativeCode { jobject surface; jobject surface; jobject inputChannel; 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 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); const char* pathStr = env->GetStringUTFChars(path, NULL); NativeCode* code = NULL; NativeCode* code = NULL; Loading @@ -115,6 +198,24 @@ loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path) delete code; delete code; return 0; 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; code->activity.callbacks = &code->callbacks; if (env->GetJavaVM(&code->activity.vm) < 0) { if (env->GetJavaVM(&code->activity.vm) < 0) { LOGW("NativeActivity GetJavaVM failed"); LOGW("NativeActivity GetJavaVM failed"); Loading @@ -122,7 +223,7 @@ loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path) return 0; return 0; } } code->activity.env = env; code->activity.env = env; code->activity.clazz = clazz; code->activity.clazz = env->NewGlobalRef(clazz); code->createActivityFunc(&code->activity, NULL, 0); code->createActivityFunc(&code->activity, NULL, 0); } } Loading Loading @@ -288,7 +389,7 @@ onInputChannelDestroyed_native(JNIEnv* env, jobject clazz, jint handle, jobject } } static const JNINativeMethod g_methods[] = { 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 }, { "unloadNativeCode", "(I)V", (void*)unloadNativeCode_native }, { "onStartNative", "(I)V", (void*)onStart_native }, { "onStartNative", "(I)V", (void*)onStart_native }, { "onResumeNative", "(I)V", (void*)onResume_native }, { "onResumeNative", "(I)V", (void*)onResume_native }, Loading @@ -306,14 +407,24 @@ static const JNINativeMethod g_methods[] = { static const char* const kNativeActivityPathName = "android/app/NativeActivity"; 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) int register_android_app_NativeActivity(JNIEnv* env) { { //LOGD("register_android_app_NativeActivity"); //LOGD("register_android_app_NativeActivity"); jclass clazz; FIND_CLASS(gNativeActivityClassInfo.clazz, kNativeActivityPathName); clazz = env->FindClass(kNativeActivityPathName); GET_METHOD_ID(gNativeActivityClassInfo.dispatchUnhandledKeyEvent, LOG_FATAL_IF(clazz == NULL, "Unable to find class android.app.NativeActivity"); gNativeActivityClassInfo.clazz, "dispatchUnhandledKeyEvent", "(Landroid/view/KeyEvent;)V"); return AndroidRuntime::registerNativeMethods( return AndroidRuntime::registerNativeMethods( env, kNativeActivityPathName, env, kNativeActivityPathName, Loading core/jni/android_view_KeyEvent.cpp +20 −3 Original line number Original line Diff line number Diff line Loading @@ -76,8 +76,23 @@ void android_view_KeyEvent_toNative(JNIEnv* env, jobject eventObj, int32_t natur milliseconds_to_nanoseconds(eventTime)); 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) \ #define FIND_CLASS(var, className) \ var = env->FindClass(className); \ var = env->FindClass(className); \ LOG_FATAL_IF(! var, "Unable to find class " className); \ LOG_FATAL_IF(! var, "Unable to find class " className); \ Loading @@ -92,7 +107,7 @@ void android_view_KeyEvent_toNative(JNIEnv* env, jobject eventObj, int32_t natur LOG_FATAL_IF(! var, "Unable to find field " fieldName); LOG_FATAL_IF(! var, "Unable to find field " fieldName); int register_android_view_KeyEvent(JNIEnv* env) { 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, GET_METHOD_ID(gKeyEventClassInfo.ctor, gKeyEventClassInfo.clazz, "<init>", "(JJIIIIIII)V"); "<init>", "(JJIIIIIII)V"); Loading @@ -118,7 +133,9 @@ int register_android_view_KeyEvent(JNIEnv* env) { GET_FIELD_ID(gKeyEventClassInfo.mCharacters, gKeyEventClassInfo.clazz, GET_FIELD_ID(gKeyEventClassInfo.mCharacters, gKeyEventClassInfo.clazz, "mCharacters", "Ljava/lang/String;"); "mCharacters", "Ljava/lang/String;"); return 0; return AndroidRuntime::registerNativeMethods( env, kKeyEventPathName, g_methods, NELEM(g_methods)); } } } // namespace android } // namespace android Loading
core/java/android/app/Activity.java +0 −1 Original line number Original line Diff line number Diff line Loading @@ -39,7 +39,6 @@ import android.os.Build; import android.os.Bundle; import android.os.Bundle; import android.os.Handler; import android.os.Handler; import android.os.IBinder; import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; import android.os.RemoteException; import android.text.Selection; import android.text.Selection; import android.text.SpannableStringBuilder; import android.text.SpannableStringBuilder; Loading
core/java/android/app/NativeActivity.java +53 −9 Original line number Original line Diff line number Diff line Loading @@ -6,9 +6,13 @@ import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager; import android.os.Bundle; import android.os.Bundle; import android.os.Looper; import android.os.MessageQueue; import android.view.InputChannel; import android.view.InputChannel; import android.view.InputQueue; import android.view.InputQueue; import android.view.KeyEvent; import android.view.SurfaceHolder; import android.view.SurfaceHolder; import android.view.View; import java.io.File; import java.io.File; Loading @@ -22,7 +26,12 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback, private int mNativeHandle; 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 unloadNativeCode(int handle); private native void onStartNative(int handle); private native void onStartNative(int handle); Loading Loading @@ -78,7 +87,7 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback, throw new IllegalArgumentException("Unable to find native library: " + libname); throw new IllegalArgumentException("Unable to find native library: " + libname); } } mNativeHandle = loadNativeCode(path); mNativeHandle = loadNativeCode(path, Looper.myQueue()); if (mNativeHandle == 0) { if (mNativeHandle == 0) { throw new IllegalArgumentException("Unable to load native library: " + path); throw new IllegalArgumentException("Unable to load native library: " + path); } } Loading @@ -87,6 +96,15 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback, @Override @Override protected void onDestroy() { protected void onDestroy() { mDestroyed = true; if (mCurSurfaceHolder != null) { onSurfaceDestroyedNative(mNativeHandle, mCurSurfaceHolder); mCurSurfaceHolder = null; } if (mCurInputQueue != null) { onInputChannelDestroyedNative(mNativeHandle, mCurInputQueue.getInputChannel()); mCurInputQueue = null; } unloadNativeCode(mNativeHandle); unloadNativeCode(mNativeHandle); super.onDestroy(); super.onDestroy(); } } Loading Loading @@ -124,32 +142,58 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback, @Override @Override public void onLowMemory() { public void onLowMemory() { super.onLowMemory(); super.onLowMemory(); if (!mDestroyed) { onLowMemoryNative(mNativeHandle); onLowMemoryNative(mNativeHandle); } } } @Override @Override public void onWindowFocusChanged(boolean hasFocus) { public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); super.onWindowFocusChanged(hasFocus); if (!mDestroyed) { onWindowFocusChangedNative(mNativeHandle, hasFocus); onWindowFocusChangedNative(mNativeHandle, hasFocus); } } } public void surfaceCreated(SurfaceHolder holder) { public void surfaceCreated(SurfaceHolder holder) { if (!mDestroyed) { mCurSurfaceHolder = holder; onSurfaceCreatedNative(mNativeHandle, holder); onSurfaceCreatedNative(mNativeHandle, holder); } } } public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { if (!mDestroyed) { mCurSurfaceHolder = holder; onSurfaceChangedNative(mNativeHandle, holder, format, width, height); onSurfaceChangedNative(mNativeHandle, holder, format, width, height); } } } public void surfaceDestroyed(SurfaceHolder holder) { public void surfaceDestroyed(SurfaceHolder holder) { mCurSurfaceHolder = null; if (!mDestroyed) { onSurfaceDestroyedNative(mNativeHandle, holder); onSurfaceDestroyedNative(mNativeHandle, holder); } } } public void onInputQueueCreated(InputQueue queue) { public void onInputQueueCreated(InputQueue queue) { if (!mDestroyed) { mCurInputQueue = queue; onInputChannelCreatedNative(mNativeHandle, queue.getInputChannel()); onInputChannelCreatedNative(mNativeHandle, queue.getInputChannel()); } } } public void onInputQueueDestroyed(InputQueue queue) { public void onInputQueueDestroyed(InputQueue queue) { mCurInputQueue = null; if (!mDestroyed) { onInputChannelDestroyedNative(mNativeHandle, queue.getInputChannel()); onInputChannelDestroyedNative(mNativeHandle, queue.getInputChannel()); } } } } void dispatchUnhandledKeyEvent(KeyEvent event) { View decor = getWindow().getDecorView(); if (decor != null) { decor.dispatchKeyEvent(event); } } }
core/java/android/view/KeyEvent.java +9 −27 Original line number Original line Diff line number Diff line Loading @@ -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 * TODO: should the dpad keys be here? arguably, because they also shouldn't be menu shortcuts */ */ public final boolean isSystem() { public final boolean isSystem() { switch (mKeyCode) { return native_isSystemKey(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; } } /** @hide */ public final boolean hasDefaultAction() { return native_hasDefaultAction(mKeyCode); } } Loading Loading @@ -1226,4 +1205,7 @@ public class KeyEvent implements Parcelable { mDownTime = in.readLong(); mDownTime = in.readLong(); mEventTime = in.readLong(); mEventTime = in.readLong(); } } private native boolean native_isSystemKey(int keyCode); private native boolean native_hasDefaultAction(int keyCode); } }
core/jni/android_app_NativeActivity.cpp +124 −13 Original line number Original line Diff line number Diff line Loading @@ -17,17 +17,63 @@ #define LOG_TAG "NativeActivity" #define LOG_TAG "NativeActivity" #include <utils/Log.h> #include <utils/Log.h> #include "JNIHelp.h" #include <poll.h> #include "android_view_InputChannel.h" #include <dlfcn.h> #include <android_runtime/AndroidRuntime.h> #include <android_runtime/AndroidRuntime.h> #include <android/native_activity.h> #include <android/native_activity.h> #include <ui/InputTransport.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 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 { struct NativeCode { NativeCode(void* _dlhandle, ANativeActivity_createFunc* _createFunc) { NativeCode(void* _dlhandle, ANativeActivity_createFunc* _createFunc) { memset(&activity, sizeof(activity), 0); memset(&activity, sizeof(activity), 0); Loading @@ -37,14 +83,26 @@ struct NativeCode { surface = NULL; surface = NULL; inputChannel = NULL; inputChannel = NULL; nativeInputQueue = NULL; nativeInputQueue = NULL; mainWorkRead = mainWorkWrite = -1; } } ~NativeCode() { ~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); setSurface(NULL); setInputChannel(NULL); setInputChannel(NULL); if (callbacks.onDestroy != NULL) { if (callbacks.onDestroy != NULL) { callbacks.onDestroy(&activity); callbacks.onDestroy(&activity); } } if (mainWorkRead >= 0) close(mainWorkRead); if (mainWorkWrite >= 0) close(mainWorkWrite); if (dlhandle != NULL) { if (dlhandle != NULL) { dlclose(dlhandle); dlclose(dlhandle); } } Loading Loading @@ -73,7 +131,7 @@ struct NativeCode { sp<InputChannel> ic = sp<InputChannel> ic = android_view_InputChannel_getInputChannel(activity.env, _channel); android_view_InputChannel_getInputChannel(activity.env, _channel); if (ic != NULL) { if (ic != NULL) { nativeInputQueue = new AInputQueue(ic); nativeInputQueue = new MyInputQueue(ic, mainWorkWrite); if (nativeInputQueue->getConsumer().initialize() != android::OK) { if (nativeInputQueue->getConsumer().initialize() != android::OK) { delete nativeInputQueue; delete nativeInputQueue; nativeInputQueue = NULL; nativeInputQueue = NULL; Loading @@ -94,11 +152,36 @@ struct NativeCode { jobject surface; jobject surface; jobject inputChannel; 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 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); const char* pathStr = env->GetStringUTFChars(path, NULL); NativeCode* code = NULL; NativeCode* code = NULL; Loading @@ -115,6 +198,24 @@ loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path) delete code; delete code; return 0; 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; code->activity.callbacks = &code->callbacks; if (env->GetJavaVM(&code->activity.vm) < 0) { if (env->GetJavaVM(&code->activity.vm) < 0) { LOGW("NativeActivity GetJavaVM failed"); LOGW("NativeActivity GetJavaVM failed"); Loading @@ -122,7 +223,7 @@ loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path) return 0; return 0; } } code->activity.env = env; code->activity.env = env; code->activity.clazz = clazz; code->activity.clazz = env->NewGlobalRef(clazz); code->createActivityFunc(&code->activity, NULL, 0); code->createActivityFunc(&code->activity, NULL, 0); } } Loading Loading @@ -288,7 +389,7 @@ onInputChannelDestroyed_native(JNIEnv* env, jobject clazz, jint handle, jobject } } static const JNINativeMethod g_methods[] = { 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 }, { "unloadNativeCode", "(I)V", (void*)unloadNativeCode_native }, { "onStartNative", "(I)V", (void*)onStart_native }, { "onStartNative", "(I)V", (void*)onStart_native }, { "onResumeNative", "(I)V", (void*)onResume_native }, { "onResumeNative", "(I)V", (void*)onResume_native }, Loading @@ -306,14 +407,24 @@ static const JNINativeMethod g_methods[] = { static const char* const kNativeActivityPathName = "android/app/NativeActivity"; 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) int register_android_app_NativeActivity(JNIEnv* env) { { //LOGD("register_android_app_NativeActivity"); //LOGD("register_android_app_NativeActivity"); jclass clazz; FIND_CLASS(gNativeActivityClassInfo.clazz, kNativeActivityPathName); clazz = env->FindClass(kNativeActivityPathName); GET_METHOD_ID(gNativeActivityClassInfo.dispatchUnhandledKeyEvent, LOG_FATAL_IF(clazz == NULL, "Unable to find class android.app.NativeActivity"); gNativeActivityClassInfo.clazz, "dispatchUnhandledKeyEvent", "(Landroid/view/KeyEvent;)V"); return AndroidRuntime::registerNativeMethods( return AndroidRuntime::registerNativeMethods( env, kNativeActivityPathName, env, kNativeActivityPathName, Loading
core/jni/android_view_KeyEvent.cpp +20 −3 Original line number Original line Diff line number Diff line Loading @@ -76,8 +76,23 @@ void android_view_KeyEvent_toNative(JNIEnv* env, jobject eventObj, int32_t natur milliseconds_to_nanoseconds(eventTime)); 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) \ #define FIND_CLASS(var, className) \ var = env->FindClass(className); \ var = env->FindClass(className); \ LOG_FATAL_IF(! var, "Unable to find class " className); \ LOG_FATAL_IF(! var, "Unable to find class " className); \ Loading @@ -92,7 +107,7 @@ void android_view_KeyEvent_toNative(JNIEnv* env, jobject eventObj, int32_t natur LOG_FATAL_IF(! var, "Unable to find field " fieldName); LOG_FATAL_IF(! var, "Unable to find field " fieldName); int register_android_view_KeyEvent(JNIEnv* env) { 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, GET_METHOD_ID(gKeyEventClassInfo.ctor, gKeyEventClassInfo.clazz, "<init>", "(JJIIIIIII)V"); "<init>", "(JJIIIIIII)V"); Loading @@ -118,7 +133,9 @@ int register_android_view_KeyEvent(JNIEnv* env) { GET_FIELD_ID(gKeyEventClassInfo.mCharacters, gKeyEventClassInfo.clazz, GET_FIELD_ID(gKeyEventClassInfo.mCharacters, gKeyEventClassInfo.clazz, "mCharacters", "Ljava/lang/String;"); "mCharacters", "Ljava/lang/String;"); return 0; return AndroidRuntime::registerNativeMethods( env, kKeyEventPathName, g_methods, NELEM(g_methods)); } } } // namespace android } // namespace android