mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-30 08:44:19 -04:00
android: allow launching pview by opening models (using Intents)
Also add code to show notification toasts. Also enable model cache by default (pointing to app cache dir)
This commit is contained in:
parent
10789f6936
commit
ae0f82911b
@ -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");
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "configVariableBool.h"
|
||||
#include "configVariableInt.h"
|
||||
|
||||
#include <android/native_activity.h>
|
||||
#include <jni.h>
|
||||
|
||||
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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -5,11 +5,15 @@
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0">
|
||||
|
||||
<uses-sdk android:minSdkVersion="9" />
|
||||
<application android:label="Panda Viewer" android:hasCode="true">
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-sdk android:minSdkVersion="21" />
|
||||
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
|
||||
|
||||
<application android:label="Panda Viewer" android:hasCode="true" android:debuggable="true">
|
||||
<activity android:name="org.panda3d.android.PandaActivity"
|
||||
android:label="Panda Viewer" android:theme="@android:style/Theme.NoTitleBar"
|
||||
android:configChanges="orientation|keyboardHidden">
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:launchMode="singleInstance">
|
||||
|
||||
<meta-data android:name="android.app.lib_name"
|
||||
android:value="pview" />
|
||||
@ -17,6 +21,36 @@
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:mimeType="model/x-egg" />
|
||||
<data android:mimeType="model/x-compressed-egg" />
|
||||
<data android:mimeType="model/x-bam" />
|
||||
<data android:mimeType="model/x-compressed-bam" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:mimeType="*/*" android:scheme="file" />
|
||||
<data android:pathPattern=".*\\.egg" />
|
||||
<data android:pathPattern=".*\\.egg.pz" />
|
||||
<data android:pathPattern=".*\\.egg.gz" />
|
||||
<data android:pathPattern=".*\\.bam" />
|
||||
<data android:pathPattern=".*\\.bam.pz" />
|
||||
<data android:pathPattern=".*\\.bam.gz" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:mimeType="*/*" scheme="content" host="com.termux.files" />
|
||||
<data android:pathPattern=".*\\.egg" />
|
||||
<data android:pathPattern=".*\\.egg.pz" />
|
||||
<data android:pathPattern=".*\\.egg.gz" />
|
||||
<data android:pathPattern=".*\\.bam" />
|
||||
<data android:pathPattern=".*\\.bam.pz" />
|
||||
<data android:pathPattern=".*\\.bam.gz" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user