aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorlanderlyoung <landerlyoung@gmail.com>2024-08-29 13:36:20 +0800
committerLanderlYoung <LanderlYoung@users.noreply.github.com>2024-08-29 14:33:42 +0800
commit68ad768bb8e63f99d3efe8e3fee83584f624a7d7 (patch)
tree7f83f8bafa2bf3c8062c69fa3864e1bd5b8035d2
parent17beebe2cca23863740ca310136026496774e52f (diff)
1. fix deprecated kotlin codeupstream/master
2. update demo code
-rw-r--r--.github/workflows/ci.yml (renamed from .github/workflows/android.yml)2
-rw-r--r--README.md6
-rw-r--r--compiler/src/main/java/io/github/landerlyoung/jenny/HandyHelper.kt2
-rw-r--r--compiler/src/main/java/io/github/landerlyoung/jenny/NativeProxyGenerator.kt8
-rwxr-xr-xrun_sample_java_test2
-rw-r--r--sample-android/src/main/cpp/ComputeIntensiveClass.cpp78
-rw-r--r--sample-android/src/main/cpp/NativeDrawable.cpp35
-rw-r--r--sample-android/src/main/java/io/github/landerlyoung/jennysampleapp/MainActivity.java34
-rw-r--r--sample-android/src/main/res/layout/content_main.xml11
9 files changed, 117 insertions, 61 deletions
diff --git a/.github/workflows/android.yml b/.github/workflows/ci.yml
index 59e3747..4296870 100644
--- a/.github/workflows/android.yml
+++ b/.github/workflows/ci.yml
@@ -1,4 +1,4 @@
-name: Android CI
+name: CI
on:
pull_request:
diff --git a/README.md b/README.md
index e6c7f5c..75d11b6 100644
--- a/README.md
+++ b/README.md
@@ -2,12 +2,12 @@
[![CI][CI_B]][CI] [![Publish][PUB_B]][PUB] [![MavenCentral][MV_B]][MV] ![GitHub code size in bytes][CS_B] ![GitHub][LC_B]
-[CI_B]: https://github.com/LanderlYoung/Jenny/workflows/Android%20CI/badge.svg
-[CI]: https://github.com/LanderlYoung/Jenny/actions?workflow=Android+CI
+[CI_B]: https://github.com/LanderlYoung/Jenny/workflows/CI/badge.svg
+[CI]: https://github.com/LanderlYoung/Jenny/actions?workflow=CI
[PUB_B]: https://github.com/LanderlYoung/Jenny/workflows/Publish/badge.svg
[PUB]: https://github.com/LanderlYoung/Jenny/actions?workflow=Publish
[MV_B]: https://img.shields.io/maven-central/v/io.github.landerlyoung/jenny-annotation
-[MV]: https://search.maven.org/artifact/io.github.landerlyoung/jenny-compiler
+[MV]: https://central.sonatype.com/artifact/io.github.landerlyoung/jenny-compiler
[CS_B]: https://img.shields.io/github/languages/code-size/LanderlYoung/Jenny
[LC_B]: https://img.shields.io/github/license/LanderlYoung/Jenny
diff --git a/compiler/src/main/java/io/github/landerlyoung/jenny/HandyHelper.kt b/compiler/src/main/java/io/github/landerlyoung/jenny/HandyHelper.kt
index 29d0f11..d2400a6 100644
--- a/compiler/src/main/java/io/github/landerlyoung/jenny/HandyHelper.kt
+++ b/compiler/src/main/java/io/github/landerlyoung/jenny/HandyHelper.kt
@@ -1 +1 @@
-/** * Copyright 2016 landerlyoung@gmail.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.github.landerlyoung.jenny import java.util.ArrayDeque import java.util.Locale import javax.lang.model.element.Element import javax.lang.model.element.ElementKind import javax.lang.model.element.ExecutableElement import javax.lang.model.element.Modifier import javax.lang.model.element.TypeElement import javax.lang.model.element.VariableElement import javax.lang.model.type.ArrayType import javax.lang.model.type.DeclaredType import javax.lang.model.type.IntersectionType import javax.lang.model.type.NoType import javax.lang.model.type.PrimitiveType import javax.lang.model.type.TypeKind import javax.lang.model.type.TypeMirror import javax.lang.model.type.TypeVariable import javax.lang.model.type.WildcardType /** * Author: landerlyoung@gmail.com * Date: 2014-12-17 * Time: 20:19 * Life with passion. Code with creativity! */ class HandyHelper(private val mEnv: Environment) { fun getBinaryMethodSignature(method: ExecutableElement): String { return Signature(method).toString() } fun getBinaryTypeSignature(type: TypeMirror): String { return Signature(type).toString() } /** * * example * Signature: (ILjava/lang/Runnable;LN/M_M;)V * JNIEXPORT void JNICALL Java_N_n__ILjava_lang_Runnable_2LN_M_1M_2 * * __ILjava_lang_Runnable_2LN_M_1M_2 */ fun getMethodOverloadPostfix(method: ExecutableElement): String { val signature = getBinaryMethodSignature(method) val paramSig = signature.subSequence(signature.indexOf('(') + 1, signature.indexOf(")")).toString() return "__" + paramSig.replace("_", "_1") .replace("/", "_") .replace(";", "_2") .stripNonASCII() } /** * @return like com.example_package.SomeClass$InnerClass */ fun getClassName(clazz: Element): String { val className = ArrayDeque<String>() val sb = StringBuilder() var e: Element? = clazz while (e != null && (e.kind.isClass || e.kind.isInterface)) { className.add(e.simpleName.toString()) e = e.enclosingElement } val pkg = mEnv.elementUtils.getPackageOf(clazz) if (pkg != null) { val pkgName = pkg.qualifiedName.toString() if (pkgName.isNotEmpty()) { sb.append(pkgName) sb.append('.') } } while (!className.isEmpty()) { sb.append(className.removeLast()) sb.append('$') } sb.deleteCharAt(sb.length - 1) return sb.toString() } /** * @return like com/example_package/SomeClass$InnerClass */ fun getSlashClassName(className: String): String { return className.replace('.', '/') } /** * @param className * * @return like com_example_1package_SomeClass_InnerClass */ fun toJNIClassName(className: String): String { return className.replace("_", "_1") .replace(".", "_") .stripNonASCII() } fun getModifiers(m: Element): String = m.modifiers.asSequence() .filter { modifier -> modifier == Modifier.PUBLIC || modifier == Modifier.PROTECTED || modifier == Modifier.PRIVATE || modifier == Modifier.FINAL || modifier == Modifier.STATIC || modifier == Modifier.ABSTRACT || modifier == Modifier.SYNCHRONIZED } .sorted() .joinToString(" ") { it.toString().toLowerCase(Locale.US) } fun getJavaMethodParam(m: ExecutableElement) = m.parameters.joinToString(", ") { it.asType().toString() + " " + it.simpleName } fun getReturnStatement(e: ExecutableElement): String = buildString { val returnType = e.returnType if (returnType is NoType) { return@buildString } append("return ") if (returnType is PrimitiveType) { if (returnType.kind == TypeKind.BOOLEAN) { append("JNI_FALSE") } else { append("0") } } else if (returnType.toString() == String::class.java.name) { append("env->NewStringUTF(\"Hello From Jenny\")") } else { append("nullptr") } append(";") } fun getConstexprStatement(it: VariableElement): String { val constValue = it.constantValue!! val t = it.asType() val nativeType = if (t == null) null else { val jniType = toJNIType(t) if (jniType == "jstring") { "auto" } else jniType } val value = if (constValue is Boolean) { if (constValue) "JNI_TRUE" else "JNI_FALSE" } else if (constValue is Number) { constValue.toString() } else if (constValue is Char) { "'${constValue}'" } else if (constValue is String) { "u8\"$constValue\"" } else { throw IllegalArgumentException("unknown type:$constValue " + constValue.javaClass) } return "static constexpr $nativeType ${it.simpleName} = ${value};" } fun getNativeMethodParam(m: ExecutableElement): String { val sb = StringBuilder() sb.append("JNIEnv* env") if (m.modifiers.contains(Modifier.STATIC)) { sb.append(", jclass clazz") } else { sb.append(", jobject thiz") } m.parameters.forEach { ve -> sb.append(", ") sb.append(toJNIType(ve.asType())) sb.append(' ') sb.append(ve.simpleName.toString()) } return sb.toString() } fun isNestedClass(clazz: Element): Boolean { val enclosingElement: Element? = clazz.enclosingElement return (enclosingElement != null && enclosingElement.kind == ElementKind.CLASS && !clazz.modifiers.contains(Modifier.STATIC)) } fun instanceOf(clazzName: String, typeMirror: TypeMirror): Boolean { var t = typeMirror while (clazzName != getNonGenericName(t)) { val base = mEnv.typeUtils.asElement(t) if (base is TypeElement) { val superClazz = base.superclass if (superClazz is NoType) return false t = superClazz } else { return false } } return true } fun getNonGenericName(t: TypeMirror): String = when (t) { is DeclaredType -> getClassName(t.asElement()) is TypeVariable -> { // function param val upper = t.upperBound getNonGenericName( if (upper is IntersectionType) { upper.bounds[0] } else { upper } ) } is WildcardType -> { // function param t.extendsBound?.let { getNonGenericName(it) } ?: java.lang.Object::class.java.name } is ArrayType -> { getNonGenericName(t.componentType) + "[]" } is PrimitiveType -> t.toString() is NoType -> "void" else -> throw IllegalArgumentException("TypeMirror kind: ${t.kind} is not supported ${t.javaClass}") } fun toJNIType(t: TypeMirror?): String { if (t == null) return "" // check if t is a subclass of java.lang.Throwable if (instanceOf(Throwable::class.java.name, t)) { return "jthrowable" } return when (t) { is PrimitiveType -> "j${t.kind.name.toLowerCase(Locale.US)}" is NoType -> "void" is ArrayType -> { if (t.componentType is PrimitiveType) { "j${t.componentType.kind.name.toLowerCase(Locale.US)}Array" } else { "jobjectArray" } } else -> { if (t is DeclaredType) { when (getClassName(t.asElement())) { "java.lang.String" -> "jstring" "java.lang.Class" -> "jclass" else -> "jobject" } } else { "jobject" } } } } private inner class Signature( private val mMethod: ExecutableElement?, private val mType: TypeMirror?) { constructor(method: ExecutableElement) : this(method, null) constructor(type: TypeMirror) : this(null, type) private fun StringBuilder.getSignatureClassName(_type: TypeMirror) { var type = _type while (type is ArrayType) { append('[') type = type.componentType } when (val name = getNonGenericName(type)) { "char" -> append('C') "byte" -> append('B') "short" -> append('S') "int" -> append('I') "long" -> append('J') "float" -> append('F') "double" -> append('D') "boolean" -> append('Z') "void" -> append('V') else -> append('L').append(name.replace('.', '/')).append(';') } } override fun toString(): String = if (mMethod != null) { buildString { append('(') if (mMethod.simpleName.contentEquals("<init>")) { val clazz = mMethod.enclosingElement if (isNestedClass(clazz)) { // generate this$0 param for nested class val enclosingClazz = clazz.enclosingElement getSignatureClassName(enclosingClazz.asType()) } } for (param in mMethod.parameters) { getSignatureClassName(param.asType()) } append(')') getSignatureClassName(mMethod.returnType) return toString() } } else { buildString { getSignatureClassName(mType!!) } } } } fun String.stripNonASCII(): String = this.replace("[^a-zA-Z0-9_]".toRegex()) { String.format(Locale.US, "_%05x", it.value.codePointAt(0)) } \ No newline at end of file
+/** * Copyright 2016 landerlyoung@gmail.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.github.landerlyoung.jenny import java.util.ArrayDeque import java.util.Locale import javax.lang.model.element.Element import javax.lang.model.element.ElementKind import javax.lang.model.element.ExecutableElement import javax.lang.model.element.Modifier import javax.lang.model.element.TypeElement import javax.lang.model.element.VariableElement import javax.lang.model.type.ArrayType import javax.lang.model.type.DeclaredType import javax.lang.model.type.IntersectionType import javax.lang.model.type.NoType import javax.lang.model.type.PrimitiveType import javax.lang.model.type.TypeKind import javax.lang.model.type.TypeMirror import javax.lang.model.type.TypeVariable import javax.lang.model.type.WildcardType /** * Author: landerlyoung@gmail.com * Date: 2014-12-17 * Time: 20:19 * Life with passion. Code with creativity! */ class HandyHelper(private val mEnv: Environment) { fun getBinaryMethodSignature(method: ExecutableElement): String { return Signature(method).toString() } fun getBinaryTypeSignature(type: TypeMirror): String { return Signature(type).toString() } /** * * example * Signature: (ILjava/lang/Runnable;LN/M_M;)V * JNIEXPORT void JNICALL Java_N_n__ILjava_lang_Runnable_2LN_M_1M_2 * * __ILjava_lang_Runnable_2LN_M_1M_2 */ fun getMethodOverloadPostfix(method: ExecutableElement): String { val signature = getBinaryMethodSignature(method) val paramSig = signature.subSequence(signature.indexOf('(') + 1, signature.indexOf(")")).toString() return "__" + paramSig.replace("_", "_1") .replace("/", "_") .replace(";", "_2") .stripNonASCII() } /** * @return like com.example_package.SomeClass$InnerClass */ fun getClassName(clazz: Element): String { val className = ArrayDeque<String>() val sb = StringBuilder() var e: Element? = clazz while (e != null && (e.kind.isClass || e.kind.isInterface)) { className.add(e.simpleName.toString()) e = e.enclosingElement } val pkg = mEnv.elementUtils.getPackageOf(clazz) if (pkg != null) { val pkgName = pkg.qualifiedName.toString() if (pkgName.isNotEmpty()) { sb.append(pkgName) sb.append('.') } } while (!className.isEmpty()) { sb.append(className.removeLast()) sb.append('$') } sb.deleteCharAt(sb.length - 1) return sb.toString() } /** * @return like com/example_package/SomeClass$InnerClass */ fun getSlashClassName(className: String): String { return className.replace('.', '/') } /** * @param className * * @return like com_example_1package_SomeClass_InnerClass */ fun toJNIClassName(className: String): String { return className.replace("_", "_1") .replace(".", "_") .stripNonASCII() } fun getModifiers(m: Element): String = m.modifiers.asSequence() .filter { modifier -> modifier == Modifier.PUBLIC || modifier == Modifier.PROTECTED || modifier == Modifier.PRIVATE || modifier == Modifier.FINAL || modifier == Modifier.STATIC || modifier == Modifier.ABSTRACT || modifier == Modifier.SYNCHRONIZED } .sorted() .joinToString(" ") { it.toString().lowercase(Locale.US) } fun getJavaMethodParam(m: ExecutableElement) = m.parameters.joinToString(", ") { it.asType().toString() + " " + it.simpleName } fun getReturnStatement(e: ExecutableElement): String = buildString { val returnType = e.returnType if (returnType is NoType) { return@buildString } append("return ") if (returnType is PrimitiveType) { if (returnType.kind == TypeKind.BOOLEAN) { append("JNI_FALSE") } else { append("0") } } else if (returnType.toString() == String::class.java.name) { append("env->NewStringUTF(\"Hello From Jenny\")") } else { append("nullptr") } append(";") } fun getConstexprStatement(it: VariableElement): String { val constValue = it.constantValue!! val t = it.asType() val nativeType = if (t == null) null else { val jniType = toJNIType(t) if (jniType == "jstring") { "auto" } else jniType } val value = if (constValue is Boolean) { if (constValue) "JNI_TRUE" else "JNI_FALSE" } else if (constValue is Number) { constValue.toString() } else if (constValue is Char) { "'${constValue}'" } else if (constValue is String) { "u8\"$constValue\"" } else { throw IllegalArgumentException("unknown type:$constValue " + constValue.javaClass) } return "static constexpr $nativeType ${it.simpleName} = ${value};" } fun getNativeMethodParam(m: ExecutableElement): String { val sb = StringBuilder() sb.append("JNIEnv* env") if (m.modifiers.contains(Modifier.STATIC)) { sb.append(", jclass clazz") } else { sb.append(", jobject thiz") } m.parameters.forEach { ve -> sb.append(", ") sb.append(toJNIType(ve.asType())) sb.append(' ') sb.append(ve.simpleName.toString()) } return sb.toString() } fun isNestedClass(clazz: Element): Boolean { val enclosingElement: Element? = clazz.enclosingElement return (enclosingElement != null && enclosingElement.kind == ElementKind.CLASS && !clazz.modifiers.contains(Modifier.STATIC)) } fun instanceOf(clazzName: String, typeMirror: TypeMirror): Boolean { var t = typeMirror while (clazzName != getNonGenericName(t)) { val base = mEnv.typeUtils.asElement(t) if (base is TypeElement) { val superClazz = base.superclass if (superClazz is NoType) return false t = superClazz } else { return false } } return true } fun getNonGenericName(t: TypeMirror): String = when (t) { is DeclaredType -> getClassName(t.asElement()) is TypeVariable -> { // function param val upper = t.upperBound getNonGenericName( if (upper is IntersectionType) { upper.bounds[0] } else { upper } ) } is WildcardType -> { // function param t.extendsBound?.let { getNonGenericName(it) } ?: java.lang.Object::class.java.name } is ArrayType -> { getNonGenericName(t.componentType) + "[]" } is PrimitiveType -> t.toString() is NoType -> "void" else -> throw IllegalArgumentException("TypeMirror kind: ${t.kind} is not supported ${t.javaClass}") } fun toJNIType(t: TypeMirror?): String { if (t == null) return "" // check if t is a subclass of java.lang.Throwable if (instanceOf(Throwable::class.java.name, t)) { return "jthrowable" } return when (t) { is PrimitiveType -> "j${t.kind.name.lowercase(Locale.US)}" is NoType -> "void" is ArrayType -> { if (t.componentType is PrimitiveType) { "j${t.componentType.kind.name.lowercase(Locale.US)}Array" } else { "jobjectArray" } } else -> { if (t is DeclaredType) { when (getClassName(t.asElement())) { "java.lang.String" -> "jstring" "java.lang.Class" -> "jclass" else -> "jobject" } } else { "jobject" } } } } private inner class Signature( private val mMethod: ExecutableElement?, private val mType: TypeMirror?) { constructor(method: ExecutableElement) : this(method, null) constructor(type: TypeMirror) : this(null, type) private fun StringBuilder.getSignatureClassName(_type: TypeMirror) { var type = _type while (type is ArrayType) { append('[') type = type.componentType } when (val name = getNonGenericName(type)) { "char" -> append('C') "byte" -> append('B') "short" -> append('S') "int" -> append('I') "long" -> append('J') "float" -> append('F') "double" -> append('D') "boolean" -> append('Z') "void" -> append('V') else -> append('L').append(name.replace('.', '/')).append(';') } } override fun toString(): String = if (mMethod != null) { buildString { append('(') if (mMethod.simpleName.contentEquals("<init>")) { val clazz = mMethod.enclosingElement if (isNestedClass(clazz)) { // generate this$0 param for nested class val enclosingClazz = clazz.enclosingElement getSignatureClassName(enclosingClazz.asType()) } } for (param in mMethod.parameters) { getSignatureClassName(param.asType()) } append(')') getSignatureClassName(mMethod.returnType) return toString() } } else { buildString { getSignatureClassName(mType!!) } } } } fun String.stripNonASCII(): String = this.replace("[^a-zA-Z0-9_]".toRegex()) { String.format(Locale.US, "_%05x", it.value.codePointAt(0)) } \ No newline at end of file
diff --git a/compiler/src/main/java/io/github/landerlyoung/jenny/NativeProxyGenerator.kt b/compiler/src/main/java/io/github/landerlyoung/jenny/NativeProxyGenerator.kt
index 6e3ae4f..5908229 100644
--- a/compiler/src/main/java/io/github/landerlyoung/jenny/NativeProxyGenerator.kt
+++ b/compiler/src/main/java/io/github/landerlyoung/jenny/NativeProxyGenerator.kt
@@ -400,7 +400,7 @@ class NativeProxyGenerator(env: Environment, clazz: TypeElement, nativeProxy: Na
private fun StringBuilder.buildFieldDefines(useJniHelper: Boolean) {
mFields.forEachIndexed { index, f ->
val isStatic = f.modifiers.contains(Modifier.STATIC)
- val camelCaseName = f.simpleName.toString().capitalize(Locale.ROOT)
+ val camelCaseName = f.simpleName.toString().capitalize()
val getterSetters = hasGetterSetter(f)
val fieldId = getFieldName(f, index)
val typeForJniCall = getTypeForJniCall(f.asType())
@@ -850,10 +850,14 @@ class NativeProxyGenerator(env: Environment, clazz: TypeElement, nativeProxy: Na
val result: String
val k = type.kind
result = if (k.isPrimitive || k == TypeKind.VOID) {
- k.name.toLowerCase(Locale.US)
+ k.name.lowercase(Locale.US)
} else {
"object"
}
return result.capitalize()
}
}
+
+// replace deprecated kotlin-stdlib one
+private fun String.capitalize():String =
+ replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.US) else it.toString() } \ No newline at end of file
diff --git a/run_sample_java_test b/run_sample_java_test
index 1c11dc6..d9a6b88 100755
--- a/run_sample_java_test
+++ b/run_sample_java_test
@@ -1,5 +1,5 @@
#! /usr/bin/env bash
-set -e
+set -e -x
echo ">>> build :sample-java"
./gradlew :sample-java:build
diff --git a/sample-android/src/main/cpp/ComputeIntensiveClass.cpp b/sample-android/src/main/cpp/ComputeIntensiveClass.cpp
index fc35b83..c880600 100644
--- a/sample-android/src/main/cpp/ComputeIntensiveClass.cpp
+++ b/sample-android/src/main/cpp/ComputeIntensiveClass.cpp
@@ -11,7 +11,7 @@
#include "gen/jenny_fusion_proxies.h"
/*
- * Class: io_github_landerlyoung_jennysampleapp_ComputeIntensiveClass
+ * Class: io.github.landerlyoung.jennysampleapp.ComputeIntensiveClass
* Method: public int addInNative(int a, int b)
* Signature: (II)I
*/
@@ -21,7 +21,7 @@ jint ComputeIntensiveClass::addInNative(JNIEnv* env, jobject thiz, jint a, jint
}
/*
- * Class: io_github_landerlyoung_jennysampleapp_ComputeIntensiveClass
+ * Class: io.github.landerlyoung.jennysampleapp.ComputeIntensiveClass
* Method: public static void computeSomething(byte[] sth)
* Signature: ([B)V
*/
@@ -30,7 +30,7 @@ void ComputeIntensiveClass::computeSomething(JNIEnv *env, jclass clazz, jbyteArr
}
/*
- * Class: io_github_landerlyoung_jennysampleapp_ComputeIntensiveClass
+ * Class: io.github.landerlyoung.jennysampleapp.ComputeIntensiveClass
* Method: public static java.lang.String greet()
* Signature: ()Ljava/lang/String;
*/
@@ -39,7 +39,7 @@ jstring ComputeIntensiveClass::greet(JNIEnv *env, jclass clazz) {
}
/*
- * Class: io_github_landerlyoung_jennysampleapp_ComputeIntensiveClass
+ * Class: io.github.landerlyoung.jennysampleapp.ComputeIntensiveClass
* Method: public final void testParamParse(int a, java.lang.String b, long[] c, float[][] d, java.lang.Exception e, java.lang.Class<java.lang.String> f, java.util.HashMap<?,?> g)
* Signature: (ILjava/lang/String;[J[[FLjava/lang/Exception;Ljava/lang/Class;Ljava/util/HashMap;)V
*/
@@ -48,7 +48,7 @@ void ComputeIntensiveClass::testParamParse(JNIEnv *env, jobject thiz, jint a, js
}
/*
- * Class: io_github_landerlyoung_jennysampleapp_ComputeIntensiveClass
+ * Class: io.github.landerlyoung.jennysampleapp.ComputeIntensiveClass
* Method: public static long returnsLong()
* Signature: ()J
*/
@@ -57,7 +57,7 @@ jlong ComputeIntensiveClass::returnsLong(JNIEnv *env, jclass clazz) {
}
/*
- * Class: io_github_landerlyoung_jennysampleapp_ComputeIntensiveClass
+ * Class: io.github.landerlyoung.jennysampleapp.ComputeIntensiveClass
* Method: public static boolean returnsBool()
* Signature: ()Z
*/
@@ -66,7 +66,7 @@ jboolean ComputeIntensiveClass::returnsBool(JNIEnv *env, jclass clazz) {
}
/*
- * Class: io_github_landerlyoung_jennysampleapp_ComputeIntensiveClass
+ * Class: io.github.landerlyoung.jennysampleapp.ComputeIntensiveClass
* Method: public static java.lang.Object returnsObject()
* Signature: ()Ljava/lang/Object;
*/
@@ -93,7 +93,7 @@ void ComputeIntensiveClass::testOverload__I(JNIEnv *env, jclass clazz, jint i) {
}
/*
- * Class: io_github_landerlyoung_jennysampleapp_ComputeIntensiveClass
+ * Class: io.github.landerlyoung.jennysampleapp.ComputeIntensiveClass
* Method: public static java.lang.String httpGet(java.lang.String url)
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
@@ -139,38 +139,62 @@ void ComputeIntensiveClass::runJniHelperTest(JNIEnv* env, jclass clazz) {
}
/*
- * Class: io_github_landerlyoung_jennysampleapp_ComputeIntensiveClass
+ * Class: io.github.landerlyoung.jennysampleapp.ComputeIntensiveClass
* Method: public int computeThenCallback(io.github.landerlyoung.jennysampleapp.Callback listener)
* Signature: (Lio/github/landerlyoung/jennysampleapp/Callback;)I
*/
jint ComputeIntensiveClass::computeThenCallback(JNIEnv* env, jobject thiz, jobject listener) {
- CallbackProxy::onJobStart(env, listener);
+ static int count = 0;
+ bool useJniHelper = count++ % 2 == 0;
+
+ if (useJniHelper) {
+ CallbackProxy proxy{listener, false};
+ auto name = proxy.getName();
+
+ auto newInstance = CallbackProxy::newInstance();
+ proxy.setLock(newInstance.getThis(false));
+ proxy.onJobProgress(20);
+
+ auto nestedClass = NestedClassProxy::newInstance(proxy.getThis(false));
+ proxy.setLock(nestedClass.getThis(false));
+ proxy.onJobProgress(50);
- auto name = CallbackProxy::getName(env, listener);
+ CallbackProxy::setAStaticField(nullptr);
+ proxy.setCount(100);
+ proxy.setLock(proxy.getThis(false));
+ proxy.onJobProgress(100);
- auto newInstance = CallbackProxy::newInstance(env);
- CallbackProxy::setLock(env, listener, newInstance);
- CallbackProxy::onJobProgress(env, listener, 20);
+ auto str = jenny::toJavaString("Yes, callback from jni w/ jnihelper");
+ proxy.onJobDone(JNI_TRUE, str);
+ } else {
+ CallbackProxy::onJobStart(env, listener);
- auto nestedClass = NestedClassProxy::newInstance(env, listener);
- CallbackProxy::setLock(env, newInstance, nestedClass);
- CallbackProxy::onJobProgress(env, listener, 50);
+ auto name = CallbackProxy::getName(env, listener);
- CallbackProxy::setAStaticField(env, nullptr);
+ auto newInstance = CallbackProxy::newInstance(env);
+ CallbackProxy::setLock(env, listener, newInstance);
+ CallbackProxy::onJobProgress(env, listener, 20);
- CallbackProxy::setCount(env, listener, 100);
- CallbackProxy::setLock(env, listener, listener);
- CallbackProxy::onJobProgress(env, listener, 100);
+ auto nestedClass = NestedClassProxy::newInstance(env, listener);
+ CallbackProxy::setLock(env, newInstance, nestedClass);
+ CallbackProxy::onJobProgress(env, listener, 50);
- jstring str = env->NewStringUTF("Yes, callback from jni");
- CallbackProxy::onJobDone(env, listener, JNI_TRUE, str);
+ CallbackProxy::setAStaticField(env, nullptr);
- env->DeleteLocalRef(name);
- env->DeleteLocalRef(str);
+ CallbackProxy::setCount(env, listener, 100);
+ CallbackProxy::setLock(env, listener, listener);
+ CallbackProxy::onJobProgress(env, listener, 100);
- env->DeleteLocalRef(newInstance);
- env->DeleteLocalRef(nestedClass);
+ jstring str = env->NewStringUTF("Yes, callback from jni w/o jnihelper");
+ CallbackProxy::onJobDone(env, listener, JNI_TRUE, str);
+
+ env->DeleteLocalRef(name);
+ env->DeleteLocalRef(str);
+
+ env->DeleteLocalRef(newInstance);
+ env->DeleteLocalRef(nestedClass);
+ }
return 0;
}
diff --git a/sample-android/src/main/cpp/NativeDrawable.cpp b/sample-android/src/main/cpp/NativeDrawable.cpp
index 41d1b70..8a7a95f 100644
--- a/sample-android/src/main/cpp/NativeDrawable.cpp
+++ b/sample-android/src/main/cpp/NativeDrawable.cpp
@@ -33,26 +33,39 @@ public:
/*
- * Class: io_github_landerlyoung_jennysampleapp_NativeDrawable
+ * Class: io.github.landerlyoung.jennysampleapp.NativeDrawable
* Method: private final long nativeInit()
* Signature: ()J
*/
jlong NativeDrawable::nativeInit(JNIEnv *env, jobject thiz) {
using jenny::GraphicsProxy;
using android::StyleProxy;
- GenericProxy::initClazz(env);
- auto fillType = android::StyleProxy::getFILL(env);
- auto paint = GraphicsProxy::newPaint(env);
- GraphicsProxy::paintSetStyle(env, paint, fillType);
+ static int count = 0;
+ bool useJniHelper = count++ % 2 == 0;
- auto paintGlobal = env->NewGlobalRef(paint);
+ if (useJniHelper) {
+ auto fillType = StyleProxy::getFILL();
+ auto paint = GraphicsProxy::newPaint();
+ GraphicsProxy::paintSetStyle(paint, fillType);
- return reinterpret_cast<jlong>(new State(paintGlobal));
+ auto paintGlobal = paint.toGlobal();
+ return reinterpret_cast<jlong>(new State(paintGlobal.release()));
+ } else {
+ auto fillType = StyleProxy::getFILL(env);
+ auto paint = GraphicsProxy::newPaint(env);
+ GraphicsProxy::paintSetStyle(env, paint, fillType);
+
+ auto paintGlobal = env->NewGlobalRef(paint);
+
+ env->DeleteLocalRef(fillType);
+ env->DeleteLocalRef(paint);
+ return reinterpret_cast<jlong>(new State(paintGlobal));
+ }
}
/*
- * Class: io_github_landerlyoung_jennysampleapp_NativeDrawable
+ * Class: io.github.landerlyoung.jennysampleapp.NativeDrawable
* Method: public final void onClick()
* Signature: ()V
*/
@@ -62,7 +75,7 @@ void NativeDrawable::onClick(JNIEnv *env, jobject thiz) {
}
/*
- * Class: io_github_landerlyoung_jennysampleapp_NativeDrawable
+ * Class: io.github.landerlyoung.jennysampleapp.NativeDrawable
* Method: public void draw(android.graphics.Canvas canvas)
* Signature: (Landroid/graphics/Canvas;)V
*/
@@ -82,10 +95,12 @@ void NativeDrawable::draw(JNIEnv *env, jobject thiz, jobject _canvas) {
RectProxy::exactCenterY(env, bounds)) * 0.7f,
state->paint
);
+
+ env->DeleteLocalRef(bounds);
}
/*
- * Class: io_github_landerlyoung_jennysampleapp_NativeDrawable
+ * Class: io.github.landerlyoung.jennysampleapp.NativeDrawable
* Method: public final void release()
* Signature: ()V
*/
diff --git a/sample-android/src/main/java/io/github/landerlyoung/jennysampleapp/MainActivity.java b/sample-android/src/main/java/io/github/landerlyoung/jennysampleapp/MainActivity.java
index 15d8b91..ebcbbba 100644
--- a/sample-android/src/main/java/io/github/landerlyoung/jennysampleapp/MainActivity.java
+++ b/sample-android/src/main/java/io/github/landerlyoung/jennysampleapp/MainActivity.java
@@ -18,15 +18,18 @@ package io.github.landerlyoung.jennysampleapp;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.view.View;
+import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.appcompat.widget.Toolbar;
+
import com.google.android.material.floatingactionbutton.FloatingActionButton;
-import com.google.android.material.snackbar.Snackbar;
+
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.widget.Toolbar;
+
public class MainActivity extends AppCompatActivity {
@@ -43,8 +46,8 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
mNativeDrawable = new NativeDrawable();
- View bg = findViewById(R.id.text);
- bg.setBackground(mNativeDrawable);
+ ImageView bg = findViewById(R.id.image);
+ bg.setImageDrawable(mNativeDrawable);
bg.setOnClickListener(v -> {
bg.invalidate();
mNativeDrawable.onClick();
@@ -57,6 +60,7 @@ public class MainActivity extends AppCompatActivity {
final ComputeIntensiveClass nativeClass = new ComputeIntensiveClass();
mTextView = findViewById(R.id.text);
+ mTextView.setOnClickListener(v -> mTextView.setText(null));
mTextView.setText("1 + 2 = " + nativeClass.addInNative(1, 2) + "\n");
mTextView.append(ComputeIntensiveClass.greet());
ComputeIntensiveClass.testOverload();
@@ -67,8 +71,10 @@ public class MainActivity extends AppCompatActivity {
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
- Snackbar.make(view, "Hello", Snackbar.LENGTH_SHORT)
- .show();
+ testComputeIntensiveClass(view);
+ }
+
+ private void testComputeIntensiveClass(View view) {
ComputeIntensiveClass.NestedNativeClass nestedNativeClass = new ComputeIntensiveClass.NestedNativeClass();
long handle = nestedNativeClass.nativeInit();
nestedNativeClass.testOverload();
@@ -79,12 +85,12 @@ public class MainActivity extends AppCompatActivity {
@Override
public void onJobDone(boolean success, String result) {
toast("success=" + success + " result=" + result
- + "\ncount=" + count + " obj==this = " + (lock == this));
+ + "\ncount=" + count + " obj==this = " + (lock == this) + "\n");
}
@Override
public void onJobProgress(long progress) {
- toast("onJobProgress = " + progress + " lock = " + System.identityHashCode(lock));
+ toast("onJobProgress = " + progress + " lock = " + lock);
}
@Override
@@ -104,8 +110,9 @@ public class MainActivity extends AppCompatActivity {
}
private void testNativeHttpGet() {
- final String json = ComputeIntensiveClass
- .httpGet("https://jsonplaceholder.typicode.com/todos/1");
+ String url = "https://jsonplaceholder.typicode.com/todos/1";
+ runOnUiThread(() -> toast("http get: " + url + "\n"));
+ final String json = ComputeIntensiveClass.httpGet(url);
runOnUiThread(() -> toast("http got\n" + json));
}
@@ -121,9 +128,4 @@ public class MainActivity extends AppCompatActivity {
mTextView.append(msg);
}
- public void test(Callback callback) {
- int a = Callback.COMPILE_CONSTANT_INT;
- int b = callback.count;
- int c = a + b;
- }
}
diff --git a/sample-android/src/main/res/layout/content_main.xml b/sample-android/src/main/res/layout/content_main.xml
index 416e148..f714105 100644
--- a/sample-android/src/main/res/layout/content_main.xml
+++ b/sample-android/src/main/res/layout/content_main.xml
@@ -15,6 +15,7 @@
android:layout_height="match_parent"
android:text="Hello World!"
android:padding="10dp"
+ android:fontFamily="monospace"
app:layout_constraintBottom_toBottomOf="@+id/content_main"
app:layout_constraintLeft_toLeftOf="@+id/content_main"
app:layout_constraintRight_toRightOf="@+id/content_main"
@@ -22,4 +23,14 @@
android:id="@+id/text"
/>
+ <ImageView
+ android:id="@+id/image"
+ android:layout_width="256dp"
+ android:layout_height="256dp"
+ android:padding="16dp"
+ android:alpha="0.5"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ />
+
</androidx.constraintlayout.widget.ConstraintLayout>