This commit is contained in:
lmoreault 2021-05-26 15:18:08 -04:00
Родитель 9540cd9256
Коммит 618ce50538
32 изменённых файлов: 569 добавлений и 409 удалений

Просмотреть файл

@ -2,14 +2,13 @@ apply plugin: 'com.android.application'
android {
compileSdkVersion 30
buildToolsVersion '28.0.2'
defaultConfig {
applicationId "com.unity3d.ads.example"
minSdkVersion 19
targetSdkVersion 30
versionCode = 3710
versionName = "3.7.1"
versionCode = 3720
versionName = "3.7.2"
}
flavorDimensions "arEnabled"

Просмотреть файл

@ -1,23 +1,23 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.2.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.4'
classpath 'com.github.dcendents:android-maven-gradle-plugin:1.4.1'
classpath 'org.jacoco:org.jacoco.core:0.8.1'
}
}
allprojects {
repositories {
google()
jcenter()
}
}
buildscript {
repositories {
jcenter()
gradlePluginPortal()
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.1.3'
classpath 'org.jacoco:org.jacoco.core:0.8.1'
classpath 'org.jfrog.buildinfo:build-info-extractor-gradle:4.20.0'
classpath 'io.github.gradle-nexus:publish-plugin:1.1.0'
}
}
apply from: 'nexusPublishing.gradle'

Просмотреть файл

@ -16,4 +16,7 @@
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
android.useAndroidX=true
android.useAndroidX=true
signing.keyId=34500891
signing.secretKeyRingFile=../gpg-private-key.gpg

0
gradle/wrapper/gradle-wrapper.jar поставляемый Normal file → Executable file
Просмотреть файл

4
gradle/wrapper/gradle-wrapper.properties поставляемый
Просмотреть файл

@ -1,6 +1,6 @@
#Thu Aug 09 12:15:12 EEST 2018
#Thu Apr 08 20:52:07 EDT 2021
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip

Просмотреть файл

@ -0,0 +1,21 @@
apply plugin: 'com.jfrog.artifactory'
Properties properties = new Properties()
if (project.rootProject.file('local.properties').exists()) {
properties.load(project.rootProject.file('local.properties').newDataInputStream())
}
artifactory {
contextUrl = 'https://unity3ddist.jfrog.io/artifactory'
publish {
repository {
repoKey = properties.getProperty("artifactory.repokey")
username = properties.getProperty("artifactory.username")
password = properties.getProperty("artifactory.apikey")
}
defaults {
// Tell the Artifactory Plugin which artifacts should be published to Artifactory.
publications('release')
}
}
}

Просмотреть файл

