diff --git a/panda/src/android/PandaActivity.java b/panda/src/android/PandaActivity.java index 8f3240900e..91e6c38533 100644 --- a/panda/src/android/PandaActivity.java +++ b/panda/src/android/PandaActivity.java @@ -14,6 +14,9 @@ package org.panda3d.android; import android.app.NativeActivity; +import android.content.Intent; +import android.net.Uri; +import android.widget.Toast; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import org.panda3d.android.NativeIStream; @@ -45,14 +48,41 @@ public class PandaActivity extends NativeActivity { return Thread.currentThread().getName(); } + public String getIntentDataPath() { + Intent intent = getIntent(); + Uri data = intent.getData(); + if (data == null) { + return null; + } + String path = data.getPath(); + if (path.startsWith("//")) { + path = path.substring(1); + } + return path; + } + + public String getCacheDirString() { + return getCacheDir().toString(); + } + + public void showToast(final String text, final int duration) { + final PandaActivity activity = this; + runOnUiThread(new Runnable() { + public void run() { + Toast toast = Toast.makeText(activity, text, duration); + toast.show(); + } + }); + } + static { - System.loadLibrary("gnustl_shared"); - System.loadLibrary("p3dtool"); - System.loadLibrary("p3dtoolconfig"); - System.loadLibrary("pandaexpress"); - System.loadLibrary("panda"); - System.loadLibrary("p3android"); - System.loadLibrary("p3framework"); + //System.loadLibrary("gnustl_shared"); + //System.loadLibrary("p3dtool"); + //System.loadLibrary("p3dtoolconfig"); + //System.loadLibrary("pandaexpress"); + //System.loadLibrary("panda"); + //System.loadLibrary("p3android"); + //System.loadLibrary("p3framework"); System.loadLibrary("pandaegg"); System.loadLibrary("pandagles"); } diff --git a/panda/src/android/android_main.cxx b/panda/src/android/android_main.cxx index 8a3d6135fd..c19ba7d58b 100644 --- a/panda/src/android/android_main.cxx +++ b/panda/src/android/android_main.cxx @@ -25,7 +25,7 @@ // struct android_app* panda_android_app = NULL; -extern int main(int argc, char **argv); +extern int main(int argc, const char **argv); /** * This function is called by native_app_glue to initialize the program. It @@ -100,6 +100,20 @@ void android_main(struct android_app* app) { } } + // Get the cache directory. Set the model-path to this location. + methodID = env->GetMethodID(activity_class, "getCacheDirString", "()Ljava/lang/String;"); + jstring jcache_dir = (jstring) env->CallObjectMethod(activity->clazz, methodID); + + if (jcache_dir != nullptr) { + const char *cache_dir; + cache_dir = env->GetStringUTFChars(jcache_dir, nullptr); + android_cat.info() << "Path to cache: " << cache_dir << "\n"; + + ConfigVariableFilename model_cache_dir("model-cache-dir", Filename()); + model_cache_dir.set_value(cache_dir); + env->ReleaseStringUTFChars(jcache_dir, cache_dir); + } + // Get the path to the APK. methodID = env->GetMethodID(activity_class, "getPackageCodePath", "()Ljava/lang/String;"); jstring code_path = (jstring) env->CallObjectMethod(activity->clazz, methodID); @@ -129,9 +143,29 @@ void android_main(struct android_app* app) { //TODO: prevent it from adding the directory multiple times. get_model_path().append_directory(asset_dir); + // Also read the intent filename. + methodID = env->GetMethodID(activity_class, "getIntentDataPath", "()Ljava/lang/String;"); + jstring filename = (jstring) env->CallObjectMethod(activity->clazz, methodID); + const char *filename_str = nullptr; + if (filename != nullptr) { + filename_str = env->GetStringUTFChars(filename, nullptr); + android_cat.info() << "Got intent filename: " << filename_str << "\n"; + + Filename fn(filename_str); + if (!fn.exists()) { + // Show a toast with the failure message. + android_show_toast(activity, string("Unable to access ") + filename_str, 1); + } + } + // Create bogus argc and argv for calling the main function. - char *argv[] = {nullptr}; - int argc = 0; + const char *argv[] = {"pview", nullptr, nullptr}; + int argc = 1; + + if (filename_str != nullptr) { + argv[1] = filename_str; + ++argc; + } while (!app->destroyRequested) { // Call the main function. This will not return until the app is done. @@ -173,6 +207,10 @@ void android_main(struct android_app* app) { android_cat.info() << "Destroy requested, exiting from android_main\n"; + if (filename_str != nullptr) { + env->ReleaseStringUTFChars(filename, filename_str); + } + // Detach the thread before exiting. activity->vm->DetachCurrentThread(); } diff --git a/panda/src/android/config_android.cxx b/panda/src/android/config_android.cxx index 92d986669d..019443be4b 100644 --- a/panda/src/android/config_android.cxx +++ b/panda/src/android/config_android.cxx @@ -24,6 +24,7 @@ struct android_app *panda_android_app = NULL; jclass jni_PandaActivity; jmethodID jni_PandaActivity_readBitmapSize; jmethodID jni_PandaActivity_readBitmap; +jmethodID jni_PandaActivity_showToast; jclass jni_BitmapFactory_Options; jfieldID jni_BitmapFactory_Options_outWidth; @@ -62,6 +63,9 @@ jint JNI_OnLoad(JavaVM *jvm, void *reserved) { jni_PandaActivity_readBitmap = env->GetStaticMethodID(jni_PandaActivity, "readBitmap", "(JI)Landroid/graphics/Bitmap;"); + jni_PandaActivity_showToast = env->GetMethodID(jni_PandaActivity, + "showToast", "(Ljava/lang/String;I)V"); + jni_BitmapFactory_Options = env->FindClass("android/graphics/BitmapFactory$Options"); jni_BitmapFactory_Options = (jclass) env->NewGlobalRef(jni_BitmapFactory_Options); @@ -83,3 +87,17 @@ void JNI_OnUnload(JavaVM *jvm, void *reserved) { env->DeleteGlobalRef(jni_PandaActivity); env->DeleteGlobalRef(jni_BitmapFactory_Options); } + +/** + * Shows a toast notification at the bottom of the activity. The duration + * should be 0 for short and 1 for long. + */ +void android_show_toast(ANativeActivity *activity, const string &message, int duration) { + Thread *thread = Thread::get_current_thread(); + JNIEnv *env = thread->get_jni_env(); + nassertv(env != nullptr); + + jstring jmsg = env->NewStringUTF(message.c_str()); + env->CallVoidMethod(activity->clazz, jni_PandaActivity_showToast, jmsg, (jint)duration); + env->DeleteLocalRef(jmsg); +} diff --git a/panda/src/android/config_android.h b/panda/src/android/config_android.h index a67ac2423f..74599ec3d9 100644 --- a/panda/src/android/config_android.h +++ b/panda/src/android/config_android.h @@ -20,6 +20,7 @@ #include "configVariableBool.h" #include "configVariableInt.h" +#include #include NotifyCategoryDecl(android, EXPORT_CLASS, EXPORT_TEMPL); @@ -30,9 +31,12 @@ extern EXPORT_CLASS struct android_app* panda_android_app; extern jclass jni_PandaActivity; extern jmethodID jni_PandaActivity_readBitmapHeader; extern jmethodID jni_PandaActivity_readBitmap; +extern jmethodID jni_PandaActivity_showToast; extern jclass jni_BitmapFactory_Options; extern jfieldID jni_BitmapFactory_Options_outWidth; extern jfieldID jni_BitmapFactory_Options_outHeight; +EXPORT_CLASS void android_show_toast(ANativeActivity *activity, const string &message, int duration); + #endif diff --git a/panda/src/android/pview.cxx b/panda/src/android/pview.cxx index 9a29b94574..2b31bb7577 100644 --- a/panda/src/android/pview.cxx +++ b/panda/src/android/pview.cxx @@ -63,12 +63,16 @@ int main(int argc, char **argv) { window->enable_keyboard(); window->setup_trackball(); framework.get_models().instance_to(window->get_render()); - // if (argc < 2) { If we have no arguments, get that trusty old triangle - // out. window->load_default_model(framework.get_models()); } else { - // window->load_models(framework.get_models(), argc, argv); } - - window->load_model(framework.get_models(), "panda-model.egg"); - window->load_model(framework.get_models(), "panda-walk4.egg"); + if (argc < 2) { + // If we have no arguments, get that trusty old triangle + // out. + window->load_default_model(framework.get_models()); + } else { + if (!window->load_models(framework.get_models(), argc, argv)) { + framework.close_framework(); + return 1; + } + } window->loop_animations(hierarchy_match_flags); diff --git a/panda/src/android/pview_manifest.xml b/panda/src/android/pview_manifest.xml index 133fa523aa..6b14579a80 100644 --- a/panda/src/android/pview_manifest.xml +++ b/panda/src/android/pview_manifest.xml @@ -5,11 +5,15 @@ android:versionCode="1" android:versionName="1.0"> - - + + + + + + android:configChanges="orientation|keyboardHidden" + android:launchMode="singleInstance"> @@ -17,6 +21,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +