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

Commit 69969e48 authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

First pass at NativeActivity.

This is a rough sketch of the new pure-native API, which you can
use through a NativeActivity in your manifest (no Java code in
the .apk needed!).

Intentionally no docs yet, the API is still being seriously
messed with.  But it works.

Change-Id: I0e916d58a0d159ecaf3689e41834eb8dc681c0c0
parent f24e66db
Loading
Loading
Loading
Loading
+41 −0
Original line number Diff line number Diff line
@@ -26276,6 +26276,34 @@
</parameter>
</method>
</class>
<class name="NativeActivity"
 extends="android.app.Activity"
 abstract="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<constructor name="NativeActivity"
 type="android.app.NativeActivity"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</constructor>
<field name="META_DATA_LIB_NAME"
 type="java.lang.String"
 transient="false"
 volatile="false"
 value="&quot;android.app.lib_name&quot;"
 static="true"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</field>
</class>
<class name="Notification"
 extends="java.lang.Object"
 abstract="false"
@@ -220539,6 +220567,19 @@
<parameter name="parent" type="java.lang.ClassLoader">
</parameter>
</constructor>
<method name="findLibrary"
 return="java.lang.String"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="libname" type="java.lang.String">
</parameter>
</method>
</class>
<class name="PotentialDeadlockError"
 extends="java.lang.VirtualMachineError"
+122 −0
Original line number Diff line number Diff line
package android.app;

import dalvik.system.PathClassLoader;

import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;

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 {
    public static final String META_DATA_LIB_NAME = "android.app.lib_name";
    
    private int mNativeHandle;
    
    private native int loadNativeCode(String path);
    private native void unloadNativeCode(int handle);
    
    private native void onStartNative(int handle);
    private native void onResumeNative(int handle);
    private native void onSaveInstanceStateNative(int handle);
    private native void onPauseNative(int handle);
    private native void onStopNative(int handle);
    private native void onLowMemoryNative(int handle);
    private native void onWindowFocusChangedNative(int handle, boolean focused);
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        String libname = "main";
        ActivityInfo ai;
        
        try {
            ai = getPackageManager().getActivityInfo(
                    getIntent().getComponent(), PackageManager.GET_META_DATA);
            if (ai.metaData != null) {
                String ln = ai.metaData.getString(META_DATA_LIB_NAME);
                if (ln != null) libname = ln;
            }
        } catch (PackageManager.NameNotFoundException e) {
            throw new RuntimeException("Error getting activity info", e);
        }
        
        String path = null;
        
        if ((ai.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) == 0) {
            // If the application does not have (Java) code, then no ClassLoader
            // has been set up for it.  We will need to do our own search for
            // the native code.
            path = ai.applicationInfo.dataDir + "/lib/" + System.mapLibraryName(libname);
            if (!(new File(path)).exists()) {
                path = null;
            }
        }
        
        if (path == null) {
            path = ((PathClassLoader)getClassLoader()).findLibrary(libname);
        }
        
        if (path == null) {
            throw new IllegalArgumentException("Unable to find native library: " + libname);
        }
        
        mNativeHandle = loadNativeCode(path);
        if (mNativeHandle == 0) {
            throw new IllegalArgumentException("Unable to load native library: " + path);
        }
        super.onCreate(savedInstanceState);
    }

    @Override
    protected void onDestroy() {
        unloadNativeCode(mNativeHandle);
        super.onDestroy();
    }

    @Override
    public void onLowMemory() {
        super.onLowMemory();
        onLowMemoryNative(mNativeHandle);
    }

    @Override
    protected void onPause() {
        super.onPause();
        onPauseNative(mNativeHandle);
    }

    @Override
    protected void onResume() {
        super.onResume();
        onResumeNative(mNativeHandle);
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        onSaveInstanceStateNative(mNativeHandle);
    }

    @Override
    protected void onStart() {
        super.onStart();
        onStartNative(mNativeHandle);
    }

    @Override
    protected void onStop() {
        super.onStop();
        onStopNative(mNativeHandle);
    }

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        onWindowFocusChangedNative(mNativeHandle, hasFocus);
    }
}
+1 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ LOCAL_SRC_FILES:= \
	Time.cpp \
	com_google_android_gles_jni_EGLImpl.cpp \
	com_google_android_gles_jni_GLImpl.cpp.arm \
	android_app_NativeActivity.cpp \
	android_opengl_GLES10.cpp \
	android_opengl_GLES10Ext.cpp \
	android_opengl_GLES11.cpp \
+3 −0
Original line number Diff line number Diff line
@@ -159,6 +159,7 @@ extern int register_android_backup_BackupDataInput(JNIEnv *env);
extern int register_android_backup_BackupDataOutput(JNIEnv *env);
extern int register_android_backup_FileBackupHelperBase(JNIEnv *env);
extern int register_android_backup_BackupHelperDispatcher(JNIEnv *env);
extern int register_android_app_NativeActivity(JNIEnv *env);

static AndroidRuntime* gCurRuntime = NULL;

@@ -1281,6 +1282,8 @@ static const RegJNIRec gRegJNI[] = {
    REG_JNI(register_android_backup_BackupDataOutput),
    REG_JNI(register_android_backup_FileBackupHelperBase),
    REG_JNI(register_android_backup_BackupHelperDispatcher),
    
    REG_JNI(register_android_app_NativeActivity),
};

