implement android import, update android project and build for release
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -21,3 +21,5 @@ panopainter-log.txt
|
||||
*.pano
|
||||
frames/
|
||||
src/version.gen.h
|
||||
com_omixlab_panopainter_MainActivity.h
|
||||
android/release
|
||||
|
||||
@@ -1,21 +1,49 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
maven {
|
||||
url "https://plugins.gradle.org/m2/"
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:2.3.1'
|
||||
classpath 'com.android.tools.build:gradle:3.2.0'
|
||||
classpath "gradle.plugin.com.gladed.gradle.androidgitversion:gradle-android-git-version:0.4.5"
|
||||
}
|
||||
}
|
||||
apply plugin: 'android'
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google() // and here
|
||||
jcenter()
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: "com.android.application"
|
||||
apply plugin: "com.gladed.androidgitversion"
|
||||
|
||||
Properties properties = new Properties()
|
||||
properties.load(project.rootProject.file('local.properties').newDataInputStream())
|
||||
def sdkDir = properties.getProperty("sdk.dir")
|
||||
def classpath = "build/intermediates/classes/debug:" + sdkDir + "/platforms/android-26/android.jar"
|
||||
def activity = "com.omixlab.panopainter.MainActivity"
|
||||
def outpath = "src/main/cpp"
|
||||
|
||||
def ver_branch = "git rev-parse --abbrev-ref HEAD".execute().text.trim()
|
||||
def ver_hash = "git log --pretty=format:%h -n 1".execute().text.trim()
|
||||
def ver_count = Integer.parseInt("git rev-list --count HEAD".execute().text.trim())
|
||||
def ver_tag = "git describe --tags --abbrev=0".execute().text.trim()
|
||||
|
||||
android {
|
||||
compileSdkVersion 19
|
||||
buildToolsVersion '25.0.0'
|
||||
compileSdkVersion 26
|
||||
android.buildToolsVersion "28.0.3"
|
||||
|
||||
defaultConfig {
|
||||
applicationId = 'com.omigamedev'
|
||||
minSdkVersion 9
|
||||
targetSdkVersion 19
|
||||
applicationId = 'com.omixlab.panopainter'
|
||||
minSdkVersion 19
|
||||
targetSdkVersion 26
|
||||
versionCode ver_count
|
||||
versionName "${ver_tag}.${ver_count}"
|
||||
// This block is different from the one you use to link Gradle
|
||||
// to your CMake or ndk-build script.
|
||||
externalNativeBuild {
|
||||
@@ -27,11 +55,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_PLATFORM=android-19',
|
||||
'-DANDROID_TOOLCHAIN=clang',
|
||||
'-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=Release',
|
||||
'-DANDROID_ARM_NEON=TRUE'
|
||||
}
|
||||
}
|
||||
ndk {
|
||||
@@ -52,10 +80,20 @@ android {
|
||||
// }
|
||||
// }
|
||||
|
||||
signingConfigs {
|
||||
release {
|
||||
storeFile file("ppkey.jks")
|
||||
storePassword "om4r@Pano#Painter_2018"
|
||||
keyAlias "PanoPainter"
|
||||
keyPassword "om4r@Pano#Painter_2018"
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFile getDefaultProguardFile('proguard-android.txt')
|
||||
signingConfig signingConfigs.release
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,3 +118,13 @@ task generateVersioning(type: Exec) {
|
||||
commandLine 'python', 'scripts/pre-build.py', 'release'
|
||||
}
|
||||
copyFiles.dependsOn(generateVersioning)
|
||||
|
||||
task generateJavaH(type: Exec) {
|
||||
workingDir "$projectDir"
|
||||
commandLine 'javah', "-jni", "-force", "-cp", "$classpath", "-d", "$outpath", "$activity"
|
||||
}
|
||||
generateVersioning.dependsOn(generateJavaH)
|
||||
|
||||
repositories {
|
||||
google()
|
||||
}
|
||||
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
|
||||
|
||||
BIN
android/ppkey.jks
Normal file
BIN
android/ppkey.jks
Normal file
Binary file not shown.
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.omigamedev"
|
||||
package="com.omixlab.panopainter"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0">
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
@@ -9,13 +9,11 @@
|
||||
<application android:label="@string/app_name"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:allowBackup="false"
|
||||
android:hasCode="false"
|
||||
android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
|
||||
<activity android:name="android.app.NativeActivity"
|
||||
<activity android:name=".MainActivity"
|
||||
android:label="@string/app_name"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:screenOrientation="sensorLandscape"
|
||||
android:noHistory="true"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<meta-data android:name="android.app.lib_name"
|
||||
android:value="native-lib" />
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "asset.h"
|
||||
#include "keymap.h"
|
||||
#include "main.h"
|
||||
#include "com_omixlab_panopainter_MainActivity.h"
|
||||
|
||||
typedef void (*GLDEBUGPROC)(GLenum source,
|
||||
GLenum type,
|
||||
@@ -51,6 +52,12 @@ typedef void (*fnDebugMessageCallback)(GLDEBUGPROC callback, const void* userPar
|
||||
EGLDisplay g_display = EGL_NO_DISPLAY;
|
||||
EGLContext g_context = EGL_NO_CONTEXT;
|
||||
|
||||
jint JNI_OnLoad(JavaVM* vm, void* /*reserved*/)
|
||||
{
|
||||
LOG("JNI_OnLoad");
|
||||
return JNI_VERSION_1_6;
|
||||
}
|
||||
|
||||
std::string utf8chr(int cp)
|
||||
{
|
||||
char c[5]={ 0x00,0x00,0x00,0x00,0x00 };
|
||||
@@ -226,6 +233,100 @@ void displayKeyboard(android_app* mApplication, bool pShow)
|
||||
lJavaVM->DetachCurrentThread();
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: com_omixlab_panopainter_MainActivity
|
||||
* Method: pickFileCallback
|
||||
* Signature: (Ljava/lang/String;)V
|
||||
*/
|
||||
std::function<void(std::string)> pick_file_callback;
|
||||
std::function<void()> pick_file_callback_context;
|
||||
extern "C"
|
||||
{
|
||||
JNIEXPORT void JNICALL Java_com_omixlab_panopainter_MainActivity_pickFileCallback(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("received %s", file_path.c_str());
|
||||
pick_file_callback_context = [file_path]
|
||||
{
|
||||
if (pick_file_callback)
|
||||
{
|
||||
LOG("callback");
|
||||
pick_file_callback(file_path);
|
||||
pick_file_callback = nullptr;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
void pick_file(android_app* mApplication, std::function<void(std::string)> callback)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
pick_file_callback = callback;
|
||||
|
||||
// Retrieves NativeActivity.
|
||||
jobject lNativeActivity = mApplication->activity->clazz;
|
||||
jclass ClassNativeActivity = lJNIEnv->GetObjectClass(lNativeActivity);
|
||||
|
||||
jmethodID MethodPickFile = lJNIEnv->GetMethodID(ClassNativeActivity, "pickFile", "()V");
|
||||
lJNIEnv->CallVoidMethod(lNativeActivity, MethodPickFile);
|
||||
|
||||
// Finished with the JVM.
|
||||
lJavaVM->DetachCurrentThread();
|
||||
}
|
||||
|
||||
|
||||
float get_display_density(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 1;
|
||||
}
|
||||
|
||||
// Retrieves NativeActivity.
|
||||
jobject lNativeActivity = mApplication->activity->clazz;
|
||||
jclass ClassNativeActivity = lJNIEnv->GetObjectClass(lNativeActivity);
|
||||
|
||||
jmethodID MethodPickFile = lJNIEnv->GetMethodID(ClassNativeActivity, "getDensity", "()F");
|
||||
float density = lJNIEnv->CallFloatMethod(lNativeActivity, MethodPickFile);
|
||||
|
||||
// Finished with the JVM.
|
||||
lJavaVM->DetachCurrentThread();
|
||||
return density;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize an EGL context for the current display.
|
||||
*/
|
||||
@@ -376,12 +477,17 @@ static int engine_init_display(struct engine* engine) {
|
||||
engine->height = h;
|
||||
engine->state.angle = 0;
|
||||
|
||||
float density = get_display_density(engine->app);
|
||||
LOG("density %f", density);
|
||||
App::I.zoom = density / 1.5;
|
||||
|
||||
g_display = display;
|
||||
g_context = context;
|
||||
|
||||
if (resuming_context)
|
||||
{
|
||||
LOG("RESUME APP");
|
||||
App::I.and_app = engine->app;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -855,11 +961,12 @@ void android_main(struct android_app* state) {
|
||||
}
|
||||
|
||||
//if (engine.animating)
|
||||
if (engine.display != EGL_NO_DISPLAY)
|
||||
{
|
||||
// Done with events; draw next animation frame.
|
||||
engine.state.angle += .01f;
|
||||
if (engine.state.angle > 1) {
|
||||
engine.state.angle = 0;
|
||||
if (pick_file_callback_context)
|
||||
{
|
||||
pick_file_callback_context();
|
||||
pick_file_callback_context = nullptr;
|
||||
}
|
||||
|
||||
// Drawing is throttled to the screen update rate, so there
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.omixlab.panopainter;
|
||||
|
||||
import android.app.NativeActivity;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
public class MainActivity extends NativeActivity {
|
||||
static {
|
||||
System.loadLibrary("native-lib");
|
||||
}
|
||||
|
||||
public native void pickFileCallback(String path);
|
||||
|
||||
public float getDensity()
|
||||
{
|
||||
return getResources().getDisplayMetrics().density;
|
||||
}
|
||||
|
||||
public void pickFile()
|
||||
{
|
||||
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
intent.setType("*/*");
|
||||
startActivityForResult(Intent.createChooser(intent, "Select a file"), 1);
|
||||
Log.v("PICK", "start");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if(requestCode == 1 && resultCode == RESULT_OK) {
|
||||
Uri uri = data.getData();
|
||||
//File myFile = new File(uri.getPath());
|
||||
//String path = myFile.getAbsolutePath();
|
||||
String path = null;
|
||||
try {
|
||||
path = PathUtil.getPath(this, uri);
|
||||
Log.v("PICK", "selected " + path);
|
||||
pickFileCallback(path);
|
||||
} catch (URISyntaxException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
94
android/src/main/java/com/omixlab/panopainter/PathUtil.java
Normal file
94
android/src/main/java/com/omixlab/panopainter/PathUtil.java
Normal file
@@ -0,0 +1,94 @@
|
||||
package com.omixlab.panopainter;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.ContentUris;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.provider.MediaStore;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
/**
|
||||
* Created by Aki on 1/7/2017.
|
||||
*/
|
||||
|
||||
public class PathUtil {
|
||||
/*
|
||||
* Gets the file path of the given Uri.
|
||||
*/
|
||||
@SuppressLint("NewApi")
|
||||
public static String getPath(Context context, Uri uri) throws URISyntaxException {
|
||||
final boolean needToCheckUri = Build.VERSION.SDK_INT >= 19;
|
||||
String selection = null;
|
||||
String[] selectionArgs = null;
|
||||
// Uri is different in versions after KITKAT (Android 4.4), we need to
|
||||
// deal with different Uris.
|
||||
if (needToCheckUri && DocumentsContract.isDocumentUri(context.getApplicationContext(), uri)) {
|
||||
if (isExternalStorageDocument(uri)) {
|
||||
final String docId = DocumentsContract.getDocumentId(uri);
|
||||
final String[] split = docId.split(":");
|
||||
return Environment.getExternalStorageDirectory() + "/" + split[1];
|
||||
} else if (isDownloadsDocument(uri)) {
|
||||
final String id = DocumentsContract.getDocumentId(uri);
|
||||
uri = ContentUris.withAppendedId(
|
||||
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
|
||||
} else if (isMediaDocument(uri)) {
|
||||
final String docId = DocumentsContract.getDocumentId(uri);
|
||||
final String[] split = docId.split(":");
|
||||
final String type = split[0];
|
||||
if ("image".equals(type)) {
|
||||
uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
|
||||
} else if ("video".equals(type)) {
|
||||
uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
|
||||
} else if ("audio".equals(type)) {
|
||||
uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
|
||||
}
|
||||
selection = "_id=?";
|
||||
selectionArgs = new String[]{ split[1] };
|
||||
}
|
||||
}
|
||||
if ("content".equalsIgnoreCase(uri.getScheme())) {
|
||||
String[] projection = { MediaStore.Images.Media.DATA };
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
|
||||
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
|
||||
if (cursor.moveToFirst()) {
|
||||
return cursor.getString(column_index);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
}
|
||||
} else if ("file".equalsIgnoreCase(uri.getScheme())) {
|
||||
return uri.getPath();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param uri The Uri to check.
|
||||
* @return Whether the Uri authority is ExternalStorageProvider.
|
||||
*/
|
||||
public static boolean isExternalStorageDocument(Uri uri) {
|
||||
return "com.android.externalstorage.documents".equals(uri.getAuthority());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param uri The Uri to check.
|
||||
* @return Whether the Uri authority is DownloadsProvider.
|
||||
*/
|
||||
public static boolean isDownloadsDocument(Uri uri) {
|
||||
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param uri The Uri to check.
|
||||
* @return Whether the Uri authority is MediaProvider.
|
||||
*/
|
||||
public static boolean isMediaDocument(Uri uri) {
|
||||
return "com.android.providers.media.documents".equals(uri.getAuthority());
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#ifdef __ANDROID__
|
||||
void displayKeyboard(android_app* mApplication, bool pShow);
|
||||
void pick_file(android_app* mApplication, std::function<void(std::string)> callback);
|
||||
#elif _WIN32
|
||||
std::string win32_open_file();
|
||||
#endif
|
||||
@@ -55,7 +56,7 @@ void App::pick_image(std::function<void(std::string path)> callback)
|
||||
callback(path);
|
||||
});
|
||||
#elif __ANDROID__
|
||||
//displayKeyboard(and_app, false);
|
||||
pick_file(and_app, callback);
|
||||
#elif _WIN32
|
||||
std::string path = win32_open_file();
|
||||
if (!path.empty())
|
||||
|
||||
Reference in New Issue
Block a user