implement android import, update android project and build for release

This commit is contained in:
2018-09-30 13:42:17 +02:00
parent 413311e56e
commit 0ec8435357
9 changed files with 321 additions and 22 deletions

2
.gitignore vendored
View File

@@ -21,3 +21,5 @@ panopainter-log.txt
*.pano
frames/
src/version.gen.h
com_omixlab_panopainter_MainActivity.h
android/release

View File

@@ -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,8 +55,8 @@ 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',
arguments '-DANDROID_TOOLCHAIN=clang',
//'-DANDROID_PLATFORM=android-19',
'-DANDROID_STL=gnustl_static',
'-DCMAKE_BUILD_TYPE=Release',
'-DANDROID_ARM_NEON=TRUE'
@@ -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()
}

View File

@@ -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

Binary file not shown.

View File

@@ -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" />

View File

@@ -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

View File

@@ -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();
}
}
}
}

View 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());
}
}

View File

@@ -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())