/*
+190 −0
Original line number Diff line number Diff line
/*
 * 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.
 */

#define LOG_TAG "NativeActivity"
#include <utils/Log.h>

#include "JNIHelp.h"
#include <android_runtime/AndroidRuntime.h>
#include <android/native_activity.h>

#include <dlfcn.h>

namespace android
{

struct NativeCode {
    android_activity_t activity;
    android_activity_callbacks_t callbacks;
    
    void* dlhandle;
    
    android_activity_create_t* createActivityFunc;
    void* clientContext;
};

static jint
loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path)
{
    const char* pathStr = env->GetStringUTFChars(path, NULL);
    NativeCode* code = NULL;
    
    void* handle = dlopen(pathStr, RTLD_LAZY);
    
    env->ReleaseStringUTFChars(path, pathStr);
    
    if (handle != NULL) {
        code = new NativeCode();
        code->dlhandle = handle;
        code->createActivityFunc = (android_activity_create_t*)
                dlsym(handle, "android_onCreateActivity");
        if (code->createActivityFunc == NULL) {
            LOGW("android_onCreateActivity not found");
            delete code;
            dlclose(handle);
            return 0;
        }
        memset(&code->activity, sizeof(code->activity), 0);
        memset(&code->callbacks, sizeof(code->callbacks), 0);
        code->activity.callbacks = &code->callbacks;
        code->activity.env = env;
        code->activity.clazz = clazz;
        code->createActivityFunc(&code->activity, NULL, 0);
    }
    
    return (jint)code;
}

static void
unloadNativeCode_native(JNIEnv* env, jobject clazz, jint handle)
{
    if (handle != 0) {
        NativeCode* code = (NativeCode*)handle;
        if (code->callbacks.onDestroy != NULL) {
            code->callbacks.onDestroy(&code->activity);
        }
        dlclose(code->dlhandle);
        delete code;
    }
}

static void
onStart_native(JNIEnv* env, jobject clazz, jint handle)
{
    if (handle != 0) {
        NativeCode* code = (NativeCode*)handle;
        if (code->callbacks.onStart != NULL) {
            code->callbacks.onStart(&code->activity);
        }
    }
}

static void
onResume_native(JNIEnv* env, jobject clazz, jint handle)
{
    if (handle != 0) {
        NativeCode* code = (NativeCode*)handle;
        if (code->callbacks.onResume != NULL) {
            code->callbacks.onResume(&code->activity);
        }
    }
}

static void
onSaveInstanceState_native(JNIEnv* env, jobject clazz, jint handle)
{
    if (handle != 0) {
        NativeCode* code = (NativeCode*)handle;
        if (code->callbacks.onSaveInstanceState != NULL) {
            size_t len = 0;
            code->callbacks.onSaveInstanceState(&code->activity, &len);
        }
    }
}

static void
onPause_native(JNIEnv* env, jobject clazz, jint handle)
{
    if (handle != 0) {
        NativeCode* code = (NativeCode*)handle;
        if (code->callbacks.onPause != NULL) {
            code->callbacks.onPause(&code->activity);
        }
    }
}

static void
onStop_native(JNIEnv* env, jobject clazz, jint handle)
{
    if (handle != 0) {
        NativeCode* code = (NativeCode*)handle;
        if (code->callbacks.onStop != NULL) {
            code->callbacks.onStop(&code->activity);
        }
    }
}

static void
onLowMemory_native(JNIEnv* env, jobject clazz, jint handle)
{
    if (handle != 0) {
        NativeCode* code = (NativeCode*)handle;
        if (code->callbacks.onLowMemory != NULL) {
            code->callbacks.onLowMemory(&code->activity);
        }
    }
}

static void
onWindowFocusChanged_native(JNIEnv* env, jobject clazz, jint handle, jboolean focused)
{
    if (handle != 0) {
        NativeCode* code = (NativeCode*)handle;
        if (code->callbacks.onWindowFocusChanged != NULL) {
            code->callbacks.onWindowFocusChanged(&code->activity, focused ? 1 : 0);
        }
    }
}

static const JNINativeMethod g_methods[] = {
    { "loadNativeCode", "(Ljava/lang/String;)I", (void*)loadNativeCode_native },
    { "unloadNativeCode", "(I)V", (void*)unloadNativeCode_native },
    { "onStartNative", "(I)V", (void*)onStart_native },
    { "onResumeNative", "(I)V", (void*)onResume_native },
    { "onSaveInstanceStateNative", "(I)V", (void*)onSaveInstanceState_native },
    { "onPauseNative", "(I)V", (void*)onPause_native },
    { "onStopNative", "(I)V", (void*)onStop_native },
    { "onLowMemoryNative", "(I)V", (void*)onLowMemory_native },
    { "onWindowFocusChangedNative", "(IZ)V", (void*)onWindowFocusChanged_native },
};

static const char* const kNativeActivityPathName = "android/app/NativeActivity";

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");

    return AndroidRuntime::registerNativeMethods(
        env, kNativeActivityPathName,
        g_methods, NELEM(g_methods));
}

}
Loading