diff --git a/.travis.yml b/.travis.yml index 4ec0908ed..c1d7debc3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ env: global: - NODE_VERSION=6.11.1 - - NDK_VERSION=r17b + - NDK_VERSION=r18b - DATE=$(date +%Y-%m-%d) - PACKAGE_VERSION=next-$DATE-$TRAVIS_BUILD_NUMBER - EMULATOR_API_LEVEL=21 diff --git a/CHANGELOG.md b/CHANGELOG.md index eec68ad38..a104a6efb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,29 @@ +5.2.0 +== + +## What's New + - [Upgrade v8 to 7.1.302.32(#1237)](https://github.com/NativeScript/android-runtime/issues/1237) + - [Add OnDiscardedError handler(#1245)](https://github.com/NativeScript/android-runtime/issues/1245) + - [Upgrade the android gradle plugin to the latest 3.3.0 version(#1251)](https://github.com/NativeScript/android-runtime/issues/1251) + - [Add android X support(#1226)](https://github.com/NativeScript/android-runtime/issues/1226) + - [Provide a JS helper function on the global object to release the native object wrapped by a JS instance(#1254)](https://github.com/NativeScript/android-runtime/issues/1254) + +## Bug Fixes + + - [ClassNotFound exception when calling nested static class with correct argument(#1195)](https://github.com/NativeScript/android-runtime/issues/1195) + - [If you refresh or close the chrome dev tools window an error will be log in the console (#1202)](https://github.com/NativeScript/android-runtime/issues/1202) + - [Debug on Android fails when stopped on breakpoint and change in .xml/.css/.html is applied(#1243)](https://github.com/NativeScript/android-runtime/issues/1243) + - [Breakpoint stop to hit when you have two open tabs and close one(#1247)](https://github.com/NativeScript/android-runtime/issues/1247) + - [ClassNotFound exception when calling nested static class with correct argument(#1195)](https://github.com/NativeScript/android-runtime/issues/1195) + - [Upgrade V8 to v7 to fix unstable sort() method(#1176)](https://github.com/NativeScript/android-runtime/issues/1176) + - [CodeCache option is broken since Android Runtime 4.1.0(#1235)](https://github.com/NativeScript/android-runtime/issues/1235) + - [Snapshots with ABI splits do not work since Android Runtime 4.1.0(#1234)](https://github.com/NativeScript/android-runtime/issues/1234) + 5.1.0 == ## What's New - - [Add a setting to wrap calls to CallJSMethod in try catch(#1223)](https://github.com/NativeScript/android-runtime/issues/12238) + - [Add a setting to wrap calls to CallJSMethod in try catch(#1223)](https://github.com/NativeScript/android-runtime/issues/1223) - [Support for abstract interface with static methods(#1157)](https://github.com/NativeScript/android-runtime/issues/1157) - [Use gradle plugin 3.2.1 instead of 3.2.0(#1209)](https://github.com/NativeScript/android-runtime/pull/1209) - [Add a concrete exception when the runtime cannot be found(#1201)](https://github.com/NativeScript/android-runtime/pull/1201) diff --git a/LICENSE b/LICENSE index 9d63a0a67..061c44028 100755 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright (c) 2015-2018 Progress Software Corporation + Copyright (c) 2015-2019 Progress Software Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/build-artifacts/project-template-gradle/settings.json b/build-artifacts/project-template-gradle/settings.json index 0e44c524d..256af84b8 100644 --- a/build-artifacts/project-template-gradle/settings.json +++ b/build-artifacts/project-template-gradle/settings.json @@ -1,3 +1,3 @@ { - "v8Version": "6.9.427.23" + "v8Version": "7.1.302.32" } \ No newline at end of file diff --git a/build.gradle b/build.gradle index 98437f3be..e707855f4 100644 --- a/build.gradle +++ b/build.gradle @@ -20,7 +20,7 @@ def useCCache = !project.hasProperty("noCCache") def isWinOs = System.properties['os.name'].toLowerCase().contains('windows') def pVersion = "no package version was provided by build.gradle build" def arVersion = "no commit sha was provided by build.gradle build" -def generateRegularRuntimePackage = !project.hasProperty("skipUnoptimized"); +def generateRegularRuntimePackage = !project.hasProperty("skipUnoptimized") def DIST_PATH = "$rootDir/dist" def TEST_APP_PATH = "$rootDir/test-app" @@ -29,19 +29,19 @@ def DIST_FRAMEWORK_PATH = "$DIST_PATH/framework" task checkEnvironmentVariables { if ("$System.env.JAVA_HOME" == "" || "$System.env.JAVA_HOME" == "null") { - throw new GradleException("Set JAVA_HOME to point to the correct Jdk location\n"); + throw new GradleException("Set JAVA_HOME to point to the correct Jdk location\n") } if ("$System.env.ANDROID_HOME" == "" || "$System.env.ANDROID_HOME" == "null") { - throw new GradleException("Set ANDROID_HOME to point to the correct Android SDK location\n"); + throw new GradleException("Set ANDROID_HOME to point to the correct Android SDK location\n") } if ("$System.env.GIT_COMMIT" == "null" && !project.hasProperty("gitCommitVersion")) { - logger.warn("Warning: The GIT_COMMIT is not set. This NativeScript Android Runtime will not be tagged with the git commit it is build from\n"); + logger.warn("Warning: The GIT_COMMIT is not set. This NativeScript Android Runtime will not be tagged with the git commit it is build from\n") } if (project.hasProperty("metadataGen") && !file("../android-metadata-generator/dist/tns-android-metadata-generator-0.0.1.tgz").exists()) { - throw new GradleException("android-metadata-generator build output not found and no metadataGen option specified. Build android-metadata-generator first.\n"); + throw new GradleException("android-metadata-generator build output not found and no metadataGen option specified. Build android-metadata-generator first.\n") } } @@ -120,9 +120,9 @@ task generateDtsgJar(type: Exec) { doFirst { workingDir "$TEST_APP_PATH" if (isWinOs) { - commandLine "cmd", "/c", "gradlew", ":dts-generator:jar" + commandLine "cmd", "/c", "gradlew", ":dts-generator:jar", "--warning-mode", "all" } else { - commandLine "./gradlew", ":dts-generator:jar" + commandLine "./gradlew", ":dts-generator:jar", "--warning-mode", "all" } } } @@ -131,9 +131,9 @@ task generateSbgJar(type: Exec) { doFirst { workingDir "$TEST_APP_PATH" if (isWinOs) { - commandLine "cmd", "/c", "gradlew", ":static-binding-generator:jar" + commandLine "cmd", "/c", "gradlew", ":static-binding-generator:jar", "--warning-mode", "all" } else { - commandLine "./gradlew", ":static-binding-generator:jar" + commandLine "./gradlew", ":static-binding-generator:jar", "--warning-mode", "all" } } } @@ -142,21 +142,9 @@ task generateMdgJar(type: Exec) { doFirst { workingDir "$TEST_APP_PATH" if (isWinOs) { - commandLine "cmd", "/c", "gradlew", ":android-metadata-generator:jar" + commandLine "cmd", "/c", "gradlew", ":android-metadata-generator:jar", "--warning-mode", "all" } else { - commandLine "./gradlew", ":android-metadata-generator:jar" - } - } -} - -task generateRuntime { - doFirst { - tasks.generateOptimizedRuntimeAar.execute(); - - tasks.generateOptimizedWithInspectorRuntimeAar.execute(); - - if (generateRegularRuntimePackage) { - tasks.generateRuntimeAar.execute(); + commandLine "./gradlew", ":android-metadata-generator:jar", "--warning-mode", "all" } } } @@ -165,9 +153,9 @@ task cleanRuntime (type: Exec) { doFirst { workingDir "$TEST_APP_PATH" if (isWinOs) { - commandLine "cmd", "/c", "gradlew", ":runtime:clean" + commandLine "cmd", "/c", "gradlew", ":runtime:clean", "--warning-mode", "all" } else { - commandLine "./gradlew", ":runtime:clean" + commandLine "./gradlew", ":runtime:clean", "--warning-mode", "all" } } } @@ -177,23 +165,24 @@ def getAssembleReleaseBuildArguments = { -> if (isWinOs) { arguments += ["cmd", "/c", "gradlew"] } else { - arguments.push("./gradlew") + arguments.add("./gradlew") } arguments += [":runtime:assembleRelease", "-PpackageVersion=${pVersion}", "-PgitCommitVersion=${arVersion}"] if (onlyX86) { - arguments.push("-PonlyX86") + arguments.add("-PonlyX86") } if (useCCache) { - arguments.push("-PuseCCache") + arguments.add("-PuseCCache") } - return arguments; + arguments += ["--warning-mode", "all"] + return arguments } task generateOptimizedRuntimeAar (type: Exec) { doFirst { workingDir "$TEST_APP_PATH" def arguments = getAssembleReleaseBuildArguments() - arguments.push("-Poptimized") + arguments.add("-Poptimized") commandLine arguments } } @@ -202,7 +191,7 @@ task generateOptimizedWithInspectorRuntimeAar (type: Exec) { doFirst { workingDir "$TEST_APP_PATH" def arguments = getAssembleReleaseBuildArguments() - arguments.push("-PoptimizedWithInspector") + arguments.add("-PoptimizedWithInspector") commandLine arguments } } @@ -316,7 +305,7 @@ task setPackageVersionInPackageJsonFile { def inputFile = new File("$DIST_PATH/package.json") def json = new JsonSlurper().parseText(inputFile.text) json.version = pVersion - def jb = new JsonBuilder(json); + def jb = new JsonBuilder(json) inputFile.text = JsonOutput.prettyPrint(jb.toString()) } } @@ -344,9 +333,17 @@ createDistDir.dependsOn(generateMdgJar) getPackageVersion.dependsOn(createDistDir) getCommitVersion.dependsOn(getPackageVersion) -generateRuntime.dependsOn(getCommitVersion) +generateOptimizedRuntimeAar.dependsOn(getCommitVersion) + +generateOptimizedWithInspectorRuntimeAar.dependsOn(generateOptimizedRuntimeAar) + +if (generateRegularRuntimePackage) { + generateRuntimeAar.dependsOn(generateOptimizedWithInspectorRuntimeAar) + buildJsParser.dependsOn(generateRuntimeAar) +} else { + buildJsParser.dependsOn(generateOptimizedWithInspectorRuntimeAar) +} -buildJsParser.dependsOn(generateRuntime) copyFilesToProjectTemeplate.dependsOn(buildJsParser) copyProjectTemplate.dependsOn(copyFilesToProjectTemeplate) copyPackageJson.dependsOn(copyProjectTemplate) @@ -377,9 +374,9 @@ task runSbgTests (type: Exec, dependsOn: 'runAstTests') { doFirst { workingDir "$TEST_APP_PATH" if (isWinOs) { - commandLine "cmd", "/c", "gradlew", ":static-binding-generator:test" + commandLine "cmd", "/c", "gradlew", ":static-binding-generator:test", "--warning-mode", "all" } else { - commandLine "./gradlew", ":static-binding-generator:test" + commandLine "./gradlew", ":static-binding-generator:test", "--warning-mode", "all" } } } @@ -389,16 +386,17 @@ def getRunTestsBuildArguments = { taskName -> if (isWinOs) { arguments += ["cmd", "/c", "gradlew"] } else { - arguments.push("./gradlew") + arguments.add("./gradlew") } - arguments +=["-b", "runtests.gradle", taskName] + arguments += ["-b", "runtests.gradle", taskName] if (onlyX86) { - arguments.push("-PonlyX86") + arguments.add("-PonlyX86") } if (useCCache) { - arguments.push("-PuseCCache") + arguments.add("-PuseCCache") } - return arguments; + arguments += ["--warning-mode", "all"] + return arguments } task runTests (type: Exec) { diff --git a/package.json b/package.json index 97babe952..e4789b802 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "tns-android", "description": "NativeScript Runtime for Android", - "version": "5.1.0", + "version": "5.2.0", "repository": { "type": "git", "url": "https://github.com/NativeScript/android-runtime.git" @@ -10,7 +10,8 @@ "**/*" ], "gradle": { - "version": "4.10.2", - "android": "3.2.1" - } + "version": "4.10.2", + "android": "3.3.0" + }, + "android_ndk_version": "18b" } diff --git a/test-app/app/build.gradle b/test-app/app/build.gradle index b35f451b9..e1bd57679 100644 --- a/test-app/app/build.gradle +++ b/test-app/app/build.gradle @@ -145,30 +145,30 @@ def applyPluginGradleConfigurations = { -> } def getAppIdentifier = { packageJsonMap -> - def appIdentifier = ""; + def appIdentifier = "" if (packageJsonMap && packageJsonMap.nativescript) { - appIdentifier = packageJsonMap.nativescript.id; + appIdentifier = packageJsonMap.nativescript.id if (!(appIdentifier instanceof String)) { - appIdentifier = appIdentifier.android; + appIdentifier = appIdentifier.android } } - return appIdentifier; + return appIdentifier } def setAppIdentifier = { -> - println "\t + setting applicationId"; - File packageJsonFile = new File("$rootDir/../../package.json"); + println "\t + setting applicationId" + File packageJsonFile = new File("$rootDir/../../package.json") if (packageJsonFile.exists()) { - def content = packageJsonFile.getText("UTF-8"); - def jsonSlurper = new JsonSlurper(); - def packageJsonMap = jsonSlurper.parseText(content); - def appIdentifier = getAppIdentifier(packageJsonMap); + def content = packageJsonFile.getText("UTF-8") + def jsonSlurper = new JsonSlurper() + def packageJsonMap = jsonSlurper.parseText(content) + def appIdentifier = getAppIdentifier(packageJsonMap) if (appIdentifier) { - project.ext.nsApplicationIdentifier = appIdentifier; - android.defaultConfig.applicationId = appIdentifier; + project.ext.nsApplicationIdentifier = appIdentifier + android.defaultConfig.applicationId = appIdentifier } } } @@ -267,12 +267,36 @@ dependencies { supportVer = supportVersion } - println "Using support library version $supportVer" + if (project.hasProperty("useAndroidX") && (useAndroidX || useAndroidX.toBoolean())) { + def androidXLegacyVersion = "1.0.0" + if (project.hasProperty("androidXLegacy")) { + androidXLegacyVersion = androidXLegacy + } + + def androidXAppCompatVersion = "1.1.0-alpha01" + if (project.hasProperty("androidXAppCompat")) { + androidXAppCompatVersion = androidXAppCompat + } + + def androidXMaterialVersion = "1.1.0-alpha01" + if (project.hasProperty("androidXMaterial")) { + androidXMaterialVersion = androidXMaterial + } - implementation "com.android.support:multidex:1.0.2" - implementation "com.android.support:support-v4:$supportVer" - implementation "com.android.support:appcompat-v7:$supportVer" - implementation "com.android.support:design:$supportVer" + println "\t + using andorid X library androidx.legacy:legacy-support-v4:$androidXLegacyVersion" + + implementation "androidx.multidex:multidex:2.0.0" + implementation "androidx.legacy:legacy-support-v4:$androidXLegacyVersion" + implementation "androidx.appcompat:appcompat:$androidXAppCompatVersion" + implementation "com.google.android.material:material:$androidXMaterialVersion" + } else { + println "\t + using support library version $supportVer" + + implementation "com.android.support:multidex:1.0.2" + implementation "com.android.support:support-v4:$supportVer" + implementation "com.android.support:appcompat-v7:$supportVer" + implementation "com.android.support:design:$supportVer" + } def sbgProjectExists = !findProject(':static-binding-generator').is(null) if (sbgProjectExists) { @@ -364,12 +388,13 @@ tasks.whenTaskAdded({ org.gradle.api.DefaultTask currentTask -> extractAllJars.finalizedBy(collectAllJars) } if (currentTask =~ /compile.+JavaWithJavac/) { + currentTask.dependsOn(makeAndroidXChanges) currentTask.dependsOn(runSbg) currentTask.finalizedBy(ensureMetadataOutDir) ensureMetadataOutDir.finalizedBy(buildMetadata) } if (currentTask =~ /merge.*Assets/) { - currentTask.shouldRunAfter(buildMetadata); + currentTask.shouldRunAfter(buildMetadata) } if (currentTask =~ /assemble.*Debug/ || currentTask =~ /assemble.*Release/) { currentTask.finalizedBy("validateAppIdMatch") @@ -388,7 +413,7 @@ task runSbg(type: JavaExec) { args "static-binding-generator.jar" doFirst { - new File("$OUTPUT_JAVA_DIR/com/tns/gen").deleteDir(); + new File("$OUTPUT_JAVA_DIR/com/tns/gen").deleteDir() } } @@ -534,6 +559,43 @@ task buildMetadata(type: JavaExec) { } } +task makeAndroidXChanges { + if (project.hasProperty("useAndroidX") && (useAndroidX || useAndroidX.toBoolean())) { + // code changes + def codeTuples = new ArrayList>() + codeTuples.add(new Tuple2('android\\.support\\.annotation\\.NonNull', 'androidx.annotation.NonNull')) + codeTuples.add(new Tuple2('android\\.support\\.v7\\.app\\.AppCompatActivity', 'androidx.appcompat.app.AppCompatActivity')) + codeTuples.add(new Tuple2('android\\.support\\.v7\\.appcompat\\.R', 'androidx.appcompat.R')) + codeTuples.add(new Tuple2('android\\.support\\.design\\.widget\\.TabLayout', 'com.google.android.material.tabs.TabLayout')) + codeTuples.add(new Tuple2('android\\.support\\.v4\\.app\\.ActivityCompat', 'androidx.core.app.ActivityCompat')) + codeTuples.add(new Tuple2('android\\.support\\.v4\\.app\\.Fragment', 'androidx.fragment.app.Fragment')) + codeTuples.add(new Tuple2('android\\.support\\.v4\\.view\\.ViewPager', 'androidx.viewpager.widget.ViewPager')) + codeTuples.add(new Tuple2('android\\.support\\.v7\\.widget\\.Toolbar', 'androidx.appcompat.widget.Toolbar')) + codeTuples.add(new Tuple2('android\\.support\\.multidex\\.MultiDex', 'androidx.multidex.MultiDex')) + + codeTuples.each { tuple -> + ant.replaceregexp(match: tuple.first, replace: tuple.second, flags: 'g', byline: true) { + fileset(dir: "$projectDir/src/debug/java/com/tns/", includes: '*.java') + } + ant.replaceregexp(match: tuple.first, replace: tuple.second, flags: 'g', byline: true) { + fileset(dir: "$projectDir/src/main/java/com/tns/", includes: '*.java') + } + } + + // resource changes + def resourceTuples = new ArrayList>() + resourceTuples.add(new Tuple2('android\\.support\\.v7\\.widget\\.Toolbar', 'androidx.appcompat.widget.Toolbar')) + resourceTuples.add(new Tuple2('android\\.support\\.v4\\.view\\.ViewPager', 'androidx.viewpager.widget.ViewPager')) + resourceTuples.add(new Tuple2('android\\.support\\.design\\.widget\\.TabLayout', 'com.google.android.material.tabs.TabLayout')) + + resourceTuples.each { tuple -> + ant.replaceregexp(match: tuple.first, replace: tuple.second, flags: 'g', byline: true) { + fileset(dir: "$projectDir/src/debug/res/layout/", includes: 'error_activity.xml') + } + } + } +} + task generateTypescriptDefinitions(type: JavaExec) { def paramz = new ArrayList() def includeDirs = ["com.android.support", "/platforms/" + android.compileSdkVersion] @@ -606,7 +668,7 @@ task validateAppIdMatch { "NativeScript CLI might not work properly.$lineSeparator" + "Remove applicationId from app.gradle and update the \"nativescript.id\" in package.json.$lineSeparator" + "Actual: ${android.defaultConfig.applicationId}$lineSeparator" + - "Expected(from \"package.json\"): ${project.nsApplicationIdentifier}$lineSeparator"; + "Expected(from \"package.json\"): ${project.nsApplicationIdentifier}$lineSeparator" logger.error(errorMessage) } diff --git a/test-app/app/src/debug/java/com/tns/ErrorReport.java b/test-app/app/src/debug/java/com/tns/ErrorReport.java index 796325d62..8fb9864c0 100644 --- a/test-app/app/src/debug/java/com/tns/ErrorReport.java +++ b/test-app/app/src/debug/java/com/tns/ErrorReport.java @@ -22,7 +22,6 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; -import android.graphics.Color; import android.os.Build; import android.os.Bundle; import android.os.Environment; diff --git a/test-app/app/src/debug/java/com/tns/NativeScriptSyncServiceSocketImpl.java b/test-app/app/src/debug/java/com/tns/NativeScriptSyncServiceSocketImpl.java index c75d178c8..5bd2f8a6e 100644 --- a/test-app/app/src/debug/java/com/tns/NativeScriptSyncServiceSocketImpl.java +++ b/test-app/app/src/debug/java/com/tns/NativeScriptSyncServiceSocketImpl.java @@ -165,7 +165,7 @@ public void run() { validateData(); if(runtime != null && doRefreshInt == DO_REFRESH_VALUE) { - runtime.runScript(new File(NativeScriptSyncServiceSocketImpl.this.context.getFilesDir(), "internal/livesync.js")); + runtime.runScript(new File(NativeScriptSyncServiceSocketImpl.this.context.getFilesDir(), "internal/livesync.js"), false); operationReportCode = OPERATION_END_REPORT_CODE; } else { operationReportCode = OPERATION_END_NO_REFRESH_REPORT_CODE; diff --git a/test-app/app/src/main/assets/app/MyActivity.js b/test-app/app/src/main/assets/app/MyActivity.js index e108d1505..5895c9c9f 100644 --- a/test-app/app/src/main/assets/app/MyActivity.js +++ b/test-app/app/src/main/assets/app/MyActivity.js @@ -13,7 +13,7 @@ } @JavaProxy("com.tns.NativeScriptActivity") - class MyActivity extends android.app.Activity + class MyActivity extends android.support.v7.app.AppCompatActivity { onCreate(bundle: android.os.Bundle) { @@ -61,4 +61,4 @@ var MyActivity = (function (_super) { JavaProxy("com.tns.NativeScriptActivity") ], MyActivity); return MyActivity; -})(android.app.Activity); \ No newline at end of file +})(android.support.v7.app.AppCompatActivity); \ No newline at end of file diff --git a/test-app/app/src/main/assets/app/mainpage.js b/test-app/app/src/main/assets/app/mainpage.js index 624a647b1..ae814e00e 100644 --- a/test-app/app/src/main/assets/app/mainpage.js +++ b/test-app/app/src/main/assets/app/mainpage.js @@ -34,6 +34,7 @@ require("./tests/testPrimitiveTypeConversion"); require("./tests/numericConversionTests"); require("./tests/inheritanceChainResolutionTest"); require("./tests/exceptionHandlingTests"); +require("./tests/discardedExceptionsTest"); require("./tests/dispatchCallbacksOnUiThreadTests"); require("./tests/stringConversionTests"); require("./tests/testsForTypescript"); @@ -51,4 +52,5 @@ require("./tests/byte-buffer-test"); require("./tests/dex-interface-implementation"); require("./tests/testInterfaceImplementation"); require("./tests/testRuntimeImplementedAPIs"); -require("./tests/testsInstanceOfOperator"); \ No newline at end of file +require("./tests/testsInstanceOfOperator"); +require("./tests/testReleaseNativeCounterpart"); \ No newline at end of file diff --git a/test-app/app/src/main/assets/app/modules/libCalc-arm.so b/test-app/app/src/main/assets/app/modules/libCalc-arm.so index d5d3a4c5b..6d3f450a4 100755 Binary files a/test-app/app/src/main/assets/app/modules/libCalc-arm.so and b/test-app/app/src/main/assets/app/modules/libCalc-arm.so differ diff --git a/test-app/app/src/main/assets/app/modules/libCalc-arm64.so b/test-app/app/src/main/assets/app/modules/libCalc-arm64.so index 0101abdb7..704534a40 100755 Binary files a/test-app/app/src/main/assets/app/modules/libCalc-arm64.so and b/test-app/app/src/main/assets/app/modules/libCalc-arm64.so differ diff --git a/test-app/app/src/main/assets/app/modules/libCalc-x86.so b/test-app/app/src/main/assets/app/modules/libCalc-x86.so index 078aa7233..cf8c97641 100755 Binary files a/test-app/app/src/main/assets/app/modules/libCalc-x86.so and b/test-app/app/src/main/assets/app/modules/libCalc-x86.so differ diff --git a/test-app/app/src/main/assets/app/tests/discardedExceptionsTest.js b/test-app/app/src/main/assets/app/tests/discardedExceptionsTest.js new file mode 100644 index 000000000..90d0370ba --- /dev/null +++ b/test-app/app/src/main/assets/app/tests/discardedExceptionsTest.js @@ -0,0 +1,27 @@ +describe("Tests discarded exception ", function () { + var originalOnDiscardedError = null; + + beforeEach(function() { + originalOnDiscardedError = global.__onDiscardedError; + }); + + it("should report discarded exception", function () { + var reportedException = null; + + global.__onDiscardedError = (error) => { + reportedException = error; + } + + var test = new com.tns.tests.DiscardedExceptionTest(); + test.reportSupressedException(); + + expect(reportedException).not.toBe(null); + expect(reportedException.nativeException).not.toBe(null); + expect(reportedException.nativeException.getMessage()).toBe('Exception to suppress'); + expect(reportedException.stackTrace).toContain('Error on "main" thread for reportSupressedException'); + }); + + afterEach(function() { + global.__onDiscardedError = originalOnDiscardedError; + }); +}); \ No newline at end of file diff --git a/test-app/app/src/main/assets/app/tests/exceptionHandlingTests.js b/test-app/app/src/main/assets/app/tests/exceptionHandlingTests.js index 742b8ac4a..5deab7438 100644 --- a/test-app/app/src/main/assets/app/tests/exceptionHandlingTests.js +++ b/test-app/app/src/main/assets/app/tests/exceptionHandlingTests.js @@ -31,12 +31,10 @@ describe("Tests exception handling ", function () { var eh = new EH(); - try - { + try { eh.triggerEvent1("test", 5); } - catch (e) - { + catch (e) { exceptionCaught = true; sameExObject = e === ex; __log("e=" + e); @@ -71,16 +69,13 @@ describe("Tests exception handling ", function () { var eh = new EH(); - try - { + try { eh.triggerEvent1("test", 5); } - catch (e) - { + catch (e) { exceptionCaught = true; nativeExceptionFound = e.nativeException !== undefined; - if (nativeExceptionFound) - { + if (nativeExceptionFound) { exMsg = e.nativeException.getMessage(); } } @@ -111,13 +106,11 @@ describe("Tests exception handling ", function () { var eh = new EH(); - try - { + try { eh.triggerEvent1WithCatchClause("test", 5); exceptionCaught = false; } - catch (e) - { + catch (e) { exceptionCaught = true; } @@ -147,13 +140,11 @@ describe("Tests exception handling ", function () { var eh = new EH(); - try - { + try { eh.triggerEvent1WithCatchClause("test", 5); exceptionCaught = false; } - catch (e) - { + catch (e) { exceptionCaught = true; } @@ -169,12 +160,10 @@ describe("Tests exception handling ", function () { var dummy = new com.tns.tests.DummyClass(); - try - { + try { dummy.methodThatThrowsException(); } - catch (e) - { + catch (e) { exceptionCaught = true; } @@ -190,12 +179,10 @@ describe("Tests exception handling ", function () { var dummy = new com.tns.tests.DummyClass(); - try - { + try { dummy.methodThatThrowsException(); } - catch (e) - { + catch (e) { var nativeException = e.nativeException; } @@ -214,12 +201,10 @@ describe("Tests exception handling ", function () { var exceptionCaught = false; - try - { + try { var dummy = new com.tns.tests.DummyClass(true /* throwsException */); } - catch (e) - { + catch (e) { exceptionCaught = true; } @@ -240,14 +225,12 @@ describe("Tests exception handling ", function () { expect(arrLength).toEqual(1); - try - { + try { var dummy = arr[arrLength]; var name = dummy.getName(); } - catch (e) - { + catch (e) { exceptionCaught = true; } @@ -270,12 +253,10 @@ describe("Tests exception handling ", function () { var last = arr[arrLength - 1]; - try - { + try { arr[arrLength] = last; } - catch (e) - { + catch (e) { exceptionCaught = true; } @@ -335,8 +316,8 @@ describe("Tests exception handling ", function () { } expect(exceptionCaught).toBe(true); expect(errMsg).toContain("Cannot compile /data/data/com.tns.testapplication/files/app/tests/syntaxErrors.js"); - expect(errMsg).toContain("SyntaxError: Unexpected token ="); - expect(errMsg).toContain("File: \"file:///data/data/com.tns.testapplication/files/app/tests/syntaxErrors.js, line: 3, column: 10"); + expect(errMsg).toContain("SyntaxError: Unexpected token class"); + expect(errMsg).toContain("File: \"file:///data/data/com.tns.testapplication/files/app/tests/syntaxErrors.js, line: 3, column: 4"); }); // run this test only for API level bigger than 25 as we have handling there diff --git a/test-app/app/src/main/assets/app/tests/testReleaseNativeCounterpart.js b/test-app/app/src/main/assets/app/tests/testReleaseNativeCounterpart.js new file mode 100644 index 000000000..4bd78ce65 --- /dev/null +++ b/test-app/app/src/main/assets/app/tests/testReleaseNativeCounterpart.js @@ -0,0 +1,81 @@ +describe("Test native counterpart release", function () { + + var myCustomEquality = function(first, second) { + return first == second; + }; + + beforeEach(function() { + jasmine.addCustomEqualityTester(myCustomEquality); + }); + + it("Calling a method on a released object should throw exception", function () { + + var errorMessage = ""; + + try{ + var object1 = new java.lang.Object(); + + global.__releaseNativeCounterpart(object1); + + object1.toString(); + } catch(e){ + errorMessage = e.message; + } + + expect(errorMessage).toBe("Failed calling toString on a java/lang/Object instance. The JavaScript instance no longer has available Java instance counterpart."); + }); + + it("Calling release on a non native object should throw exception", function () { + + var errorMessage = ""; + + try{ + var object2 = {prop: "test"}; + global.__releaseNativeCounterpart(object2); + } catch(e){ + errorMessage = e.message; + } + + expect(errorMessage).toBe("Trying to release a non native object!"); + }); + + + it("Calling release on a non native primitive type should throw exception", function () { + + var errorMessage = ""; + + try{ + global.__releaseNativeCounterpart(42); + } catch(e){ + errorMessage = e.message; + } + + expect(errorMessage).toBe("Argument is not an object!"); + }); + + it("Calling the __releaseNativeCounterpart function with 0 arguments should throw exception", function(){ + var errorMessage = ""; + + try{ + global.__releaseNativeCounterpart(); + } catch(e){ + errorMessage = e.message; + } + + expect(errorMessage).toBe("Unexpected arguments count!"); + }); + + it("Calling the __releaseNativeCounterpart function with more than 1 arguments should throw exception", function(){ + var errorMessage = ""; + + try{ + global.__releaseNativeCounterpart({},{}); + } catch(e){ + errorMessage = e.message; + } + + expect(errorMessage).toBe("Unexpected arguments count!"); + }); + + +}); \ No newline at end of file diff --git a/test-app/app/src/main/assets/app/tests/testsWithContext.js b/test-app/app/src/main/assets/app/tests/testsWithContext.js index 958d12589..b8c0082c9 100644 --- a/test-app/app/src/main/assets/app/tests/testsWithContext.js +++ b/test-app/app/src/main/assets/app/tests/testsWithContext.js @@ -116,13 +116,15 @@ exports.run = function(cntxt) it("TestOldAPIForGettingMethodsListForMethodsWithParametersFromMissingType", function () { __log("TEST: TestOldAPIForGettingMethodsListForMethodsWithParametersFromMissingType"); - var til = new android.support.design.widget.TextInputLayout(context); - var editText = new android.widget.EditText(context); - var relativeLayout = new android.widget.RelativeLayout(context); - var relativeLayoutParams = new android.widget.RelativeLayout.LayoutParams(android.widget.RelativeLayout.LayoutParams.MATCH_PARENT, android.widget.RelativeLayout.LayoutParams.MATCH_PARENT); - relativeLayout.setLayoutParams(relativeLayoutParams); - editText.setHint("TEST"); - til.addView(editText); + if(android.support.design && android.support.design.widget) { + var til = new android.support.design.widget.TextInputLayout(context); + var editText = new android.widget.EditText(context); + var relativeLayout = new android.widget.RelativeLayout(context); + var relativeLayoutParams = new android.widget.RelativeLayout.LayoutParams(android.widget.RelativeLayout.LayoutParams.MATCH_PARENT, android.widget.RelativeLayout.LayoutParams.MATCH_PARENT); + relativeLayout.setLayoutParams(relativeLayoutParams); + editText.setHint("TEST"); + til.addView(editText); + } }); }); }; \ No newline at end of file diff --git a/test-app/app/src/main/java/com/tns/AndroidJsV8Inspector.java b/test-app/app/src/main/java/com/tns/AndroidJsV8Inspector.java index df9a1a891..5c3996f24 100644 --- a/test-app/app/src/main/java/com/tns/AndroidJsV8Inspector.java +++ b/test-app/app/src/main/java/com/tns/AndroidJsV8Inspector.java @@ -23,8 +23,6 @@ import fi.iki.elonen.NanoWSD; class AndroidJsV8Inspector { - private static boolean DEBUG_LOG_ENABLED = false; - private JsV8InspectorServer server; private static String ApplicationDir; private String packageName; @@ -43,6 +41,8 @@ class AndroidJsV8Inspector { private final Object debugBrkLock; + private Logger currentRuntimeLogger; + private static AtomicBoolean ReadyToProcessMessages = new AtomicBoolean(false); private LinkedBlockingQueue inspectorMessages = new LinkedBlockingQueue(); @@ -60,10 +60,12 @@ public void start() throws IOException { mainHandler = currentRuntime.getHandler(); - this.server = new JsV8InspectorServer(this.packageName + "-inspectorServer"); + currentRuntimeLogger = currentRuntime.getLogger(); + + this.server = new JsV8InspectorServer(this.packageName + "-inspectorServer", currentRuntimeLogger); this.server.start(-1); - if (DEBUG_LOG_ENABLED) { + if (currentRuntimeLogger.isEnabled()) { Log.d("V8Inspector", "start debugger ThreadId:" + Thread.currentThread().getId()); } @@ -158,22 +160,22 @@ private static String getMimeType(String url) { // getMimeType may sometime return incorrect results in the context of NativeScript // e.g. `.ts` returns video/MP2TS switch (extension) { - case "js": - type = "text/javascript"; - break; - case "json": - type = "application/json"; - break; - case "css": - type = "text/css"; - break; - case "ts": - type = "text/typescript"; - break; - // handle shared libraries so they are marked properly and don't appear in the sources tab - case "so": - type = "application/binary"; - break; + case "js": + type = "text/javascript"; + break; + case "json": + type = "application/json"; + break; + case "css": + type = "text/css"; + break; + case "ts": + type = "text/typescript"; + break; + // handle shared libraries so they are marked properly and don't appear in the sources tab + case "so": + type = "application/binary"; + break; } } @@ -214,13 +216,16 @@ private void processDebugBreakMessages() { } private class JsV8InspectorServer extends NanoWSD { - JsV8InspectorServer(String name) { + private Logger currentRuntimeLogger; + + JsV8InspectorServer(String name, Logger runtimeLogger) { super(name); + currentRuntimeLogger = runtimeLogger; } @Override protected Response serveHttp(IHTTPSession session) { - if (DEBUG_LOG_ENABLED) { + if (currentRuntimeLogger.isEnabled()) { Log.d("{N}.v8-inspector", "http request for " + session.getUri()); } return super.serveHttp(session); @@ -228,18 +233,21 @@ protected Response serveHttp(IHTTPSession session) { @Override protected WebSocket openWebSocket(IHTTPSession handshake) { - return new JsV8InspectorWebSocket(handshake); + return new JsV8InspectorWebSocket(handshake, currentRuntimeLogger); } } private class JsV8InspectorWebSocket extends NanoWSD.WebSocket { - JsV8InspectorWebSocket(NanoHTTPD.IHTTPSession handshakeRequest) { + private Logger currentRuntimeLogger; + + JsV8InspectorWebSocket(NanoHTTPD.IHTTPSession handshakeRequest, Logger runtimeLogger) { super(handshakeRequest); + currentRuntimeLogger = runtimeLogger; } @Override protected void onOpen() { - if (DEBUG_LOG_ENABLED) { + if (currentRuntimeLogger.isEnabled()) { Log.d("V8Inspector", "onOpen: ThreadID: " + Thread.currentThread().getId()); } @@ -248,14 +256,14 @@ protected void onOpen() { @Override protected void onClose(NanoWSD.WebSocketFrame.CloseCode code, String reason, boolean initiatedByRemote) { - if (DEBUG_LOG_ENABLED) { + if (currentRuntimeLogger.isEnabled()) { Log.d("V8Inspector", "onClose"); } mainHandler.post(new Runnable() { @Override public void run() { - if (DEBUG_LOG_ENABLED) { + if (currentRuntimeLogger.isEnabled()) { Log.d("V8Inspector", "Disconnecting"); } disconnect(); @@ -265,7 +273,7 @@ public void run() { @Override protected void onMessage(final NanoWSD.WebSocketFrame message) { - if (DEBUG_LOG_ENABLED) { + if (currentRuntimeLogger.isEnabled()) { Log.d("V8Inspector", "To dbg backend: " + message.getTextPayload() + " ThreadId:" + Thread.currentThread().getId()); } @@ -299,7 +307,7 @@ public void run() { @Override public void send(String payload) throws IOException { - if (DEBUG_LOG_ENABLED) { + if (currentRuntimeLogger.isEnabled()) { Log.d("V8Inspector", "To dbg client: " + payload); } @@ -322,7 +330,10 @@ protected void onPong(NanoWSD.WebSocketFrame pong) { @Override protected void onException(IOException exception) { - exception.printStackTrace(); + // when the chrome inspector is disconnected by closing the tab a "Broken pipe" exception is thrown which we don't need to log, only in verbose logging mode + if(!exception.getMessage().equals("Broken pipe") || currentRuntimeLogger.isEnabled()) { + exception.printStackTrace(); + } disconnect(); } } diff --git a/test-app/app/src/main/java/com/tns/NativeScriptUncaughtExceptionHandler.java b/test-app/app/src/main/java/com/tns/NativeScriptUncaughtExceptionHandler.java index 92c75e6c5..087f7e7d2 100644 --- a/test-app/app/src/main/java/com/tns/NativeScriptUncaughtExceptionHandler.java +++ b/test-app/app/src/main/java/com/tns/NativeScriptUncaughtExceptionHandler.java @@ -21,7 +21,7 @@ public NativeScriptUncaughtExceptionHandler(Logger logger, Context context) { public void uncaughtException(Thread thread, Throwable ex) { String currentThreadMessage = "An uncaught Exception occurred on \"" + thread.getName() + "\" thread.\n"; - String errorMessage = currentThreadMessage + getErrorMessage(ex); + String errorMessage = currentThreadMessage + Runtime.getStackTraceErrorMessage(ex); if (Runtime.isInitialized()) { try { @@ -64,27 +64,4 @@ public void uncaughtException(Thread thread, Throwable ex) { defaultHandler.uncaughtException(thread, ex); } } - - private static String getErrorMessage(Throwable ex) { - String content; - java.io.PrintStream ps = null; - - try { - java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream(); - ps = new java.io.PrintStream(baos); - ex.printStackTrace(ps); - - try { - content = baos.toString("US-ASCII"); - } catch (java.io.UnsupportedEncodingException e) { - content = e.getMessage(); - } - } finally { - if (ps != null) { - ps.close(); - } - } - - return content; - } } diff --git a/test-app/app/src/main/java/com/tns/tests/DiscardedExceptionTest.java b/test-app/app/src/main/java/com/tns/tests/DiscardedExceptionTest.java new file mode 100644 index 000000000..74959fd84 --- /dev/null +++ b/test-app/app/src/main/java/com/tns/tests/DiscardedExceptionTest.java @@ -0,0 +1,11 @@ +package com.tns.tests; + +public class DiscardedExceptionTest { + public void reportSupressedException() { + try { + throw new Exception("Exception to suppress"); + } catch (Throwable ex) { + com.tns.Runtime.passSuppressedExceptionToJs(ex, "reportSupressedException"); + } + } +} diff --git a/test-app/build-tools/android-dts-generator b/test-app/build-tools/android-dts-generator index cce79ede4..32ad4e004 160000 --- a/test-app/build-tools/android-dts-generator +++ b/test-app/build-tools/android-dts-generator @@ -1 +1 @@ -Subproject commit cce79ede41dee84aee7e967dc5326a0e2d00f359 +Subproject commit 32ad4e0042e4af4a86761734b001ec7022f6135f diff --git a/test-app/build-tools/android-metadata-generator/build.gradle b/test-app/build-tools/android-metadata-generator/build.gradle index 9bcb52ff5..c2df40ad3 100644 --- a/test-app/build-tools/android-metadata-generator/build.gradle +++ b/test-app/build-tools/android-metadata-generator/build.gradle @@ -17,7 +17,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.2.1' + classpath 'com.android.tools.build:gradle:3.3.0' } } @@ -36,7 +36,7 @@ compileJava { compileJava.outputs.dir("$rootDir/dist/classes") dependencies { - compile 'org.apache.bcel:bcel:6.0' + compile 'org.apache.bcel:bcel:6.2' compile files("./src/libs/dx.jar") } diff --git a/test-app/build-tools/android-metadata-generator/src/src/com/telerik/metadata/bcl/ClassInfo.java b/test-app/build-tools/android-metadata-generator/src/src/com/telerik/metadata/bcl/ClassInfo.java index 6082ac788..af70c1e09 100644 --- a/test-app/build-tools/android-metadata-generator/src/src/com/telerik/metadata/bcl/ClassInfo.java +++ b/test-app/build-tools/android-metadata-generator/src/src/com/telerik/metadata/bcl/ClassInfo.java @@ -7,6 +7,8 @@ import com.telerik.metadata.desc.MethodDescriptor; import org.apache.bcel.classfile.Attribute; +import org.apache.bcel.classfile.ConstantClass; +import org.apache.bcel.classfile.ConstantPool; import org.apache.bcel.classfile.ConstantUtf8; import org.apache.bcel.classfile.Field; import org.apache.bcel.classfile.InnerClass; @@ -36,19 +38,18 @@ private void init() { return; } boolean found = false; + String fullClassName = getClassName(clazz.getClassNameIndex()); + if (fullClassName == null) { + return; + } + for (Attribute a : clazz.getAttributes()) { if (a instanceof InnerClasses) { InnerClass[] i = ((InnerClasses) a).getInnerClasses(); for (InnerClass ic : i) { + String innerClassName = getClassName(ic.getInnerClassIndex()); - ConstantUtf8 cname = (ConstantUtf8) clazz - .getConstantPool().getConstant(ic.getInnerNameIndex()); - if (cname == null) { - continue; - } - - String innerClassname = cname.getBytes(); - if (name.equals(innerClassname)) { + if (fullClassName.equals(innerClassName)) { int flags = ic.getInnerAccessFlags(); clazz.setAccessFlags(flags); found = true; @@ -63,6 +64,19 @@ private void init() { } } + private String getClassName(int classIndex) { + ConstantPool constantPool = clazz.getConstantPool(); + ConstantClass innerClassNameIndex = (ConstantClass)constantPool.getConstant(classIndex); + if (innerClassNameIndex == null) { + return null; + } + ConstantUtf8 className = (ConstantUtf8)constantPool.getConstant(innerClassNameIndex.getNameIndex()); + if (className == null) { + return null; + } + return className.getBytes(); + } + @Override public boolean isClass() { return clazz.isClass(); diff --git a/test-app/build-tools/jsparser/tests/cases/decorated_double_assignment_ts/app/myCustomActivity.android.ts b/test-app/build-tools/jsparser/tests/cases/decorated_double_assignment_ts/app/myCustomActivity.android.ts index b577da7d1..a8a6ba239 100644 --- a/test-app/build-tools/jsparser/tests/cases/decorated_double_assignment_ts/app/myCustomActivity.android.ts +++ b/test-app/build-tools/jsparser/tests/cases/decorated_double_assignment_ts/app/myCustomActivity.android.ts @@ -1,7 +1,7 @@ import Bundle = android.os.Bundle; @JavaProxy('org.nativescript.MyCustomActivity') -export class TestActivity extends android.app.Activity { +export class TestActivity extends android.support.v7.app.AppCompatActivity { static readonly TEST1: string = "my_test"; public onCreate(savedInstanceState?: Bundle): void { super.onCreate(savedInstanceState); diff --git a/test-app/build-tools/jsparser/tests/cases/decorated_double_assignment_ts/app/myCustomActivity_ts.android.js b/test-app/build-tools/jsparser/tests/cases/decorated_double_assignment_ts/app/myCustomActivity_ts.android.js index 48bf750fb..1206bc37a 100644 --- a/test-app/build-tools/jsparser/tests/cases/decorated_double_assignment_ts/app/myCustomActivity_ts.android.js +++ b/test-app/build-tools/jsparser/tests/cases/decorated_double_assignment_ts/app/myCustomActivity_ts.android.js @@ -16,5 +16,5 @@ var TestActivity = (function (_super) { JavaProxy('org.nativescript.MyCustomActivity') ], TestActivity); return TestActivity; -}(android.app.Activity)); +}(android.support.v7.app.AppCompatActivity)); exports.TestActivity = TestActivity; \ No newline at end of file diff --git a/test-app/build-tools/static-binding-generator/src/main/java/org/nativescript/staticbindinggenerator/Generator.java b/test-app/build-tools/static-binding-generator/src/main/java/org/nativescript/staticbindinggenerator/Generator.java index 0527bf09e..31c833540 100644 --- a/test-app/build-tools/static-binding-generator/src/main/java/org/nativescript/staticbindinggenerator/Generator.java +++ b/test-app/build-tools/static-binding-generator/src/main/java/org/nativescript/staticbindinggenerator/Generator.java @@ -13,6 +13,7 @@ import java.nio.file.Paths; import java.util.ArrayDeque; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -39,14 +40,14 @@ public class Generator { private static final String LINE_SEPARATOR = System.getProperty("line.separator"); private static final String AUTO_GENERATED_FILE_PROLOGUE = - "/* AUTO-GENERATED FILE. DO NOT MODIFY." + LINE_SEPARATOR + - " * This class was automatically generated by the" + LINE_SEPARATOR + - " * static binding generator from the resources it found." + LINE_SEPARATOR + - " * Please do not modify by hand." + LINE_SEPARATOR + - " */" + LINE_SEPARATOR; + "/* AUTO-GENERATED FILE. DO NOT MODIFY." + LINE_SEPARATOR + + " * This class was automatically generated by the" + LINE_SEPARATOR + + " * static binding generator from the resources it found." + LINE_SEPARATOR + + " * Please do not modify by hand." + LINE_SEPARATOR + + " */" + LINE_SEPARATOR; private final File outputDir; - private final List libs; + private final List libs; private final Map classes; private final boolean suppressCallJSMethodExceptions; @@ -212,7 +213,7 @@ private String getNormalizedName(String filename) { return sb.toString(); } - private Map getPublicApi(JavaClass clazz) throws ClassNotFoundException { + private Map getPublicApi(JavaClass clazz, List userImplementedInterfacesNames) throws ClassNotFoundException { Map api = new HashMap(); JavaClass currentClass = clazz; String clazzName = clazz.getClassName(); @@ -224,7 +225,7 @@ private Map getPublicApi(JavaClass clazz) throws ClassNotFo methods.add(m); } - collectInterfaceMethods(clazz, methods); + collectInterfaceMethods(clazz, userImplementedInterfacesNames, methods); for (Method m : methods) { if (!m.isSynthetic() && (m.isPublic() || m.isProtected()) && !m.isStatic()) { String name = m.getName(); @@ -302,7 +303,7 @@ private Map readDir(String path, boolean throwOnError) throws while (!d.isEmpty()) { File cur = d.pollFirst(); File[] files = cur.listFiles(); - for (File f: files) { + for (File f : files) { if (f.isFile() && f.getName().endsWith(CLASS_EXT)) { ClassParser cp = new ClassParser(f.getAbsolutePath()); JavaClass clazz = cp.parse(); @@ -337,9 +338,8 @@ private String getFullMethodSignature(Method m) { private void writeBinding(Writer w, DataRow dataRow, JavaClass clazz, String packageName, String name) throws ClassNotFoundException { String[] implInterfaces = dataRow.getInterfaces(); - collectImplementedInterfaces(implInterfaces, clazz); - Map api = getPublicApi(clazz); + Map api = getPublicApi(clazz, Arrays.asList(dataRow.getInterfaces())); w.writeln("package " + packageName + ";"); w.writeln(); @@ -403,7 +403,7 @@ private void writeBinding(Writer w, DataRow dataRow, JavaClass clazz, String pac } Set notImplementedObjectMethods = new HashSet(); Method[] currentIfaceMethods = clazz.getMethods(); - ArrayList ifaceMethods = new ArrayList(); + Set ifaceMethods = new HashSet<>(); for (Method m : currentIfaceMethods) { if (!m.getName().equals("")) { ifaceMethods.add(m); @@ -445,7 +445,7 @@ private void writeBinding(Writer w, DataRow dataRow, JavaClass clazz, String pac } } else { List interfaceMethods = new ArrayList(); - collectInterfaceMethods(clazz, interfaceMethods); + collectInterfaceMethods(clazz, Arrays.asList(dataRow.getInterfaces()), interfaceMethods); for (String methodName : dataRow.getMethods()) { if (api.containsKey(methodName)) { List methodGroup = api.get(methodName).getList(); @@ -480,8 +480,8 @@ private void writeBinding(Writer w, DataRow dataRow, JavaClass clazz, String pac private boolean isClassApplication(JavaClass clazz) { String className = clazz.getClassName(); return className.equals("android.app.Application") || - className.equals("android.support.multidex.MultiDexApplication") || - className.equals("android.test.mock.MockApplication"); + className.equals("android.support.multidex.MultiDexApplication") || + className.equals("android.test.mock.MockApplication"); } private void writeMethodBody(Method m, Writer w, boolean isApplicationClass, boolean isActivityClass, boolean isInterfaceMethod) { @@ -642,7 +642,7 @@ private void writeMethodBody(Method m, boolean isConstructor, boolean isApplicat w.write("\t\t"); Type ret = m.getReturnType(); - if(this.suppressCallJSMethodExceptions) { + if (this.suppressCallJSMethodExceptions) { w.writeln("try {"); w.write("\t\t\t"); } @@ -658,9 +658,10 @@ private void writeMethodBody(Method m, boolean isConstructor, boolean isApplicat writeType(ret, w); w.writeln(".class, args);"); - if(this.suppressCallJSMethodExceptions) { + if (this.suppressCallJSMethodExceptions) { w.writeln("\t\t} catch (Throwable t) {"); - w.writeln("\t\t\tandroid.util.Log.w(\"Error\", t);"); + w.writeln("\t\t\tcom.tns.Runtime.passSuppressedExceptionToJs(t, \"" + m.getName() + "\");"); + w.writeln("\t\t\tandroid.util.Log.w(\"Warning\", \"NativeScript discarding uncaught JS exception!\");"); if (!ret.equals(Type.VOID)) { w.write("\t\t\t"); w.write("return "); @@ -687,7 +688,7 @@ private void writeType(Type t, Writer w) { w.write(type); } - private void collectInterfaceMethods(JavaClass clazz, List methods) throws ClassNotFoundException { + private void collectInterfaceMethods(JavaClass clazz, List userImplementedInterfacesNames, List methods) throws ClassNotFoundException { JavaClass currentClass = clazz; while (true) { @@ -698,6 +699,12 @@ private void collectInterfaceMethods(JavaClass clazz, List methods) thro queue.add(name); } + for (String userImplementedInterfaceName : userImplementedInterfacesNames) { + if (userImplementedInterfaceName != null && !userImplementedInterfaceName.equals("")) { + queue.add(userImplementedInterfaceName); + } + } + while (!queue.isEmpty()) { String ifaceName = queue.poll(); JavaClass currentInterface = getClass(ifaceName); @@ -747,15 +754,17 @@ private boolean isApplicationClass(JavaClass clazz, Map class private boolean isActivityClass(JavaClass clazz, Map classes) throws ClassNotFoundException { boolean isActivityClass = false; - String activityClassname = "android.app.Activity"; + List activityClassNames = Arrays.asList("android.app.Activity", "android.support.v7.app.AppCompatActivity", "androidx.appcompat.app.AppCompatActivity"); JavaClass currentClass = clazz; while (true) { String currentClassname = currentClass.getClassName(); - isActivityClass = currentClassname.equals(activityClassname); - if (isActivityClass) { - break; + for (String activityClassName : activityClassNames) { + isActivityClass = currentClassname.equals(activityClassName); + if (isActivityClass) { + return true; + } } if (currentClassname.endsWith("java.lang.Object")) { @@ -822,7 +831,7 @@ private void cleanPreviouslyAutoGeneratedFiles(File folder) { // some javascript files containing native extends are removed, // their corresponding java classes will also be removed. File[] files = folder.listFiles(); - for (File file: files) { + for (File file : files) { if (file.isDirectory()) { this.cleanPreviouslyAutoGeneratedFiles(file); } else if ("java".equalsIgnoreCase(this.getFileExtension(file.toString()))) { @@ -865,4 +874,4 @@ private String readFile(File file) { } } } -} +} \ No newline at end of file diff --git a/test-app/build.gradle b/test-app/build.gradle index 56dc9966f..1d1846917 100644 --- a/test-app/build.gradle +++ b/test-app/build.gradle @@ -7,7 +7,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.2.1' + classpath 'com.android.tools.build:gradle:3.3.0' } } diff --git a/test-app/gradle.properties b/test-app/gradle.properties index aac7c9b46..a0b287cbb 100644 --- a/test-app/gradle.properties +++ b/test-app/gradle.properties @@ -9,6 +9,8 @@ # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. +# android.enableJetifier=true +android.useAndroidX=true org.gradle.jvmargs=-Xmx1536m # When configured, Gradle will run in incubating parallel mode. diff --git a/test-app/runtests.gradle b/test-app/runtests.gradle index 096053de2..cddedd83e 100644 --- a/test-app/runtests.gradle +++ b/test-app/runtests.gradle @@ -1,6 +1,6 @@ def isWinOs = System.properties['os.name'].toLowerCase().contains('windows') -def runOnDevice = project.hasProperty("runOnDevice"); -def runOnDeviceOrEmulator = runOnDevice ? "-d" : "-e"; +def runOnDevice = project.hasProperty("runOnDevice") +def runOnDeviceOrEmulator = runOnDevice ? "-d" : "-e" def onlyX86 = project.hasProperty("onlyX86") def useCCache = project.hasProperty("useCCache") @@ -37,7 +37,7 @@ def getBuildArguments = { -> if (useCCache) { arguments.push("-PuseCCache") } - return arguments; + return arguments } task installApk(type: Exec) { diff --git a/test-app/runtime/build.gradle b/test-app/runtime/build.gradle index b9ce2782f..80336ce4c 100644 --- a/test-app/runtime/build.gradle +++ b/test-app/runtime/build.gradle @@ -32,7 +32,7 @@ android { java.srcDirs = [bindingGeneratorSourcePath, defaultSrcPath] } } - compileSdkVersion 26 + compileSdkVersion 28 buildToolsVersion project.ext._buildToolsVersion defaultConfig { @@ -61,7 +61,7 @@ android { arguments.push("-DOPTIMIZED_WITH_INSPECTOR_BUILD=true") } - if(useCCache) { + if (useCCache) { arguments.push("-DUSE_CCACHE=true") } @@ -104,6 +104,8 @@ allprojects { dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') + testImplementation 'junit:junit:4.12' + testImplementation 'org.mockito:mockito-core:1.10.19' } tasks.whenTaskAdded { task -> @@ -112,6 +114,11 @@ tasks.whenTaskAdded { task -> setRuntimeCommit.dependsOn(setPackageVersion) task.dependsOn(setRuntimeCommit) } + + if(taskName.contains("bundleReleaseAar")){ + task.dependsOn("testDebugUnitTest") + } + if (taskName.contains("Strip")) { task.finalizedBy(revertVersionFile) } diff --git a/test-app/runtime/src/main/cpp/ArgConverter.cpp b/test-app/runtime/src/main/cpp/ArgConverter.cpp index 3c12f5e97..168d3f068 100644 --- a/test-app/runtime/src/main/cpp/ArgConverter.cpp +++ b/test-app/runtime/src/main/cpp/ArgConverter.cpp @@ -216,7 +216,7 @@ int64_t ArgConverter::ConvertToJavaLong(Isolate* isolate, const Local& va assert(!valueProp.IsEmpty()); - string num = ConvertToString(valueProp->ToString()); + string num = ConvertToString(valueProp->ToString(isolate)); int64_t longValue = atoll(num.c_str()); @@ -241,7 +241,8 @@ string ArgConverter::ConvertToString(const v8::Local& s) { if (s.IsEmpty()) { return string(); } else { - String::Utf8Value str(s); + auto isolate = v8::Isolate::GetCurrent(); + String::Utf8Value str(isolate, s); return string(*str); } } @@ -259,7 +260,8 @@ u16string ArgConverter::ConvertToUtf16String(const v8::Local& s) { jstring ArgConverter::ConvertToJavaString(const Local& value) { JEnv env; - String::Value stringValue(value); + auto isolate = v8::Isolate::GetCurrent(); + String::Value stringValue(isolate, value); return env.NewString((const jchar*) *stringValue, stringValue.length()); } @@ -276,18 +278,8 @@ Local ArgConverter::ConvertToV8String(Isolate* isolate, const char* data return String::NewFromUtf8(isolate, (const char*) data, String::kNormalString, length); } -Local ArgConverter::ConvertToV8UTF16String(Isolate* isolate, const string& string) { - auto utf16str = Util::ConvertFromUtf8ToUtf16(string); - - return ConvertToV8UTF16String(isolate, utf16str); -} - Local ArgConverter::ConvertToV8UTF16String(Isolate* isolate, const u16string& utf16string) { return String::NewFromTwoByte(isolate, ((const uint16_t*) utf16string.data())); } -Local ArgConverter::ConvertToV8UTF16String(v8::Isolate* isolate, const uint16_t* utf16string, int size) { - return String::NewFromTwoByte(isolate, utf16string, NewStringType::kNormal, size).ToLocalChecked(); -} - std::map ArgConverter::s_type_long_operations_cache; \ No newline at end of file diff --git a/test-app/runtime/src/main/cpp/ArgConverter.h b/test-app/runtime/src/main/cpp/ArgConverter.h index a7d439296..6ebbf2a6a 100644 --- a/test-app/runtime/src/main/cpp/ArgConverter.h +++ b/test-app/runtime/src/main/cpp/ArgConverter.h @@ -40,10 +40,6 @@ class ArgConverter { static v8::Local ConvertToV8String(v8::Isolate* isolate, const char* data, int length); - static v8::Local ConvertToV8UTF16String(v8::Isolate* isolate, const std::string& string); - - static v8::Local ConvertToV8UTF16String(v8::Isolate* isolate, const uint16_t* utf16string, int size); - static v8::Local ConvertToV8UTF16String(v8::Isolate* isolate, const std::u16string& utf16string); private: diff --git a/test-app/runtime/src/main/cpp/ArrayElementAccessor.cpp b/test-app/runtime/src/main/cpp/ArrayElementAccessor.cpp index a81957a53..221a29c51 100644 --- a/test-app/runtime/src/main/cpp/ArrayElementAccessor.cpp +++ b/test-app/runtime/src/main/cpp/ArrayElementAccessor.cpp @@ -83,6 +83,7 @@ void ArrayElementAccessor::SetArrayElement(Isolate* isolate, const Local HandleScope handleScope(isolate); auto runtime = Runtime::GetRuntime(isolate); auto objectManager = runtime->GetObjectManager(); + auto context = isolate->GetCurrentContext(); auto arr = objectManager->GetJavaObjectByJsObject(array); @@ -90,15 +91,15 @@ void ArrayElementAccessor::SetArrayElement(Isolate* isolate, const Local jboolean isCopy = false; if (elementSignature == "Z") { //bool - jboolean boolElementValue = (jboolean) value->BooleanValue(); + jboolean boolElementValue = (jboolean) value->BooleanValue(context).ToChecked(); jbooleanArray boolArr = static_cast(arr); env.SetBooleanArrayRegion(boolArr, index, 1, &boolElementValue); } else if (elementSignature == "B") { //byte - jbyte byteElementValue = (jbyte) value->Int32Value(); + jbyte byteElementValue = (jbyte) value->Int32Value(context).ToChecked(); jbyteArray byteArr = static_cast(arr); env.SetByteArrayRegion(byteArr, index, 1, &byteElementValue); } else if (elementSignature == "C") { //char - String::Utf8Value utf8(value->ToString()); + String::Utf8Value utf8(isolate, value->ToString(isolate)); JniLocalRef s(env.NewString((jchar*) *utf8, 1)); const char* singleChar = env.GetStringUTFChars(s, &isCopy); jchar charElementValue = *singleChar; @@ -106,11 +107,11 @@ void ArrayElementAccessor::SetArrayElement(Isolate* isolate, const Local jcharArray charArr = static_cast(arr); env.SetCharArrayRegion(charArr, index, 1, &charElementValue); } else if (elementSignature == "S") { //short - jshort shortElementValue = (jshort) value->Int32Value(); + jshort shortElementValue = (jshort) value->Int32Value(context).ToChecked(); jshortArray shortArr = static_cast(arr); env.SetShortArrayRegion(shortArr, index, 1, &shortElementValue); } else if (elementSignature == "I") { //int - jint intElementValue = value->Int32Value(); + jint intElementValue = value->Int32Value(context).ToChecked(); jintArray intArr = static_cast(arr); env.SetIntArrayRegion(intArr, index, 1, &intElementValue); } else if (elementSignature == "J") { //long @@ -118,16 +119,16 @@ void ArrayElementAccessor::SetArrayElement(Isolate* isolate, const Local if (value->IsObject()) { longElementValue = (jlong) ArgConverter::ConvertToJavaLong(isolate, value); } else { - longElementValue = (jlong) value->IntegerValue(); + longElementValue = (jlong) value->IntegerValue(context).ToChecked(); } jlongArray longArr = static_cast(arr); env.SetLongArrayRegion(longArr, index, 1, &longElementValue); } else if (elementSignature == "F") { //float - jfloat floatElementValue = (jfloat) value->NumberValue(); + jfloat floatElementValue = (jfloat) value->NumberValue(context).ToChecked(); jfloatArray floatArr = static_cast(arr); env.SetFloatArrayRegion(floatArr, index, 1, &floatElementValue); } else if (elementSignature == "D") { //double - jdouble doubleElementValue = (jdouble) value->NumberValue(); + jdouble doubleElementValue = (jdouble) value->NumberValue(context).ToChecked(); jdoubleArray doubleArr = static_cast(arr); env.SetDoubleArrayRegion(doubleArr, index, 1, &doubleElementValue); } else { //string or object diff --git a/test-app/runtime/src/main/cpp/CallbackHandlers.cpp b/test-app/runtime/src/main/cpp/CallbackHandlers.cpp index f1fbb6ffc..318ab6590 100644 --- a/test-app/runtime/src/main/cpp/CallbackHandlers.cpp +++ b/test-app/runtime/src/main/cpp/CallbackHandlers.cpp @@ -559,6 +559,7 @@ CallbackHandlers::GetImplementedInterfaces(JEnv &env, const Local &imple vector interfacesToImplement; auto propNames = implementationObject->GetOwnPropertyNames(); + auto isolate = implementationObject->GetIsolate(); for (int i = 0; i < propNames->Length(); i++) { auto name = propNames->Get(i).As(); auto prop = implementationObject->Get(name); @@ -566,14 +567,15 @@ CallbackHandlers::GetImplementedInterfaces(JEnv &env, const Local &imple bool arrFound = !prop.IsEmpty() && prop->IsArray(); if (arrFound) { - v8::String::Utf8Value propName(name); + v8::String::Utf8Value propName(isolate, name); std::string arrNameC = std::string(*propName); if (arrNameC == "interfaces") { - auto interfacesArr = prop->ToObject(); + auto interfacesArr = prop->ToObject(isolate); - auto isolate = implementationObject->GetIsolate(); + auto context = isolate->GetCurrentContext(); int length = interfacesArr->Get( - v8::String::NewFromUtf8(isolate, "length"))->ToObject()->Uint32Value(); + v8::String::NewFromUtf8(isolate, "length"))->ToObject(isolate)->Uint32Value( + context).ToChecked(); if (length > 0) { for (int i = 0; i < length; i++) { @@ -615,6 +617,7 @@ CallbackHandlers::GetMethodOverrides(JEnv &env, const Local &implementat vector methodNames; auto propNames = implementationObject->GetOwnPropertyNames(); + auto isolate = implementationObject->GetIsolate(); for (int i = 0; i < propNames->Length(); i++) { auto name = propNames->Get(i).As(); auto method = implementationObject->Get(name); @@ -622,7 +625,7 @@ CallbackHandlers::GetMethodOverrides(JEnv &env, const Local &implementat bool methodFound = !method.IsEmpty() && method->IsFunction(); if (methodFound) { - String::Utf8Value stringValue(name); + String::Utf8Value stringValue(isolate, name); jstring value = env.NewStringUTF(*stringValue); methodNames.push_back(value); } @@ -645,7 +648,8 @@ CallbackHandlers::GetMethodOverrides(JEnv &env, const Local &implementat void CallbackHandlers::LogMethodCallback(const v8::FunctionCallbackInfo &args) { try { if ((args.Length() > 0) && args[0]->IsString()) { - String::Utf8Value message(args[0]->ToString()); + auto isolate = args.GetIsolate(); + String::Utf8Value message(isolate, args[0]->ToString(isolate)); DEBUG_WRITE("%s", *message); } } catch (NativeScriptException &e) { @@ -668,6 +672,38 @@ void CallbackHandlers::TimeCallback(const v8::FunctionCallbackInfo &a args.GetReturnValue().Set(duration); } +void CallbackHandlers::ReleaseNativeCounterpartCallback( + const v8::FunctionCallbackInfo &info) { + try { + SET_PROFILER_FRAME(); + + validateProvidedArgumentsLength(info, 1); + + auto isolate = info.GetIsolate(); + Handle obj = info[0].As(); + + auto runtime = Runtime::GetRuntime(isolate); + auto objectManager = runtime->GetObjectManager(); + objectManager->ReleaseNativeCounterpart(obj); + } catch (NativeScriptException &e) { + e.ReThrowToV8(); + } catch (std::exception e) { + stringstream ss; + ss << "Error: c++ exception: " << e.what() << endl; + NativeScriptException nsEx(ss.str()); + nsEx.ReThrowToV8(); + } catch (...) { + NativeScriptException nsEx(std::string("Error: c++ exception!")); + nsEx.ReThrowToV8(); + } +} + +void CallbackHandlers::validateProvidedArgumentsLength(const v8::FunctionCallbackInfo &args, int expectedSize) { + if(args.Length() != expectedSize){ + throw NativeScriptException("Unexpected arguments count!"); + } +} + void CallbackHandlers::DumpReferenceTablesMethodCallback( const v8::FunctionCallbackInfo &args) { DumpReferenceTablesMethod(); @@ -887,7 +923,7 @@ void CallbackHandlers::NewThreadCallback(const v8::FunctionCallbackInfoGetFrame( - 0)->GetScriptName(); + isolate, 0)->GetScriptName(); auto currentExecutingScriptNameStr = ArgConverter::ConvertToString( currentExecutingScriptName); auto lastForwardSlash = currentExecutingScriptNameStr.find_last_of("/"); @@ -952,9 +988,10 @@ CallbackHandlers::WorkerObjectPostMessageCallback(const v8::FunctionCallbackInfo ArgConverter::ConvertToV8String(isolate, "workerId"), jsId); - Local msg = tns::JsonStringifyObject(isolate, args[0])->ToString(); + Local msg = tns::JsonStringifyObject(isolate, args[0])->ToString(isolate); + auto context = isolate->GetCurrentContext(); // get worker's ID that is associated on the other side - in Java - auto id = jsId->Int32Value(); + auto id = jsId->Int32Value(context).ToChecked(); JEnv env; auto mId = env.GetStaticMethodID(RUNTIME_CLASS, "sendMessageFromMainToWorker", @@ -1049,7 +1086,7 @@ CallbackHandlers::WorkerGlobalPostMessageCallback(const v8::FunctionCallbackInfo return; } - Local msg = tns::JsonStringifyObject(isolate, args[0])->ToString(); + Local msg = tns::JsonStringifyObject(isolate, args[0])->ToString(isolate); JEnv env; auto mId = env.GetStaticMethodID(RUNTIME_CLASS, "sendMessageFromWorkerToMain", @@ -1145,6 +1182,7 @@ CallbackHandlers::WorkerObjectTerminateCallback(const v8::FunctionCallbackInfoGetCurrentContext(); Local jsId; @@ -1153,13 +1191,13 @@ CallbackHandlers::WorkerObjectTerminateCallback(const v8::FunctionCallbackInfoInt32Value(); + auto id = jsId->Int32Value(context).ToChecked(); Local isTerminated; V8GetPrivateValue(isolate, thiz, ArgConverter::ConvertToV8String(isolate, "isTerminated"), isTerminated); - if (!isTerminated.IsEmpty() && isTerminated->BooleanValue()) { + if (!isTerminated.IsEmpty() && isTerminated->BooleanValue(context).ToChecked()) { DEBUG_WRITE( "Main: WorkerObjectTerminateCallback - Worker(id=%d)'s terminate has already been called.", id); @@ -1204,7 +1242,7 @@ void CallbackHandlers::WorkerGlobalCloseCallback(const v8::FunctionCallbackInfo< auto isTerminating = globalObject->Get( ArgConverter::ConvertToV8String(isolate, "isTerminating")); - if (!isTerminating.IsEmpty() && isTerminating->BooleanValue()) { + if (!isTerminating.IsEmpty() && isTerminating->BooleanValue(context).ToChecked()) { DEBUG_WRITE("WORKER: WorkerThreadCloseCallback - Worker is currently terminating..."); return; } @@ -1273,7 +1311,7 @@ void CallbackHandlers::CallWorkerScopeOnErrorHandle(Isolate *isolate, TryCatch & auto result = func->Call(Undefined(isolate), 1, args1); // return 'true'-like value, don't bubble up to main Worker.onerror - if (!result.IsEmpty() && result->BooleanValue()) { + if (!result.IsEmpty() && result->BooleanValue(context).ToChecked()) { // Do nothing, exception has been handled return; } @@ -1281,7 +1319,7 @@ void CallbackHandlers::CallWorkerScopeOnErrorHandle(Isolate *isolate, TryCatch & // will account for exceptions thrown inside the error handler if (innerTc.HasCaught()) { - auto lno = innerTc.Message()->GetLineNumber(); + auto lno = innerTc.Message()->GetLineNumber(context).ToChecked(); auto msg = innerTc.Message()->Get(); Local outStackTrace = innerTc.StackTrace(context).FromMaybe(Local()); Local stackTrace; @@ -1295,7 +1333,7 @@ void CallbackHandlers::CallWorkerScopeOnErrorHandle(Isolate *isolate, TryCatch & } // throw so that it may bubble up to main - auto lno = tc.Message()->GetLineNumber(); + auto lno = tc.Message()->GetLineNumber(context).ToChecked(); auto msg = tc.Message()->Get(); auto source = tc.Message()->GetScriptResourceName()->ToString(isolate); Local outStackTrace = tc.StackTrace(context).FromMaybe(Local()); @@ -1367,7 +1405,8 @@ CallbackHandlers::CallWorkerObjectOnErrorHandle(Isolate *isolate, jint workerId, // Handle exceptions thrown in onmessage with the worker.onerror handler, if present auto result = func->Call(Undefined(isolate), 1, args1); - if (!result.IsEmpty() && result->BooleanValue()) { + auto context = isolate->GetCurrentContext(); + if (!result.IsEmpty() && result->BooleanValue(context).ToChecked()) { // Do nothing, exception is handled and does not need to be raised to application level return; } @@ -1442,6 +1481,8 @@ jmethodID CallbackHandlers::ENABLE_VERBOSE_LOGGING_METHOD_ID = nullptr; jmethodID CallbackHandlers::DISABLE_VERBOSE_LOGGING_METHOD_ID = nullptr; jmethodID CallbackHandlers::INIT_WORKER_METHOD_ID = nullptr; + + NumericCasts CallbackHandlers::castFunctions; ArrayElementAccessor CallbackHandlers::arrayElementAccessor; FieldAccessor CallbackHandlers::fieldAccessor; diff --git a/test-app/runtime/src/main/cpp/CallbackHandlers.h b/test-app/runtime/src/main/cpp/CallbackHandlers.h index 72fb2567b..ebf8ca9e1 100644 --- a/test-app/runtime/src/main/cpp/CallbackHandlers.h +++ b/test-app/runtime/src/main/cpp/CallbackHandlers.h @@ -111,6 +111,8 @@ namespace tns { static void DisableVerboseLoggingMethodCallback(const v8::FunctionCallbackInfo &args); + static void ReleaseNativeCounterpartCallback(const v8::FunctionCallbackInfo &info); + static v8::Local FindClass(v8::Isolate *isolate, const std::string &className); static void NewThreadCallback(const v8::FunctionCallbackInfo &args); @@ -194,6 +196,8 @@ namespace tns { */ static jobjectArray GetJavaStringArray(JEnv &env, int length); + static void validateProvidedArgumentsLength(const v8::FunctionCallbackInfo &args, int expectedSize); + static short MAX_JAVA_STRING_ARRAY_LENGTH; static jclass RUNTIME_CLASS; @@ -235,6 +239,8 @@ namespace tns { jfieldID _fieldID; jobject _runtime; }; + + }; } diff --git a/test-app/runtime/src/main/cpp/DOMDomainCallbackHandlers.cpp b/test-app/runtime/src/main/cpp/DOMDomainCallbackHandlers.cpp index ec075f30c..f73e2789d 100644 --- a/test-app/runtime/src/main/cpp/DOMDomainCallbackHandlers.cpp +++ b/test-app/runtime/src/main/cpp/DOMDomainCallbackHandlers.cpp @@ -54,7 +54,8 @@ void DOMDomainCallbackHandlers::ChildNodeInsertedCallback(const v8::FunctionCall return; } - domAgentInstance->m_frontend.childNodeInserted(parentId->Int32Value(), lastId->Int32Value(), std::move(domNode)); + auto context = isolate->GetCurrentContext(); + domAgentInstance->m_frontend.childNodeInserted(parentId->Int32Value(context).ToChecked(), lastId->Int32Value(context).ToChecked(), std::move(domNode)); } catch (NativeScriptException& e) { e.ReThrowToV8(); } catch (std::exception e) { @@ -87,7 +88,8 @@ void DOMDomainCallbackHandlers::ChildNodeRemovedCallback(const v8::FunctionCallb auto parentId = args[0]->ToNumber(isolate); auto nodeId = args[1]->ToNumber(isolate); - domAgentInstance->m_frontend.childNodeRemoved(parentId->Int32Value(), nodeId->Int32Value()); + auto context = isolate->GetCurrentContext(); + domAgentInstance->m_frontend.childNodeRemoved(parentId->Int32Value(context).ToChecked(), nodeId->Int32Value(context).ToChecked()); } catch (NativeScriptException& e) { e.ReThrowToV8(); } catch (std::exception e) { @@ -118,12 +120,13 @@ void DOMDomainCallbackHandlers::AttributeModifiedCallback(const v8::FunctionCall } auto nodeId = args[0]->ToNumber(isolate); - auto attributeName = args[1]->ToString(); - auto attributeValue = args[2]->ToString(); + auto attributeName = args[1]->ToString(isolate); + auto attributeValue = args[2]->ToString(isolate); - domAgentInstance->m_frontend.attributeModified(nodeId->Int32Value(), - v8_inspector::toProtocolString(attributeName), - v8_inspector::toProtocolString(attributeValue)); + auto context = isolate->GetCurrentContext(); + domAgentInstance->m_frontend.attributeModified(nodeId->Int32Value(context).ToChecked(), + v8_inspector::toProtocolString(isolate, attributeName), + v8_inspector::toProtocolString(isolate, attributeValue)); } catch (NativeScriptException& e) { e.ReThrowToV8(); } catch (std::exception e) { @@ -153,10 +156,11 @@ void DOMDomainCallbackHandlers::AttributeRemovedCallback(const v8::FunctionCallb } auto nodeId = args[0]->ToNumber(isolate); - auto attributeName = args[1]->ToString(); + auto attributeName = args[1]->ToString(isolate); - domAgentInstance->m_frontend.attributeRemoved(nodeId->Int32Value(), - v8_inspector::toProtocolString(attributeName)); + auto context = isolate->GetCurrentContext(); + domAgentInstance->m_frontend.attributeRemoved(nodeId->Int32Value(context).ToChecked(), + v8_inspector::toProtocolString(isolate, attributeName)); } catch (NativeScriptException& e) { e.ReThrowToV8(); } catch (std::exception e) { diff --git a/test-app/runtime/src/main/cpp/FieldAccessor.cpp b/test-app/runtime/src/main/cpp/FieldAccessor.cpp index 1757ece8e..fb9777d46 100644 --- a/test-app/runtime/src/main/cpp/FieldAccessor.cpp +++ b/test-app/runtime/src/main/cpp/FieldAccessor.cpp @@ -234,28 +234,29 @@ void FieldAccessor::SetJavaField(Isolate* isolate, const Local& target, auto clazz = fieldData->clazz; if (isPrimitiveType) { + auto context = isolate->GetCurrentContext(); switch (fieldTypeName[0]) { case 'Z': { //bool //TODO: validate value is a boolean before calling if (isStatic) { - env.SetStaticBooleanField(clazz, fieldId, value->BooleanValue()); + env.SetStaticBooleanField(clazz, fieldId, value->BooleanValue(context).ToChecked()); } else { - env.SetBooleanField(targetJavaObject, fieldId, value->BooleanValue()); + env.SetBooleanField(targetJavaObject, fieldId, value->BooleanValue(context).ToChecked()); } break; } case 'B': { //byte //TODO: validate value is a byte before calling if (isStatic) { - env.SetStaticByteField(clazz, fieldId, value->Int32Value()); + env.SetStaticByteField(clazz, fieldId, value->Int32Value(context).ToChecked()); } else { - env.SetByteField(targetJavaObject, fieldId, value->Int32Value()); + env.SetByteField(targetJavaObject, fieldId, value->Int32Value(context).ToChecked()); } break; } case 'C': { //char //TODO: validate value is a single char - String::Utf8Value stringValue(value->ToString()); + String::Utf8Value stringValue(isolate, value->ToString(isolate)); JniLocalRef strValue(env.NewStringUTF(*stringValue)); const char* chars = env.GetStringUTFChars(strValue, 0); @@ -270,18 +271,18 @@ void FieldAccessor::SetJavaField(Isolate* isolate, const Local& target, case 'S': { //short //TODO: validate value is a short before calling if (isStatic) { - env.SetStaticShortField(clazz, fieldId, value->Int32Value()); + env.SetStaticShortField(clazz, fieldId, value->Int32Value(context).ToChecked()); } else { - env.SetShortField(targetJavaObject, fieldId, value->Int32Value()); + env.SetShortField(targetJavaObject, fieldId, value->Int32Value(context).ToChecked()); } break; } case 'I': { //int //TODO: validate value is a int before calling if (isStatic) { - env.SetStaticIntField(clazz, fieldId, value->Int32Value()); + env.SetStaticIntField(clazz, fieldId, value->Int32Value(context).ToChecked()); } else { - env.SetIntField(targetJavaObject, fieldId, value->Int32Value()); + env.SetIntField(targetJavaObject, fieldId, value->Int32Value(context).ToChecked()); } break; @@ -297,17 +298,17 @@ void FieldAccessor::SetJavaField(Isolate* isolate, const Local& target, } case 'F': { //float if (isStatic) { - env.SetStaticFloatField(clazz, fieldId, static_cast(value->NumberValue())); + env.SetStaticFloatField(clazz, fieldId, static_cast(value->NumberValue(context).ToChecked())); } else { - env.SetFloatField(targetJavaObject, fieldId, static_cast(value->NumberValue())); + env.SetFloatField(targetJavaObject, fieldId, static_cast(value->NumberValue(context).ToChecked())); } break; } case 'D': { //double if (isStatic) { - env.SetStaticDoubleField(clazz, fieldId, value->NumberValue()); + env.SetStaticDoubleField(clazz, fieldId, value->NumberValue(context).ToChecked()); } else { - env.SetDoubleField(targetJavaObject, fieldId, value->NumberValue()); + env.SetDoubleField(targetJavaObject, fieldId, value->NumberValue(context).ToChecked()); } break; } @@ -326,7 +327,7 @@ void FieldAccessor::SetJavaField(Isolate* isolate, const Local& target, //TODO: validate valie is a string; result = ArgConverter::ConvertToJavaString(value); } else { - auto objectWithHiddenID = value->ToObject(); + auto objectWithHiddenID = value->ToObject(isolate); result = objectManager->GetJavaObjectByJsObject(objectWithHiddenID); } } diff --git a/test-app/runtime/src/main/cpp/JsArgConverter.cpp b/test-app/runtime/src/main/cpp/JsArgConverter.cpp index 56fed5803..5a64a7cc3 100644 --- a/test-app/runtime/src/main/cpp/JsArgConverter.cpp +++ b/test-app/runtime/src/main/cpp/JsArgConverter.cpp @@ -98,7 +98,7 @@ bool JsArgConverter::ConvertArg(const Local& arg, int index) { sprintf(buff, "Cannot convert string to %s at index %d", typeSignature.c_str(), index); } } else if (arg->IsObject()) { - auto jsObject = arg->ToObject(); + auto jsObject = arg->ToObject(m_isolate); auto castType = NumericCasts::GetCastType(m_isolate, jsObject); @@ -107,12 +107,13 @@ bool JsArgConverter::ConvertArg(const Local& arg, int index) { auto runtime = Runtime::GetRuntime(m_isolate); auto objectManager = runtime->GetObjectManager(); + auto context = m_isolate->GetCurrentContext(); switch (castType) { case CastType::Char: castValue = NumericCasts::GetCastValue(jsObject); if (castValue->IsString()) { - string value = ArgConverter::ConvertToString(castValue->ToString()); + string value = ArgConverter::ConvertToString(castValue->ToString(m_isolate)); m_args[index].c = (jchar) value[0]; success = true; } @@ -121,12 +122,12 @@ bool JsArgConverter::ConvertArg(const Local& arg, int index) { case CastType::Byte: castValue = NumericCasts::GetCastValue(jsObject); if (castValue->IsString()) { - string strValue = ArgConverter::ConvertToString(castValue->ToString()); + string strValue = ArgConverter::ConvertToString(castValue->ToString(m_isolate)); int byteArg = atoi(strValue.c_str()); jbyte value = (jbyte) byteArg; success = ConvertFromCastFunctionObject(value, index); } else if (castValue->IsInt32()) { - jbyte value = (jbyte) castValue->ToInt32(m_isolate)->Int32Value(); + jbyte value = (jbyte) castValue->ToInt32(m_isolate)->Int32Value(context).ToChecked(); success = ConvertFromCastFunctionObject(value, index); } break; @@ -134,12 +135,12 @@ bool JsArgConverter::ConvertArg(const Local& arg, int index) { case CastType::Short: castValue = NumericCasts::GetCastValue(jsObject); if (castValue->IsString()) { - string strValue = ArgConverter::ConvertToString(castValue->ToString()); + string strValue = ArgConverter::ConvertToString(castValue->ToString(m_isolate)); int shortArg = atoi(strValue.c_str()); jshort value = (jshort) shortArg; success = ConvertFromCastFunctionObject(value, index); } else if (castValue->IsInt32()) { - jshort value = (jshort) castValue->ToInt32(m_isolate)->Int32Value(); + jshort value = (jshort) castValue->ToInt32(m_isolate)->Int32Value(context).ToChecked(); success = ConvertFromCastFunctionObject(value, index); } break; @@ -147,12 +148,12 @@ bool JsArgConverter::ConvertArg(const Local& arg, int index) { case CastType::Long: castValue = NumericCasts::GetCastValue(jsObject); if (castValue->IsString()) { - string strValue = ArgConverter::ConvertToString(castValue->ToString()); + string strValue = ArgConverter::ConvertToString(castValue->ToString(m_isolate)); int64_t longArg = atoll(strValue.c_str()); jlong value = (jlong) longArg; success = ConvertFromCastFunctionObject(value, index); } else if (castValue->IsInt32()) { - jlong value = (jlong) castValue->ToInt32(m_isolate)->IntegerValue(); + jlong value = (jlong) castValue->ToInt32(m_isolate)->IntegerValue(context).ToChecked(); success = ConvertFromCastFunctionObject(value, index); } break; @@ -160,7 +161,7 @@ bool JsArgConverter::ConvertArg(const Local& arg, int index) { case CastType::Float: castValue = NumericCasts::GetCastValue(jsObject); if (castValue->IsNumber()) { - double floatArg = castValue->ToNumber(m_isolate)->NumberValue(); + double floatArg = castValue->ToNumber(m_isolate)->NumberValue(context).ToChecked(); jfloat value = (jfloat) floatArg; success = ConvertFromCastFunctionObject(value, index); } @@ -169,7 +170,7 @@ bool JsArgConverter::ConvertArg(const Local& arg, int index) { case CastType::Double: castValue = NumericCasts::GetCastValue(jsObject); if (castValue->IsNumber()) { - double doubleArg = castValue->ToNumber(m_isolate)->NumberValue(); + double doubleArg = castValue->ToNumber(m_isolate)->NumberValue(context).ToChecked(); jdouble value = (jdouble) doubleArg; success = ConvertFromCastFunctionObject(value, index); } @@ -230,20 +231,21 @@ bool JsArgConverter::ConvertJavaScriptNumber(const Local& jsValue, int in }; const auto& typeSignature = m_tokens.at(index); + auto context = m_isolate->GetCurrentContext(); const char typePrefix = typeSignature[0]; switch (typePrefix) { case 'B': // byte - value.b = (jbyte) jsValue->Int32Value(); + value.b = (jbyte) jsValue->Int32Value(context).ToChecked(); break; case 'S': // short - value.s = (jshort) jsValue->Int32Value(); + value.s = (jshort) jsValue->Int32Value(context).ToChecked(); break; case 'I': // int - value.i = (jint) jsValue->Int32Value(); + value.i = (jint) jsValue->Int32Value(context).ToChecked(); break; case 'J': // long @@ -252,16 +254,16 @@ bool JsArgConverter::ConvertJavaScriptNumber(const Local& jsValue, int in auto numObj = Local::Cast(jsValue); value.j = (jlong) numObj->ValueOf(); } else { - value.j = (jlong) jsValue->IntegerValue(); + value.j = (jlong) jsValue->IntegerValue(context).ToChecked(); } break; case 'F': // float - value.f = (jfloat) jsValue->NumberValue(); + value.f = (jfloat) jsValue->NumberValue(context).ToChecked(); break; case 'D': // double - value.d = (jdouble) jsValue->NumberValue(); + value.d = (jdouble) jsValue->NumberValue(context).ToChecked(); break; default: @@ -280,16 +282,17 @@ bool JsArgConverter::ConvertJavaScriptBoolean(const Local& jsValue, int i bool success; const auto& typeSignature = m_tokens.at(index); + auto context = m_isolate->GetCurrentContext(); if (typeSignature == "Z") { bool argValue; if (jsValue->IsBoolean()) { - argValue = jsValue->BooleanValue(); + argValue = jsValue->BooleanValue(context).ToChecked(); } else { auto boolObj = Local::Cast(jsValue); auto val = boolObj->Get(V8StringConstants::GetValueOf(m_isolate)); if (!val.IsEmpty() && val->IsFunction()) { - argValue = val.As()->Call(boolObj, 0, nullptr)->BooleanValue(); + argValue = val.As()->Call(boolObj, 0, nullptr)->BooleanValue(context).ToChecked(); } else { argValue = false; } @@ -320,6 +323,7 @@ bool JsArgConverter::ConvertJavaScriptArray(const Local& jsArr, int index jsize arrLength = jsArr->Length(); const auto& arraySignature = m_tokens.at(index); + auto context = m_isolate->GetCurrentContext(); string elementType = arraySignature.substr(1); @@ -332,21 +336,21 @@ bool JsArgConverter::ConvertJavaScriptArray(const Local& jsArr, int index case 'Z': arr = m_env.NewBooleanArray(arrLength); for (jsize i = 0; i < arrLength; i++) { - jboolean value = jsArr->Get(i)->BooleanValue(); + jboolean value = jsArr->Get(i)->BooleanValue(context).ToChecked(); m_env.SetBooleanArrayRegion((jbooleanArray) arr, i, 1, &value); } break; case 'B': arr = m_env.NewByteArray(arrLength); for (jsize i = 0; i < arrLength; i++) { - jbyte value = jsArr->Get(i)->Int32Value(); + jbyte value = jsArr->Get(i)->Int32Value(context).ToChecked(); m_env.SetByteArrayRegion((jbyteArray) arr, i, 1, &value); } break; case 'C': arr = m_env.NewCharArray(arrLength); for (jsize i = 0; i < arrLength; i++) { - String::Utf8Value utf8(jsArr->Get(i)->ToString()); + String::Utf8Value utf8(m_isolate, jsArr->Get(i)->ToString(m_isolate)); JniLocalRef s(m_env.NewString((jchar*) *utf8, 1)); const char* singleChar = m_env.GetStringUTFChars(s, nullptr); jchar value = *singleChar; @@ -357,35 +361,35 @@ bool JsArgConverter::ConvertJavaScriptArray(const Local& jsArr, int index case 'S': arr = m_env.NewShortArray(arrLength); for (jsize i = 0; i < arrLength; i++) { - jshort value = jsArr->Get(i)->Int32Value(); + jshort value = jsArr->Get(i)->Int32Value(context).ToChecked(); m_env.SetShortArrayRegion((jshortArray) arr, i, 1, &value); } break; case 'I': arr = m_env.NewIntArray(arrLength); for (jsize i = 0; i < arrLength; i++) { - jint value = jsArr->Get(i)->Int32Value(); + jint value = jsArr->Get(i)->Int32Value(context).ToChecked(); m_env.SetIntArrayRegion((jintArray) arr, i, 1, &value); } break; case 'J': arr = m_env.NewLongArray(arrLength); for (jsize i = 0; i < arrLength; i++) { - jlong value = jsArr->Get(i)->NumberValue(); + jlong value = jsArr->Get(i)->NumberValue(context).ToChecked(); m_env.SetLongArrayRegion((jlongArray) arr, i, 1, &value); } break; case 'F': arr = m_env.NewFloatArray(arrLength); for (jsize i = 0; i < arrLength; i++) { - jfloat value = jsArr->Get(i)->NumberValue(); + jfloat value = jsArr->Get(i)->NumberValue(context).ToChecked(); m_env.SetFloatArrayRegion((jfloatArray) arr, i, 1, &value); } break; case 'D': arr = m_env.NewDoubleArray(arrLength); for (jsize i = 0; i < arrLength; i++) { - jdouble value = jsArr->Get(i)->NumberValue(); + jdouble value = jsArr->Get(i)->NumberValue(context).ToChecked(); m_env.SetDoubleArrayRegion((jdoubleArray) arr, i, 1, &value); } break; diff --git a/test-app/runtime/src/main/cpp/JsArgToArrayConverter.cpp b/test-app/runtime/src/main/cpp/JsArgToArrayConverter.cpp index 866e724e2..e37ee67dc 100644 --- a/test-app/runtime/src/main/cpp/JsArgToArrayConverter.cpp +++ b/test-app/runtime/src/main/cpp/JsArgToArrayConverter.cpp @@ -59,18 +59,19 @@ bool JsArgToArrayConverter::ConvertArg(const Local& arg, int index) { JEnv env; Type returnType = JType::getClassType(m_return_type); + auto context = m_isolate->GetCurrentContext(); if (arg.IsEmpty()) { s << "Cannot convert empty JavaScript object"; success = false; } else if (arg->IsInt32() && (returnType == Type::Int || returnType == Type::Null)) { - jint value = arg->Int32Value(); + jint value = arg->Int32Value(context).ToChecked(); auto javaObject = JType::NewInt(env, value); SetConvertedObject(env, index, javaObject); success = true; } else if (arg->IsNumber() || arg->IsNumberObject()) { - double d = arg->NumberValue(); + double d = arg->NumberValue(context).ToChecked(); int64_t i = (int64_t) d; //if returnType isNumber and this check is true, the number we'll try to convert is whole(integer) @@ -109,13 +110,13 @@ bool JsArgToArrayConverter::ConvertArg(const Local& arg, int index) { success = true; } } else if (arg->IsBoolean()) { - jboolean value = arg->BooleanValue(); + jboolean value = arg->BooleanValue(context).ToChecked(); auto javaObject = JType::NewBoolean(env, value); SetConvertedObject(env, index, javaObject); success = true; } else if (arg->IsBooleanObject()) { auto boolObj = Local::Cast(arg); - jboolean value = boolObj->BooleanValue() ? JNI_TRUE : JNI_FALSE; + jboolean value = boolObj->BooleanValue(context).ToChecked() ? JNI_TRUE : JNI_FALSE; auto javaObject = JType::NewBoolean(env, value); SetConvertedObject(env, index, javaObject); @@ -126,7 +127,7 @@ bool JsArgToArrayConverter::ConvertArg(const Local& arg, int index) { success = true; } else if (arg->IsObject()) { - auto jsObj = arg->ToObject(); + auto jsObj = arg->ToObject(m_isolate); auto castType = NumericCasts::GetCastType(m_isolate, jsObj); @@ -148,7 +149,7 @@ bool JsArgToArrayConverter::ConvertArg(const Local& arg, int index) { castValue = NumericCasts::GetCastValue(jsObj); charValue = '\0'; if (castValue->IsString()) { - string str = ArgConverter::ConvertToString(castValue->ToString()); + string str = ArgConverter::ConvertToString(castValue->ToString(m_isolate)); charValue = (jchar) str[0]; } javaObject = JType::NewChar(env, charValue); @@ -160,11 +161,11 @@ bool JsArgToArrayConverter::ConvertArg(const Local& arg, int index) { castValue = NumericCasts::GetCastValue(jsObj); byteValue = 0; if (castValue->IsString()) { - string value = ArgConverter::ConvertToString(castValue->ToString()); + string value = ArgConverter::ConvertToString(castValue->ToString(m_isolate)); int byteArg = atoi(value.c_str()); byteValue = (jbyte) byteArg; } else if (castValue->IsInt32()) { - int byteArg = castValue->ToInt32(m_isolate)->Int32Value(); + int byteArg = castValue->ToInt32(m_isolate)->Int32Value(context).ToChecked(); byteValue = (jbyte) byteArg; } javaObject = JType::NewByte(env, byteValue); @@ -176,11 +177,11 @@ bool JsArgToArrayConverter::ConvertArg(const Local& arg, int index) { castValue = NumericCasts::GetCastValue(jsObj); shortValue = 0; if (castValue->IsString()) { - string value = ArgConverter::ConvertToString(castValue->ToString()); + string value = ArgConverter::ConvertToString(castValue->ToString(m_isolate)); int shortArg = atoi(value.c_str()); shortValue = (jshort) shortArg; } else if (castValue->IsInt32()) { - jlong shortArg = castValue->ToInt32(m_isolate)->Int32Value(); + jlong shortArg = castValue->ToInt32(m_isolate)->Int32Value(context).ToChecked(); shortValue = (jshort) shortArg; } javaObject = JType::NewShort(env, shortValue); @@ -192,10 +193,10 @@ bool JsArgToArrayConverter::ConvertArg(const Local& arg, int index) { castValue = NumericCasts::GetCastValue(jsObj); longValue = 0; if (castValue->IsString()) { - auto strValue = ArgConverter::ConvertToString(castValue->ToString()); + auto strValue = ArgConverter::ConvertToString(castValue->ToString(m_isolate)); longValue = atoll(strValue.c_str()); } else if (castValue->IsInt32()) { - longValue = castValue->ToInt32(m_isolate)->Int32Value(); + longValue = castValue->ToInt32(m_isolate)->Int32Value(context).ToChecked(); } javaObject = JType::NewLong(env, longValue); SetConvertedObject(env, index, javaObject); @@ -206,7 +207,7 @@ bool JsArgToArrayConverter::ConvertArg(const Local& arg, int index) { castValue = NumericCasts::GetCastValue(jsObj); floatValue = 0; if (castValue->IsNumber()) { - double floatArg = castValue->ToNumber(m_isolate)->NumberValue(); + double floatArg = castValue->ToNumber(m_isolate)->NumberValue(context).ToChecked(); floatValue = (jfloat) floatArg; } javaObject = JType::NewFloat(env, floatValue); @@ -218,7 +219,7 @@ bool JsArgToArrayConverter::ConvertArg(const Local& arg, int index) { castValue = NumericCasts::GetCastValue(jsObj); doubleValue = 0; if (castValue->IsNumber()) { - double doubleArg = castValue->ToNumber(m_isolate)->NumberValue(); + double doubleArg = castValue->ToNumber(m_isolate)->NumberValue(context).ToChecked(); doubleValue = (jdouble) doubleArg; } javaObject = JType::NewDouble(env, doubleValue); @@ -263,7 +264,7 @@ bool JsArgToArrayConverter::ConvertArg(const Local& arg, int index) { if (success) { SetConvertedObject(env, index, obj.Move(), obj.IsGlobal()); } else { - String::Utf8Value jsObjStr(jsObj); + String::Utf8Value jsObjStr(m_isolate, jsObj); s << "Cannot marshal JavaScript argument " << (*jsObjStr ? *jsObjStr : "") << " at index " << index << " to Java type."; } break; diff --git a/test-app/runtime/src/main/cpp/JsV8InspectorClient.cpp b/test-app/runtime/src/main/cpp/JsV8InspectorClient.cpp index ca5af221a..2be0386a8 100644 --- a/test-app/runtime/src/main/cpp/JsV8InspectorClient.cpp +++ b/test-app/runtime/src/main/cpp/JsV8InspectorClient.cpp @@ -205,12 +205,13 @@ void JsV8InspectorClient::sendToFrontEndCallback(const v8::FunctionCallbackInfo< } try { + auto isolate = args.GetIsolate(); if ((args.Length() > 0) && args[0]->IsString()) { - std::string message = ArgConverter::ConvertToString(args[0]->ToString()); + std::string message = ArgConverter::ConvertToString(args[0]->ToString(isolate)); std::string level = "log"; if (args.Length() > 1 && args[1]->IsString()) { - level = ArgConverter::ConvertToString(args[1]->ToString()); + level = ArgConverter::ConvertToString(args[1]->ToString(isolate)); } JEnv env; @@ -239,7 +240,7 @@ void JsV8InspectorClient::consoleLogCallback(const string& message, const string auto isolate = Runtime::GetRuntime(0)->GetIsolate(); auto stack = v8::StackTrace::CurrentStackTrace(isolate, 1, v8::StackTrace::StackTraceOptions::kDetailed); - auto frame = stack->GetFrame(0); + auto frame = stack->GetFrame(isolate, 0); // will be no-op in non-debuggable builds v8_inspector::V8LogAgentImpl::EntryAdded(message, logLevel, ArgConverter::ConvertToString(frame->GetScriptNameOrSourceURL()), frame->GetLineNumber()); diff --git a/test-app/runtime/src/main/cpp/MetadataNode.cpp b/test-app/runtime/src/main/cpp/MetadataNode.cpp index b29748cb7..3de140281 100644 --- a/test-app/runtime/src/main/cpp/MetadataNode.cpp +++ b/test-app/runtime/src/main/cpp/MetadataNode.cpp @@ -57,7 +57,7 @@ Local MetadataNode::CreateExtendedJSWrapper(Isolate* isolate, ObjectMana auto extdCtorFunc = Local::New(isolate, *cacheData.extendedCtorFunction); auto context = isolate->GetCurrentContext(); extInstance->SetPrototype(context, extdCtorFunc->Get(V8StringConstants::GetPrototype(isolate))); - extInstance->Set(ConvertToV8String("constructor"), extdCtorFunc); + extInstance->Set(ArgConverter::ConvertToV8String(isolate, "constructor"), extdCtorFunc); SetInstanceMetadata(isolate, extInstance, cacheData.node); } @@ -308,8 +308,8 @@ void MetadataNode::FieldAccessorGetterCallback(Local property, const Prope auto fieldCallbackData = reinterpret_cast(info.Data().As()->Value()); if ((!fieldCallbackData->isStatic && thiz->StrictEquals(info.Holder())) - // check whether there's a declaring type to get the class from it - || (fieldCallbackData->declaringType == "")) { + // check whether there's a declaring type to get the class from it + || (fieldCallbackData->declaringType == "")) { info.GetReturnValue().SetUndefined(); return; } @@ -462,13 +462,13 @@ vector MetadataNode::SetInstanceMethodsFromSt auto funcData = External::New(isolate, callbackData); auto funcTemplate = FunctionTemplate::New(isolate, MethodCallback, funcData); - auto funcName = ConvertToV8String(entry.name); + auto funcName = ArgConverter::ConvertToV8String(isolate, entry.name); if (s_profilerEnabled) { auto func = funcTemplate->GetFunction(); Local wrapperFunc = Wrap(isolate, func, entry.name, origin, false /* isCtorFunc */); Local ctorFunc = ctorFuncTemplate->GetFunction(); - Local protoObject = ctorFunc->Get(ConvertToV8String("prototype")).As(); + Local protoObject = ctorFunc->Get(ArgConverter::ConvertToV8String(isolate, "prototype")).As(); if (!protoObject.IsEmpty() && !protoObject->IsUndefined() && !protoObject->IsNull()) { protoObject->Set(funcName, wrapperFunc); } @@ -516,7 +516,7 @@ void MetadataNode::SetInstanceFieldsFromStaticMetadata(Isolate* isolate, LocaldeclaringType = curType; auto fieldData = External::New(isolate, fieldInfo); @@ -883,7 +883,7 @@ void MetadataNode::InterfaceConstructorCallback(const v8::FunctionCallbackInfoIsObject()) { throw NativeScriptException(string("First argument must be implementation object")); } - implementationObject = info[0]->ToObject(); + implementationObject = info[0]->ToObject(isolate); } else if (info.Length() == 2) { if (!info[0]->IsString()) { throw NativeScriptException(string("First argument must be string")); @@ -892,8 +892,8 @@ void MetadataNode::InterfaceConstructorCallback(const v8::FunctionCallbackInfoToString(); - implementationObject = info[1]->ToObject(); + v8ExtendName = info[0]->ToString(isolate); + implementationObject = info[1]->ToObject(isolate); } else { throw NativeScriptException(string("Invalid number of arguments")); } @@ -1219,6 +1219,7 @@ void MetadataNode::PackageGetterCallback(Local property, const PropertyCal } bool MetadataNode::ValidateExtendArguments(const FunctionCallbackInfo& info, bool extendLocationFound, string& extendLocation, v8::Local& extendName, Local& implementationObject, bool isTypeScriptExtend) { + auto isolate = info.GetIsolate(); if (info.Length() == 1) { if (!extendLocationFound) { @@ -1237,7 +1238,7 @@ bool MetadataNode::ValidateExtendArguments(const FunctionCallbackInfo& in throw NativeScriptException(exceptionMessage); } - implementationObject = info[0]->ToObject(); + implementationObject = info[0]->ToObject(isolate); } else if (info.Length() == 2 || isTypeScriptExtend) { if (!info[0]->IsString()) { stringstream ss; @@ -1256,7 +1257,7 @@ bool MetadataNode::ValidateExtendArguments(const FunctionCallbackInfo& in } DEBUG_WRITE("ExtendsCallMethodHandler: getting extend name"); - extendName = info[0]->ToString(); + extendName = info[0]->ToString(isolate); bool isValidExtendName = IsValidExtendName(extendName); if (!isValidExtendName) { stringstream ss; @@ -1265,7 +1266,7 @@ bool MetadataNode::ValidateExtendArguments(const FunctionCallbackInfo& in throw NativeScriptException(exceptionMessage); } - implementationObject = info[1]->ToObject(); + implementationObject = info[1]->ToObject(isolate); } else { stringstream ss; ss << "Invalid extend() call at location: " << extendLocation.c_str(); @@ -1317,6 +1318,7 @@ void MetadataNode::ExtendMethodCallback(const v8::FunctionCallbackInfoIsString()) { stringstream ss; @@ -1335,7 +1337,8 @@ void MetadataNode::ExtendMethodCallback(const v8::FunctionCallbackInfo()); hasDot = strName.find('.') != string::npos; } else if (info.Length() == 3) { - if (info[2]->IsBoolean() && info[2]->BooleanValue()) { + auto context = isolate->GetCurrentContext(); + if (info[2]->IsBoolean() && info[2]->BooleanValue(context).ToChecked()) { isTypeScriptExtend = true; } } @@ -1344,7 +1347,7 @@ void MetadataNode::ExtendMethodCallback(const v8::FunctionCallbackInfo(); implementationObject = info[1].As(); } else { - auto isValidExtendLocation = GetExtendLocation(extendLocation, isTypeScriptExtend); + auto isValidExtendLocation = GetExtendLocation(isolate, extendLocation, isTypeScriptExtend); auto validArgs = ValidateExtendArguments(info, isValidExtendLocation, extendLocation, extendName, implementationObject, isTypeScriptExtend); if (!validArgs) { @@ -1365,8 +1368,6 @@ void MetadataNode::ExtendMethodCallback(const v8::FunctionCallbackInfo()); } - auto isolate = info.GetIsolate(); - //resolve class (pre-generated or generated runtime from dex generator) uint8_t nodeType = s_metadataReader.GetNodeType(node->m_treeNode); bool isInterface = s_metadataReader.IsNodeTypeInterface(nodeType); @@ -1454,15 +1455,15 @@ bool MetadataNode::IsValidExtendName(const Local& name) { return true; } -bool MetadataNode::GetExtendLocation(string& extendLocation, bool isTypeScriptExtend) { +bool MetadataNode::GetExtendLocation(v8::Isolate* isolate, string& extendLocation, bool isTypeScriptExtend) { stringstream extendLocationStream; auto stackTrace = StackTrace::CurrentStackTrace(Isolate::GetCurrent(), 3, StackTrace::kOverview); if (!stackTrace.IsEmpty()) { Local frame; if (isTypeScriptExtend) { - frame = stackTrace->GetFrame(2); // the _super.apply call to ts_helpers will always be the third call frame + frame = stackTrace->GetFrame(isolate, 2); // the _super.apply call to ts_helpers will always be the third call frame } else { - frame = stackTrace->GetFrame(0); + frame = stackTrace->GetFrame(isolate, 0); } if (!frame.IsEmpty()) { @@ -1614,12 +1615,12 @@ void MetadataNode::BuildMetadata(const string& filesPath) { timeval time2; gettimeofday(&time2, nullptr); - __android_log_print(ANDROID_LOG_DEBUG, "TNS.Native", "lenNodes=%d, lenNames=%d, lenValues=%d", lenNodes, lenNames, lenValues); + DEBUG_WRITE("lenNodes=%d, lenNames=%d, lenValues=%d", lenNodes, lenNames, lenValues); long millis1 = (time1.tv_sec * 1000) + (time1.tv_usec / 1000); long millis2 = (time2.tv_sec * 1000) + (time2.tv_usec / 1000); - __android_log_print(ANDROID_LOG_DEBUG, "TNS.Native", "time=%ld", (millis2 - millis1)); + DEBUG_WRITE("time=%ld", (millis2 - millis1)); BuildMetadata(lenNodes, reinterpret_cast(nodes), lenNames, reinterpret_cast(names), lenValues, reinterpret_cast(values)); @@ -1646,7 +1647,7 @@ void MetadataNode::CreateTopLevelNamespaces(Isolate* isolate, const LocalCreateWrapper(isolate); string nameSpace = node->m_treeNode->name; // if the namespaces matches a javascript keyword, prefix it with $ to avoid TypeScript and JavaScript errors - if(IsJavascriptKeyword(nameSpace)) { + if (IsJavascriptKeyword(nameSpace)) { nameSpace = "$" + nameSpace; } global->Set(ArgConverter::ConvertToV8String(isolate, nameSpace), packageObj); @@ -1678,7 +1679,7 @@ bool MetadataNode::IsJavascriptKeyword(std::string word) { "double", "else", "enum", "eval", "export", "extends", "false", "final", "finally", "float", "for", "function", "goto", "if", "implements", "import", "in", "instanceof", "int", "interface", "let", "long", "native", "new", "null", "package", "private", "protected", "public", "return", "short", "static", "super", "switch", "synchronized", "this", "throw", "throws", "transient", "true", "try", "typeof", "var", "void", "volatile", "while", "with", "yield" - }; + }; keywords = set(kw, kw + sizeof(kw)/sizeof(kw[0])); } @@ -1732,7 +1733,7 @@ Local MetadataNode::Wrap(Isolate* isolate, const Local& func if (!result.IsEmpty()) { ret = result.As(); ret->Set(ArgConverter::ConvertToV8String(isolate, "__func"), function); - ret->SetName(ConvertToV8String(actualName)); + ret->SetName(ArgConverter::ConvertToV8String(isolate, actualName)); auto prototypePropName = V8StringConstants::GetPrototype(isolate); ret->Set(prototypePropName, function->Get(prototypePropName)); @@ -1806,7 +1807,7 @@ void MetadataNode::SetMissingBaseMethods(Isolate* isolate, const vectorSet(funcName, funcTemplate); } @@ -1842,7 +1843,7 @@ void MetadataNode::RegisterSymbolHasInstanceCallback(Isolate* isolate, MetadataE auto hasInstanceFunc = hasInstanceTemplate->GetFunction(); PropertyDescriptor descriptor(hasInstanceFunc, false); auto hasInstanceSymbol = Symbol::GetHasInstance(isolate); - interface->ToObject()->DefineProperty(isolate->GetCurrentContext(), hasInstanceSymbol, descriptor); + interface->ToObject(isolate)->DefineProperty(isolate->GetCurrentContext(), hasInstanceSymbol, descriptor); } void MetadataNode::SymbolHasInstanceCallback(const v8::FunctionCallbackInfo& info) { @@ -1862,7 +1863,7 @@ void MetadataNode::SymbolHasInstanceCallback(const v8::FunctionCallbackInfoGetObjectManager(); - auto obj = objectManager->GetJavaObjectByJsObject(arg->ToObject()); + auto obj = objectManager->GetJavaObjectByJsObject(arg->ToObject(isolate)); if (obj.IsNull()) { // Couldn't find a corresponding java instance counterpart. This could happen diff --git a/test-app/runtime/src/main/cpp/MetadataNode.h b/test-app/runtime/src/main/cpp/MetadataNode.h index 77c36b8a6..c46237ddc 100644 --- a/test-app/runtime/src/main/cpp/MetadataNode.h +++ b/test-app/runtime/src/main/cpp/MetadataNode.h @@ -128,7 +128,7 @@ class MetadataNode { static void ArrayIndexedPropertySetterCallback(uint32_t index, v8::Local value, const v8::PropertyCallbackInfo& info); static bool IsValidExtendName(const v8::Local& name); - static bool GetExtendLocation(std::string& extendLocation, bool isTypeScriptExtend); + static bool GetExtendLocation(v8::Isolate* isolate, std::string& extendLocation, bool isTypeScriptExtend); static ExtendedClassCacheData GetCachedExtendedClassData(v8::Isolate* isolate, const std::string& proxyClassName); static void RegisterSymbolHasInstanceCallback(v8::Isolate* isolate, MetadataEntry entry, v8::Local interface); diff --git a/test-app/runtime/src/main/cpp/MethodCache.cpp b/test-app/runtime/src/main/cpp/MethodCache.cpp index 40506fb61..2eddbb107 100644 --- a/test-app/runtime/src/main/cpp/MethodCache.cpp +++ b/test-app/runtime/src/main/cpp/MethodCache.cpp @@ -118,7 +118,7 @@ string MethodCache::GetType(Isolate* isolate, const v8::Local& value) string type; if (value->IsObject()) { - auto objVal = value->ToObject(); + auto objVal = value->ToObject(isolate); Local nullNode; //out V8GetPrivateValue(isolate, objVal, V8StringConstants::GetNullNodeName(isolate), nullNode); @@ -152,13 +152,14 @@ string MethodCache::GetType(Isolate* isolate, const v8::Local& value) } else if (value->IsString() || value->IsStringObject()) { type = "string"; } else if (value->IsNumber() || value->IsNumberObject()) { - double d = value->NumberValue(); + auto context = isolate->GetCurrentContext(); + double d = value->NumberValue(context).ToChecked(); int64_t i = (int64_t) d; bool isInteger = d == i; type = isInteger ? "intnumber" : "doublenumber"; } else if (value->IsObject()) { - auto object = value->ToObject(); + auto object = value->ToObject(isolate); auto castType = NumericCasts::GetCastType(isolate, object); MetadataNode* node; diff --git a/test-app/runtime/src/main/cpp/ModuleInternal.cpp b/test-app/runtime/src/main/cpp/ModuleInternal.cpp index 4e30fdaf3..02e989adb 100644 --- a/test-app/runtime/src/main/cpp/ModuleInternal.cpp +++ b/test-app/runtime/src/main/cpp/ModuleInternal.cpp @@ -286,7 +286,8 @@ Local ModuleInternal::LoadModule(Isolate* isolate, const string& moduleP if (Util::EndsWith(modulePath, ".js")) { auto script = LoadScript(isolate, modulePath, fullRequiredModulePath); - moduleFunc = script->Run().As(); + auto context = isolate->GetCurrentContext(); + moduleFunc = script->Run(context).ToLocalChecked().As(); if (tc.HasCaught()) { throw NativeScriptException(tc, "Error running script " + modulePath); } @@ -378,15 +379,12 @@ Local