From daf348442695a7288e7a03afd98d4002c34decf3 Mon Sep 17 00:00:00 2001 From: omigamedev Date: Sun, 30 Sep 2018 23:51:15 +0200 Subject: [PATCH] disable ssl in curl on android, implement interactive permission for android 23+ --- android/build.gradle | 10 +- android/src/main/cpp/main.cpp | 54 ++++++++++- .../com/omixlab/panopainter/MainActivity.java | 97 +++++++++++++++++++ src/app.cpp | 10 ++ src/canvas.cpp | 4 +- src/canvas_modes.cpp | 2 +- src/log.cpp | 3 + src/node_canvas.cpp | 2 +- src/node_dialog_cloud.cpp | 4 + 9 files changed, 175 insertions(+), 11 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index ad0a783..1f57e52 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -86,11 +86,11 @@ android { //cFlags "-D_EXAMPLE_C_FLAG1", "-D_EXAMPLE_C_FLAG2" // Sets a flag to enable format macro constants for the C++ compiler. //cppFlags "-D__STDC_FORMAT_MACROS" - arguments '-DANDROID_TOOLCHAIN=clang', - //'-DANDROID_PLATFORM=android-19', - '-DANDROID_STL=gnustl_static', - '-DCMAKE_BUILD_TYPE=Release', - '-DANDROID_ARM_NEON=TRUE' + arguments "-DANDROID_TOOLCHAIN=clang", + //"-DANDROID_PLATFORM=android-19", + "-DANDROID_STL=gnustl_static", + "-DCMAKE_BUILD_TYPE=${flavor_cap}", + "-DANDROID_ARM_NEON=TRUE" } } ndk { diff --git a/android/src/main/cpp/main.cpp b/android/src/main/cpp/main.cpp index 1353c92..7e512a2 100755 --- a/android/src/main/cpp/main.cpp +++ b/android/src/main/cpp/main.cpp @@ -259,6 +259,15 @@ JNIEXPORT void JNICALL Java_com_omixlab_panopainter_MainActivity_pickFileCallbac } }; } +JNIEXPORT void JNICALL Java_com_omixlab_panopainter_MainActivity_pickExternalCallback(JNIEnv *env, jobject, jstring path) +{ + const char* path_utf = env->GetStringUTFChars(path, nullptr); + std::string file_path = path_utf; // create a copy + env->ReleaseStringUTFChars(path, path_utf); + + LOG("data_path %s", file_path.c_str()); + App::I.data_path = file_path; +} } void pick_file(android_app* mApplication, std::function callback) @@ -294,7 +303,6 @@ void pick_file(android_app* mApplication, std::function callb lJavaVM->DetachCurrentThread(); } - float get_display_density(android_app* mApplication) { // Attaches the current thread to the JVM. @@ -327,6 +335,42 @@ float get_display_density(android_app* mApplication) return density; } +std::string get_data_path(android_app* mApplication) +{ + // Attaches the current thread to the JVM. + jint lResult; + jint lFlags = 0; + + JavaVM* lJavaVM = mApplication->activity->vm; + JNIEnv* lJNIEnv = mApplication->activity->env; + + JavaVMAttachArgs lJavaVMAttachArgs; + lJavaVMAttachArgs.version = JNI_VERSION_1_6; + lJavaVMAttachArgs.name = "NativeThread"; + lJavaVMAttachArgs.group = NULL; + + lResult=lJavaVM->AttachCurrentThread(&lJNIEnv, &lJavaVMAttachArgs); + if (lResult == JNI_ERR) + { + return ""; + } + + // Retrieves NativeActivity. + jobject lNativeActivity = mApplication->activity->clazz; + jclass ClassNativeActivity = lJNIEnv->GetObjectClass(lNativeActivity); + + jmethodID MethodPickFile = lJNIEnv->GetMethodID(ClassNativeActivity, "getDataPath", "()Ljava/lang/String;"); + jstring path = (jstring)lJNIEnv->CallObjectMethod(lNativeActivity, MethodPickFile); + + const char* path_utf = lJNIEnv->GetStringUTFChars(path, nullptr); + std::string file_path = path_utf; // create a copy + lJNIEnv->ReleaseStringUTFChars(path, path_utf); + + // Finished with the JVM. + lJavaVM->DetachCurrentThread(); + return file_path; +} + /** * Initialize an EGL context for the current display. */ @@ -594,7 +638,13 @@ static int engine_init_display(struct engine* engine) { Asset::m_am = engine->app->activity->assetManager; App::I.and_app = engine->app; App::I.and_engine = engine; - App::I.data_path = "/sdcard/PanoPainter";// engine->app->activity->externalDataPath; + + //std::string base_path = engine->app->activity->externalDataPath ? + // engine->app->activity->externalDataPath : get_data_path(engine->app); + if (App::I.data_path.empty() || App::I.data_path == ".") + App::I.data_path = get_data_path(engine->app); + LOG("data_path %s", App::I.data_path.c_str()); + App::I.width = w; App::I.height = h; App::I.redraw = true; diff --git a/android/src/main/java/com/omixlab/panopainter/MainActivity.java b/android/src/main/java/com/omixlab/panopainter/MainActivity.java index c9566e5..42d3081 100644 --- a/android/src/main/java/com/omixlab/panopainter/MainActivity.java +++ b/android/src/main/java/com/omixlab/panopainter/MainActivity.java @@ -1,11 +1,20 @@ package com.omixlab.panopainter; +import android.Manifest; +import android.app.Activity; import android.app.NativeActivity; import android.content.Intent; +import android.content.pm.PackageManager; import android.net.Uri; +import android.os.Bundle; +import android.os.Environment; import android.util.Log; import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.IOException; import java.net.URISyntaxException; public class MainActivity extends NativeActivity { @@ -13,7 +22,95 @@ public class MainActivity extends NativeActivity { System.loadLibrary("native-lib"); } + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + checkPermissionReadStorage(); + } + public native void pickFileCallback(String path); + public native void pickExternalCallback(String path); + + public void setRootPath() + { + Log.v("MainActivity", "permission granted"); + File d = Environment.getExternalStorageDirectory(); + File pano_dir = new File(d, "PanoPainter"); + + if (!pano_dir.exists()) + { + if (pano_dir.mkdirs()) + Log.v("MainActivity", "create path " + pano_dir.getAbsolutePath()); + else + Log.v("MainActivity", "create path failed"); + + } + pickExternalCallback(pano_dir.getAbsolutePath()); + } + public void checkPermissionReadStorage(){ + Log.v("MainActivity", "permission checking"); + if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M) { + setRootPath(); + } else { + if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + + // Should we show an explanation? + /*if (shouldShowRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE)) { + + // Show an expanation to the user *asynchronously* -- don't block + // this thread waiting for the user's response! After the user + // sees the explanation, try again to request the permission. + Log.v("MainActivity", "permission explanation"); + + + } else { +*/ + // No explanation needed, we can request the permission. + + requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1); + Log.v("MainActivity", "permission request"); + + // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an + // app-defined int constant. The callback method gets the + // result of the request. + // } + } else { + Log.v("MainActivity", "permission already granted"); + setRootPath(); + } + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, + String permissions[], int[] grantResults) { + switch (requestCode) { + case 1: { + //premission to read storage + if (grantResults.length > 0 + && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + + // permission was granted, yay! Do the + // contacts-related task you need to do. + setRootPath(); + } else { + Log.v("MainActivity", "permission denied"); + + // permission denied, boo! Disable the + // functionality that depends on this permission. + //Toast.makeText(this, "We Need permission Storage", Toast.LENGTH_SHORT).show(); + } + return; + } + + // other 'case' lines to check for other + // permissions this app might request + } + } + + public String getDataPath() { + return getExternalFilesDir(null).getAbsolutePath(); + } public float getDensity() { diff --git a/src/app.cpp b/src/app.cpp index 806badc..039b15f 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -202,9 +202,13 @@ void App::download(std::string filename, std::function progress) auto dest = data_path + "/" + filename; FILE* fp = fopen(dest.c_str(), "wb"); std::string url = "https://panopainter.com/cloud/cloud-dwl.php?file=" + filename; + LOG("download %s to %s", url.c_str(), dest.c_str()); curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_data_write); +#ifdef __ANDROID__ + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); +#endif if (progress) { curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, progress_callback_download); @@ -237,6 +241,9 @@ bool App::check_license() //curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_data_handler); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 2L); +#ifdef __ANDROID__ + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); +#endif auto err = curl_easy_perform(curl); curl_easy_cleanup(curl); @@ -274,6 +281,9 @@ void App::upload(std::string filename, std::string name, std::functionm_width || new_size.y != m_canvas->m_height) { -#if __IOS__ +#if defined(__IOS__) || defined(__ANDROID__) m_canvas->m_mixer.create((int)new_size.x * m_canvas->m_mixer_scale, (int)new_size.y * m_canvas->m_mixer_scale, -1, GL_RGBA16F); #else diff --git a/src/node_dialog_cloud.cpp b/src/node_dialog_cloud.cpp index e5db967..b9d784c 100644 --- a/src/node_dialog_cloud.cpp +++ b/src/node_dialog_cloud.cpp @@ -69,10 +69,14 @@ void NodeDialogCloud::load_thumbs_thread() curl_easy_setopt(curl, CURLOPT_WRITEDATA, &res); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_data_handler); curl_easy_setopt(curl, CURLOPT_URL, "https://panopainter.com/cloud/cloud-list.php"); +#ifdef __ANDROID__ + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); +#endif auto err = curl_easy_perform(curl); if (err != CURLE_OK) { + LOG("connection error: %d", err); async_start(); text->set_text("Could not connect to the server"); async_update();