@ -1,62 +1,51 @@
import com.android.ddmlib.DdmPreferences
apply plugin: 'com.android.library'
apply plugin: 'com.jfrog.bintray'
apply plugin: 'com.github.dcendents.android-maven'
apply plugin: 'jacoco'
ext {
bintrayRepo = "UnityAds"
bintrayName = "unityads"
publishedGroupId = 'com.unity3d.ads'
libraryName = 'unity-ads'
artifact = 'unity-ads'
archivesBaseName = 'unity-ads'
libraryDescription = 'Monetize your entire player base and reach new audiences with video ads.'
siteUrl = 'https://github.com/Unity-Technologies/unity-ads-android'
gitUrl = 'https://github.com/Unity-Technologies/unity-ads-android.git'
libraryVersion = '3.7.1'
developerId = 'sbankhead'
developerName = 'Steven Bankhead'
developerEmail = 'sbankhead@unity3d.com'
licenseName = 'Unity Ads License'
licenseUrl = 'https://unity3d.com/legal/monetization-services-terms-of-service'
allLicenses = ["Unity Ads License"]
Properties properties = new Properties()
if (project.rootProject.file('local.properties').exists()) {
properties.load(project.rootProject.file('local.properties').newDataInputStream())
}
version = libraryVersion
dependencies {
testImplementation 'junit:junit:4.12'
androidTestImplementation 'org.mockito:mockito-core:2.25.0'
androidTestImplementation 'org.mockito:mockito-android:2.25.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test:rules:1.1.1'
compileOnly 'com.google.ar:core:1.0.0'
}
ext {
GROUP_ID = "com.unity3d.ads"
ARTIFACT_ID = "unity-ads"
VERSION_ID = "3.7.2"
VERSION_CODE = 3720
SIGN_AAR = properties.getProperty("SIGN_AAR") ?: false
}
android {
compileSdkVersion 30
buildToolsVersion '28.0.2'
com.android.ddmlib.DdmPreferences.setLogLevel("verbose")
com.android.ddmlib.DdmPreferences.setTimeOut(10 * 60000)
DdmPreferences.setLogLevel("verbose")
DdmPreferences.setTimeOut(10 * 60000)
defaultPublishConfig "release"
lintOptions {
abortOnError false
}
defaultConfig {
minSdkVersion 19
targetSdkVersion 30
/*
Please ensure that the last two digits of version number does not exceed 50 unless
it is a China SDK. This is because adding 50 to the version number is a one-to-one
mapping between normal SDK and China SDK.
Example : version number 2350 corresponds to China version of 2300.
All SDK with version numbers with last two digits >= 50 will be treated
as China SDK for filtering in the backend.
*/
versionCode = 3710
versionName = "3.7.1"
versionCode = VERSION_CODE
versionName = VERSION_ID
setProperty("archivesBaseName", "unity-ads")
buildConfigField('String', 'WEBVIEW_BRANCH', getPropertyStringWithDefaultValue('WEBVIEW_BRANCH', '"' + versionName + '"'))
buildConfigField('int', 'VERSION_CODE', "$versionCode")
buildConfigField('String', 'VERSION_NAME', "\"$versionName\"")
testBuildType "debug"
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
@ -80,59 +69,43 @@ android {
consumerProguardFiles 'proguard-rules.pro'
}
}
libraryVariants.all { variant ->
variant.outputs.all { output ->
if (outputFile != null && outputFileName.endsWith('.aar')) {
outputFileName = "${archivesBaseName}-${variant.buildType.name}.aar"
}
}
}
testVariants.all { variant ->
variant.outputs.all { output ->
outputFileName = "../../androidTest.apk"
}
}
}
dependencies {
testImplementation 'junit:junit:4.12'
androidTestImplementation 'org.mockito:mockito-core:2.25.0'
androidTestImplementation 'org.mockito:mockito-android:2.25.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test:rules:1.1.1'
compileOnly 'com.google.ar:core:1.0.0'
}
task javadoc(type: Javadoc, overwrite: true) {
task javadoc(type: Javadoc) {
description "Generates Javadoc for Release"
source = android.sourceSets.main.java.srcDirs
ext.androidJar = "${android.sdkDirectory}/platforms/${android.compileSdkVersion}/android.jar"
ext.generatedClass = "build/generated/source/buildConfig/release/"
doFirst {
classpath = project.files(android.getBootClasspath().join(File.pathSeparator)) + files(ext.androidJar)
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
classpath += files(ext.androidJar)
classpath += fileTree(dir: 'libs', include: ['*.jar'])
classpath += files(ext.generatedClass)
}
options {
links "http://docs.oracle.com/javase/7/docs/api/"
linksOffline "http://developer.android.com/reference","${android.sdkDirectory}/docs/reference"
}
exclude '**/R.java'
exclude 'com/unity3d/services/ar/view/GLSurfaceView.java'
exclude 'com/unity3d/services/ar/api/AR.java'
exclude 'com/unity3d/services/ar/ARUtils.java'
exclude 'com/unity3d/services/ar/configuration/ARModuleConfiguration.java'
exclude 'com/unity3d/services/ar/view/ARView.java'
exclude 'com/unity3d/services/ar/view/ARViewHandler.java'
exclude 'com/unity3d/services/ar/view/BackgroundRenderer.java'
exclude 'com/unity3d/services/ar/view/DisplayRotationHelper.java'
destinationDir = file("../javadoc/")
}
task androidJavadocsJar(type: Jar, dependsOn: javadoc) {
classifier = "javadoc"
baseName = "${archivesBaseName}"
archiveClassifier.set("javadoc")
archiveBaseName.set("${archivesBaseName}")
from javadoc.destinationDir
}
task androidSourcesJar(type: Jar) {
classifier = "sources"
baseName = "${archivesBaseName}"
archiveClassifier.set("sources")
archiveBaseName.set("${archivesBaseName}")
from android.sourceSets.main.java.srcDirs
}
@ -141,66 +114,6 @@ artifacts {
archives androidSourcesJar
}
jacoco {
toolVersion = '0.8.1'
}
tasks.withType(Test) {
jacoco.includeNoLocationClasses = true
}
task jacocoTestReport(type: JacocoReport) {
reports {
xml.enabled = true
html.enabled = true
}
def fileFilter = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*', '**/*Test*.*', 'android/**/*.*']
def javaClasses = fileTree(dir: "$project.buildDir/intermediates/classes/debug", excludes: fileFilter)
def javaSrc = "$project.projectDir/src/main/java"
sourceDirectories = files([javaSrc])
classDirectories = files([javaClasses])
executionData = fileTree(dir: project.buildDir, includes: [
'outputs/code-coverage/connected/*coverage.ec'
])
}
// Bintray
task localProperties {
if (!file("$rootDir/local.properties").exists()) {
file("$rootDir/local.properties").withWriterAppend { w -> "" }
}
}
bintray {
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
user = properties.getProperty("bintray.user")
key = properties.getProperty("bintray.apikey")
configurations = ['archives']
pkg {
repo = bintrayRepo
name = bintrayName
desc = libraryDescription
websiteUrl = siteUrl
vcsUrl = gitUrl
licenses = allLicenses
publish = true
publicDownloadNumbers = false
version {
desc = libraryDescription
gpg {
sign = true //Determines whether to GPG sign the files. The default is false
passphrase = properties.getProperty("bintray.gpg.password")
//Optional. The passphrase for GPG signing'
}
}
}
}
def getPropertyStringWithDefaultValue(String key, String defaultValue) {
def value = project.getProperties().get(key)
// Ensure that string is quoted
@ -211,6 +124,6 @@ def getPropertyStringWithDefaultValue(String key, String defaultValue) {
return value != null ? value : defaultValue
}
if (project.rootProject.file('local.properties').exists()) {
apply from: 'mavenPomBintrayUpload.gradle'
}
apply from: 'publishing.gradle'
apply from: 'artifactory.gradle'
apply from: 'jacoco.gradle'

26
unity-ads/jacoco.gradle Normal file
Просмотреть файл

@ -0,0 +1,26 @@
apply plugin: 'jacoco'
jacoco {
toolVersion = '0.8.1'
}
tasks.withType(Test) {
jacoco.includeNoLocationClasses = true
}
task jacocoTestReport(type: JacocoReport) {
reports {
xml.enabled = true
html.enabled = true
}
def fileFilter = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*', '**/*Test*.*', 'android/**/*.*']
def javaClasses = fileTree(dir: "$project.buildDir/intermediates/classes/debug", excludes: fileFilter)
def javaSrc = "$project.projectDir/src/main/java"
sourceDirectories.setFrom(files([javaSrc]))
classDirectories.setFrom(files([javaClasses]))
executionData.setFrom(fileTree(dir: project.buildDir, includes: [
'outputs/code-coverage/connected/*coverage.ec'
]))
}

Просмотреть файл

@ -1,42 +0,0 @@
apply plugin: 'com.github.dcendents.android-maven'
group = publishedGroupId // Maven Group ID for the artifact
install {
repositories.mavenInstaller {
// This generates POM.xml with proper parameters
pom {
project {
packaging 'aar'
groupId publishedGroupId
artifactId artifact
// Add your description here
name libraryName
description libraryDescription
url siteUrl
// Set your license
licenses {
license {
name licenseName
url licenseUrl
}
}
developers {
developer {
id developerId
name developerName
email developerEmail
}
}
scm {
connection gitUrl
developerConnection gitUrl
url siteUrl
}
}
}
}
}

Просмотреть файл

@ -0,0 +1,46 @@
apply plugin: 'maven-publish'
apply plugin: 'signing'
publishing {
publications {
release(MavenPublication) {
groupId GROUP_ID
artifactId ARTIFACT_ID
version VERSION_ID
artifact("$buildDir/outputs/aar/unity-ads-release.aar")
artifact androidSourcesJar
artifact androidJavadocsJar
pom {
name = ARTIFACT_ID
description = 'Monetize your entire player base and reach new audiences with video ads.'
url = 'https://github.com/Unity-Technologies/unity-ads-android'
licenses {
license {
name = 'Unity Ads License'
url = 'https://unity3d.com/legal/monetization-services-terms-of-service'
}
}
scm {
connection = 'https://github.com/Unity-Technologies/unity-ads-android.git'
developerConnection = 'https://github.com/Unity-Technologies/unity-ads-android.git'
url = 'https://github.com/Unity-Technologies/unity-ads-android'
}
developers {
developer {
id = 'Unity Ads'
name = 'Unity Ads'
email = 'ads-sdk@unity3d.com'
}
}
}
}
}
}
signing {
required { SIGN_AAR }
sign publishing.publications.release
}

Просмотреть файл

@ -13,6 +13,7 @@ import com.unity3d.ads.test.instrumentation.services.ads.webplayer.WebPlayerView
import com.unity3d.ads.test.instrumentation.services.banners.BannerViewCacheTests;
import com.unity3d.ads.test.instrumentation.services.core.configuration.InitializationNotificationCenterTest;
import com.unity3d.ads.test.instrumentation.services.core.webview.bridge.WebViewBridgeSharedObjectTests;
import com.unity3d.ads.test.instrumentation.services.core.webview.bridge.invocation.WebViewBridgeInvocationRunnableTests;
import com.unity3d.ads.test.instrumentation.services.core.webview.bridge.invocation.WebViewBridgeInvocationTests;
import com.unity3d.ads.test.legacy.ConfigurationTest;
import com.unity3d.services.analytics.AcquisitionTypeTest;
@ -33,6 +34,7 @@ import org.junit.runners.Suite;
BannerViewCacheTests.class,
WebViewBridgeSharedObjectTests.class,
WebViewBridgeInvocationTests.class,
WebViewBridgeInvocationRunnableTests.class,
LoadOperationTests.class,
LoadModuleTests.class,
LoadModuleDecoratorTimeoutTests.class,

Просмотреть файл

@ -62,7 +62,7 @@ public class LoadModuleTests {
loadModule.executeAdOperation(webViewBridgeInvokerMock, loadOperationState);
TestUtilities.SleepCurrentThread(uiThreadDelay);
Mockito.verify(loadListenerMock, times(1)).onUnityAdsFailedToLoad(null, UnityAds.UnityAdsLoadError.INVALID_ARGUMENT,"[UnityAds] Placement ID cannot be null");
Mockito.verify(loadListenerMock, times(1)).onUnityAdsFailedToLoad("", UnityAds.UnityAdsLoadError.INVALID_ARGUMENT,"[UnityAds] Placement ID cannot be null");
}
@Test

Просмотреть файл

@ -0,0 +1,85 @@
package com.unity3d.ads.test.instrumentation.services.ads.operation;
import androidx.test.rule.ActivityTestRule;
import com.unity3d.ads.IUnityAdsShowListener;
import com.unity3d.ads.UnityAds;
import com.unity3d.ads.UnityAdsShowOptions;
import com.unity3d.ads.test.TestUtilities;
import com.unity3d.ads.test.instrumentation.InstrumentationTestActivity;
import com.unity3d.services.ads.operation.show.IShowModule;
import com.unity3d.services.ads.operation.show.ShowModule;
import com.unity3d.services.ads.operation.show.ShowModuleDecoratorTimeout;
import com.unity3d.services.ads.operation.show.ShowOperationState;
import com.unity3d.services.core.request.ISDKMetricSender;
import com.unity3d.services.core.webview.bridge.CallbackStatus;
import com.unity3d.services.core.webview.bridge.IWebViewBridgeInvoker;
import com.unity3d.services.core.webview.bridge.invocation.WebViewBridgeInvocation;
import com.unity3d.services.core.webview.bridge.invocation.WebViewBridgeInvocationRunnable;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mockito;
import java.lang.reflect.Method;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.when;
public class ShowModuleDecoratorTimeoutTests {
private static String placementId = "TestPlacementId";
private static UnityAdsShowOptions showOptions = new UnityAdsShowOptions();
private ISDKMetricSender sdkMetricSender;
private static int showTimeout = 50;
private static int uiThreadDelay = 150;
private IUnityAdsShowListener showListenerMock;
private IShowModule showModule;
@Rule
public final ActivityTestRule<InstrumentationTestActivity> _activityRule = new ActivityTestRule<>(InstrumentationTestActivity.class);
@Before
public void beforeEachTest() {
showListenerMock = mock(IUnityAdsShowListener.class);
sdkMetricSender = mock(ISDKMetricSender.class);
// We need a real instance since ShowModule will create the Operation object (which holds the State with Listener ID)
showModule = new ShowModule(sdkMetricSender);
}
@After
public void afterEachTest() {
//Allow for any timeout threads to complete before starting the next test to prevent inaccurate mock counts
TestUtilities.SleepCurrentThread(showTimeout);
}
@Test
public void testShowModuleDecoratorTimeout() {
ShowModuleDecoratorTimeout showModuleDecoratorTimeout = new ShowModuleDecoratorTimeout(showModule);
ShowOperationState showOperationState = new ShowOperationState(placementId, showListenerMock, _activityRule.getActivity(), showOptions, OperationTestUtilities.createConfigurationWithShowTimeout(showTimeout));
showModuleDecoratorTimeout.executeAdOperation(mock(IWebViewBridgeInvoker.class), showOperationState);
TestUtilities.SleepCurrentThread(uiThreadDelay);
Mockito.verify(showListenerMock, times(1)).onUnityAdsShowFailure(placementId, UnityAds.UnityAdsShowError.INTERNAL_ERROR, "[UnityAds] Timeout while trying to show TestPlacementId");
}
@Test
public void testShowModuleDecoratorShowConsentNoTimeout() {
ShowModuleDecoratorTimeout showModuleDecoratorTimeout = new ShowModuleDecoratorTimeout(showModule);
ShowOperationState showOperationState = new ShowOperationState(placementId, showListenerMock, _activityRule.getActivity(), showOptions, OperationTestUtilities.createConfigurationWithShowTimeout(showTimeout));
IWebViewBridgeInvoker webViewBridgeInvoker = mock(IWebViewBridgeInvoker.class);
when(webViewBridgeInvoker.invokeMethod(anyString(), anyString(), any(Method.class), any())).thenReturn(true);
showModuleDecoratorTimeout.executeAdOperation(webViewBridgeInvoker, showOperationState);
WebViewBridgeInvocationRunnable.onInvocationComplete(CallbackStatus.OK);
showModuleDecoratorTimeout.onUnityAdsShowConsent(showOperationState.getId());
TestUtilities.SleepCurrentThread(uiThreadDelay);
Mockito.verify(showListenerMock, times(0)).onUnityAdsShowFailure(anyString(), any(UnityAds.UnityAdsShowError.class), anyString());
}
}

Просмотреть файл

@ -62,7 +62,7 @@ public class ShowModuleTests {
_showModule.executeAdOperation(_webViewBridgeInvokerMock, showOperationState);
TestUtilities.SleepCurrentThread(uiThreadDelay);
Mockito.verify((_showListenerMock), times(1)).onUnityAdsShowFailure(null, UnityAds.UnityAdsShowError.INVALID_ARGUMENT, "[UnityAds] Placement ID cannot be null");
Mockito.verify((_showListenerMock), times(1)).onUnityAdsShowFailure("", UnityAds.UnityAdsShowError.INVALID_ARGUMENT, "[UnityAds] Placement ID cannot be null");
}
@Test
@ -77,7 +77,7 @@ public class ShowModuleTests {
_showModule.executeAdOperation(_webViewBridgeInvokerMock, showOperationState);
TestUtilities.SleepCurrentThread(uiThreadDelay);
Mockito.verify((_showListenerMock), times(1)).onUnityAdsShowFailure(placementId, UnityAds.UnityAdsShowError.INTERNAL_ERROR, "WebViewBridgeInvocation:execute: invokeMethod failure");
Mockito.verify((_showListenerMock), times(1)).onUnityAdsShowFailure(placementId, UnityAds.UnityAdsShowError.INTERNAL_ERROR, "WebViewBridgeInvocationRunnable:run: invokeMethod failure");
Mockito.verify(_sdkMetricSender, times(1)).SendSDKMetricEventWithTag(SDKMetricEvents.native_show_callback_error, new HashMap<String, String> (){{
put("cbs", "invocationFailure");
}});

Просмотреть файл

@ -0,0 +1,115 @@
package com.unity3d.ads.test.instrumentation.services.core.webview.bridge.invocation;
import com.unity3d.ads.test.TestUtilities;
import com.unity3d.services.core.webview.bridge.CallbackStatus;
import com.unity3d.services.core.webview.bridge.IWebViewBridgeInvoker;
import com.unity3d.services.core.webview.bridge.invocation.IWebViewBridgeInvocationCallback;
import com.unity3d.services.core.webview.bridge.invocation.WebViewBridgeInvocationRunnable;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import java.lang.reflect.Method;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
public class WebViewBridgeInvocationRunnableTests {
private static String className = "ClassName";
private static String methodName = "MethodName";
private static int invocationTimeout = 100;
private static Object params = new Object();
private static int uiThreadDelay = 10;
private IWebViewBridgeInvoker webViewBridgeInvokerMock;
private IWebViewBridgeInvocationCallback invocationCallbackMock;
private WebViewBridgeInvocationRunnable runnable;
@Before
public void beforeEachTest() {
webViewBridgeInvokerMock = mock(IWebViewBridgeInvoker.class);
invocationCallbackMock = mock(IWebViewBridgeInvocationCallback.class);
}
@After
public void afterEachTest() {
TestUtilities.SleepCurrentThread(invocationTimeout);
}
@Test
public void runCallsInvocationFailureWhenWebViewBridgeInvokerFails() {
runnable = new WebViewBridgeInvocationRunnable(invocationCallbackMock, webViewBridgeInvokerMock, className, methodName, invocationTimeout, params);
doAnswer(new Answer() {
public Object answer(InvocationOnMock invocation) {
return false;
}}).when(webViewBridgeInvokerMock).invokeMethod(anyString(), anyString(), any(Method.class), any(Object.class));
runnable.run();
TestUtilities.SleepCurrentThread(uiThreadDelay);
VerifyInvocationCallbackMockCalls(invocationCallbackMock, 0, 1, 0, "WebViewBridgeInvocationRunnable:run: invokeMethod failure", null);
}
@Test
public void runCallsInvocationSuccessWhenCallbackStatusOk() {
runnable = new WebViewBridgeInvocationRunnable(invocationCallbackMock, webViewBridgeInvokerMock, className, methodName, invocationTimeout, params);
doAnswer(new Answer() {
public Object answer(InvocationOnMock invocation) {
runnable.onInvocationComplete(CallbackStatus.OK);
return true;
}}).when(webViewBridgeInvokerMock).invokeMethod(anyString(), anyString(), any(Method.class), any(Object.class));
runnable.run();
TestUtilities.SleepCurrentThread(uiThreadDelay);
VerifyInvocationCallbackMockCalls(invocationCallbackMock, 1, 0, 0);
}
@Test
public void runCallsInvocationFailureWhenCallbackStatusNotOk() {
runnable = new WebViewBridgeInvocationRunnable(invocationCallbackMock, webViewBridgeInvokerMock, className, methodName, invocationTimeout, params);
doAnswer(new Answer() {
public Object answer(InvocationOnMock invocation) {
runnable.onInvocationComplete(CallbackStatus.ERROR);
return true;
}}).when(webViewBridgeInvokerMock).invokeMethod(anyString(), anyString(), any(Method.class), any(Object.class));
runnable.run();
TestUtilities.SleepCurrentThread(uiThreadDelay);
VerifyInvocationCallbackMockCalls(invocationCallbackMock, 0, 1, 0, "WebViewBridgeInvocationRunnable:run CallbackStatus.Error", CallbackStatus.ERROR);
}
@Test
public void runCallsInvocationTimeoutWhenResponseTimeoutIsReached() {
runnable = new WebViewBridgeInvocationRunnable(invocationCallbackMock, webViewBridgeInvokerMock, className, methodName, 10, params);
doAnswer(new Answer() {
public Object answer(InvocationOnMock invocation) {
return true;
}}).when(webViewBridgeInvokerMock).invokeMethod(anyString(), anyString(), any(Method.class), any(Object.class));
runnable.run();
TestUtilities.SleepCurrentThread(100);
VerifyInvocationCallbackMockCalls(invocationCallbackMock, 0, 0, 1);
}
private void VerifyInvocationCallbackMockCalls(IWebViewBridgeInvocationCallback webViewBridgeInvocationCallback, int onSuccessCalls, int onFailureCalls, int onTimeoutCalls, String onFailureMessage, CallbackStatus callbackStatus) {
Mockito.verify(webViewBridgeInvocationCallback, times(onSuccessCalls)).onSuccess();
Mockito.verify(webViewBridgeInvocationCallback, times(onFailureCalls)).onFailure(onFailureMessage, callbackStatus);
Mockito.verify(webViewBridgeInvocationCallback, times(onTimeoutCalls)).onTimeout();
}
private void VerifyInvocationCallbackMockCalls(IWebViewBridgeInvocationCallback webViewBridgeInvocationCallback, int onSuccessCalls, int onFailureCalls, int onTimeoutCalls) {
Mockito.verify(webViewBridgeInvocationCallback, times(onSuccessCalls)).onSuccess();
Mockito.verify(webViewBridgeInvocationCallback, times(onFailureCalls)).onFailure(anyString(), any(CallbackStatus.class));
Mockito.verify(webViewBridgeInvocationCallback, times(onTimeoutCalls)).onTimeout();
}
}

Просмотреть файл

@ -4,20 +4,15 @@ import com.unity3d.ads.test.TestUtilities;
import com.unity3d.services.core.webview.bridge.IWebViewBridgeInvoker;
import com.unity3d.services.core.webview.bridge.invocation.IWebViewBridgeInvocationCallback;
import com.unity3d.services.core.webview.bridge.invocation.WebViewBridgeInvocation;
import com.unity3d.services.core.webview.bridge.CallbackStatus;
import com.unity3d.services.core.webview.bridge.invocation.WebViewBridgeInvocationRunnable;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import java.lang.reflect.Method;
import java.util.concurrent.ExecutorService;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
@ -26,7 +21,6 @@ public class WebViewBridgeInvocationTests {
private static String methodName = "MethodName";
private static int invocationTimeout = 100;
private static Object params = new Object();
private static int uiThreadDelay = 10;
private IWebViewBridgeInvoker webViewBridgeInvokerMock;
private IWebViewBridgeInvocationCallback invocationCallbackMock;
@ -43,91 +37,11 @@ public class WebViewBridgeInvocationTests {
}
@Test
public void invokeCallsOnSuccessCallbackWhenInvocationCompleteOk() {
final WebViewBridgeInvocation webViewBridgeInvocation = new WebViewBridgeInvocation(webViewBridgeInvokerMock, invocationCallbackMock);
doAnswer(new Answer() {
public Object answer(InvocationOnMock invocation) {
webViewBridgeInvocation.onInvocationComplete(CallbackStatus.OK);
return true;
}}).when(webViewBridgeInvokerMock).invokeMethod(anyString(),anyString(), any(Method.class),any(Object.class));
public void invokeCallsWebViewBridgeInvocationSingleThreadedExecutorSubmit() {
ExecutorService executorMock = mock(ExecutorService.class);
final WebViewBridgeInvocation webViewBridgeInvocation = new WebViewBridgeInvocation(executorMock, webViewBridgeInvokerMock, invocationCallbackMock);
webViewBridgeInvocation.invoke(className, methodName, invocationTimeout, params);
TestUtilities.SleepCurrentThread(uiThreadDelay);
VerifyInvocationCallbackMockCalls(invocationCallbackMock, 1, 0, 0);
Mockito.verify(executorMock, times(1)).submit(any(WebViewBridgeInvocationRunnable.class));
}
@Test
public void invokeCallsOnFailureCallbackWhenInvocationCompleteError() {
final WebViewBridgeInvocation webViewBridgeInvocation = new WebViewBridgeInvocation(webViewBridgeInvokerMock, invocationCallbackMock);
doAnswer(new Answer() {
public Object answer(InvocationOnMock invocation) {
webViewBridgeInvocation.onInvocationComplete(CallbackStatus.ERROR);
return true;
}}).when(webViewBridgeInvokerMock).invokeMethod(anyString(),anyString(), any(Method.class),any(Object.class));
webViewBridgeInvocation.invoke(className, methodName, invocationTimeout, params);
TestUtilities.SleepCurrentThread(uiThreadDelay);
VerifyInvocationCallbackMockCalls(invocationCallbackMock, 0,1,0, "WebViewBridgeInvocation:OnInvocationComplete: CallbackStatus.Error", CallbackStatus.ERROR);
}
@Test
public void invokeCallsOnTimeoutCallbackWhenNoInvocationResponse() {
WebViewBridgeInvocation webViewBridgeInvocation = new WebViewBridgeInvocation(webViewBridgeInvokerMock, invocationCallbackMock);
doAnswer(new Answer() {
public Object answer(InvocationOnMock invocation) {
return true;
}}).when(webViewBridgeInvokerMock).invokeMethod(anyString(),anyString(), any(Method.class),any(Object.class));
webViewBridgeInvocation.invoke(className, methodName, 100, params);
TestUtilities.SleepCurrentThread(250);
VerifyInvocationCallbackMockCalls(invocationCallbackMock, 0,0,1);
}
@Test(expected = IllegalArgumentException.class)
public void WebViewBridgeInvocationThrowsNPEWhenInvokedWithNullWebViewBridgeInvoker() {
new WebViewBridgeInvocation(null, mock(IWebViewBridgeInvocationCallback.class));
}
@Test
public void NoErrorIsThrownWhenWebViewBridgeInvocationIsInitializedWithNullCallbackAndInvokeMethodIsCalledAndFails() {
final WebViewBridgeInvocation webViewBridgeInvocation = new WebViewBridgeInvocation(webViewBridgeInvokerMock, null);
doAnswer(new Answer() {
public Object answer(InvocationOnMock invocation) {
webViewBridgeInvocation.onInvocationComplete(CallbackStatus.ERROR);
return false;
}}).when(webViewBridgeInvokerMock).invokeMethod(anyString(),anyString(), any(Method.class),any(Object.class));
webViewBridgeInvocation.invoke(className, methodName, invocationTimeout, params);
TestUtilities.SleepCurrentThread(uiThreadDelay);
}
@Test
public void invokeCallsOnFailureCallbackWhenInvokerFails() {
IWebViewBridgeInvocationCallback invocationCallbackMock = mock(IWebViewBridgeInvocationCallback.class);
final WebViewBridgeInvocation webViewBridgeInvocation = new WebViewBridgeInvocation(webViewBridgeInvokerMock, invocationCallbackMock);
doAnswer(new Answer() {
public Object answer(InvocationOnMock invocation) {
return false;
}}).when(webViewBridgeInvokerMock).invokeMethod(anyString(),anyString(), any(Method.class),any(Object.class));
webViewBridgeInvocation.invoke(className, methodName, invocationTimeout, params);
TestUtilities.SleepCurrentThread(uiThreadDelay);
VerifyInvocationCallbackMockCalls(invocationCallbackMock, 0,1,0, "WebViewBridgeInvocation:execute: invokeMethod failure", null);
}
private void VerifyInvocationCallbackMockCalls(IWebViewBridgeInvocationCallback webViewBridgeInvocationCallback, int onSuccessCalls, int onFailureCalls, int onTimeoutCalls, String onFailureMessage, CallbackStatus callbackStatus) {
Mockito.verify(webViewBridgeInvocationCallback, times(onSuccessCalls)).onSuccess();
Mockito.verify(webViewBridgeInvocationCallback, times(onFailureCalls)).onFailure(onFailureMessage, callbackStatus);
Mockito.verify(webViewBridgeInvocationCallback, times(onTimeoutCalls)).onTimeout();
}
private void VerifyInvocationCallbackMockCalls(IWebViewBridgeInvocationCallback webViewBridgeInvocationCallback, int onSuccessCalls, int onFailureCalls, int onTimeoutCalls) {
Mockito.verify(webViewBridgeInvocationCallback, times(onSuccessCalls)).onSuccess();
Mockito.verify(webViewBridgeInvocationCallback, times(onFailureCalls)).onFailure(anyString(), any(CallbackStatus.class));
Mockito.verify(webViewBridgeInvocationCallback, times(onTimeoutCalls)).onTimeout();
}
}
}

Просмотреть файл

@ -13,6 +13,13 @@ public class Show {
callback.invoke();
}
@WebViewExposed
public static void sendShowConsentEvent(final String placementId, final String listenerId, WebViewCallback callback) {
ShowModule.getInstance().onUnityAdsShowConsent(listenerId);
callback.invoke();
}
@WebViewExposed
public static void sendShowStartEvent(final String placementId, final String listenerId, WebViewCallback callback) {
ShowModule.getInstance().onUnityAdsShowStart(listenerId);

Просмотреть файл

@ -1,16 +1,20 @@
package com.unity3d.services.ads.operation;
import com.unity3d.services.core.request.ISDKMetricSender;
import com.unity3d.services.core.request.SDKMetricSender;
import com.unity3d.services.core.webview.bridge.IWebViewSharedObject;
import com.unity3d.services.core.webview.bridge.WebViewBridgeSharedObjectStore;
import com.unity3d.services.core.webview.bridge.invocation.WebViewBridgeInvocationSingleThreadedExecutor;
import java.util.concurrent.ExecutorService;
public abstract class AdModule<T extends IWebViewSharedObject, T2> extends WebViewBridgeSharedObjectStore<T> implements IAdModule<T, T2> {
protected ISDKMetricSender _sdkMetricSender;
protected ExecutorService _executorService;
protected AdModule(ISDKMetricSender sdkMetricSender) {
super();
_sdkMetricSender = sdkMetricSender;
_executorService = WebViewBridgeInvocationSingleThreadedExecutor.getInstance().getExecutorService();
}
public ISDKMetricSender getMetricSender() {

Просмотреть файл

@ -2,8 +2,6 @@ package com.unity3d.services.ads.operation;
import com.unity3d.services.core.webview.bridge.invocation.IWebViewBridgeInvocation;
import java.util.UUID;
public abstract class AdOperation implements IAdOperation {
private static String invocationClassName = "webview";

Просмотреть файл

@ -0,0 +1,29 @@
package com.unity3d.services.ads.operation;
import android.os.ConditionVariable;
import com.unity3d.services.core.configuration.Configuration;
import com.unity3d.services.core.webview.bridge.IWebViewSharedObject;
import java.util.UUID;
public class OperationState implements IWebViewSharedObject {
private static String _emptyPlacementId = "";
public String id;
public String placementId;
public Configuration configuration;
public ConditionVariable timeoutCV;
public OperationState(String placementId, Configuration configuration) {
this.placementId = placementId == null ? _emptyPlacementId : placementId;
this.configuration = configuration;
this.timeoutCV = new ConditionVariable();
id = UUID.randomUUID().toString();
}
@Override
public String getId() {
return id;
}
}

Просмотреть файл

@ -14,6 +14,7 @@ import com.unity3d.services.core.webview.bridge.CallbackStatus;
import com.unity3d.services.core.webview.bridge.IWebViewBridgeInvoker;
import com.unity3d.services.core.webview.bridge.invocation.IWebViewBridgeInvocationCallback;
import com.unity3d.services.core.webview.bridge.invocation.WebViewBridgeInvocation;
import com.unity3d.services.core.webview.bridge.invocation.WebViewBridgeInvocationSingleThreadedExecutor;
import org.json.JSONException;
import org.json.JSONObject;
@ -49,7 +50,7 @@ public class LoadModule extends AdModule<ILoadOperation, LoadOperationState> imp
return;
}
LoadOperation loadOperation = new LoadOperation(state, new WebViewBridgeInvocation(webViewBridgeInvoker, new IWebViewBridgeInvocationCallback() {
LoadOperation loadOperation = new LoadOperation(state, new WebViewBridgeInvocation(_executorService, webViewBridgeInvoker, new IWebViewBridgeInvocationCallback() {
@Override
public void onSuccess() {
@ -73,12 +74,14 @@ public class LoadModule extends AdModule<ILoadOperation, LoadOperationState> imp
}
}));
JSONObject invocationParameters = new JSONObject();
JSONObject parameters = new JSONObject();
JSONObject options = new JSONObject();
try {
invocationParameters.put("listenerId", loadOperation.getId());
invocationParameters.put("placementId", state.placementId);
invocationParameters.put("time", Device.getElapsedRealtime());
invocationParameters.put("options", state.loadOptions.getData());
options.put("headerBiddingOptions", state.loadOptions.getData());
parameters.put("options", options);
parameters.put("listenerId", loadOperation.getId());
parameters.put("placementId", state.placementId);
parameters.put("time", Device.getElapsedRealtime());
} catch (JSONException e) {
sendOnUnityAdsFailedToLoad(state, UnityAds.UnityAdsLoadError.INTERNAL_ERROR, errorMsgFailedToCreateLoadRequest);
return;
@ -88,7 +91,7 @@ public class LoadModule extends AdModule<ILoadOperation, LoadOperationState> imp
}
set(loadOperation);
loadOperation.invoke(state.configuration.getWebViewBridgeTimeout(), invocationParameters);
loadOperation.invoke(state.configuration.getWebViewBridgeTimeout(), parameters);
}
public void onUnityAdsAdLoaded(String operationId) {

Просмотреть файл

@ -5,7 +5,6 @@ import com.unity3d.services.core.configuration.IInitializationListener;
import com.unity3d.services.core.configuration.IInitializationNotificationCenter;
import com.unity3d.services.core.misc.Utilities;
import com.unity3d.services.core.properties.SdkProperties;
import com.unity3d.services.core.request.SDKMetricEvents;
import com.unity3d.services.core.webview.bridge.IWebViewBridgeInvoker;
import java.util.Map;

Просмотреть файл

@ -1,33 +1,17 @@
package com.unity3d.services.ads.operation.load;
import android.os.ConditionVariable;
import com.unity3d.ads.IUnityAdsLoadListener;
import com.unity3d.ads.UnityAdsLoadOptions;
import com.unity3d.services.core.webview.bridge.IWebViewSharedObject;
import com.unity3d.services.ads.operation.OperationState;
import com.unity3d.services.core.configuration.Configuration;
import java.util.UUID;
public class LoadOperationState implements IWebViewSharedObject {
public String id;
public class LoadOperationState extends OperationState {
public IUnityAdsLoadListener listener;
public UnityAdsLoadOptions loadOptions;
public String placementId;
public Configuration configuration;
public ConditionVariable timeoutCV;
public LoadOperationState(String placementId, IUnityAdsLoadListener listener, UnityAdsLoadOptions loadOptions, Configuration configuration) {
super(placementId, configuration);
this.listener = listener;
this.loadOptions = loadOptions;
this.placementId = placementId;
this.configuration = configuration;
this.timeoutCV = new ConditionVariable();
id = UUID.randomUUID().toString();
}
@Override
public String getId() {
return id;
}
}

Просмотреть файл

@ -5,6 +5,7 @@ import com.unity3d.services.ads.operation.IAdModule;
public interface IShowModule extends IAdModule<IShowOperation, ShowOperationState> {
void onUnityAdsShowFailure(String id, UnityAds.UnityAdsShowError error, String message);
void onUnityAdsShowConsent(String id);
void onUnityAdsShowStart(String id);
void onUnityAdsShowClick(String id);
void onUnityAdsShowComplete(String id, UnityAds.UnityAdsShowCompletionState state);

Просмотреть файл

@ -18,6 +18,7 @@ import com.unity3d.services.core.webview.bridge.CallbackStatus;
import com.unity3d.services.core.webview.bridge.IWebViewBridgeInvoker;
import com.unity3d.services.core.webview.bridge.invocation.IWebViewBridgeInvocationCallback;
import com.unity3d.services.core.webview.bridge.invocation.WebViewBridgeInvocation;
import com.unity3d.services.core.webview.bridge.invocation.WebViewBridgeInvocationSingleThreadedExecutor;
import org.json.JSONException;
import org.json.JSONObject;
@ -46,7 +47,7 @@ public class ShowModule extends AdModule<IShowOperation, ShowOperationState> imp
sendOnUnityAdsFailedToShow(state, errorMsgPlacementIdNull, UnityAds.UnityAdsShowError.INVALID_ARGUMENT);
return;
}
IShowOperation showOperation = new ShowOperation(state, new WebViewBridgeInvocation(webViewBridgeInvoker, new IWebViewBridgeInvocationCallback() {
IShowOperation showOperation = new ShowOperation(state, new WebViewBridgeInvocation(_executorService, webViewBridgeInvoker, new IWebViewBridgeInvocationCallback() {
@Override
public void onSuccess() {
}
@ -72,11 +73,12 @@ public class ShowModule extends AdModule<IShowOperation, ShowOperationState> imp
ClientProperties.setActivity(state.activity);
Display defaultDisplay = ((WindowManager)state.activity.getSystemService(state.activity.WINDOW_SERVICE)).getDefaultDisplay();
JSONObject parameters = new JSONObject();
JSONObject options = new JSONObject();
JSONObject display = new JSONObject();
try {
options.put("requestedOrientation", state.activity.getRequestedOrientation());
display.put("requestedOrientation", state.activity.getRequestedOrientation());
display.put("rotation", defaultDisplay.getRotation());
if (Build.VERSION.SDK_INT >= 13) {
Point displaySize = new Point();
@ -88,10 +90,11 @@ public class ShowModule extends AdModule<IShowOperation, ShowOperationState> imp
display.put("height", defaultDisplay.getHeight());
}
options.put("display", display);
options.put("options", state.showOptions.getData());
options.put("listenerId", showOperation.getId());
options.put("placementId", state.placementId);
options.put("time", Device.getElapsedRealtime());
options.put("headerBiddingOptions", state.showOptions.getData());
parameters.put("options", options);
parameters.put("listenerId", showOperation.getId());
parameters.put("placementId", state.placementId);
parameters.put("time", Device.getElapsedRealtime());
} catch (JSONException e) {
sendOnUnityAdsFailedToShow(state, "[UnityAds] Error creating show options", UnityAds.UnityAdsShowError.INTERNAL_ERROR);
return;
@ -101,7 +104,7 @@ public class ShowModule extends AdModule<IShowOperation, ShowOperationState> imp
}
set(showOperation);
showOperation.invoke(state.configuration.getWebViewBridgeTimeout(), options);
showOperation.invoke(state.configuration.getWebViewBridgeTimeout(), parameters);
}
public void onUnityAdsShowFailure(String id, UnityAds.UnityAdsShowError error, String message) {
@ -111,6 +114,12 @@ public class ShowModule extends AdModule<IShowOperation, ShowOperationState> imp
remove(id);
}
public void onUnityAdsShowConsent(String id) {
final IShowOperation showOperation = get(id);
if (showOperation == null || showOperation.getShowOperationState() == null) return;
// We do nothing for now since we don't report back to the user API
}
public void onUnityAdsShowStart(String id) {
final IShowOperation showOperation = get(id);
if (showOperation == null || showOperation.getShowOperationState() == null) return;

Просмотреть файл

@ -26,6 +26,9 @@ public class ShowModuleDecorator implements IShowModule {
_showModule.onUnityAdsShowFailure(id, error, message);
}
@Override
public void onUnityAdsShowConsent(String id) { _showModule.onUnityAdsShowConsent(id);}
@Override
public void onUnityAdsShowStart(String id) {
_showModule.onUnityAdsShowStart(id);

Просмотреть файл

@ -36,6 +36,12 @@ public class ShowModuleDecoratorTimeout extends ShowModuleDecorator {
});
}
@Override
public void onUnityAdsShowConsent(String id) {
releaseOperationTimeoutLock(id);
super.onUnityAdsShowConsent(id);
}
@Override
public void onUnityAdsShowFailure(String id, UnityAds.UnityAdsShowError error, String message) {
releaseOperationTimeoutLock(id);

Просмотреть файл

@ -1,36 +1,21 @@
package com.unity3d.services.ads.operation.show;
import android.app.Activity;
import android.os.ConditionVariable;
import com.unity3d.ads.IUnityAdsShowListener;
import com.unity3d.ads.UnityAdsShowOptions;
import com.unity3d.services.ads.operation.OperationState;
import com.unity3d.services.core.configuration.Configuration;
import com.unity3d.services.core.webview.bridge.IWebViewSharedObject;
import java.util.UUID;
public class ShowOperationState implements IWebViewSharedObject {
public String id;
public class ShowOperationState extends OperationState {
public Activity activity;
public IUnityAdsShowListener listener;
public String placementId;
public UnityAdsShowOptions showOptions;
public Configuration configuration;
public ConditionVariable timeoutCV;
public ShowOperationState(String placementId, IUnityAdsShowListener listener, Activity activity, UnityAdsShowOptions showOptions, Configuration configuration) {
super(placementId, configuration);
this.listener = listener;
this.placementId = placementId;
this.activity = activity;
this.showOptions = showOptions;
this.configuration = configuration;
this.timeoutCV = new ConditionVariable();
id = UUID.randomUUID().toString();
}
@Override
public String getId() {
return id;
}
}

Просмотреть файл

@ -154,11 +154,15 @@ public class VideoPlayerView extends VideoView {
}
});
start();
stopVideoProgressTimer();
startVideoProgressTimer();
try {
start();
stopVideoProgressTimer();
startVideoProgressTimer();
WebViewApp.getCurrentApp().sendEvent(WebViewEventCategory.VIDEOPLAYER, VideoPlayerEvent.PLAY, _videoUrl);
WebViewApp.getCurrentApp().sendEvent(WebViewEventCategory.VIDEOPLAYER, VideoPlayerEvent.PLAY, _videoUrl);
} catch (IllegalStateException ex) {
WebViewApp.getCurrentApp().sendEvent(WebViewEventCategory.VIDEOPLAYER, VideoPlayerEvent.ILLEGAL_STATE, _videoUrl, false);
}
}
public void setInfoListenerEnabled (boolean enabled) {

Просмотреть файл

@ -1,25 +1,17 @@
package com.unity3d.services.core.webview.bridge.invocation;
import android.os.ConditionVariable;
import com.unity3d.services.core.webview.bridge.CallbackStatus;
import com.unity3d.services.core.webview.bridge.IWebViewBridgeInvoker;
import java.lang.reflect.Method;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class WebViewBridgeInvocation implements IWebViewBridgeInvocation {
private static ConditionVariable responseTimeout;
private static IWebViewBridgeInvocationCallback invocationCallback;
private IWebViewBridgeInvoker _webViewBridgeInvoker;
private Method webViewBridgeCallbackMethod;
private ExecutorService _executorService;
private ExecutorService executorService;
public WebViewBridgeInvocation(IWebViewBridgeInvoker webViewBridgeInvoker, IWebViewBridgeInvocationCallback invocationCallback) {
responseTimeout = new ConditionVariable();
public WebViewBridgeInvocation(ExecutorService _executorService, IWebViewBridgeInvoker webViewBridgeInvoker, IWebViewBridgeInvocationCallback invocationCallback) {
this._executorService = _executorService;
this.invocationCallback = invocationCallback;
if (webViewBridgeInvoker == null) {
@ -27,50 +19,11 @@ public class WebViewBridgeInvocation implements IWebViewBridgeInvocation {
}
_webViewBridgeInvoker = webViewBridgeInvoker;
executorService = Executors.newSingleThreadExecutor();
try {
webViewBridgeCallbackMethod = WebViewBridgeInvocation.class.getMethod("onInvocationComplete", CallbackStatus.class);
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("loadCallback cannot be null");
}
}
@Override
public synchronized void invoke(final String className, final String methodName, final int timeoutLengthInMilliSeconds, final Object...invocationParameters) {
executorService.submit(new Runnable() {
@Override
public void run() {
if (!_webViewBridgeInvoker.invokeMethod(className, methodName, webViewBridgeCallbackMethod, invocationParameters)) {
if (invocationCallback != null) {
invocationCallback.onFailure("WebViewBridgeInvocation:execute: invokeMethod failure", null);
}
return;
}
if (!responseTimeout.block(timeoutLengthInMilliSeconds)) {
if (invocationCallback != null) {
invocationCallback.onTimeout();
}
}
}
});
public synchronized void invoke(final String className, final String methodName, final int timeoutLengthInMilliSeconds, final Object... invocationParameters) {
_executorService.submit(
new WebViewBridgeInvocationRunnable(invocationCallback, _webViewBridgeInvoker, className, methodName, timeoutLengthInMilliSeconds, invocationParameters));
}
public static synchronized void onInvocationComplete(CallbackStatus status) {
if (responseTimeout != null) {
responseTimeout.open();
}
if (invocationCallback == null) return;
switch (status) {
case OK:
invocationCallback.onSuccess();
break;
default:
invocationCallback.onFailure("WebViewBridgeInvocation:OnInvocationComplete: CallbackStatus.Error", status);
break;
}
}
}
}

Просмотреть файл

@ -0,0 +1,69 @@
package com.unity3d.services.core.webview.bridge.invocation;
import android.os.ConditionVariable;
import com.unity3d.services.core.webview.bridge.CallbackStatus;
import com.unity3d.services.core.webview.bridge.IWebViewBridgeInvoker;
import java.lang.reflect.Method;
public class WebViewBridgeInvocationRunnable implements Runnable {
private static ConditionVariable _responseTimeout;
private static CallbackStatus _callbackStatus;
private IWebViewBridgeInvocationCallback _invocationCallback;
private IWebViewBridgeInvoker _webViewBridgeInvoker;
private Method _webViewBridgeCallbackMethod;
private String _className;
private String _methodName;
private int _timeoutLengthInMilliSeconds;
private Object[] _invocationParameters;
public WebViewBridgeInvocationRunnable(IWebViewBridgeInvocationCallback invocationCallback, IWebViewBridgeInvoker webViewBridgeInvoker, String className, String methodName, int timeoutLengthInMilliSeconds, Object...invocationParameters) {
try {
_webViewBridgeCallbackMethod = WebViewBridgeInvocationRunnable.class.getMethod("onInvocationComplete", CallbackStatus.class);
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("WebViewBridgeInvocation callback method cannot be found", e);
}
_invocationCallback = invocationCallback;
_webViewBridgeInvoker = webViewBridgeInvoker;
_className = className;
_methodName = methodName;
_timeoutLengthInMilliSeconds = timeoutLengthInMilliSeconds;
_invocationParameters = invocationParameters;
}
@Override
public void run() {
_callbackStatus = null;
_responseTimeout = new ConditionVariable();
boolean invokeMethodSuccess = _webViewBridgeInvoker.invokeMethod(_className, _methodName, _webViewBridgeCallbackMethod, _invocationParameters);
if (_invocationCallback == null) return;
if (!invokeMethodSuccess) {
_invocationCallback.onFailure("WebViewBridgeInvocationRunnable:run: invokeMethod failure", null);
return;
}
if (_responseTimeout.block(_timeoutLengthInMilliSeconds)) {
if (_callbackStatus == CallbackStatus.OK) {
_invocationCallback.onSuccess();
} else {
_invocationCallback.onFailure("WebViewBridgeInvocationRunnable:run CallbackStatus.Error", _callbackStatus);
}
} else {
_invocationCallback.onTimeout();
}
}
public static synchronized void onInvocationComplete(CallbackStatus status) {
_callbackStatus = status;
if (_responseTimeout != null) {
_responseTimeout.open();
}
}
}

Просмотреть файл

@ -0,0 +1,24 @@
package com.unity3d.services.core.webview.bridge.invocation;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class WebViewBridgeInvocationSingleThreadedExecutor {
private static WebViewBridgeInvocationSingleThreadedExecutor instance;
private ExecutorService _ExecutorService;
public static WebViewBridgeInvocationSingleThreadedExecutor getInstance() {
if (instance == null) {
instance = new WebViewBridgeInvocationSingleThreadedExecutor();
}
return instance;
}
private WebViewBridgeInvocationSingleThreadedExecutor() {
_ExecutorService = Executors.newSingleThreadExecutor();
}
public ExecutorService getExecutorService() {
return _ExecutorService;
}
}