Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7f6c6e8f authored by Dianne Hackborn's avatar Dianne Hackborn Committed by Android Git Automerger
Browse files

am 3c80a4a0: Implement default key handling for native code.

Merge commit '3c80a4a0' into gingerbread-plus-aosp

* commit '3c80a4a0':
  Implement default key handling for native code.
parents b2d1a71b 3c80a4a0
Loading
Loading
Loading
Loading
+0 −1
Original line number Original line Diff line number Diff line
@@ -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;
+53 −9
Original line number Original line Diff line number Diff line
@@ -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;


@@ -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);
@@ -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);
        }
        }
@@ -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();
    }
    }
@@ -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);
        }
    }
}
+9 −27
Original line number Original line Diff line number Diff line
@@ -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);
    }
    }




@@ -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);
}
}
+124 −13
Original line number Original line Diff line number Diff line
@@ -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);
@@ -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);
        }
        }
@@ -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;
@@ -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;
@@ -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");
@@ -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);
    }
    }
    
    
@@ -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 },
@@ -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,
+20 −3
Original line number Original line Diff line number Diff line
@@ -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); \
@@ -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");
@@ -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