This commit is contained in:
runner 2023-05-02 17:02:03 +00:00
Родитель ce3cb3ab2c
Коммит 97924e9f4b
257 изменённых файлов: 6799 добавлений и 3958 удалений

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

@ -1,4 +1,4 @@
Unity Advertisements copyright © 2022 Unity Technologies.
Unity Advertisements copyright © 2023 Unity Technologies.
This software is subject to, and made available under, the terms of service for Operate Solutions (see https://unity3d.com/legal/one-operate-services-terms-of-service), and is an "Operate Service" as defined therein.
Your use of the Services constitutes your acceptance of such terms. Unless expressly provided otherwise, the software under this license is made available strictly on an "AS IS" BASIS WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. Please review the terms of service for details on these and other terms and conditions.

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

@ -1,14 +1,14 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 32
compileSdkVersion 33
defaultConfig {
applicationId "com.unity3d.ads.example"
minSdkVersion 19
targetSdkVersion 32
versionCode = 4610
versionName = "4.6.1"
targetSdkVersion 33
versionCode = 4700
versionName = "4.7.0"
}
buildTypes {

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

@ -7,12 +7,15 @@ allprojects {
buildscript {
ext {
kotlin_version = '1.4.32' // 1.5 deprecated Java6
coroutines_version = '1.4.3' // 1.6.0 deprecated Java6
kotlin_version = '1.8.10'
coroutines_version = '1.6.4'
dokka_version = '1.6.10'
startup_runtime_version = '1.1.1'
unity_identifiers_version = '1.0.0'
lifecycle_version = '2.5.1'
okhttp_version = '3.12.13' // 3.13+ requires Java8 / Android5+(21)
androidx_webkit = '1.6.1'
androidx_core = '1.9.0'
}
repositories {
@ -21,8 +24,7 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:7.1.3'
classpath 'org.jacoco:org.jacoco.core:0.8.5'
classpath 'com.android.tools.build:gradle:7.4.2'
classpath 'org.jfrog.buildinfo:build-info-extractor-gradle:4.20.0'
classpath 'io.github.gradle-nexus:publish-plugin:1.1.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"

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

@ -14,6 +14,7 @@ static def tasksDependentOnScar(String buildType) {
"merge${buildType}JavaResource",
"sync${buildType}LibJars",
"extract${buildType}Annotations",
"desugar${buildType}FileDependencies",
"dokkaJavadoc"
]
}

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

@ -20,4 +20,7 @@ android.useAndroidX=true
android.disableAutomaticComponentCreation=true
signing.keyId=34500891
signing.secretKeyRingFile=../gpg-private-key.gpg
signing.secretKeyRingFile=../gpg-private-key.gpg
# https://kotlinlang.org/docs/whatsnew18.html#usage-of-the-latest-kotlin-stdlib-version-in-transitive-dependencies
kotlin.stdlib.jdk.variants.version.alignment=false

Двоичные данные
gradle/wrapper/gradle-wrapper.jar поставляемый

Двоичный файл не отображается.

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

@ -1,6 +1,6 @@
#Thu Apr 08 20:52:07 EDT 2021
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip

314
gradlew поставляемый
Просмотреть файл

@ -1,79 +1,129 @@
#!/usr/bin/env bash
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
##
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
MAX_FD=maximum
warn ( ) {
warn () {
echo "$*"
}
} >&2
die ( ) {
die () {
echo
echo "$*"
echo
exit 1
}
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
APP_HOME="`pwd -P`"
cd "$SAVED" >&-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD="$JAVA_HOME/bin/java"
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@ -82,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
@ -90,75 +140,105 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

66
gradlew.bat поставляемый
Просмотреть файл

@ -1,4 +1,20 @@
@if "%DEBUG%" == "" @echo off
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@ -8,20 +24,24 @@
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@ -35,7 +55,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@ -45,44 +65,26 @@ echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal

13
qodana.yml Normal file
Просмотреть файл

@ -0,0 +1,13 @@
version: 1.0
linter: jetbrains/qodana-jvm-android:2023.1-eap
exclude:
- name: All
paths:
- app
- unity-scaradapter-1920
- unity-scaradapter-1950
- unity-scaradapter-2000
- unity-scaradapter-2100
- unity-scaradapter-common
include:
- name: SizeReplaceableByIsEmpty

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

@ -13,23 +13,20 @@ if (project.rootProject.file('local.properties').exists()) {
ext {
GROUP_ID = "com.unity3d.ads"
ARTIFACT_ID = "unity-ads"
VERSION_ID = "4.6.1"
VERSION_CODE = 4610
VERSION_ID = "4.7.0"
VERSION_CODE = 4700
SIGN_AAR = properties.getProperty("SIGN_AAR") ?: false
}
android {
namespace = GROUP_ID
compileSdkVersion 32
compileSdk 33
compileSdkExtension 5
DdmPreferences.setLogLevel("verbose")
DdmPreferences.setTimeOut(10 * 60000)
lintOptions {
abortOnError false
}
defaultConfig {
targetSdkVersion 32
targetSdkVersion 33
minSdkVersion 19
versionCode = VERSION_CODE
versionName = VERSION_ID
@ -51,29 +48,8 @@ android {
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
if (it.name.contains("UnitTest")) {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
kotlinOptions {
jvmTarget = "1.8"
}
} else {
sourceCompatibility = JavaVersion.VERSION_1_6
targetCompatibility = JavaVersion.VERSION_1_6
kotlinOptions {
jvmTarget = "1.6"
}
}
kotlinOptions {
apiVersion = "1.4"
languageVersion = "1.4"
freeCompilerArgs = freeCompilerArgs + "-Xopt-in=kotlin.RequiresOptIn" + "-Xallow-result-return-type"
}
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
buildTypes {
@ -88,16 +64,22 @@ android {
consumerProguardFiles 'proguard-rules.pro'
}
}
lint {
abortOnError false
}
}
dependencies {
debugImplementation fileTree(dir: 'libs/Debug', include: ['*.jar'])
releaseImplementation fileTree(dir: 'libs/Release', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation(platform("org.jetbrains.kotlin:kotlin-bom:$kotlin_version"))
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
implementation "androidx.startup:startup-runtime:$startup_runtime_version"
implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version"
implementation "com.unity3d.services.identifiers:unity-services-identifiers:$unity_identifiers_version"
implementation "com.squareup.okhttp3:okhttp:$okhttp_version"
implementation "androidx.webkit:webkit:$androidx_webkit"
implementation "androidx.core:core-ktx:$androidx_core"
androidTestCompileOnly project(':unity-scaradapter-2100')
androidTestCompileOnly project(':unity-scaradapter-2000')
androidTestCompileOnly project(':unity-scaradapter-1950')
@ -120,16 +102,18 @@ dependencies {
compileOnly project(':unity-scaradapter-1920')
compileOnly project(':unity-scaradapter-common')
testImplementation 'junit:junit:4.13.2'
testImplementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version"
testImplementation "org.jetbrains.kotlin:kotlin-stdlib"
testImplementation "org.jetbrains.kotlin:kotlin-test-junit"
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version"
testImplementation "org.mockito.kotlin:mockito-kotlin:4.0.0"
testImplementation 'org.mockito:mockito-core:2.28.2'
testImplementation 'com.android.billingclient:billing:4.0.0'
testImplementation "io.mockk:mockk:1.11.0"
testImplementation("io.mockk:mockk:1.13.4")
testImplementation 'org.json:json:20180813'
testImplementation 'org.powermock:powermock-api-mockito2:2.0.2'
testImplementation 'org.powermock:powermock-module-junit4:2.0.2'
testImplementation "com.squareup.okhttp3:mockwebserver:$okhttp_version"
}
task androidSourcesJar(type: Jar) {
@ -160,5 +144,4 @@ def getPropertyStringWithDefaultValue(String key, String defaultValue) {
}
apply from: 'publishing.gradle'
apply from: 'artifactory.gradle'
apply from: 'jacoco.gradle'
apply from: 'artifactory.gradle'

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

@ -1,26 +0,0 @@
apply plugin: 'jacoco'
jacoco {
toolVersion = '0.8.5'
}
tasks.withType(Test) {
jacoco.includeNoLocationClasses = true
}
task jacocoTestReport(type: JacocoReport) {
reports {
xml.getRequired().set(true)
html.getRequired().set(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'
]))
}

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

@ -70,7 +70,7 @@ publishing {
}
// List all dependencies and write to POM
configurations.api.getAllDependencies().each cl
configurations.implementation.getAllDependencies().each cl
configurations.releaseImplementation.getAllDependencies().each cl
}
}

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

@ -12,7 +12,7 @@ import com.unity3d.ads.test.instrumentation.services.ads.webplayer.WebPlayerView
import com.unity3d.ads.test.instrumentation.services.ads.webplayer.WebPlayerViewSettingsCacheTest;
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.device.AsyncTokenStorageTest;
import com.unity3d.ads.test.instrumentation.services.core.device.InMemoryAsyncTokenStorageTest;
import com.unity3d.ads.test.instrumentation.services.core.device.DeviceInfoReaderCompressorTest;
import com.unity3d.ads.test.instrumentation.services.core.device.DeviceInfoReaderFilterProviderTest;
import com.unity3d.ads.test.instrumentation.services.core.device.DeviceInfoReaderWithFilterTest;
@ -52,7 +52,7 @@ import org.junit.runners.Suite;
ShowModuleTests.class,
ConfigurationTest.class,
GmaScarTestSuite.class,
AsyncTokenStorageTest.class,
InMemoryAsyncTokenStorageTest.class,
NativeTokenGeneratorTest.class,
DeviceInfoReaderCompressorTest.class,
DeviceInfoReaderFilterProviderTest.class,

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

@ -22,10 +22,10 @@ import com.unity3d.ads.test.legacy.SdkPropertiesTest;
import com.unity3d.ads.test.legacy.StorageDiskTest;
import com.unity3d.ads.test.legacy.StorageGeneralTest;
import com.unity3d.ads.test.legacy.StorageMemoryTest;
import com.unity3d.ads.test.legacy.TokenStorageTest;
import com.unity3d.ads.test.legacy.InMemoryTokenStorageTest;
import com.unity3d.ads.test.legacy.UtilitiesTest;
import com.unity3d.ads.test.legacy.VideoViewTest;
import com.unity3d.ads.test.legacy.VolumeChangeTest;
import com.unity3d.ads.test.legacy.VolumeChangeContentObserverTest;
import com.unity3d.ads.test.legacy.WebPlayerViewTest;
import com.unity3d.ads.test.legacy.WebRequestThreadPoolTest;
import com.unity3d.ads.test.legacy.WebViewAppTest;
@ -65,12 +65,12 @@ import org.junit.runners.Suite;
WebViewBridgeTest.class,
WebViewCallbackTest.class,
LifecycleListenerTest.class,
VolumeChangeTest.class,
VolumeChangeContentObserverTest.class,
UtilitiesTest.class,
WebPlayerViewTest.class,
PreferencesTest.class,
WebRequestThreadPoolTest.class,
TokenStorageTest.class
InMemoryTokenStorageTest.class
})
public class LegacyTestSuite {}

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

@ -78,10 +78,10 @@ public class HybridTest {
private class HybridTestConfiguration extends Configuration {
@Override
public String[] getModuleConfigurationList () {
ArrayList<String> moduleConfigurationList = new ArrayList<>(Arrays.asList(super.getModuleConfigurationList()));
moduleConfigurationList.add("com.unity3d.ads.test.hybrid.HybridTestModuleConfiguration");
return moduleConfigurationList.toArray(new String[moduleConfigurationList.size()]);
public Class<?>[] getModuleConfigurationList () {
ArrayList<Class> moduleConfigurationList = new ArrayList<>(Arrays.asList(super.getModuleConfigurationList()));
moduleConfigurationList.add(HybridTestModuleConfiguration.class);
return moduleConfigurationList.toArray(new Class[moduleConfigurationList.size()]);
}
}

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

@ -14,9 +14,6 @@ public class HybridTestModuleConfiguration implements IModuleConfiguration {
public boolean resetState(Configuration configuration) {
return true;
}
public boolean initModuleState(Configuration configuration) {
return true;
}
public boolean initErrorState(Configuration configuration, ErrorState state, String message) {
return true;
}

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

@ -2,6 +2,7 @@ package com.unity3d.ads.test.instrumentation.services.ads.gmascar.adapters;
import com.unity3d.scar.adapter.common.IAdsErrorHandler;
import com.unity3d.scar.adapter.common.IScarAdapter;
import com.unity3d.scar.adapter.common.WebViewAdsError;
import com.unity3d.services.ads.gmascar.adapters.ScarAdapterFactory;
import com.unity3d.services.ads.gmascar.finder.ScarAdapterVersion;
@ -14,9 +15,9 @@ import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class ScarAdapterFactoryTest {
@Mock
private IAdsErrorHandler adsErrorHandlerMock;
private IAdsErrorHandler<WebViewAdsError> adsErrorHandlerMock;
private ScarAdapterFactory _scarAdapterFactory = new ScarAdapterFactory();
private final ScarAdapterFactory _scarAdapterFactory = new ScarAdapterFactory();
@Test
public void testScarAdapterFactory1920() {

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

@ -11,7 +11,7 @@ import com.unity3d.services.ads.gmascar.managers.BiddingBaseManager;
import com.unity3d.services.ads.gmascar.models.BiddingSignals;
import com.unity3d.services.ads.gmascar.utils.ScarRequestHandler;
import com.unity3d.services.core.properties.ClientProperties;
import com.unity3d.services.core.request.metrics.ISDKMetrics;
import com.unity3d.services.core.request.metrics.SDKMetricsSender;
import com.unity3d.services.core.request.metrics.Metric;
import com.unity3d.services.core.request.metrics.ScarMetric;
@ -31,7 +31,7 @@ public class BiddingBaseManagerTest {
IUnityAdsTokenListener publisherListener;
@Mock
ISDKMetrics _metricSenderMock;
SDKMetricsSender _metricSenderMock;
@Mock
ScarRequestHandler _scarRequestHandlerMock;

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

@ -15,7 +15,7 @@ import com.unity3d.services.ads.operation.load.LoadOperation;
import com.unity3d.services.ads.operation.load.LoadOperationState;
import com.unity3d.services.core.request.metrics.AdOperationError;
import com.unity3d.services.core.request.metrics.AdOperationMetric;
import com.unity3d.services.core.request.metrics.ISDKMetrics;
import com.unity3d.services.core.request.metrics.SDKMetricsSender;
import com.unity3d.services.core.request.metrics.Metric;
import com.unity3d.services.core.webview.bridge.IWebViewBridgeInvoker;
import com.unity3d.services.core.webview.bridge.invocation.IWebViewBridgeInvocation;
@ -42,13 +42,13 @@ public class BaseLoadModuleTests {
private IWebViewBridgeInvoker webViewBridgeInvokerMock;
private IUnityAdsLoadListener loadListenerMock;
private BaseLoadModule baseLoadModule;
private ISDKMetrics sdkMetrics;
private SDKMetricsSender sdkMetrics;
@Before
public void beforeEachTest() {
webViewBridgeInvokerMock = mock(IWebViewBridgeInvoker.class);
loadListenerMock = mock(IUnityAdsLoadListener.class);
sdkMetrics = mock(ISDKMetrics.class);
sdkMetrics = mock(SDKMetricsSender.class);
baseLoadModule = new LoadModule(sdkMetrics);
}

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

@ -12,7 +12,7 @@ import com.unity3d.services.ads.operation.load.LoadBannerOperationState;
import com.unity3d.services.banners.UnityBannerSize;
import com.unity3d.services.core.request.metrics.AdOperationError;
import com.unity3d.services.core.request.metrics.AdOperationMetric;
import com.unity3d.services.core.request.metrics.ISDKMetrics;
import com.unity3d.services.core.request.metrics.SDKMetricsSender;
import com.unity3d.services.core.request.metrics.Metric;
import com.unity3d.services.core.webview.bridge.IWebViewBridgeInvoker;
@ -39,7 +39,7 @@ public class LoadBannerModuleTests {
private IWebViewBridgeInvoker webViewBridgeInvokerMock;
private IUnityAdsLoadListener loadListenerMock;
private LoadBannerModule loadBannerModule;
private ISDKMetrics sdkMetrics;
private SDKMetricsSender sdkMetrics;
final ArgumentCaptor<JSONObject> parametersCaptor = ArgumentCaptor.forClass(JSONObject.class);
@ -48,7 +48,7 @@ public class LoadBannerModuleTests {
public void beforeEachTest() {
webViewBridgeInvokerMock = mock(IWebViewBridgeInvoker.class);
loadListenerMock = mock(IUnityAdsLoadListener.class);
sdkMetrics = mock(ISDKMetrics.class);
sdkMetrics = mock(SDKMetricsSender.class);
loadBannerModule = new LoadBannerModule(sdkMetrics);
}

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

@ -14,7 +14,7 @@ import com.unity3d.services.core.configuration.Configuration;
import com.unity3d.services.core.configuration.ErrorState;
import com.unity3d.services.core.configuration.IInitializationNotificationCenter;
import com.unity3d.services.core.properties.SdkProperties;
import com.unity3d.services.core.request.metrics.ISDKMetrics;
import com.unity3d.services.core.request.metrics.SDKMetricsSender;
import com.unity3d.services.core.webview.bridge.IWebViewBridgeInvoker;
import org.junit.Before;
@ -29,7 +29,7 @@ public class LoadModuleDecoratorInitializationBufferTests {
private IInitializationNotificationCenter initializationNotificationCenterMock;
private IWebViewBridgeInvoker webViewBridgeInvokerMock;
private LoadOperationState loadOperationStateMock;
private ISDKMetrics sdkMetrics;
private SDKMetricsSender sdkMetrics;
@Before
public void beforeEachTest() {
@ -37,7 +37,7 @@ public class LoadModuleDecoratorInitializationBufferTests {
initializationNotificationCenterMock = mock(IInitializationNotificationCenter.class);
webViewBridgeInvokerMock = mock(IWebViewBridgeInvoker.class);
loadOperationStateMock = mock(LoadOperationState.class);
sdkMetrics = mock(ISDKMetrics.class);
sdkMetrics = mock(SDKMetricsSender.class);
}
@Test

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

@ -15,7 +15,7 @@ import com.unity3d.services.ads.operation.load.LoadModuleDecoratorTimeout;
import com.unity3d.services.ads.operation.load.LoadOperationState;
import com.unity3d.services.core.configuration.Configuration;
import com.unity3d.services.core.configuration.ConfigurationReader;
import com.unity3d.services.core.request.metrics.ISDKMetrics;
import com.unity3d.services.core.request.metrics.SDKMetricsSender;
import com.unity3d.services.core.webview.bridge.IWebViewBridgeInvoker;
import org.junit.Before;
@ -34,14 +34,14 @@ public class LoadModuleDecoratorTimeoutTests {
private IUnityAdsLoadListener loadListenerMock;
private ILoadModule loadModuleMock;
private ISDKMetrics sdkMetricsMock;
private SDKMetricsSender sdkMetricsMock;
private ConfigurationReader configurationReaderMock;
@Before
public void beforeEachTest() {
loadListenerMock = mock(IUnityAdsLoadListener.class);
loadModuleMock = mock(ILoadModule.class);
sdkMetricsMock = mock(ISDKMetrics.class);
sdkMetricsMock = mock(SDKMetricsSender.class);
configurationReaderMock = mock(ConfigurationReader.class);
Mockito.when(configurationReaderMock.getCurrentConfiguration()).thenReturn(new Configuration());

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

@ -2,25 +2,16 @@ package com.unity3d.ads.test.instrumentation.services.ads.operation;
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.timeout;
import com.unity3d.ads.IUnityAdsLoadListener;
import com.unity3d.ads.UnityAds;
import com.unity3d.ads.UnityAdsLoadOptions;
import com.unity3d.services.ads.operation.load.LoadBannerModule;
import com.unity3d.services.ads.operation.load.LoadBannerOperationState;
import com.unity3d.services.ads.operation.load.LoadModule;
import com.unity3d.services.ads.operation.load.LoadOperation;
import com.unity3d.services.ads.operation.load.LoadOperationState;
import com.unity3d.services.banners.UnityBannerSize;
import com.unity3d.services.core.request.metrics.AdOperationError;
import com.unity3d.services.core.request.metrics.AdOperationMetric;
import com.unity3d.services.core.request.metrics.ISDKMetrics;
import com.unity3d.services.core.request.metrics.Metric;
import com.unity3d.services.core.request.metrics.SDKMetricsSender;
import com.unity3d.services.core.webview.bridge.IWebViewBridgeInvoker;
import com.unity3d.services.core.webview.bridge.invocation.IWebViewBridgeInvocation;
import org.json.JSONException;
import org.json.JSONObject;
@ -45,7 +36,7 @@ public class LoadModuleTests {
private IWebViewBridgeInvoker webViewBridgeInvokerMock;
private IUnityAdsLoadListener loadListenerMock;
private LoadModule loadModule;
private ISDKMetrics sdkMetrics;
private SDKMetricsSender sdkMetrics;
final ArgumentCaptor<JSONObject> parametersCaptor = ArgumentCaptor.forClass(JSONObject.class);
@ -54,7 +45,7 @@ public class LoadModuleTests {
public void beforeEachTest() {
webViewBridgeInvokerMock = mock(IWebViewBridgeInvoker.class);
loadListenerMock = mock(IUnityAdsLoadListener.class);
sdkMetrics = mock(ISDKMetrics.class);
sdkMetrics = mock(SDKMetricsSender.class);
loadModule = new LoadModule(sdkMetrics);
}

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

@ -19,7 +19,7 @@ import com.unity3d.services.ads.operation.show.ShowModuleDecoratorTimeout;
import com.unity3d.services.ads.operation.show.ShowOperationState;
import com.unity3d.services.core.configuration.Configuration;
import com.unity3d.services.core.configuration.ConfigurationReader;
import com.unity3d.services.core.request.metrics.ISDKMetrics;
import com.unity3d.services.core.request.metrics.SDKMetricsSender;
import com.unity3d.services.core.webview.bridge.CallbackStatus;
import com.unity3d.services.core.webview.bridge.IWebViewBridgeInvoker;
import com.unity3d.services.core.webview.bridge.invocation.WebViewBridgeInvocationRunnable;
@ -40,7 +40,7 @@ public class ShowModuleDecoratorTimeoutTests {
private IUnityAdsShowListener showListenerMock;
private IShowModule showModule;
private ISDKMetrics sdkMetricsMock;
private SDKMetricsSender sdkMetricsMock;
private ConfigurationReader configurationReaderMock;
@Rule
@ -49,7 +49,7 @@ public class ShowModuleDecoratorTimeoutTests {
@Before
public void beforeEachTest() {
showListenerMock = mock(IUnityAdsShowListener.class);
sdkMetricsMock = mock(ISDKMetrics.class);
sdkMetricsMock = mock(SDKMetricsSender.class);
configurationReaderMock = mock(ConfigurationReader.class);
// We need a real instance since ShowModule will create the Operation object (which holds the State with Listener ID)
showModule = new ShowModule(sdkMetricsMock);

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

@ -18,7 +18,7 @@ import com.unity3d.services.ads.operation.show.ShowOperation;
import com.unity3d.services.ads.operation.show.ShowOperationState;
import com.unity3d.services.core.request.metrics.AdOperationError;
import com.unity3d.services.core.request.metrics.AdOperationMetric;
import com.unity3d.services.core.request.metrics.ISDKMetrics;
import com.unity3d.services.core.request.metrics.SDKMetricsSender;
import com.unity3d.services.core.request.metrics.Metric;
import com.unity3d.services.core.webview.bridge.IWebViewBridgeInvoker;
import com.unity3d.services.core.webview.bridge.invocation.IWebViewBridgeInvocation;
@ -43,7 +43,7 @@ public class ShowModuleTests {
private IUnityAdsShowListener _showListenerMock;
private IShowModule _showModule;
private ISDKMetrics _sdkMetrics;
private SDKMetricsSender _sdkMetrics;
private IWebViewBridgeInvoker _webViewBridgeInvokerMock;
@Rule
@ -53,7 +53,7 @@ public class ShowModuleTests {
public void beforeEachTest() {
_showListenerMock = mock(IUnityAdsShowListener.class);
_webViewBridgeInvokerMock = mock(IWebViewBridgeInvoker.class);
_sdkMetrics = mock(ISDKMetrics.class);
_sdkMetrics = mock(SDKMetricsSender.class);
_showModule = new ShowModule(_sdkMetrics);
}

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

@ -3,17 +3,25 @@ package com.unity3d.ads.test.instrumentation.services.banners;
import androidx.test.rule.ActivityTestRule;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.unity3d.ads.UnityAds;
import com.unity3d.ads.test.instrumentation.InstrumentationTestActivity;
import com.unity3d.services.ads.operation.load.ILoadModule;
import com.unity3d.services.ads.operation.load.ILoadOperation;
import com.unity3d.services.ads.operation.load.LoadBannerModule;
import com.unity3d.services.ads.operation.load.LoadOperationState;
import com.unity3d.services.banners.BannerErrorCode;
import com.unity3d.services.banners.BannerErrorInfo;
import com.unity3d.services.banners.BannerView;
import com.unity3d.services.banners.UnityBannerSize;
import com.unity3d.services.banners.BannerViewCache;
import com.unity3d.services.core.request.metrics.SDKMetricsSender;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import java.lang.reflect.Field;
import java.util.concurrent.Semaphore;
import static org.junit.Assert.assertEquals;
@ -94,20 +102,46 @@ public class BannerViewCacheTests {
}
@Test
public void testTriggerBannerErrorEvent() throws InterruptedException {
public void testTriggerBannerErrorEvent() throws InterruptedException, NoSuchFieldException, IllegalAccessException {
BannerViewCache bannerViewCache = new BannerViewCache();
final BannerView bannerView = new BannerView(_activityRule.getActivity(), "test", new UnityBannerSize(320, 50));
final BannerErrorInfo bannerErrorInfo = new BannerErrorInfo("test error", BannerErrorCode.NATIVE_ERROR);
String bannerAdId = bannerViewCache.addBannerView(bannerView);
LoadOperationState loadOperationState = Mockito.mock(LoadOperationState.class);
Mockito.when(loadOperationState.isBanner()).thenReturn(true);
Mockito.when(loadOperationState.duration()).thenReturn(Long.MAX_VALUE);
loadOperationState.placementId = "test";
ILoadOperation loadOperation = Mockito.mock(ILoadOperation.class);
Mockito.when(loadOperation.getLoadOperationState()).thenReturn(loadOperationState);
ILoadModule loadBannerModule = new LoadBannerModule(Mockito.mock(SDKMetricsSender.class));
ILoadModule spy = Mockito.spy(loadBannerModule);
Mockito.when(spy.get(Mockito.anyString())).thenReturn(loadOperation);
Mockito.doAnswer(invocation -> {
Mockito.doAnswer(invocation1 -> {
LoadOperationState state = invocation.getArgument(1);
state.onUnityAdsFailedToLoad(UnityAds.UnityAdsLoadError.INTERNAL_ERROR, "test error");
return null;
}).when(loadOperation).onUnityAdsFailedToLoad(Mockito.anyString(), Mockito.any(), Mockito.any());
return null;
}).when(spy).executeAdOperation(Mockito.any(), Mockito.any());
Field instance = LoadBannerModule.class.getDeclaredField("_instance");
instance.setAccessible(true);
instance.set(LoadBannerModule.class, spy);
final Semaphore _errorSemaphore = new Semaphore(0);
bannerView.setListener(new BannerView.Listener() {
@Override
public void onBannerFailedToLoad(BannerView bannerAdView, BannerErrorInfo _bannerErrorInfo) {
assertEquals(bannerView, bannerAdView);
assertEquals(bannerErrorInfo, _bannerErrorInfo);
Mockito.verify(spy).onUnityAdsFailedToLoad(bannerAdId, UnityAds.UnityAdsLoadError.INTERNAL_ERROR, "test error");
_errorSemaphore.release();
}
});
bannerView.load();
bannerViewCache.triggerBannerErrorEvent(bannerAdId, bannerErrorInfo);
_errorSemaphore.acquire();
}

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

@ -1,5 +1,7 @@
package com.unity3d.ads.test.instrumentation.services.core.device;
import static com.unity3d.services.core.device.reader.JsonStorageKeyNames.AUID_ID_KEY;
import static com.unity3d.services.core.device.reader.JsonStorageKeyNames.SESSION_ID_KEY;
import static com.unity3d.services.core.device.reader.JsonStorageKeyNames.USER_NON_BEHAVIORAL_KEY;
import android.app.Application;
@ -11,7 +13,7 @@ import com.unity3d.services.core.configuration.ConfigurationReader;
import com.unity3d.services.core.configuration.Experiments;
import com.unity3d.services.core.configuration.PrivacyConfig;
import com.unity3d.services.core.configuration.PrivacyConfigStorage;
import com.unity3d.services.core.device.reader.DeviceInfoReaderBuilder;
import com.unity3d.services.core.device.reader.builder.DeviceInfoReaderBuilder;
import com.unity3d.services.core.device.reader.IDeviceInfoReader;
import com.unity3d.services.core.device.reader.IGameSessionIdReader;
import com.unity3d.services.core.lifecycle.CachedLifecycle;
@ -61,11 +63,26 @@ public class DeviceInfoReaderBuilderTest {
}
@Test
public void testDeviceInfoReaderBuilderWithPrivacy() {
public void testDeviceInfoReaderBuilderWithoutSnb() {
Mockito.when(_privacyConfigMock.allowedToSendPii()).thenReturn(true);
Mockito.when(_privacyConfigMock.shouldSendNonBehavioral()).thenReturn(false);
DeviceInfoReaderBuilder deviceInfoReaderBuilder = new DeviceInfoReaderBuilder(_configReaderMock, _privacyConfigStorageMock, _gameSessionIdReaderMock);
IDeviceInfoReader deviceInfoReader = deviceInfoReaderBuilder.build();
Map<String, Object> deviceInfoData = deviceInfoReader.getDeviceInfoData();
Assert.assertNull(deviceInfoData.get(USER_NON_BEHAVIORAL_KEY));
Assert.assertNotNull(deviceInfoData.get(SESSION_ID_KEY));
Assert.assertNotNull(deviceInfoData.get(AUID_ID_KEY));
}
@Test
public void testDeviceInfoReaderBuilderWithSnb() {
Mockito.when(_privacyConfigMock.allowedToSendPii()).thenReturn(true);
Mockito.when(_privacyConfigMock.shouldSendNonBehavioral()).thenReturn(true);
DeviceInfoReaderBuilder deviceInfoReaderBuilder = new DeviceInfoReaderBuilder(_configReaderMock, _privacyConfigStorageMock, _gameSessionIdReaderMock);
IDeviceInfoReader deviceInfoReader = deviceInfoReaderBuilder.build();
Map<String, Object> deviceInfoData = deviceInfoReader.getDeviceInfoData();
Assert.assertNotNull(deviceInfoData.get(USER_NON_BEHAVIORAL_KEY));
Assert.assertNotNull(deviceInfoData.get(SESSION_ID_KEY));
Assert.assertNotNull(deviceInfoData.get(AUID_ID_KEY));
}
}

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

@ -4,18 +4,21 @@ import android.app.Application;
import androidx.test.platform.app.InstrumentationRegistry;
import com.unity3d.ads.metadata.MetaData;
import com.unity3d.services.core.configuration.Configuration;
import com.unity3d.services.core.configuration.ConfigurationReader;
import com.unity3d.services.core.configuration.Experiments;
import com.unity3d.services.core.configuration.PrivacyConfig;
import com.unity3d.services.core.configuration.PrivacyConfigStorage;
import com.unity3d.services.core.device.reader.DeviceInfoReaderPrivacyBuilder;
import com.unity3d.services.core.device.Storage;
import com.unity3d.services.core.device.StorageManager;
import com.unity3d.services.core.device.reader.IDeviceInfoReader;
import com.unity3d.services.core.device.reader.IGameSessionIdReader;
import com.unity3d.services.core.lifecycle.CachedLifecycle;
import com.unity3d.services.core.device.reader.builder.DeviceInfoReaderPrivacyBuilder;
import com.unity3d.services.core.properties.ClientProperties;
import com.unity3d.services.core.properties.SdkProperties;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
@ -58,12 +61,57 @@ public class DeviceInfoReaderPrivacyBuilderTest {
Mockito.when(_configReaderMock.getCurrentConfiguration()).thenReturn(_configurationMock);
}
@After
public void tearDown() {
StorageManager.getStorage(StorageManager.StorageType.PUBLIC).clearStorage();
StorageManager.getStorage(StorageManager.StorageType.PUBLIC).initStorage();
}
@Test
public void testDeviceInfoReaderPrivacyBuilder() {
DeviceInfoReaderPrivacyBuilder deviceInfoReaderPrivacyBuilder = new DeviceInfoReaderPrivacyBuilder(_configReaderMock, _privacyConfigStorageMock, _gameSessionIdReaderMock);
IDeviceInfoReader deviceInfoReader = deviceInfoReaderPrivacyBuilder.build();
Map<String, Object> deviceInfoData = deviceInfoReader.getDeviceInfoData();
validatePrivacyGenerics(deviceInfoData);
}
@Test
public void testDeviceInfoReaderPrivacyBuilderSettingNonBehavioralTrue() {
setUserNonBehavioralFlag(true);
DeviceInfoReaderPrivacyBuilder deviceInfoReaderPrivacyBuilder = new DeviceInfoReaderPrivacyBuilder(_configReaderMock, _privacyConfigStorageMock, _gameSessionIdReaderMock);
IDeviceInfoReader deviceInfoReader = deviceInfoReaderPrivacyBuilder.build();
Map<String, Object> deviceInfoData = deviceInfoReader.getDeviceInfoData();
validatePrivacyGenerics(deviceInfoData);
Assert.assertTrue((Boolean) deviceInfoData.get("user.nonBehavioral"));
}
@Test
public void testDeviceInfoReaderPrivacyBuilderSettingNonBehavioralFalse() {
setUserNonBehavioralFlag(false);
DeviceInfoReaderPrivacyBuilder deviceInfoReaderPrivacyBuilder = new DeviceInfoReaderPrivacyBuilder(_configReaderMock, _privacyConfigStorageMock, _gameSessionIdReaderMock);
IDeviceInfoReader deviceInfoReader = deviceInfoReaderPrivacyBuilder.build();
Map<String, Object> deviceInfoData = deviceInfoReader.getDeviceInfoData();
validatePrivacyGenerics(deviceInfoData);
Assert.assertFalse((Boolean) deviceInfoData.get("user.nonBehavioral"));
}
@Test
public void testDeviceInfoReaderPrivacyBuilderSettingNonBehavioralMissing() {
DeviceInfoReaderPrivacyBuilder deviceInfoReaderPrivacyBuilder = new DeviceInfoReaderPrivacyBuilder(_configReaderMock, _privacyConfigStorageMock, _gameSessionIdReaderMock);
IDeviceInfoReader deviceInfoReader = deviceInfoReaderPrivacyBuilder.build();
Map<String, Object> deviceInfoData = deviceInfoReader.getDeviceInfoData();
validatePrivacyGenerics(deviceInfoData);
Assert.assertNull(deviceInfoData.get("user.nonBehavioral"));
}
private void validatePrivacyGenerics(Map<String, Object> deviceInfoData) {
Assert.assertEquals("privacy", deviceInfoData.get("callType"));
Assert.assertEquals(SdkProperties.getVersionName(), deviceInfoData.get("sdkVersionName"));
}
private void setUserNonBehavioralFlag(boolean flagValue) {
MetaData userMetaData = new MetaData(InstrumentationRegistry.getInstrumentation().getContext());
userMetaData.set("user.nonbehavioral", flagValue);
userMetaData.commit();
}
}

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

@ -0,0 +1,66 @@
package com.unity3d.ads.test.instrumentation.services.core.device;
import static com.unity3d.services.core.device.reader.JsonStorageKeyNames.USER_NON_BEHAVIORAL_KEY;
import com.unity3d.services.core.device.reader.DeviceInfoReaderWithBehavioralFlag;
import com.unity3d.services.core.device.reader.IDeviceInfoReader;
import com.unity3d.services.core.device.reader.pii.NonBehavioralFlag;
import com.unity3d.services.core.device.reader.pii.NonBehavioralFlagReader;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.Map;
@RunWith(MockitoJUnitRunner.class)
public class DeviceInfoReaderWithNonBehavioralFlagTest {
@Mock
private IDeviceInfoReader _deviceInfoReaderMock;
@Mock
private NonBehavioralFlagReader _nonBehavioralFlagReaderMock;
@Test
public void testDeviceInfoReaderWithBehavioralFlagWhenBehavioralFlagFalse() {
// given
Mockito.when(_nonBehavioralFlagReaderMock.getUserNonBehavioralFlag()).thenReturn(NonBehavioralFlag.FALSE);
// when
DeviceInfoReaderWithBehavioralFlag deviceInfoReaderWithBehavioralFlag = new DeviceInfoReaderWithBehavioralFlag(_deviceInfoReaderMock, _nonBehavioralFlagReaderMock);
Map<String, Object> deviceInfoData = deviceInfoReaderWithBehavioralFlag.getDeviceInfoData();
// then
Assert.assertEquals(false, deviceInfoData.get(USER_NON_BEHAVIORAL_KEY));
}
@Test
public void testDeviceInfoReaderWithBehavioralFlagWhenBehavioralFlagTrue() {
// given
Mockito.when(_nonBehavioralFlagReaderMock.getUserNonBehavioralFlag()).thenReturn(NonBehavioralFlag.TRUE);
// when
DeviceInfoReaderWithBehavioralFlag deviceInfoReaderWithBehavioralFlag = new DeviceInfoReaderWithBehavioralFlag(_deviceInfoReaderMock, _nonBehavioralFlagReaderMock);
Map<String, Object> deviceInfoData = deviceInfoReaderWithBehavioralFlag.getDeviceInfoData();
// then
Assert.assertEquals(true, deviceInfoData.get(USER_NON_BEHAVIORAL_KEY));
}
@Test
public void testDeviceInfoReaderWithBehavioralFlagWhenBehavioralFlagUnknown() {
// given
Mockito.when(_nonBehavioralFlagReaderMock.getUserNonBehavioralFlag()).thenReturn(NonBehavioralFlag.UNKNOWN);
// when
DeviceInfoReaderWithBehavioralFlag deviceInfoReaderWithBehavioralFlag = new DeviceInfoReaderWithBehavioralFlag(_deviceInfoReaderMock, _nonBehavioralFlagReaderMock);
Map<String, Object> deviceInfoData = deviceInfoReaderWithBehavioralFlag.getDeviceInfoData();
// then
Assert.assertNull(deviceInfoData.get(USER_NON_BEHAVIORAL_KEY));
}
}

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

@ -0,0 +1,91 @@
package com.unity3d.ads.test.instrumentation.services.core.device;
import static com.unity3d.services.core.device.reader.JsonStorageKeyNames.USER_NON_BEHAVIORAL_KEY;
import com.unity3d.services.core.configuration.PrivacyConfig;
import com.unity3d.services.core.configuration.PrivacyConfigStorage;
import com.unity3d.services.core.device.reader.DeviceInfoReaderWithPrivacy;
import com.unity3d.services.core.device.reader.IDeviceInfoReader;
import com.unity3d.services.core.device.reader.pii.PiiDataProvider;
import com.unity3d.services.core.device.reader.pii.PiiTrackingStatusReader;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.HashMap;
import java.util.Map;
@RunWith(MockitoJUnitRunner.class)
public class DeviceInfoReaderWithPrivacyTest {
private static final String FAKE_ADVERTISER_ID = "fakeSessionId";
private static final boolean FAKE_NONBEHAVIORAL = true;
@Mock
private PrivacyConfig _privacyConfigMock;
@Mock
private IDeviceInfoReader _deviceInfoReaderMock;
@Mock
private PrivacyConfigStorage _privacyConfigStorageMock;
@Mock
private PiiDataProvider _piiDataProviderMock;
@Mock
private PiiTrackingStatusReader _piiTrackingStatusReaderMock;
@Before
public void setup() {
Mockito.when(_deviceInfoReaderMock.getDeviceInfoData()).thenReturn(new HashMap<>());
Mockito.when(_privacyConfigStorageMock.getPrivacyConfig()).thenReturn(_privacyConfigMock);
Mockito.when(_piiDataProviderMock.getAdvertisingTrackingId()).thenReturn(FAKE_ADVERTISER_ID);
Mockito.when(_piiTrackingStatusReaderMock.getUserNonBehavioralFlag()).thenReturn(FAKE_NONBEHAVIORAL);
}
@Test
public void testDeviceInfoReaderWithPrivacySnbDisabled() {
// given
Mockito.when(_privacyConfigMock.shouldSendNonBehavioral()).thenReturn(false);
// when
DeviceInfoReaderWithPrivacy deviceInfoReaderWithPrivacy = new DeviceInfoReaderWithPrivacy(_deviceInfoReaderMock, _privacyConfigStorageMock, _piiDataProviderMock, _piiTrackingStatusReaderMock);
Map<String, Object> deviceInfoData = deviceInfoReaderWithPrivacy.getDeviceInfoData();
// then
Assert.assertNull(deviceInfoData.get(USER_NON_BEHAVIORAL_KEY));
}
@Test
public void testDeviceInfoReaderWithPrivacySnbEnabledNbTrue() {
// given
Mockito.when(_privacyConfigMock.shouldSendNonBehavioral()).thenReturn(true);
Mockito.when(_piiTrackingStatusReaderMock.getUserNonBehavioralFlag()).thenReturn(true);
// when
DeviceInfoReaderWithPrivacy deviceInfoReaderWithPrivacy = new DeviceInfoReaderWithPrivacy(_deviceInfoReaderMock, _privacyConfigStorageMock, _piiDataProviderMock, _piiTrackingStatusReaderMock);
Map<String, Object> deviceInfoData = deviceInfoReaderWithPrivacy.getDeviceInfoData();
// then
Assert.assertEquals(true, deviceInfoData.get(USER_NON_BEHAVIORAL_KEY));
}
@Test
public void testDeviceInfoReaderWithPrivacySnbEnabledNbFalse() {
// given
Mockito.when(_privacyConfigMock.shouldSendNonBehavioral()).thenReturn(true);
Mockito.when(_piiTrackingStatusReaderMock.getUserNonBehavioralFlag()).thenReturn(false);
// when
DeviceInfoReaderWithPrivacy deviceInfoReaderWithPrivacy = new DeviceInfoReaderWithPrivacy(_deviceInfoReaderMock, _privacyConfigStorageMock, _piiDataProviderMock, _piiTrackingStatusReaderMock);
Map<String, Object> deviceInfoData = deviceInfoReaderWithPrivacy.getDeviceInfoData();
// then
Assert.assertEquals(false, deviceInfoData.get(USER_NON_BEHAVIORAL_KEY));
}
}

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

@ -0,0 +1,40 @@
package com.unity3d.ads.test.instrumentation.services.core.device;
import static com.unity3d.services.core.device.reader.JsonStorageKeyNames.SESSION_ID_KEY;
import com.unity3d.services.core.device.reader.DeviceInfoReaderWithSessionId;
import com.unity3d.services.core.device.reader.IDeviceInfoReader;
import com.unity3d.services.core.properties.Session;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.Map;
@RunWith(MockitoJUnitRunner.class)
public class DeviceInfoReaderWithSessionIdTest {
private static final String FAKE_SESSION_ID = "fakeSessionId";
@Mock
private IDeviceInfoReader _deviceInfoReaderMock;
@Mock
private Session _sessionMock;
@Test
public void testDeviceInfoReaderWithSessionId() {
// given
Mockito.when(_sessionMock.getId()).thenReturn(FAKE_SESSION_ID);
// when
DeviceInfoReaderWithSessionId deviceInfoReaderWithBehavioralFlag = new DeviceInfoReaderWithSessionId(_deviceInfoReaderMock, _sessionMock);
Map<String, Object> deviceInfoData = deviceInfoReaderWithBehavioralFlag.getDeviceInfoData();
// then
Assert.assertEquals(FAKE_SESSION_ID, deviceInfoData.get(SESSION_ID_KEY));
}
}

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

@ -13,16 +13,12 @@ import static org.mockito.Mockito.when;
import android.os.Handler;
import android.os.Message;
import com.unity3d.ads.IUnityAdsTokenListener;
import com.unity3d.services.ads.gmascar.managers.IBiddingManager;
import com.unity3d.services.ads.token.AsyncTokenStorage;
import com.unity3d.services.ads.token.INativeTokenGenerator;
import com.unity3d.services.ads.token.INativeTokenGeneratorListener;
import com.unity3d.services.ads.token.TokenStorage;
import com.unity3d.services.ads.token.*;
import com.unity3d.services.core.configuration.Configuration;
import com.unity3d.services.core.properties.ClientProperties;
import com.unity3d.services.core.properties.SdkProperties;
import com.unity3d.services.core.request.metrics.ISDKMetrics;
import com.unity3d.services.core.request.metrics.SDKMetricsSender;
import com.unity3d.services.core.request.metrics.Metric;
import com.unity3d.services.core.request.metrics.TSIMetric;
import com.unity3d.services.core.webview.WebViewApp;
@ -46,7 +42,7 @@ import java.util.HashMap;
import java.util.List;
@RunWith(MockitoJUnitRunner.class)
public class AsyncTokenStorageTest {
public class InMemoryAsyncTokenStorageTest {
@Mock
INativeTokenGenerator _nativeTokenGenerator;
@ -55,7 +51,7 @@ public class AsyncTokenStorageTest {
@Mock
IBiddingManager _biddingManager;
@Mock
ISDKMetrics _sdkMetrics;
SDKMetricsSender _sdkMetrics;
@Mock
TokenStorage _tokenStorage;
@ -72,7 +68,7 @@ public class AsyncTokenStorageTest {
WebViewApp.setCurrentApp(webViewApp);
SdkProperties.setInitializeState(SdkProperties.InitializationState.INITIALIZING);
_asyncTokenStorage = new AsyncTokenStorage(_nativeTokenGenerator, _handler, _sdkMetrics, _tokenStorage);
_asyncTokenStorage = new InMemoryAsyncTokenStorage(_nativeTokenGenerator, _handler, _sdkMetrics, _tokenStorage);
_asyncTokenStorage.setConfiguration(new Configuration());
Mockito.when(_biddingManager.getTokenIdentifier()).thenReturn(SCAR_TOKEN_IDENTIFIER_MOCK);
@ -436,7 +432,7 @@ public class AsyncTokenStorageTest {
Metric _metric = TSIMetric.newAsyncTokenAvailable(new HashMap<String, String>(){{
put ("state", "initializing");
}});
_asyncTokenStorage = new AsyncTokenStorage(_nativeTokenGenerator, _handler, _sdkMetrics, _tokenStorage);
_asyncTokenStorage = new InMemoryAsyncTokenStorage(_nativeTokenGenerator, _handler, _sdkMetrics, _tokenStorage);
_asyncTokenStorage.getToken(_biddingManager);
Mockito.verify(_biddingManager, Mockito.times(0)).onUnityAdsTokenReady(nullable(String.class));
@ -462,7 +458,7 @@ public class AsyncTokenStorageTest {
Metric _metric = TSIMetric.newAsyncTokenAvailable(new HashMap<String, String>(){{
put ("state", "initializing");
}});
_asyncTokenStorage = new AsyncTokenStorage(_nativeTokenGenerator, _handler, _sdkMetrics, _tokenStorage);
_asyncTokenStorage = new InMemoryAsyncTokenStorage(_nativeTokenGenerator, _handler, _sdkMetrics, _tokenStorage);
Mockito.when(_biddingManager.getFormattedToken(anyString())).thenReturn(SCAR_TOKEN_IDENTIFIER_MOCK + ":queue_token_1");
_asyncTokenStorage.getToken(_biddingManager);
@ -512,7 +508,7 @@ public class AsyncTokenStorageTest {
@Test
public void testNullConfiguration() throws JSONException {
_asyncTokenStorage = new AsyncTokenStorage(_nativeTokenGenerator, _handler, _sdkMetrics, _tokenStorage);
_asyncTokenStorage = new InMemoryAsyncTokenStorage(_nativeTokenGenerator, _handler, _sdkMetrics, _tokenStorage);
_asyncTokenStorage.getToken(_biddingManager);
Mockito.verify(_biddingManager, Mockito.times(0)).onUnityAdsTokenReady(nullable(String.class));
@ -568,4 +564,4 @@ public class AsyncTokenStorageTest {
return true;
}
}
}
}

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

@ -9,9 +9,7 @@ import static org.mockito.Mockito.when;
import com.unity3d.services.ads.token.INativeTokenGeneratorListener;
import com.unity3d.services.ads.token.NativeTokenGenerator;
import com.unity3d.services.core.configuration.PrivacyConfig;
import com.unity3d.services.core.configuration.PrivacyConfigStorage;
import com.unity3d.services.core.device.reader.DeviceInfoReaderBuilder;
import com.unity3d.services.core.device.reader.builder.DeviceInfoReaderBuilder;
import com.unity3d.services.core.device.reader.IDeviceInfoReader;
import org.junit.Before;

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

@ -1,26 +1,27 @@
package com.unity3d.ads.test.integration;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.doCallRealMethod;
import com.unity3d.services.core.configuration.Configuration;
import com.unity3d.services.core.di.IServicesRegistry;
import com.unity3d.services.core.di.ServiceProvider;
import com.unity3d.services.core.domain.ISDKDispatchers;
import com.unity3d.services.core.properties.InitializationStatusReader;
import com.unity3d.services.core.properties.SdkProperties;
import com.unity3d.services.core.request.metrics.ISDKMetrics;
import com.unity3d.services.core.request.metrics.SDKMetricsSender;
import com.unity3d.services.core.request.metrics.Metric;
import com.unity3d.services.core.request.metrics.MetricSender;
import com.unity3d.services.core.request.metrics.SDKMetrics;
import kotlinx.coroutines.Dispatchers;
import org.json.JSONObject;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
import java.lang.reflect.Field;
@ -29,15 +30,12 @@ import java.util.concurrent.atomic.AtomicBoolean;
@RunWith(MockitoJUnitRunner.class)
public class SDKMetricsTest {
@Mock
InitializationStatusReader _initStatusReaderMock;
@Mock
Configuration _configurationMock;
@InjectMocks
@Spy
public MetricSender _metricSenderMock;
private final HashMap<String, String> TEST_STATE_TAGS = new HashMap<String, String> (){{
@ -50,6 +48,20 @@ public class SDKMetricsTest {
Field configurationIsSetField = SDKMetrics.class.getDeclaredField("_configurationIsSet");
configurationIsSetField.setAccessible(true);
configurationIsSetField.set(new Object(), new AtomicBoolean(false));
IServicesRegistry registry = Mockito.mock(IServicesRegistry.class);
Field serviceRegistry = ServiceProvider.class.getDeclaredField("serviceRegistry");
serviceRegistry.setAccessible(true);
serviceRegistry.set(ServiceProvider.class, registry);
Mockito.doAnswer(invocation -> {
Class jObject = kotlin.jvm.JvmClassMappingKt.getJavaClass(invocation.getArgument(1));
if (jObject.getName().contains("ISDKDispatchers")) {
ISDKDispatchers dispatchers = Mockito.mock(ISDKDispatchers.class);
Mockito.when(dispatchers.getIo()).thenReturn(Dispatchers.getIO());
return dispatchers;
}
return Mockito.mock(jObject);
}).when(registry).getService(Mockito.any(), Mockito.any());
_metricSenderMock = Mockito.spy(new MetricSender(_configurationMock, _initStatusReaderMock));
}
@Test
@ -58,15 +70,14 @@ public class SDKMetricsTest {
}
@Test
public void testUsingNullAndEmptyEvents() {
ISDKMetrics metrics = SDKMetrics.getInstance();
metrics.sendEvent(null);
public void testUsingEmptyEvents() {
SDKMetricsSender metrics = SDKMetrics.getInstance();
metrics.sendEvent("");
}
@Test
public void testUsingInstanceAfterShutdown() {
ISDKMetrics metrics = SDKMetrics.getInstance();
SDKMetricsSender metrics = SDKMetrics.getInstance();
metrics.sendEvent("test_event");
SDKMetrics.setConfiguration(new Configuration());
metrics.sendEvent("test_event_2");
@ -132,7 +143,7 @@ public class SDKMetricsTest {
final ArgumentCaptor<Metric> metricCapture = ArgumentCaptor.forClass(Metric.class);
Mockito.when(_initStatusReaderMock.getInitializationStateString(Mockito.<SdkProperties.InitializationState>any())).thenReturn("initialized");
_metricSenderMock.sendMetricWithInitState(new Metric("native_test", 14, null));
_metricSenderMock.sendMetricWithInitState(new Metric("native_test", 14));
Mockito.verify(_metricSenderMock).sendMetric(metricCapture.capture());
Assert.assertEquals(TEST_STATE_TAGS, metricCapture.getValue().getTags());
@ -157,11 +168,11 @@ public class SDKMetricsTest {
SDKMetrics.getInstance();
Field instanceField = SDKMetrics.class.getDeclaredField("_instance");
instanceField.setAccessible(true);
Object instanceFieldObj = instanceField.get(ISDKMetrics.class);
Object instanceFieldObj = instanceField.get(SDKMetricsSender.class);
Assert.assertEquals(expectedMetricsClass, instanceFieldObj.getClass());
Mockito.when(mockConfiguration.getMetricSampleRate()).thenReturn(newMsr);
SDKMetrics.setConfiguration(mockConfiguration);
instanceFieldObj = instanceField.get(ISDKMetrics.class);
instanceFieldObj = instanceField.get(SDKMetricsSender.class);
Assert.assertEquals(expectedMetricsClass, instanceFieldObj.getClass());
}
}

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

@ -1,15 +1,15 @@
package com.unity3d.ads.test.legacy;
import android.os.Handler;
import android.os.Looper;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.unity3d.ads.IUnityAdsTokenListener;
import com.unity3d.services.ads.gmascar.managers.IBiddingManager;
import com.unity3d.services.ads.token.AsyncTokenStorage;
import com.unity3d.services.ads.token.TokenEvent;
import com.unity3d.services.ads.token.TokenStorage;
import com.unity3d.services.ads.token.*;
import com.unity3d.services.core.configuration.Configuration;
import com.unity3d.services.core.properties.ClientProperties;
import com.unity3d.services.core.properties.SdkProperties;
import com.unity3d.services.core.request.metrics.SDKMetrics;
import com.unity3d.services.core.webview.WebViewApp;
import com.unity3d.services.core.webview.WebViewEventCategory;
@ -23,20 +23,32 @@ import org.junit.runner.RunWith;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.any;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.concurrent.CountDownLatch;
import java.util.function.Predicate;
@RunWith(AndroidJUnit4.class)
public class TokenStorageTest {
public class InMemoryTokenStorageTest {
private TokenStorage tokenStorage;
private AsyncTokenStorage asyncTokenStorage;
@Before
public void reset() {
MockWebViewApp webViewApp = new MockWebViewApp();
WebViewApp.setCurrentApp(webViewApp);
TokenStorage.getInstance().deleteTokens();
TokenStorage.getInstance().setPeekMode(false);
TokenStorage.getInstance().setInitToken(null);
tokenStorage = new InMemoryTokenStorage();
tokenStorage.deleteTokens();
tokenStorage.setInitToken(null);
asyncTokenStorage = new InMemoryAsyncTokenStorage(
null,
new Handler(Looper.getMainLooper()),
SDKMetrics.getInstance(),
tokenStorage
);
}
@After
@ -50,30 +62,30 @@ public class TokenStorageTest {
public void testCreateGetToken() throws JSONException {
MockWebViewApp currentApp = (MockWebViewApp)WebViewApp.getCurrentApp();
TokenStorage.getInstance().createTokens(getTestArray());
tokenStorage.createTokens(getTestArray());
String firstToken = TokenStorage.getInstance().getToken();
String firstToken = tokenStorage.getToken();
assertEquals("Token create+get test: first value was not one", firstToken, "one");
assertEquals("Token create+get test: event count not one after first event", currentApp.getEventCount(), 1);
assertEquals("Token create+get test: event category not TOKEN in first event", currentApp.getLastEventCategory(), WebViewEventCategory.TOKEN);
assertEquals("Token create+get test: event ID not TOKEN_ACCESS in first event", currentApp.getLastEventId(), TokenEvent.TOKEN_ACCESS);
assertEquals("Token create+get test: access counter is not zero in first event", currentApp.getLastParams()[0], 0);
String secondToken = TokenStorage.getInstance().getToken();
String secondToken = tokenStorage.getToken();
assertEquals("Token create+get test: second value was not two", secondToken, "two");
assertEquals("Token create+get test: event count not two after second event", currentApp.getEventCount(), 2);
assertEquals("Token create+get test: event category not TOKEN in second event", currentApp.getLastEventCategory(), WebViewEventCategory.TOKEN);
assertEquals("Token create+get test: event ID not TOKEN_ACCESS in second event", currentApp.getLastEventId(), TokenEvent.TOKEN_ACCESS);
assertEquals("Token create+get test: access counter is not one in second event", currentApp.getLastParams()[0], 1);
String thirdToken = TokenStorage.getInstance().getToken();
String thirdToken = tokenStorage.getToken();
assertEquals("Token create+get test: third value was not three", thirdToken, "three");
assertEquals("Token create+get test: event count not three after third event", currentApp.getEventCount(), 3);
assertEquals("Token create+get test: event category not TOKEN in third event", currentApp.getLastEventCategory(), WebViewEventCategory.TOKEN);
assertEquals("Token create+get test: event ID not TOKEN_ACCESS in third event", currentApp.getLastEventId(), TokenEvent.TOKEN_ACCESS);
assertEquals("Token create+get test: access counter is not two in third event", currentApp.getLastParams()[0], 2);
String nullToken = TokenStorage.getInstance().getToken();
String nullToken = tokenStorage.getToken();
assertNull("Token create+get test: value is not null when queue is empty", nullToken);
assertEquals("Token create+get test: event count not four after fourth event", currentApp.getEventCount(), 4);
assertEquals("Token create+get test: event category not TOKEN in fourth event", currentApp.getLastEventCategory(), WebViewEventCategory.TOKEN);
@ -84,10 +96,10 @@ public class TokenStorageTest {
public void testCreateDeleteToken() throws JSONException {
MockWebViewApp currentApp = (MockWebViewApp)WebViewApp.getCurrentApp();
TokenStorage.getInstance().createTokens(getTestArray());
TokenStorage.getInstance().deleteTokens();
tokenStorage.createTokens(getTestArray());
tokenStorage.deleteTokens();
String nullToken = TokenStorage.getInstance().getToken();
String nullToken = tokenStorage.getToken();
assertNull("Token create+delete test: value is not null when queue was deleted", nullToken);
assertEquals("Token create+delete test: webview event was triggered when queue was deleted", currentApp.getEventCount(), 0);
}
@ -96,96 +108,66 @@ public class TokenStorageTest {
public void testCreateAppendGetToken() throws JSONException {
MockWebViewApp currentApp = (MockWebViewApp)WebViewApp.getCurrentApp();
TokenStorage.getInstance().createTokens(getTestArray());
tokenStorage.createTokens(getTestArray());
String firstToken = TokenStorage.getInstance().getToken();
String firstToken = tokenStorage.getToken();
assertEquals("Token create+append+get test: first value was not one", firstToken, "one");
assertEquals("Token create+append+get test: event count not one after first event", currentApp.getEventCount(), 1);
assertEquals("Token create+append+get test: event category not TOKEN in first event", currentApp.getLastEventCategory(), WebViewEventCategory.TOKEN);
assertEquals("Token create+append+get test: event ID not TOKEN_ACCESS in first event", currentApp.getLastEventId(), TokenEvent.TOKEN_ACCESS);
assertEquals("Token create+append+get test: access counter is not zero in first event", currentApp.getLastParams()[0], 0);
TokenStorage.getInstance().appendTokens(getTestArray());
tokenStorage.appendTokens(getTestArray());
String secondToken = TokenStorage.getInstance().getToken();
String secondToken = tokenStorage.getToken();
assertEquals("Token create+append+get test: second value was not two", secondToken, "two");
assertEquals("Token create+append+get test: event count not two after second event", currentApp.getEventCount(), 2);
assertEquals("Token create+append+get test: event category not TOKEN in second event", currentApp.getLastEventCategory(), WebViewEventCategory.TOKEN);
assertEquals("Token create+append+get test: event ID not TOKEN_ACCESS in second event", currentApp.getLastEventId(), TokenEvent.TOKEN_ACCESS);
assertEquals("Token create+append+get test: access counter is not one in second event", currentApp.getLastParams()[0], 1);
String thirdToken = TokenStorage.getInstance().getToken();
String thirdToken = tokenStorage.getToken();
assertEquals("Token create+append+get test: third value was not three", thirdToken, "three");
assertEquals("Token create+append+get test: event count not three after third event", currentApp.getEventCount(), 3);
assertEquals("Token create+append+get test: event category not TOKEN in third event", currentApp.getLastEventCategory(), WebViewEventCategory.TOKEN);
assertEquals("Token create+append+get test: event ID not TOKEN_ACCESS in third event", currentApp.getLastEventId(), TokenEvent.TOKEN_ACCESS);
assertEquals("Token create+append+get test: access counter is not two in third event", currentApp.getLastParams()[0], 2);
String fourthToken = TokenStorage.getInstance().getToken();
String fourthToken = tokenStorage.getToken();
assertEquals("Token create+append+get test: fourth value was not one", fourthToken, "one");
assertEquals("Token create+append+get test: event count not four after fourth event", currentApp.getEventCount(), 4);
assertEquals("Token create+append+get test: event category not TOKEN in fourth event", currentApp.getLastEventCategory(), WebViewEventCategory.TOKEN);
assertEquals("Token create+append+get test: event ID not TOKEN_ACCESS in fourth event", currentApp.getLastEventId(), TokenEvent.TOKEN_ACCESS);
assertEquals("Token create+append+get test: access counter is not three in fourth event", currentApp.getLastParams()[0], 3);
String fifthToken = TokenStorage.getInstance().getToken();
String fifthToken = tokenStorage.getToken();
assertEquals("Token create+append+get test: fifth value was not two", fifthToken, "two");
assertEquals("Token create+append+get test: event count not five after fifth event", currentApp.getEventCount(), 5);
assertEquals("Token create+append+get test: event category not TOKEN in fifth event", currentApp.getLastEventCategory(), WebViewEventCategory.TOKEN);
assertEquals("Token create+append+get test: event ID not TOKEN_ACCESS in fifth event", currentApp.getLastEventId(), TokenEvent.TOKEN_ACCESS);
assertEquals("Token create+append+get test: access counter is not four in fifth event", currentApp.getLastParams()[0], 4);
String sixthToken = TokenStorage.getInstance().getToken();
String sixthToken = tokenStorage.getToken();
assertEquals("Token create+append+get test: sixth value was not three", sixthToken, "three");
assertEquals("Token create+append+get test: event count not six after sixth event", currentApp.getEventCount(), 6);
assertEquals("Token create+append+get test: event category not TOKEN in sixth event", currentApp.getLastEventCategory(), WebViewEventCategory.TOKEN);
assertEquals("Token create+append+get test: event ID not TOKEN_ACCESS in sixth event", currentApp.getLastEventId(), TokenEvent.TOKEN_ACCESS);
assertEquals("Token create+append+get test: access counter is not five in sixth event", currentApp.getLastParams()[0], 5);
String nullToken = TokenStorage.getInstance().getToken();
String nullToken = tokenStorage.getToken();
assertNull("Token create+append+get test: value is not null when queue is empty", nullToken);
assertEquals("Token create+append+get test: event count not seven after seventh event", currentApp.getEventCount(), 7);
assertEquals("Token create+append+get test: event category not TOKEN in seventh event", currentApp.getLastEventCategory(), WebViewEventCategory.TOKEN);
assertEquals("Token create+append+get test: event ID not QUEUE_EMPTY in seventh event", currentApp.getLastEventId(), TokenEvent.QUEUE_EMPTY);
}
@Test
public void testPeekMode() throws JSONException {
String staticToken = "static_token";
MockWebViewApp currentApp = (MockWebViewApp)WebViewApp.getCurrentApp();
JSONArray array = new JSONArray();
array.put(staticToken);
TokenStorage.getInstance().setPeekMode(true);
TokenStorage.getInstance().createTokens(array);
String firstToken = TokenStorage.getInstance().getToken();
assertEquals("Token peekmode test: first value was not correct", firstToken, staticToken);
assertEquals("Token peekmode test: event count not one after first event", currentApp.getEventCount(), 1);
assertEquals("Token peekmode test: event category not TOKEN in first event", currentApp.getLastEventCategory(), WebViewEventCategory.TOKEN);
assertEquals("Token peekmode test: event ID not TOKEN_ACCESS in first event", currentApp.getLastEventId(), TokenEvent.TOKEN_ACCESS);
assertEquals("Token peekmode test: access counter is not zero in first event", currentApp.getLastParams()[0], 0);
String secondToken = TokenStorage.getInstance().getToken();
assertEquals("Token peekmode test: second value was not correct", secondToken, staticToken);
assertEquals("Token peekmode test: event count not two after second event", currentApp.getEventCount(), 2);
assertEquals("Token peekmode test: event category not TOKEN in second event", currentApp.getLastEventCategory(), WebViewEventCategory.TOKEN);
assertEquals("Token peekmode test: event ID not TOKEN_ACCESS in second event", currentApp.getLastEventId(), TokenEvent.TOKEN_ACCESS);
assertEquals("Token peekmode test: access counter is not one in second event", currentApp.getLastParams()[0], 1);
String thirdToken = TokenStorage.getInstance().getToken();
assertEquals("Token peekmode test: third value was not correct", thirdToken, staticToken);
assertEquals("Token peekmode test: event count not one after third event", currentApp.getEventCount(), 3);
assertEquals("Token peekmode test: event category not TOKEN in third event", currentApp.getLastEventCategory(), WebViewEventCategory.TOKEN);
assertEquals("Token peekmode test: event ID not TOKEN_ACCESS in third event", currentApp.getLastEventId(), TokenEvent.TOKEN_ACCESS);
assertEquals("Token peekmode test: access counter is not two in third event", currentApp.getLastParams()[0], 2);
}
@Test(timeout = 2000)
public void testDeadlockRegression() throws InterruptedException {
TokenStorage.getInstance().deleteTokens();
public void testDeadlockRegression() throws InterruptedException, IllegalAccessException {
tokenStorage.deleteTokens();
Field field = Arrays.stream(InMemoryTokenStorage.class.getDeclaredFields()).filter(f -> f.getName().contains("asyncTokenStorage")).findFirst().get();
field.setAccessible(true);
field.set(tokenStorage, kotlin.LazyKt.lazyOf(asyncTokenStorage));
ClientProperties.setApplicationContext(androidx.test.core.app.ApplicationProvider.getApplicationContext());
SdkProperties.setInitializeState(SdkProperties.InitializationState.INITIALIZING);
@ -195,7 +177,7 @@ public class TokenStorageTest {
final CountDownLatch tokensReady = new CountDownLatch(tokenRequestCount);
final String[] actualToken = {"", ""};
AsyncTokenStorage.getInstance().setConfiguration(new Configuration());
asyncTokenStorage.setConfiguration(new Configuration());
Thread appendTokens = new Thread(new Runnable() {
@Override
@ -206,7 +188,7 @@ public class TokenStorageTest {
e.printStackTrace();
}
try {
TokenStorage.getInstance().appendTokens(getTestArray());
tokenStorage.appendTokens(getTestArray());
} catch (JSONException e) {
e.printStackTrace();
}
@ -220,7 +202,7 @@ public class TokenStorageTest {
for (int i = 0; i < tokenRequestCount; i++) {
final int finalI = i;
AsyncTokenStorage.getInstance().getToken(new IBiddingManager() {
asyncTokenStorage.getToken(new IBiddingManager() {
@Override
public String getTokenIdentifier() {
return "";

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

@ -178,21 +178,6 @@ public class InitializeThreadTest {
assertEquals("Init state reset test: next state config url is not set", config.getConfigUrl(), null);
}
@Test
public void testInitializeStateAdBlockerCheck() {
Configuration goodConfig = new Configuration("http://www.unity3d.com/test");
InitializeThread.InitializeStateInitModules state = new InitializeThread.InitializeStateInitModules(goodConfig);
Object nextState = state.execute();
assertTrue("Init state ad blocker check test: next state is not load config", nextState instanceof InitializeThread.InitializeStateConfig);
Configuration badConfig = new Configuration("http://localhost/test");
InitializeThread.InitializeStateInitModules state2 = new InitializeThread.InitializeStateInitModules(badConfig);
Object nextState2 = state2.execute();
assertTrue("Init state ad blocker check test: next state is not error state", nextState2 instanceof InitializeThread.InitializeStateError);
}
@Test
public void testInitializeStateConfig() {
Configuration initConfig = new Configuration(SdkProperties.getConfigUrl());

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

@ -4,6 +4,7 @@ import android.os.ConditionVariable;
import android.os.Handler;
import android.os.Looper;
import android.os.Parcel;
import android.webkit.ValueCallback;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@ -104,7 +105,7 @@ public class InvocationTest {
public void run() {
WebViewApp.getCurrentApp().setWebView(new WebView(ClientProperties.getApplicationContext(), false) {
@Override
public void invokeJavascript(String data) {
public void evaluateJavascript(String data, ValueCallback<String> callback) {
BatchInvocationTestApi.JAVASCRIPT_INVOKED = true;
}
});
@ -142,7 +143,7 @@ public class InvocationTest {
public void run() {
WebViewApp.getCurrentApp().setWebView(new WebView(ClientProperties.getApplicationContext(), false) {
@Override
public void invokeJavascript(String data) {
public void evaluateJavascript(String data, ValueCallback<String> callback) {
BatchInvocationTestApi.JAVASCRIPT_INVOKED = true;
}
});

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

@ -1,36 +1,40 @@
package com.unity3d.ads.test.legacy;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import android.app.Activity;
import android.content.Context;
import android.media.AudioManager;
import android.os.ConditionVariable;
import android.os.Handler;
import android.os.Looper;
import android.view.ViewGroup;
import androidx.test.filters.RequiresDevice;
import androidx.test.filters.SdkSuppress;
import androidx.test.platform.app.InstrumentationRegistry;
import android.view.ViewGroup;
import com.unity3d.services.core.api.DeviceInfo;
import com.unity3d.services.core.device.IVolumeChangeListener;
import com.unity3d.services.core.device.VolumeChange;
import com.unity3d.services.core.log.DeviceLog;
import com.unity3d.services.core.properties.ClientProperties;
import com.unity3d.ads.test.TestUtilities;
import com.unity3d.services.ads.video.VideoPlayerEvent;
import com.unity3d.services.ads.video.VideoPlayerView;
import com.unity3d.services.core.device.DeviceInfoEvent;
import com.unity3d.services.core.device.VolumeChange;
import com.unity3d.services.core.device.VolumeChangeContentObserver;
import com.unity3d.services.core.device.VolumeChangeListener;
import com.unity3d.services.core.log.DeviceLog;
import com.unity3d.services.core.properties.ClientProperties;
import com.unity3d.services.core.webview.WebViewApp;
import com.unity3d.services.core.webview.WebViewEventCategory;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.util.concurrent.CountDownLatch;
public class VolumeChangeTest extends AdUnitActivityTestBaseClass {
public class VolumeChangeContentObserverTest extends AdUnitActivityTestBaseClass {
@Before
public void setup() {
WebViewApp.setCurrentApp(null);
@ -41,6 +45,7 @@ public class VolumeChangeTest extends AdUnitActivityTestBaseClass {
@SdkSuppress(minSdkVersion = 21)
public void testVolumeChange() throws Exception {
final Activity activity = waitForActivityStart(null);
final VolumeChange volumeChange = new VolumeChangeContentObserver();
ClientProperties.setApplicationContext(InstrumentationRegistry.getInstrumentation().getTargetContext());
@ -69,7 +74,7 @@ public class VolumeChangeTest extends AdUnitActivityTestBaseClass {
CONDITION_VARIABLE.open();
}
}
if (eventCategory.equals(WebViewEventCategory.DEVICEINFO) && eventId.equals(DeviceInfo.DeviceInfoEvent.VOLUME_CHANGED)) {
if (eventCategory.equals(WebViewEventCategory.DEVICEINFO) && eventId.equals(DeviceInfoEvent.VOLUME_CHANGED)) {
EVENT_PARAMS = params;
CONDITION_VARIABLE.open();
}
@ -108,11 +113,11 @@ public class VolumeChangeTest extends AdUnitActivityTestBaseClass {
mockWebViewApp.CONDITION_VARIABLE = cv;
success = cv.block(3000);
IVolumeChangeListener vcl = new IVolumeChangeListener() {
VolumeChangeListener vcl = new VolumeChangeListener() {
@Override
public void onVolumeChanged(int volume) {
DeviceLog.debug("VOLUME_CHANGED: " + volume);
WebViewApp.getCurrentApp().sendEvent(WebViewEventCategory.DEVICEINFO, DeviceInfo.DeviceInfoEvent.VOLUME_CHANGED, volume);
WebViewApp.getCurrentApp().sendEvent(WebViewEventCategory.DEVICEINFO, DeviceInfoEvent.VOLUME_CHANGED, volume);
}
@Override
@ -121,7 +126,7 @@ public class VolumeChangeTest extends AdUnitActivityTestBaseClass {
}
};
VolumeChange.registerListener(vcl);
volumeChange.registerListener(vcl);
am.setStreamVolume(AudioManager.STREAM_MUSIC, 1, 0);
@ -134,10 +139,10 @@ public class VolumeChangeTest extends AdUnitActivityTestBaseClass {
assertNotNull("First EVENT_PARAMS NULL", mockWebViewApp.EVENT_PARAMS[0]);
assertEquals("Volume not what was expected", 1, (int)mockWebViewApp.EVENT_PARAMS[0]);
VolumeChange.unregisterListener(vcl);
volumeChange.unregisterListener(vcl);
am.setStreamVolume(AudioManager.STREAM_MUSIC, 3, 0);
VolumeChange.registerListener(vcl);
volumeChange.registerListener(vcl);
am.setStreamVolume(AudioManager.STREAM_MUSIC, 2, 0);
cv = new ConditionVariable();
@ -152,4 +157,32 @@ public class VolumeChangeTest extends AdUnitActivityTestBaseClass {
assertTrue("Didn't get activity finish", waitForActivityFinish(activity));
}
@Test(timeout = 10000)
public void testVolumeChangeThreadConcurrency() throws InterruptedException {
final VolumeChangeListener vcl = Mockito.mock(VolumeChangeListener.class);
final int clearListenerThreadCount = 10;
final CountDownLatch registerListenerLatch = new CountDownLatch(1);
final VolumeChange volumeChange = new VolumeChangeContentObserver();
final CountDownLatch clearListenerLatch = new CountDownLatch(clearListenerThreadCount);
for (int threadCount = 0; threadCount < clearListenerThreadCount; threadCount++) {
Thread clearListenerThread = new Thread(() -> {
try {
registerListenerLatch.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
volumeChange.clearAllListeners();
clearListenerLatch.countDown();
});
clearListenerThread.start();
}
registerListenerLatch.countDown();
volumeChange.registerListener(vcl);
clearListenerLatch.await();
}
}

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

@ -4,6 +4,7 @@ import android.content.Context;
import android.os.ConditionVariable;
import android.os.Handler;
import android.os.Looper;
import android.webkit.ValueCallback;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@ -64,6 +65,7 @@ public class WebViewAppTest {
public void run() {
WebViewApp.getCurrentApp().setWebAppLoaded(true);
WebViewApp.getCurrentApp().setWebAppInitialized(false);
WebViewApp.getCurrentApp().setWebAppFailureCode(1);
}
}, 100);
ErrorState webViewErrorState = WebViewApp.create(conf);
@ -542,7 +544,7 @@ public class WebViewAppTest {
}
@Override
public void invokeJavascript(String data) {
public void evaluateJavascript(String data, ValueCallback<String> callback) {
JS_INVOKED = true;
JS_CALL = data;
}

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

@ -1,12 +1,18 @@
package com.unity3d.ads.test.legacy;
import android.net.Uri;
import android.os.ConditionVariable;
import android.os.Handler;
import android.os.Looper;
import android.webkit.ValueCallback;
import androidx.annotation.NonNull;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.webkit.JavaScriptReplyProxy;
import androidx.webkit.WebMessageCompat;
import com.unity3d.services.core.configuration.Configuration;
import com.unity3d.services.core.configuration.IExperiments;
import com.unity3d.services.core.properties.ClientProperties;
import com.unity3d.ads.test.TestUtilities;
import com.unity3d.services.core.webview.WebView;
@ -17,21 +23,29 @@ import com.unity3d.services.core.webview.bridge.WebViewBridgeInterface;
import com.unity3d.services.core.webview.bridge.WebViewCallback;
import com.unity3d.services.core.webview.bridge.WebViewExposed;
import kotlinx.coroutines.Dispatchers;
import org.jetbrains.annotations.NotNull;
import org.json.JSONException;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import static org.junit.Assert.*;
import java.lang.reflect.Method;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeoutException;
@RunWith(AndroidJUnit4.class)
@RunWith(MockitoJUnitRunner.class)
public class WebViewBridgeInterfaceTest {
@Mock
private JavaScriptReplyProxy javaScriptProxy;
private static boolean nativeCallbackInvoked = false;
private static CallbackStatus nativeCallbackStatus = null;
private static String nativeCallbackValue = null;
@ -98,7 +112,7 @@ public class WebViewBridgeInterfaceTest {
WebViewApp.getCurrentApp().setWebAppInitialized(true);
WebViewApp.getCurrentApp().setWebView(new WebView(ClientProperties.getApplicationContext(), false) {
@Override
public void invokeJavascript(String data) {
public void evaluateJavascript(String data, ValueCallback<String> callback) {
}
});
@ -129,24 +143,72 @@ public class WebViewBridgeInterfaceTest {
webInterface.handleInvocation("[[\"com.unity3d.ads.test.legacy.WebViewBridgeInterfaceTest$WebViewBridgeTestApi\", \"apiTestMethodNoParams\", null, \"CALLBACK_01\"]]");
}
@Test(expected = ClassCastException.class)
public void testOnHandleInvocationShouldFailParametersNull() {
WebViewBridgeInterface webInterface = new WebViewBridgeInterface();
webInterface.onHandleInvocation(
WebViewApp.getCurrentApp().getWebView(),
new WebMessageCompat("[[\"com.unity3d.ads.test.legacy.WebViewBridgeInterfaceTest$WebViewBridgeTestApi\", \"apiTestMethodNoParams\", null, \"CALLBACK_01\"]]"),
Uri.EMPTY,
true,
javaScriptProxy
);
}
@Test (expected = NullPointerException.class)
public void testHandleCallbackShouldFailParametersNull () throws Exception {
WebViewBridgeInterface webInterface = new WebViewBridgeInterface();
webInterface.handleCallback("CALLBACK_01", "OK", null);
}
@Test(expected = JSONException.class)
public void testOnHandleCallbackShouldFailParametersNull() {
WebViewBridgeInterface webInterface = new WebViewBridgeInterface();
webInterface.onHandleCallback(
WebViewApp.getCurrentApp().getWebView(),
new WebMessageCompat("{\"id\":\"CALLBACK_01\",\"status\":\"OK\"}"),
Uri.EMPTY,
true,
javaScriptProxy
);
}
@Test (expected = ClassCastException.class)
public void testHandleInvocationShouldFailParametersEmpty () throws JSONException {
WebViewBridgeInterface webInterface = new WebViewBridgeInterface();
webInterface.handleInvocation("[[\"com.unity3d.ads.test.legacy.WebViewBridgeInterfaceTest$WebViewBridgeTestApi\", \"apiTestMethodNoParams\", \"\", \"CALLBACK_01\"]]");
}
@Test(expected = ClassCastException.class)
public void testOnHandleInvocationShouldFailParametersEmpty() {
WebViewBridgeInterface webInterface = new WebViewBridgeInterface();
webInterface.onHandleInvocation(
WebViewApp.getCurrentApp().getWebView(),
new WebMessageCompat("[[\"com.unity3d.ads.test.legacy.WebViewBridgeInterfaceTest$WebViewBridgeTestApi\", \"apiTestMethodNoParams\", \"\", \"CALLBACK_01\"]]"),
Uri.EMPTY,
true,
javaScriptProxy
);
}
@Test (expected = JSONException.class)
public void testHandleCallbackShouldFailParametersEmpty () throws Exception {
WebViewBridgeInterface webInterface = new WebViewBridgeInterface();
webInterface.handleCallback("CALLBACK_01", "OK", "");
}
@Test(expected = JSONException.class)
public void testOnHandleCallbackShouldFailParametersEmpty() {
WebViewBridgeInterface webInterface = new WebViewBridgeInterface();
webInterface.onHandleCallback(
WebViewApp.getCurrentApp().getWebView(),
new WebMessageCompat("{\"id\":\"CALLBACK_01\",\"status\":\"OK\",\"parameters\":\"\"}"),
Uri.EMPTY,
true,
javaScriptProxy
);
}
@Test
public void testHandleInvocationShouldSucceed () throws JSONException {
WebViewBridgeInterface webInterface = new WebViewBridgeInterface();
@ -155,6 +217,20 @@ public class WebViewBridgeInterfaceTest {
assertEquals("CallbackID's didn't match", "CALLBACK_01", WebViewBridgeTestApi.callback.getCallbackId());
}
@Test
public void testOnHandleInvocationShouldSucceed() {
WebViewBridgeInterface webInterface = new WebViewBridgeInterface();
webInterface.onHandleInvocation(
WebViewApp.getCurrentApp().getWebView(),
new WebMessageCompat("[[\"com.unity3d.ads.test.legacy.WebViewBridgeInterfaceTest$WebViewBridgeTestApi\", \"apiTestMethodNoParams\", [], \"CALLBACK_01\"]]"),
Uri.EMPTY,
true,
javaScriptProxy
);
assertTrue("ApiMethod should have been invoked but wasn't", WebViewBridgeTestApi.invoked);
assertEquals("CallbackID's didn't match", "CALLBACK_01", WebViewBridgeTestApi.callback.getCallbackId());
}
@Test
public void testHandleInvocationWithParamsShouldSucceed () throws JSONException {
WebViewBridgeInterface webInterface = new WebViewBridgeInterface();
@ -164,6 +240,21 @@ public class WebViewBridgeInterfaceTest {
assertEquals("Callback value wasn't same as was originally given", "test", WebViewBridgeTestApi.value);
}
@Test
public void testOnHandleInvocationWithParamsShouldSucceed() {
WebViewBridgeInterface webInterface = new WebViewBridgeInterface();
webInterface.onHandleInvocation(
WebViewApp.getCurrentApp().getWebView(),
new WebMessageCompat("[[\"com.unity3d.ads.test.legacy.WebViewBridgeInterfaceTest$WebViewBridgeTestApi\", \"apiTestMethod\", [\"test\"], \"CALLBACK_01\"]]"),
Uri.EMPTY,
true,
javaScriptProxy
);
assertTrue("ApiMethod should have been invoked but wasn't", WebViewBridgeTestApi.invoked);
assertEquals("CallbackID's didn't match", "CALLBACK_01", WebViewBridgeTestApi.callback.getCallbackId());
assertEquals("Callback value wasn't same as was originally given", "test", WebViewBridgeTestApi.value);
}
@Test (expected = NullPointerException.class)
public void testHandleCallbackShouldFailCallbackNotAdded () throws Exception {
WebViewBridgeInterface webInterface = new WebViewBridgeInterface();
@ -172,6 +263,20 @@ public class WebViewBridgeInterfaceTest {
webInterface.handleCallback(callback.getId(), "OK", "[]");
}
@Test(expected = NullPointerException.class)
public void testOnHandleCallbackShouldFailCallbackNotAdded() throws Exception {
WebViewBridgeInterface webInterface = new WebViewBridgeInterface();
Method m = getClass().getMethod("staticTestHandleCallback", CallbackStatus.class);
NativeCallback callback = new NativeCallback(m);
webInterface.onHandleCallback(
WebViewApp.getCurrentApp().getWebView(),
new WebMessageCompat("{\"id\":\"" + callback.getId() + "\",\"status\":\"OK\",\"parameters\":\"[]\"}"),
Uri.EMPTY,
true,
javaScriptProxy
);
}
@Test (expected = NullPointerException.class)
public void testHandleCallbackShouldFailMethodNotStatic () throws Exception {
WebViewBridgeInterface webInterface = new WebViewBridgeInterface();
@ -181,6 +286,21 @@ public class WebViewBridgeInterfaceTest {
webInterface.handleCallback(callback.getId(), "OK", "[]");
}
@Test(expected = NullPointerException.class)
public void testOnHandleCallbackShouldFailMethodNotStatic() throws Exception {
WebViewBridgeInterface webInterface = new WebViewBridgeInterface();
Method m = getClass().getMethod("instanceTestHandleCallback", CallbackStatus.class);
NativeCallback callback = new NativeCallback(m);
WebViewApp.getCurrentApp().addCallback(callback);
webInterface.onHandleCallback(
WebViewApp.getCurrentApp().getWebView(),
new WebMessageCompat("{\"id\":\"" + callback.getId() + "\",\"status\":\"OK\",\"parameters\":\"[]\"}"),
Uri.EMPTY,
true,
javaScriptProxy
);
}
@Test
public void testHandleCallbackShouldSucceed () throws Exception {
WebViewBridgeInterface webInterface = new WebViewBridgeInterface();
@ -192,6 +312,23 @@ public class WebViewBridgeInterfaceTest {
assertEquals("NativeCallback status wasn't OK", CallbackStatus.OK, nativeCallbackStatus);
}
@Test
public void testOnHandleCallbackShouldSucceed() throws Exception {
WebViewBridgeInterface webInterface = new WebViewBridgeInterface();
Method m = getClass().getMethod("staticTestHandleCallback", CallbackStatus.class);
NativeCallback callback = new NativeCallback(m);
WebViewApp.getCurrentApp().addCallback(callback);
webInterface.onHandleCallback(
WebViewApp.getCurrentApp().getWebView(),
new WebMessageCompat("{\"id\":\"" + callback.getId() + "\",\"status\":\"OK\",\"parameters\":\"[]\"}"),
Uri.EMPTY,
true,
javaScriptProxy
);
assertTrue("NativeCallback -method should have been invoked but wasn't", nativeCallbackInvoked);
assertEquals("NativeCallback status wasn't OK", CallbackStatus.OK, nativeCallbackStatus);
}
@Test
public void testHandleCallbackWithParamsShouldSucceed () throws Exception {
WebViewBridgeInterface webInterface = new WebViewBridgeInterface();
@ -206,6 +343,26 @@ public class WebViewBridgeInterfaceTest {
assertEquals("The value received wasn't the same than was originally given", "test", nativeCallbackValue);
}
@Test
public void testOnHandleCallbackWithParamsShouldSucceed() throws Exception {
WebViewBridgeInterface webInterface = new WebViewBridgeInterface();
Method m = getClass().getMethod("staticTestHandleCallbackStringParam", CallbackStatus.class, String.class);
NativeCallback callback = new NativeCallback(m);
WebViewApp.getCurrentApp().addCallback(callback);
webInterface.onHandleCallback(
WebViewApp.getCurrentApp().getWebView(),
new WebMessageCompat("{\"id\":\"" + callback.getId() + "\",\"status\":\"OK\",\"parameters\":[\"test\"]}"),
Uri.EMPTY,
true,
javaScriptProxy
);
assertTrue("NativeCallback -method should have been invoked but wasn't", nativeCallbackInvoked);
assertEquals("NativeCallback status wasn't OK", CallbackStatus.OK, nativeCallbackStatus);
assertNotNull("Received value should not be null", nativeCallbackValue);
assertEquals("The value received wasn't the same than was originally given", "test", nativeCallbackValue);
}
public static void staticTestHandleCallback (CallbackStatus status) {
nativeCallbackInvoked = true;
nativeCallbackStatus = status;

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

@ -11,9 +11,11 @@ import android.os.Parcel;
import android.os.Parcelable;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
import com.unity3d.ads.test.TestUtilities;
import com.unity3d.services.core.configuration.Configuration;
import com.unity3d.services.core.properties.ClientProperties;
import com.unity3d.services.core.webview.WebViewApp;
import com.unity3d.services.core.webview.bridge.CallbackStatus;
import com.unity3d.services.core.webview.bridge.NativeCallback;
@ -121,22 +123,23 @@ public class WebViewBridgeTest {
@Test (expected = NullPointerException.class)
public void testAllNull () throws Exception {
WebViewBridge.handleInvocation(null, null, null, null);
WebViewBridge.getInstance().handleInvocation(null, null, null, null);
}
@Test (expected = NullPointerException.class)
public void testClassNameSetOthersNull () throws Exception {
WebViewBridge.handleInvocation("com.unity3d.ads.test.legacy.WebViewBridgeTest$WebViewBridgeTestApi", null, null, null);
WebViewBridge.getInstance().handleInvocation("com.unity3d.ads.test.legacy.WebViewBridgeTest$WebViewBridgeTestApi", null, null, null);
}
@Test (expected = NullPointerException.class)
public void testClassNameMethodSetOthersNull () throws Exception {
WebViewBridge.handleInvocation("com.unity3d.ads.test.legacy.WebViewBridgeTest$WebViewBridgeTestApi", "apiTestMethod", null, null);
WebViewBridge.getInstance().handleInvocation("com.unity3d.ads.test.legacy.WebViewBridgeTest$WebViewBridgeTestApi", "apiTestMethod", null, null);
}
@Test (expected = NullPointerException.class)
public void testOthersSetParametersNull () throws Exception {
WebViewBridge.handleInvocation("com.unity3d.ads.test.legacy.WebViewBridgeTest$WebViewBridgeTestApi", "apiTestMethod", null, new MockWebViewCallback("APICALLBACK_01", 1));
WebViewBridge.getInstance().handleInvocation("com.unity3d.ads.test.legacy.WebViewBridgeTest$WebViewBridgeTestApi", "apiTestMethod", null, new MockWebViewCallback("APICALLBACK_01", 1));
}
@Test
@ -144,7 +147,7 @@ public class WebViewBridgeTest {
boolean gotException = false;
try {
WebViewBridge.handleInvocation("com.unity3d.ads.test.legacy.WebViewBridgeTest$WebViewBridgeTestApi", null, new Object[]{"test"}, new MockWebViewCallback("APICALLBACK_01", 1));
WebViewBridge.getInstance().handleInvocation("com.unity3d.ads.test.legacy.WebViewBridgeTest$WebViewBridgeTestApi", null, new Object[]{"test"}, new MockWebViewCallback("APICALLBACK_01", 1));
}
catch (NoSuchMethodException e) {
assertEquals("Should have received exception of type NoSuchMethodException", NoSuchMethodException.class, e.getClass());
@ -162,7 +165,7 @@ public class WebViewBridgeTest {
boolean gotException = false;
try {
WebViewBridge.handleInvocation(null, "apiTestMethod", new Object[]{"test"}, new MockWebViewCallback("APICALLBACK_01", 1));
WebViewBridge.getInstance().handleInvocation(null, "apiTestMethod", new Object[]{"test"}, new MockWebViewCallback("APICALLBACK_01", 1));
}
catch (NoSuchMethodException e) {
assertEquals("Should have received exception of type NoSuchMethodException", NoSuchMethodException.class, e.getClass());
@ -180,7 +183,7 @@ public class WebViewBridgeTest {
boolean gotException = false;
try {
WebViewBridge.handleInvocation("com.unity3d.ads.test.legacy.WebViewBridgeTest$WebViewBridgeTestApina", "apiTestMethod", new Object[]{"test"}, new MockWebViewCallback("APICALLBACK_01", 1));
WebViewBridge.getInstance().handleInvocation("com.unity3d.ads.test.legacy.WebViewBridgeTest$WebViewBridgeTestApina", "apiTestMethod", new Object[]{"test"}, new MockWebViewCallback("APICALLBACK_01", 1));
}
catch (NoSuchMethodException e) {
assertEquals("Should have received exception of type NoSuchMethodException", NoSuchMethodException.class, e.getClass());
@ -198,7 +201,7 @@ public class WebViewBridgeTest {
boolean gotException = false;
try {
WebViewBridge.handleInvocation("com.unity3d.ads.test.legacy.WebViewBridgeTest$WebViewBridgeTestApi", "apinaTestMethod", new Object[]{"test"}, new MockWebViewCallback("APICALLBACK_01", 1));
WebViewBridge.getInstance().handleInvocation("com.unity3d.ads.test.legacy.WebViewBridgeTest$WebViewBridgeTestApi", "apinaTestMethod", new Object[]{"test"}, new MockWebViewCallback("APICALLBACK_01", 1));
}
catch (NoSuchMethodException e) {
assertEquals("Should have received exception of type NoSuchMethodException", NoSuchMethodException.class, e.getClass());
@ -213,7 +216,7 @@ public class WebViewBridgeTest {
@Test (expected = NullPointerException.class)
public void testAllSetParametersWrong () throws Exception {
WebViewBridge.handleInvocation("com.unity3d.ads.test.legacy.WebViewBridgeTest$WebViewBridgeTestApi", "apiTestMethod", new Object[]{1, "test"}, new MockWebViewCallback("APICALLBACK_01", 1));
WebViewBridge.getInstance().handleInvocation("com.unity3d.ads.test.legacy.WebViewBridgeTest$WebViewBridgeTestApi", "apiTestMethod", new Object[]{1, "test"}, new MockWebViewCallback("APICALLBACK_01", 1));
}
@Test
@ -221,7 +224,7 @@ public class WebViewBridgeTest {
boolean gotException = false;
try {
WebViewBridge.handleInvocation("", "apiTestMethod", new Object[]{"test"}, new MockWebViewCallback("APICALLBACK_01", 1));
WebViewBridge.getInstance().handleInvocation("", "apiTestMethod", new Object[]{"test"}, new MockWebViewCallback("APICALLBACK_01", 1));
}
catch (NoSuchMethodException e) {
assertEquals("Should have received exception of type NoSuchMethodException", NoSuchMethodException.class, e.getClass());
@ -239,7 +242,7 @@ public class WebViewBridgeTest {
boolean gotException = false;
try {
WebViewBridge.handleInvocation("com.unity3d.ads.test.legacy.WebViewBridgeTest$WebViewBridgeTestApi", "", new Object[]{"test"}, new MockWebViewCallback("APICALLBACK_01", 1));
WebViewBridge.getInstance().handleInvocation("com.unity3d.ads.test.legacy.WebViewBridgeTest$WebViewBridgeTestApi", "", new Object[]{"test"}, new MockWebViewCallback("APICALLBACK_01", 1));
}
catch (NoSuchMethodException e) {
assertEquals("Should have received exception of type NoSuchMethodException", NoSuchMethodException.class, e.getClass());
@ -254,7 +257,7 @@ public class WebViewBridgeTest {
@Test (expected = IllegalArgumentException.class)
public void testOthersSetCallbackNull () throws Exception {
WebViewBridge.handleInvocation("com.unity3d.ads.test.legacy.WebViewBridgeTest$WebViewBridgeTestApi", "apiTestMethod", new Object[]{"test"}, null);
WebViewBridge.getInstance().handleInvocation("com.unity3d.ads.test.legacy.WebViewBridgeTest$WebViewBridgeTestApi", "apiTestMethod", new Object[]{"test"}, null);
}
public class MockWebViewCallback extends WebViewCallback {
@ -296,7 +299,7 @@ public class WebViewBridgeTest {
boolean gotException = false;
try {
WebViewBridge.handleInvocation("com.unity3d.ads.test.legacy.WebViewBridgeTest$WebViewBridgeTestApi", "wrongMethodName", new Object[]{"test"}, new MockWebViewCallback("APICALLBACK_01", 1));
WebViewBridge.getInstance().handleInvocation("com.unity3d.ads.test.legacy.WebViewBridgeTest$WebViewBridgeTestApi", "wrongMethodName", new Object[]{"test"}, new MockWebViewCallback("APICALLBACK_01", 1));
}
catch (Exception e) {
assertEquals("Should have received exception of type NoSuchMethodException", NoSuchMethodException.class, e.getClass());
@ -314,7 +317,7 @@ public class WebViewBridgeTest {
@Test
public void testAllSetMethodNoParams () throws Exception {
WebViewBridge.handleInvocation("com.unity3d.ads.test.legacy.WebViewBridgeTest$WebViewBridgeTestApi", "apiTestMethodNoParams", new Object[]{}, new MockWebViewCallback("APICALLBACK_01", 1));
WebViewBridge.getInstance().handleInvocation("com.unity3d.ads.test.legacy.WebViewBridgeTest$WebViewBridgeTestApi", "apiTestMethodNoParams", new Object[]{}, new MockWebViewCallback("APICALLBACK_01", 1));
assertEquals(true, WebViewBridgeTestApi.invoked);
assertNull(WebViewBridgeTestApi.value);
assertNotNull(WebViewBridgeTestApi.callback);
@ -323,7 +326,7 @@ public class WebViewBridgeTest {
@Test
public void testOthersSetParametersNullMethodNoParams () throws Exception {
WebViewBridge.handleInvocation("com.unity3d.ads.test.legacy.WebViewBridgeTest$WebViewBridgeTestApi", "apiTestMethodNoParams", null, new MockWebViewCallback("APICALLBACK_01", 1));
WebViewBridge.getInstance().handleInvocation("com.unity3d.ads.test.legacy.WebViewBridgeTest$WebViewBridgeTestApi", "apiTestMethodNoParams", null, new MockWebViewCallback("APICALLBACK_01", 1));
assertEquals(true, WebViewBridgeTestApi.invoked);
assertNull(WebViewBridgeTestApi.value);
assertNotNull(WebViewBridgeTestApi.callback);
@ -332,7 +335,7 @@ public class WebViewBridgeTest {
@Test
public void testAllSetCorrectly () throws Exception {
WebViewBridge.handleInvocation("com.unity3d.ads.test.legacy.WebViewBridgeTest$WebViewBridgeTestApi", "apiTestMethod", new Object[]{"test"}, new MockWebViewCallback("APICALLBACK_01", 1));
WebViewBridge.getInstance().handleInvocation("com.unity3d.ads.test.legacy.WebViewBridgeTest$WebViewBridgeTestApi", "apiTestMethod", new Object[]{"test"}, new MockWebViewCallback("APICALLBACK_01", 1));
assertEquals(true, WebViewBridgeTestApi.invoked);
assertEquals("test", WebViewBridgeTestApi.value);
assertNotNull(WebViewBridgeTestApi.callback);
@ -341,7 +344,7 @@ public class WebViewBridgeTest {
@Test
public void testAllSetCallbackEmpty () throws Exception {
WebViewBridge.handleInvocation("com.unity3d.ads.test.legacy.WebViewBridgeTest$WebViewBridgeTestApi", "apiTestMethod", new Object[]{"test"}, new MockWebViewCallback("", 1));
WebViewBridge.getInstance().handleInvocation("com.unity3d.ads.test.legacy.WebViewBridgeTest$WebViewBridgeTestApi", "apiTestMethod", new Object[]{"test"}, new MockWebViewCallback("", 1));
assertEquals(true, WebViewBridgeTestApi.invoked);
assertEquals("test", WebViewBridgeTestApi.value);
assertNotNull(WebViewBridgeTestApi.callback);
@ -365,7 +368,7 @@ public class WebViewBridgeTest {
NativeCallback ncb = new NativeCallback(ncbm);
WebViewApp.getCurrentApp().addCallback(ncb);
Object[] params = new Object[]{"Test"};
WebViewBridge.handleCallback(ncb.getId(), CallbackStatus.OK.toString(), params);
WebViewBridge.getInstance().handleCallback(ncb.getId(), CallbackStatus.OK.toString(), params);
assertEquals("Native Callback status was expected to be OK", CallbackStatus.OK, nativeCallbackStatus);
assertTrue("Native Callback should have finished", nativeCallbackFinished);
assertEquals("Native callback should have received a string as a parameter with value \"Test\"", "Test", nativeCallbackValue);
@ -377,7 +380,7 @@ public class WebViewBridgeTest {
NativeCallback ncb = new NativeCallback(ncbm);
WebViewApp.getCurrentApp().addCallback(ncb);
Object[] params = null;
WebViewBridge.handleCallback(ncb.getId(), CallbackStatus.OK.toString(), params);
WebViewBridge.getInstance().handleCallback(ncb.getId(), CallbackStatus.OK.toString(), params);
assertEquals("Native Callback status was expected to be OK", CallbackStatus.OK, nativeCallbackStatus);
assertTrue("Native Callback should have finished", nativeCallbackFinished);
assertNull("Native callback should have not received a value \"Test\"", nativeCallbackValue);
@ -389,7 +392,7 @@ public class WebViewBridgeTest {
NativeCallback ncb = new NativeCallback(ncbm);
WebViewApp.getCurrentApp().addCallback(ncb);
Object[] params = new Object[]{"Test"};
WebViewBridge.handleCallback(ncb.getId(), "INVALID_STATUS", params);
WebViewBridge.getInstance().handleCallback(ncb.getId(), "INVALID_STATUS", params);
}
@Test (expected = NullPointerException.class)

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

@ -62,7 +62,7 @@ public class MetricCommonTagsTest {
mediationMetaData.set("adapter_version", "456");
mediationMetaData.commit();
currentTags = commonTags.asMap();
currentTags = commonTags.toMap();
assertNull("Incorrect metricSampleRate value", currentTags.get("msr"));
assertEquals("Incorrect mediation name value", "MediationNetwork", currentTags.get("m_name"));
@ -78,7 +78,7 @@ public class MetricCommonTagsTest {
MetricCommonTags commonTags = new MetricCommonTags();
currentTags = commonTags.asMap();
currentTags = commonTags.toMap();
assertNull("Incorrect mediation name value", currentTags.get("m_name"));
assertNull("Incorrect mediation version value", currentTags.get("m_ver"));
@ -90,7 +90,7 @@ public class MetricCommonTagsTest {
mediationMetaData.set("adapter_version", "456");
mediationMetaData.commit();
currentTags = commonTags.asMap();
currentTags = commonTags.toMap();
assertEquals("Incorrect mediation name value", "MediationNetwork", currentTags.get("m_name"));
assertEquals("Incorrect mediation version value", "123", currentTags.get("m_ver"));
@ -104,7 +104,7 @@ public class MetricCommonTagsTest {
MetricCommonTags commonTags = new MetricCommonTags();
currentTags = commonTags.asMap();
currentTags = commonTags.toMap();
assertNull("Incorrect mediation name value", currentTags.get("m_name"));
assertNull("Incorrect mediation version value", currentTags.get("m_ver"));
@ -116,7 +116,7 @@ public class MetricCommonTagsTest {
mediationMetaData.set("adapter_version", "456");
mediationMetaData.commit();
currentTags = commonTags.asMap();
currentTags = commonTags.toMap();
assertNull("Incorrect mediation name value", currentTags.get("m_name"));
assertEquals("Incorrect mediation version value", "123", currentTags.get("m_ver"));
@ -130,7 +130,7 @@ public class MetricCommonTagsTest {
MetricCommonTags commonTags = new MetricCommonTags();
currentTags = commonTags.asMap();
currentTags = commonTags.toMap();
assertNull("Incorrect experiment tag tsi_prw value", currentTags.get("tsi_prw"));
assertNull("Incorrect experiment tag wac value", currentTags.get("wac"));
@ -148,7 +148,7 @@ public class MetricCommonTagsTest {
MetricCommonTags commonTags = new MetricCommonTags();
commonTags.updateWithConfig(configMock);
currentTags = commonTags.asMap();
currentTags = commonTags.toMap();
assertNull("Incorrect experiment tag tsi_prw value", currentTags.get("tsi_prw"));
assertEquals("Incorrect experiment tag wac value","true", currentTags.get("wac"));

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

@ -5,6 +5,8 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="com.google.android.gms.permission.AD_ID"/>
<uses-permission android:name="android.permission.ACCESS_ADSERVICES_TOPICS" />
<uses-permission android:name="android.permission.ACCESS_ADSERVICES_ATTRIBUTION" />
<application>
<activity
@ -48,6 +50,10 @@
android:name="com.unity3d.services.core.configuration.AdsSdkInitializer"
android:value="androidx.startup" />
</provider>
<property android:name="android.adservices.AD_SERVICES_CONFIG"
android:resource="@xml/ad_services_config" />
</application>
</manifest>

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

@ -3,12 +3,13 @@ package com.unity3d.services
import com.unity3d.services.core.domain.ISDKDispatchers
import com.unity3d.services.core.request.metrics.Metric
import com.unity3d.services.core.request.metrics.SDKMetrics
import com.unity3d.services.core.request.metrics.SDKMetricsSender
import kotlinx.coroutines.CoroutineExceptionHandler
import java.lang.IllegalStateException
import java.lang.RuntimeException
import kotlin.coroutines.CoroutineContext
class SDKErrorHandler(private val dispatchers: ISDKDispatchers) : CoroutineExceptionHandler {
class SDKErrorHandler(private val dispatchers: ISDKDispatchers, private val sdkMetricsSender: SDKMetricsSender) : CoroutineExceptionHandler {
override val key = CoroutineExceptionHandler.Key
@ -25,9 +26,9 @@ class SDKErrorHandler(private val dispatchers: ISDKDispatchers) : CoroutineExcep
else -> "native_exception"
}
sendMetric(Metric(name, "{$className}_$line", null))
sendMetric(Metric(name, "{$className}_$line"))
}
private fun sendMetric(metric: Metric) = SDKMetrics.getInstance().sendMetric(metric);
private fun sendMetric(metric: Metric) = sdkMetricsSender.sendMetric(metric);
}

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

@ -1,187 +0,0 @@
package com.unity3d.services;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.os.Build;
import android.text.TextUtils;
import com.unity3d.ads.IUnityAdsInitializationListener;
import com.unity3d.ads.UnityAds;
import com.unity3d.services.core.configuration.Configuration;
import com.unity3d.services.core.configuration.ConfigurationReader;
import com.unity3d.services.core.configuration.EnvironmentCheck;
import com.unity3d.services.core.configuration.InitializeEventsMetricSender;
import com.unity3d.services.core.configuration.InitializeThread;
import com.unity3d.services.core.device.Device;
import com.unity3d.services.core.log.DeviceLog;
import com.unity3d.services.core.properties.ClientProperties;
import com.unity3d.services.core.properties.SdkProperties;
import com.unity3d.services.core.properties.Session;
public class UnityServices {
public enum UnityServicesError {
INVALID_ARGUMENT,
INIT_SANITY_CHECK_FAIL
}
/**
* Initializes Unity Ads. Unity Ads should be initialized when app starts.
* @param context Current Android application context of calling app
* @param gameId Unique identifier for a game, given by Unity Ads admin tools or Unity editor
* @param testMode If true, only test ads are shown
* @param initializationListener Listener for IUnityAdsInitializationListener callbacks
*/
public static void initialize(final Context context, final String gameId, final boolean testMode, final IUnityAdsInitializationListener initializationListener) {
DeviceLog.entered();
if (SdkProperties.getCurrentInitializationState() != SdkProperties.InitializationState.NOT_INITIALIZED) {
String differingParameters = "";
String previousGameId = ClientProperties.getGameId();
if (previousGameId != null && !previousGameId.equals(gameId)) {
differingParameters += createExpectedParametersString("Game ID", ClientProperties.getGameId(), gameId);
}
boolean previousTestMode = SdkProperties.isTestMode();
if (previousTestMode != testMode) {
differingParameters += createExpectedParametersString("Test Mode", previousTestMode, testMode);
}
if (!TextUtils.isEmpty(differingParameters)) {
String message = "Unity Ads SDK failed to initialize due to already being initialized with different parameters" + differingParameters;
DeviceLog.warning(message);
if (initializationListener != null) {
initializationListener.onInitializationFailed(UnityAds.UnityAdsInitializationError.INVALID_ARGUMENT, message);
}
return;
}
}
SdkProperties.addInitializationListener(initializationListener);
if(SdkProperties.getCurrentInitializationState() == SdkProperties.InitializationState.INITIALIZED_SUCCESSFULLY) {
SdkProperties.notifyInitializationComplete();
return;
}
if(SdkProperties.getCurrentInitializationState() == SdkProperties.InitializationState.INITIALIZED_FAILED) {
SdkProperties.notifyInitializationFailed(UnityAds.UnityAdsInitializationError.INTERNAL_ERROR, "Unity Ads SDK failed to initialize due to previous failed reason");
return;
}
if(SdkProperties.getCurrentInitializationState() == SdkProperties.InitializationState.INITIALIZING) {
return;
}
SdkProperties.setInitializeState(SdkProperties.InitializationState.INITIALIZING);
ClientProperties.setGameId(gameId);
SdkProperties.setTestMode(testMode);
if(!isSupported()) {
DeviceLog.error("Error while initializing Unity Services: device is not supported");
SdkProperties.notifyInitializationFailed(UnityAds.UnityAdsInitializationError.INTERNAL_ERROR, "Unity Ads SDK failed to initialize due to device is not supported");
return;
}
SdkProperties.setInitializationTime(Device.getElapsedRealtime());
SdkProperties.setInitializationTimeSinceEpoch(System.currentTimeMillis());
if(gameId == null || gameId.length() == 0) {
DeviceLog.error("Error while initializing Unity Services: empty game ID, halting Unity Ads init");
SdkProperties.notifyInitializationFailed(UnityAds.UnityAdsInitializationError.INVALID_ARGUMENT, "Unity Ads SDK failed to initialize due to empty game ID");
return;
}
if(context == null) {
DeviceLog.error("Error while initializing Unity Services: null context, halting Unity Ads init");
SdkProperties.notifyInitializationFailed(UnityAds.UnityAdsInitializationError.INVALID_ARGUMENT, "Unity Ads SDK failed to initialize due to null context");
return;
}
if (context instanceof Application) {
ClientProperties.setApplication((Application) context);
} else if (context instanceof Activity) {
if (((Activity) context).getApplication() != null) {
ClientProperties.setApplication(((Activity) context).getApplication());
} else {
DeviceLog.error("Error while initializing Unity Services: cannot retrieve application from context, halting Unity Ads init");
SdkProperties.notifyInitializationFailed(UnityAds.UnityAdsInitializationError.INVALID_ARGUMENT, "Unity Ads SDK failed to initialize due to inability to retrieve application from context");
return;
}
} else {
DeviceLog.error("Error while initializing Unity Services: invalid context, halting Unity Ads init");
SdkProperties.notifyInitializationFailed(UnityAds.UnityAdsInitializationError.INVALID_ARGUMENT, "Unity Ads SDK failed to initialize due to invalid context");
return;
}
if(testMode) {
DeviceLog.info("Initializing Unity Services " + SdkProperties.getVersionName() + " (" + SdkProperties.getVersionCode() + ") with game id " + gameId + " in test mode, session " + Session.Default.getId());
} else {
DeviceLog.info("Initializing Unity Services " + SdkProperties.getVersionName() + " (" + SdkProperties.getVersionCode() + ") with game id " + gameId + " in production mode, session " + Session.Default.getId());
}
SdkProperties.setDebugMode(SdkProperties.getDebugMode());
if (context.getApplicationContext() != null) {
ClientProperties.setApplicationContext(context.getApplicationContext());
} else {
DeviceLog.error("Error while initializing Unity Services: cannot retrieve application context, halting Unity Ads init");
SdkProperties.notifyInitializationFailed(UnityAds.UnityAdsInitializationError.INVALID_ARGUMENT, "Unity Ads SDK failed to initialize due to inability to retrieve application context");
return;
}
if(!EnvironmentCheck.isEnvironmentOk()) {
DeviceLog.error("Error during Unity Services environment check, halting Unity Services init");
SdkProperties.notifyInitializationFailed(UnityAds.UnityAdsInitializationError.INTERNAL_ERROR, "Unity Ads SDK failed to initialize due to environment check failed");
return;
}
DeviceLog.info("Unity Services environment check OK");
ConfigurationReader configurationReader = new ConfigurationReader();
Configuration configuration = configurationReader.getCurrentConfiguration();
boolean isNewInitFlow = configuration.getExperiments().isNewInitFlowEnabled();
InitializeEventsMetricSender.getInstance().setNewInitFlow(isNewInitFlow);
if (isNewInitFlow) {
UnityAdsSDK.INSTANCE.initialize();
} else {
InitializeThread.initialize(configuration);
}
}
public static boolean isSupported() {
return Build.VERSION.SDK_INT >= 16;
}
public static boolean isInitialized() {
return SdkProperties.isInitialized();
}
public static String getVersion() {
return SdkProperties.getVersionName();
}
/**
* Toggles debug mode on/off
*
* @param debugMode If true, debug mode is on and there will be lots of debug output from Unity Services. If false, there will be only some short log messages from Unity Services.
*/
public static void setDebugMode(boolean debugMode) {
SdkProperties.setDebugMode(debugMode);
}
/**
* Get current debug mode status
*
* @return If true, debug mode is on. If false, debug mode is off.
*/
public static boolean getDebugMode() {
return SdkProperties.getDebugMode();
}
private static String createExpectedParametersString(String fieldName, Object current, Object received) {
String currentSafeString = current == null ? "null" : current.toString();
String receivedSafeString = received == null ? "null" : received.toString();
return "\n - " + fieldName + " Current: " + currentSafeString + " | Received: " + receivedSafeString;
}
}

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

@ -0,0 +1,210 @@
package com.unity3d.services
import android.app.Activity
import android.app.Application
import android.content.Context
import com.unity3d.ads.IUnityAdsInitializationListener
import com.unity3d.ads.UnityAds
import com.unity3d.ads.UnityAds.UnityAdsInitializationError
import com.unity3d.services.UnityAdsSDK.initialize
import com.unity3d.services.core.configuration.ConfigurationReader
import com.unity3d.services.core.configuration.EnvironmentCheck
import com.unity3d.services.core.configuration.InitializeEventsMetricSender
import com.unity3d.services.core.configuration.InitializeThread
import com.unity3d.services.core.device.Device
import com.unity3d.services.core.log.DeviceLog
import com.unity3d.services.core.properties.ClientProperties
import com.unity3d.services.core.properties.SdkProperties
import com.unity3d.services.core.properties.SdkProperties.InitializationState
import com.unity3d.services.core.properties.Session.Default.id
import com.unity3d.services.core.request.metrics.InitMetric
object UnityServices {
/**
* Initializes Unity Ads. Unity Ads should be initialized when app starts.
* @param context Current Android application context of calling app
* @param gameId Unique identifier for a game, given by Unity Ads admin tools or Unity editor
* @param testMode If true, only test ads are shown
* @param initializationListener Listener for IUnityAdsInitializationListener callbacks
*/
@JvmStatic
fun initialize(
context: Context?,
gameId: String?,
testMode: Boolean,
initializationListener: IUnityAdsInitializationListener?
) {
DeviceLog.entered()
gameId?.toIntOrNull() ?: run {
initializationListener?.onInitializationFailed(
UnityAdsInitializationError.INVALID_ARGUMENT,
"gameId \"$gameId\" should be a number."
)
return
}
if (SdkProperties.getCurrentInitializationState() != InitializationState.NOT_INITIALIZED) {
val previousGameId = ClientProperties.getGameId()
val previousTestMode = SdkProperties.isTestMode()
val differingParameters = buildString {
if (previousGameId != null && previousGameId != gameId) {
appendLine(createExpectedParametersString("Game ID", previousGameId, gameId))
}
if (previousTestMode != testMode) {
appendLine(createExpectedParametersString("Test Mode", previousTestMode, testMode))
}
}
val params = if (differingParameters.isNotEmpty()) {
InitializeEventsMetricSender.getInstance().sendMetric(InitMetric.newInitDiffParams())
"different parameters: \n$differingParameters"
} else {
InitializeEventsMetricSender.getInstance().sendMetric(InitMetric.newInitSameParams())
"the same Game ID: $gameId and Test Mode: $testMode values."
}
DeviceLog.warning("Unity Ads SDK initialize has already been called with $params Responding with first initialization result.")
}
SdkProperties.addInitializationListener(initializationListener)
when (SdkProperties.getCurrentInitializationState()) {
InitializationState.INITIALIZED_SUCCESSFULLY -> {
SdkProperties.notifyInitializationComplete()
return
}
InitializationState.INITIALIZED_FAILED -> {
SdkProperties.notifyInitializationFailed(
UnityAds.UnityAdsInitializationError.INTERNAL_ERROR,
"Unity Ads SDK failed to initialize due to previous failed reason"
)
return
}
InitializationState.INITIALIZING -> return
else -> SdkProperties.setInitializeState(InitializationState.INITIALIZING)
}
ClientProperties.setGameId(gameId)
SdkProperties.setTestMode(testMode)
if (!isSupported) {
DeviceLog.error("Error while initializing Unity Services: device is not supported")
SdkProperties.notifyInitializationFailed(
UnityAds.UnityAdsInitializationError.INTERNAL_ERROR,
"Unity Ads SDK failed to initialize due to device is not supported"
)
return
}
SdkProperties.setInitializationTime(Device.getElapsedRealtime())
SdkProperties.setInitializationTimeSinceEpoch(System.currentTimeMillis())
if (gameId.isNullOrEmpty()) {
DeviceLog.error("Error while initializing Unity Services: empty game ID, halting Unity Ads init")
SdkProperties.notifyInitializationFailed(
UnityAds.UnityAdsInitializationError.INVALID_ARGUMENT,
"Unity Ads SDK failed to initialize due to empty game ID"
)
return
}
if (context == null) {
DeviceLog.error("Error while initializing Unity Services: null context, halting Unity Ads init")
SdkProperties.notifyInitializationFailed(
UnityAds.UnityAdsInitializationError.INVALID_ARGUMENT,
"Unity Ads SDK failed to initialize due to null context"
)
return
}
if (context is Application) {
ClientProperties.setApplication(context)
} else if (context is Activity) {
if (context.application != null) {
ClientProperties.setApplication(context.application)
} else {
DeviceLog.error("Error while initializing Unity Services: cannot retrieve application from context, halting Unity Ads init")
SdkProperties.notifyInitializationFailed(
UnityAds.UnityAdsInitializationError.INVALID_ARGUMENT,
"Unity Ads SDK failed to initialize due to inability to retrieve application from context"
)
return
}
} else {
DeviceLog.error("Error while initializing Unity Services: invalid context, halting Unity Ads init")
SdkProperties.notifyInitializationFailed(
UnityAds.UnityAdsInitializationError.INVALID_ARGUMENT,
"Unity Ads SDK failed to initialize due to invalid context"
)
return
}
val mode = if (testMode) "test mode" else "production mode"
DeviceLog.info("Initializing Unity Services ${SdkProperties.getVersionName()} (${SdkProperties.getVersionCode()}) with game id $gameId in $mode, session $id")
SdkProperties.setDebugMode(SdkProperties.getDebugMode())
if (context.applicationContext != null) {
ClientProperties.setApplicationContext(context.applicationContext)
} else {
DeviceLog.error("Error while initializing Unity Services: cannot retrieve application context, halting Unity Ads init")
SdkProperties.notifyInitializationFailed(
UnityAds.UnityAdsInitializationError.INVALID_ARGUMENT,
"Unity Ads SDK failed to initialize due to inability to retrieve application context"
)
return
}
if (!EnvironmentCheck.isEnvironmentOk()) {
DeviceLog.error("Error during Unity Services environment check, halting Unity Services init")
SdkProperties.notifyInitializationFailed(
UnityAds.UnityAdsInitializationError.INTERNAL_ERROR,
"Unity Ads SDK failed to initialize due to environment check failed"
)
return
}
DeviceLog.info("Unity Services environment check OK")
initialize()
}
@JvmStatic
val isSupported: Boolean = true
@JvmStatic
val isInitialized: Boolean
get() = SdkProperties.isInitialized()
@JvmStatic
val version: String
get() = SdkProperties.getVersionName()
@JvmStatic
var debugMode: Boolean
/**
* Get current debug mode status
*
* @return If true, debug mode is on. If false, debug mode is off.
*/
get() = SdkProperties.getDebugMode()
/**
* Toggles debug mode on/off
*
* @param debugMode If true, debug mode is on and there will be lots of debug output from Unity Services. If false, there will be only some short log messages from Unity Services.
*/
set(debugMode) {
SdkProperties.setDebugMode(debugMode)
}
private fun createExpectedParametersString(fieldName: String, current: Any?, received: Any?): String =
"- $fieldName Current: $current | Received: $received"
enum class UnityServicesError {
INVALID_ARGUMENT,
INIT_SANITY_CHECK_FAIL
}
}

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

@ -1,5 +1,7 @@
package com.unity3d.services.ads;
import static com.unity3d.services.core.misc.Utilities.wrapCustomerListener;
import android.app.Activity;
import android.content.Context;
@ -21,11 +23,12 @@ import com.unity3d.services.ads.token.AsyncTokenStorage;
import com.unity3d.services.ads.token.TokenStorage;
import com.unity3d.services.core.configuration.Configuration;
import com.unity3d.services.core.configuration.ConfigurationReader;
import com.unity3d.services.core.configuration.IExperiments;
import com.unity3d.services.core.log.DeviceLog;
import com.unity3d.services.core.misc.Utilities;
import com.unity3d.services.core.properties.ClientProperties;
import com.unity3d.services.core.request.metrics.AdOperationMetric;
import com.unity3d.services.core.request.metrics.SDKMetrics;
import com.unity3d.services.core.request.metrics.SDKMetricsSender;
import com.unity3d.services.core.webview.WebViewApp;
import com.unity3d.services.core.webview.bridge.WebViewBridgeInvoker;
@ -33,6 +36,9 @@ public final class UnityAdsImplementation implements IUnityAds {
private static Configuration configuration = null;
private static WebViewBridgeInvoker webViewBridgeInvoker = new WebViewBridgeInvoker();
private static IUnityAds instance;
private final TokenStorage tokenStorage = Utilities.getService(TokenStorage.class);
private final AsyncTokenStorage asyncTokenStorage = Utilities.getService(AsyncTokenStorage.class);
private final SDKMetricsSender sdkMetricsSender = Utilities.getService(SDKMetricsSender.class);
public static IUnityAds getInstance() {
if (instance == null) {
@ -138,7 +144,7 @@ public final class UnityAdsImplementation implements IUnityAds {
}
private void handleShowError(IUnityAdsShowListener showListener, String placementId, UnityAds.UnityAdsShowError error, String message) {
SDKMetrics.getInstance().sendMetricWithInitState(AdOperationMetric.newAdShowFailure(error, 0L));
sdkMetricsSender.sendMetricWithInitState(AdOperationMetric.newAdShowFailure(error, 0L));
if (showListener == null) return;
showListener.onUnityAdsShowFailure(placementId, error, message);
}
@ -172,7 +178,7 @@ public final class UnityAdsImplementation implements IUnityAds {
@Override
public String getToken() {
// Getting the available token from storage
final String token = TokenStorage.getInstance().getToken();
final String token = tokenStorage.getToken();
if (token == null || token.isEmpty()) {
return null;
}
@ -191,14 +197,16 @@ public final class UnityAdsImplementation implements IUnityAds {
return;
} else if (ClientProperties.getApplicationContext() == null) {
// Invalidating app Context.
listener.onUnityAdsTokenReady(null);
wrapCustomerListener(() ->
listener.onUnityAdsTokenReady(null));
return;
}
Configuration config = configuration == null ? new ConfigurationReader().getCurrentConfiguration() : configuration;
BiddingBaseManager manager = BiddingManagerFactory.getInstance().createManager(listener, config.getExperiments());
manager.start();
AsyncTokenStorage.getInstance().getToken(manager);
asyncTokenStorage.getToken(manager);
}
public static void setConfiguration(Configuration configuration) {

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

@ -1,34 +1,16 @@
package com.unity3d.services.ads.adunit;
import android.app.Activity;
import android.content.pm.ActivityInfo;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Build;
import android.content.Context;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
import com.unity3d.services.ads.api.AdUnit;
import com.unity3d.services.core.api.Intent;
import com.unity3d.services.core.log.DeviceLog;
import com.unity3d.services.core.misc.ViewUtilities;
import com.unity3d.services.core.webview.WebViewApp;
import com.unity3d.services.core.webview.WebViewEventCategory;
import com.unity3d.services.core.webview.bridge.SharedInstances;
import org.json.JSONArray;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
public class AdUnitActivity extends Activity {
public class AdUnitActivity extends Activity implements IAdUnitActivity {
public static final String EXTRA_VIEWS = "views";
public static final String EXTRA_ACTIVITY_ID = "activityId";
@ -38,480 +20,141 @@ public class AdUnitActivity extends Activity {
public static final String EXTRA_KEEP_SCREEN_ON = "keepScreenOn";
public static final String EXTRA_DISPLAY_CUTOUT_MODE = "displayCutoutMode";
protected AdUnitRelativeLayout _layout;
private String[] _views;
private int _orientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
private int _systemUiVisibility;
private int _activityId;
private ArrayList<Integer> _keyEventList;
boolean _keepScreenOn;
private Map<String, IAdUnitViewHandler> _viewHandlers;
private int _displayCutoutMode;
protected AdUnitActivityController _controller;
private final IAdUnitViewHandlerFactory _adUnitViewHandlerFactory = new AdUnitViewHandlerFactory();
protected AdUnitActivityController createController() {
return new AdUnitActivityController(this, SharedInstances.INSTANCE.getWebViewEventSender(), new AdUnitViewHandlerFactory());
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// This error condition will trigger if activity is backgrounded while activity is in foreground,
// app process is killed while app is in background and then app is yet again launched to foreground
if(WebViewApp.getCurrentApp() == null) {
DeviceLog.error("Unity Ads web app is null, closing Unity Ads activity from onCreate");
finish();
return;
}
AdUnit.setAdUnitActivity(this);
Intent.setActiveActivity(this);
createLayout();
ViewUtilities.removeViewFromParent(_layout);
addContentView(_layout, _layout.getLayoutParams());
AdUnitEvent event;
if (savedInstanceState == null) {
_views = getIntent().getStringArrayExtra(EXTRA_VIEWS);
_keyEventList = getIntent().getIntegerArrayListExtra(EXTRA_KEY_EVENT_LIST);
if (getIntent().hasExtra(EXTRA_ORIENTATION)) {
_orientation = getIntent().getIntExtra(EXTRA_ORIENTATION, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
}
if (getIntent().hasExtra(EXTRA_SYSTEM_UI_VISIBILITY)) {
_systemUiVisibility = getIntent().getIntExtra(EXTRA_SYSTEM_UI_VISIBILITY, 0);
}
if (getIntent().hasExtra(EXTRA_ACTIVITY_ID)) {
_activityId = getIntent().getIntExtra(EXTRA_ACTIVITY_ID, -1);
}
if (getIntent().hasExtra(EXTRA_DISPLAY_CUTOUT_MODE)) {
_displayCutoutMode = getIntent().getIntExtra(EXTRA_DISPLAY_CUTOUT_MODE, 0);
}
event = AdUnitEvent.ON_CREATE;
} else {
_views = savedInstanceState.getStringArray(EXTRA_VIEWS);
_orientation = savedInstanceState.getInt(EXTRA_ORIENTATION, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
_systemUiVisibility = savedInstanceState.getInt(EXTRA_SYSTEM_UI_VISIBILITY, 0);
_keyEventList = savedInstanceState.getIntegerArrayList(EXTRA_KEY_EVENT_LIST);
_keepScreenOn = savedInstanceState.getBoolean(EXTRA_KEEP_SCREEN_ON);
_activityId = savedInstanceState.getInt(EXTRA_ACTIVITY_ID, -1);
_displayCutoutMode = savedInstanceState.getInt(EXTRA_DISPLAY_CUTOUT_MODE, 0);
setKeepScreenOn(_keepScreenOn);
event = AdUnitEvent.ON_RESTORE;
}
setOrientation(_orientation);
setSystemUiVisibility(_systemUiVisibility);
setLayoutInDisplayCutoutMode(_displayCutoutMode);
if(_views != null) {
for (String viewName : _views) {
IAdUnitViewHandler handler = getViewHandler(viewName);
if (handler != null) {
handler.onCreate(this, savedInstanceState);
}
}
}
WebViewApp.getCurrentApp().sendEvent(WebViewEventCategory.ADUNIT, event, _activityId);
_controller = createController();
_controller.onCreate(savedInstanceState);
}
public AdUnitRelativeLayout getLayout() {
return _layout;
return _controller.getLayout();
}
@Override
protected void onStart() {
super.onStart();
if(WebViewApp.getCurrentApp() == null) {
if(!isFinishing()) {
DeviceLog.error("Unity Ads web app is null, closing Unity Ads activity from onStart");
finish();
}
return;
}
if (_viewHandlers != null) {
for (Map.Entry<String, IAdUnitViewHandler> entry : _viewHandlers.entrySet()) {
if (entry.getValue() != null) {
entry.getValue().onStart(this);
}
}
}
WebViewApp.getCurrentApp().sendEvent(WebViewEventCategory.ADUNIT, AdUnitEvent.ON_START, _activityId);
_controller.onStart();
}
@Override
protected void onStop() {
super.onStop();
if(WebViewApp.getCurrentApp() == null) {
if(!isFinishing()) {
DeviceLog.error("Unity Ads web app is null, closing Unity Ads activity from onStop");
finish();
}
return;
}
if (_viewHandlers != null) {
for (Map.Entry<String, IAdUnitViewHandler> entry : _viewHandlers.entrySet()) {
if (entry.getValue() != null) {
entry.getValue().onStop(this);
}
}
}
WebViewApp.getCurrentApp().sendEvent(WebViewEventCategory.ADUNIT, AdUnitEvent.ON_STOP, _activityId);
_controller.onStop();
}
@Override
protected void onResume() {
super.onResume();
if(WebViewApp.getCurrentApp() == null) {
if(!isFinishing()) {
DeviceLog.error("Unity Ads web app is null, closing Unity Ads activity from onResume");
finish();
}
return;
}
setViews(_views);
if (_viewHandlers != null) {
for (Map.Entry<String, IAdUnitViewHandler> entry : _viewHandlers.entrySet()) {
if (entry.getValue() != null) {
entry.getValue().onResume(this);
}
}
}
WebViewApp.getCurrentApp().sendEvent(WebViewEventCategory.ADUNIT, AdUnitEvent.ON_RESUME, _activityId);
_controller.onResume();
}
@Override
protected void onPause() {
super.onPause();
if(WebViewApp.getCurrentApp() == null) {
if(!isFinishing()) {
DeviceLog.error("Unity Ads web app is null, closing Unity Ads activity from onPause");
finish();
}
return;
}
if (WebViewApp.getCurrentApp().getWebView() == null) {
DeviceLog.warning("Unity Ads web view is null, from onPause");
} else if (isFinishing()) {
ViewUtilities.removeViewFromParent(WebViewApp.getCurrentApp().getWebView());
}
if (_viewHandlers != null) {
for (Map.Entry<String, IAdUnitViewHandler> entry : _viewHandlers.entrySet()) {
if (entry.getValue() != null) {
entry.getValue().onPause(this);
}
}
}
WebViewApp.getCurrentApp().sendEvent(WebViewEventCategory.ADUNIT, AdUnitEvent.ON_PAUSE, isFinishing(), _activityId);
_controller.onPause();
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(EXTRA_ORIENTATION, _orientation);
outState.putInt(EXTRA_SYSTEM_UI_VISIBILITY, _systemUiVisibility);
outState.putIntegerArrayList(EXTRA_KEY_EVENT_LIST, _keyEventList);
outState.putBoolean(EXTRA_KEEP_SCREEN_ON, _keepScreenOn);
outState.putStringArray(EXTRA_VIEWS, _views);
outState.putInt(EXTRA_ACTIVITY_ID, _activityId);
_controller.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
if(WebViewApp.getCurrentApp() == null) {
if(!isFinishing()) {
DeviceLog.error("Unity Ads web app is null, closing Unity Ads activity from onDestroy");
finish();
}
return;
}
WebViewApp.getCurrentApp().sendEvent(WebViewEventCategory.ADUNIT, AdUnitEvent.ON_DESTROY, isFinishing(), _activityId);
if (_viewHandlers != null) {
for (Map.Entry<String, IAdUnitViewHandler> entry : _viewHandlers.entrySet()) {
if (entry.getValue() != null) {
entry.getValue().onDestroy(this);
}
}
}
if (AdUnit.getCurrentAdUnitActivityId() == _activityId) {
AdUnit.setAdUnitActivity(null);
}
Intent.removeActiveActivity(this);
_controller.onDestroy();
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (_keyEventList != null) {
if (_keyEventList.contains(keyCode)) {
WebViewApp.getCurrentApp().sendEvent(WebViewEventCategory.ADUNIT, AdUnitEvent.KEY_DOWN, keyCode, event.getEventTime(), event.getDownTime(), event.getRepeatCount(), _activityId);
return true;
}
}
return false;
return _controller.onKeyDown(keyCode, event);
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
if (hasFocus) {
WebViewApp.getCurrentApp().sendEvent(WebViewEventCategory.ADUNIT, AdUnitEvent.ON_FOCUS_GAINED, _activityId);
} else {
WebViewApp.getCurrentApp().sendEvent(WebViewEventCategory.ADUNIT, AdUnitEvent.ON_FOCUS_LOST, _activityId);
}
_controller.onWindowFocusChanged(hasFocus);
super.onWindowFocusChanged(hasFocus);
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
try {
JSONArray permissionsArray = new JSONArray();
JSONArray grantResultsArray = new JSONArray();
for (String permission : permissions) {
permissionsArray.put(permission);
}
for (int grantResult : grantResults) {
grantResultsArray.put(grantResult);
}
WebViewApp.getCurrentApp().sendEvent(WebViewEventCategory.PERMISSIONS, PermissionsEvent.PERMISSIONS_RESULT, requestCode, permissionsArray, grantResultsArray);
}
catch (Exception e) {
WebViewApp.getCurrentApp().sendEvent(WebViewEventCategory.PERMISSIONS, PermissionsEvent.PERMISSIONS_ERROR, e.getMessage());
}
_controller.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
/* API */
@Override
public void setViewFrame (String view, int x, int y, int width, int height) {
IAdUnitViewHandler handler = getViewHandler(view);
View targetView = null;
if (view.equals("adunit")) {
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(width, height);
params.setMargins(x, y, 0, 0);
_layout.setLayoutParams(params);
}
else if (handler != null) {
targetView = handler.getView();
}
if (targetView != null) {
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(width, height);
params.setMargins(x, y, 0, 0);
targetView.setLayoutParams(params);
}
_controller.setViewFrame(view, x, y, width, height);
}
@Override
public Map<String, Integer> getViewFrame (String view) {
IAdUnitViewHandler handler = getViewHandler(view);
View targetView = null;
if (view.equals("adunit")) {
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams)_layout.getLayoutParams();
HashMap<String, Integer> map = new HashMap<>();
map.put("x", params.leftMargin);
map.put("y", params.topMargin);
map.put("width", _layout.getWidth());
map.put("height", _layout.getHeight());
return map;
}
else if (handler != null) {
targetView = handler.getView();
}
if (targetView != null) {
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams)targetView.getLayoutParams();
HashMap<String, Integer> map = new HashMap<>();
map.put("x", params.leftMargin);
map.put("y", params.topMargin);
map.put("width", targetView.getWidth());
map.put("height", targetView.getHeight());
return map;
}
return null;
return _controller.getViewFrame(view);
}
@Override
public void setViews (String[] views) {
String[] actualViews;
if (views == null)
actualViews = new String[0];
else
actualViews = views;
ArrayList<String> newViews = new ArrayList<>(Arrays.asList(actualViews));
if (_views == null) {
_views = new String[0];
}
ArrayList<String> removedViews = new ArrayList<>(Arrays.asList(_views));
removedViews.removeAll(newViews);
for (String view : removedViews) {
IAdUnitViewHandler handler = getViewHandler(view);
handler.destroy();
}
_views = actualViews;
for (String view : actualViews) {
if (view == null) {
continue;
}
IAdUnitViewHandler handler = getViewHandler(view);
handler.create(this);
if (!handleViewPlacement(handler.getView())) {
return;
}
}
_controller.setViews(views);
}
private boolean handleViewPlacement (View view) {
if (view == null) {
finish();
DeviceLog.error("Could not place view because it is null, finishing activity");
return false;
}
if (view.getParent() != null && view.getParent().equals(_layout)) {
_layout.bringChildToFront(view);
}
else {
ViewUtilities.removeViewFromParent(view);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
params.addRule(RelativeLayout.CENTER_IN_PARENT);
params.setMargins(0, 0, 0, 0);
view.setPadding(0, 0, 0, 0);
_layout.addView(view, params);
}
return true;
@Override
public Context getContext() {
return this;
}
@Override
public String[] getViews () {
return _views;
return _controller.getViews();
}
@Override
public void setOrientation (int orientation) {
_orientation = orientation;
setRequestedOrientation(orientation);
_controller.setOrientation(orientation);
}
// Returns true if successfully set, false if error
@Override
public boolean setKeepScreenOn(boolean keepScreenOn) {
_keepScreenOn = keepScreenOn;
// If activity is non-visual there is no window
if(getWindow() == null)
return false;
if(keepScreenOn) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
} else {
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
return true;
return _controller.setKeepScreenOn(keepScreenOn);
}
@Override
public boolean setSystemUiVisibility (int flags) {
_systemUiVisibility = flags;
if (Build.VERSION.SDK_INT >= 11) {
try {
getWindow().getDecorView().setSystemUiVisibility(flags);
return true;
}
catch (Exception e) {
DeviceLog.exception("Error while setting SystemUIVisibility", e);
return false;
}
}
return false;
return _controller.setSystemUiVisibility(flags);
}
@Override
public void setKeyEventList (ArrayList<Integer> keyevents) {
_keyEventList = keyevents;
_controller.setKeyEventList(keyevents);
}
public IAdUnitViewHandler getViewHandler(String name) {
IAdUnitViewHandler viewHandler;
if (_viewHandlers != null && _viewHandlers.containsKey(name)) {
viewHandler = _viewHandlers.get(name);
}
else {
viewHandler = _adUnitViewHandlerFactory.createViewHandler(name);
if (viewHandler != null) {
if (_viewHandlers == null) {
_viewHandlers = new HashMap<>();
}
_viewHandlers.put(name, viewHandler);
}
}
return viewHandler;
return _controller.getViewHandler(name);
}
@Override
public void setLayoutInDisplayCutoutMode(int flags) {
_displayCutoutMode = flags;
// LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES also needs system ui flags View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
if (Build.VERSION.SDK_INT >= 28 && getWindow() != null) {
WindowManager.LayoutParams lp = getWindow().getAttributes();
try {
Field layoutInDisplayCutoutMode = lp.getClass().getField("layoutInDisplayCutoutMode");
layoutInDisplayCutoutMode.setInt(lp, flags);
} catch (IllegalAccessException e) {
DeviceLog.debug("Error setting layoutInDisplayCutoutMode", e);
} catch (NoSuchFieldException e) {
DeviceLog.debug("Error getting layoutInDisplayCutoutMode", e);
}
}
_controller.setLayoutInDisplayCutoutMode(flags);
}
/* LAYOUT */
protected void createLayout () {
if (_layout != null) {
return;
}
_layout = new AdUnitRelativeLayout(this);
_layout.setLayoutParams(new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
ViewUtilities.setBackground(_layout, new ColorDrawable(Color.BLACK));
@Override
public Activity getActivity() {
return this;
}
}

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

@ -0,0 +1,498 @@
package com.unity3d.services.ads.adunit;
import static com.unity3d.services.ads.adunit.AdUnitActivity.*;
import android.content.pm.ActivityInfo;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Build;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
import com.unity3d.services.ads.api.AdUnit;
import com.unity3d.services.core.api.Intent;
import com.unity3d.services.core.log.DeviceLog;
import com.unity3d.services.core.misc.ViewUtilities;
import com.unity3d.services.core.webview.WebViewApp;
import com.unity3d.services.core.webview.WebViewEventCategory;
import com.unity3d.services.core.webview.bridge.IEventSender;
import org.json.JSONArray;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
public class AdUnitActivityController {
protected AdUnitRelativeLayout _layout;
private String[] _views;
private int _orientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
private int _systemUiVisibility;
private int _activityId;
private ArrayList<Integer> _keyEventList;
boolean _keepScreenOn;
private Map<String, IAdUnitViewHandler> _viewHandlers;
private int _displayCutoutMode;
private final IAdUnitActivity _adUnitActivity;
private final IEventSender _eventSender;
private final IAdUnitViewHandlerFactory _adUnitViewHandlerFactory;
public AdUnitActivityController(IAdUnitActivity activity, IEventSender eventSender, IAdUnitViewHandlerFactory adUnitViewHandlerFactory) {
_adUnitActivity = activity;
_eventSender = eventSender;
_adUnitViewHandlerFactory = adUnitViewHandlerFactory;
}
public void onCreate(Bundle savedInstanceState) {
// This error condition will trigger if activity is backgrounded while activity is in foreground,
// app process is killed while app is in background and then app is yet again launched to foreground
if(!_eventSender.canSend()) {
DeviceLog.error("Unity Ads web app is null, closing Unity Ads activity from onCreate");
_adUnitActivity.finish();
return;
}
AdUnit.setAdUnitActivity(_adUnitActivity);
Intent.setActiveActivity(_adUnitActivity.getActivity());
createLayout();
ViewUtilities.removeViewFromParent(_layout);
_adUnitActivity.addContentView(_layout, _layout.getLayoutParams());
AdUnitEvent event;
if (savedInstanceState == null) {
_views = _adUnitActivity.getIntent().getStringArrayExtra(EXTRA_VIEWS);
_keyEventList = _adUnitActivity.getIntent().getIntegerArrayListExtra(EXTRA_KEY_EVENT_LIST);
if (_adUnitActivity.getIntent().hasExtra(EXTRA_ORIENTATION)) {
_orientation = _adUnitActivity.getIntent().getIntExtra(EXTRA_ORIENTATION, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
}
if (_adUnitActivity.getIntent().hasExtra(EXTRA_SYSTEM_UI_VISIBILITY)) {
_systemUiVisibility = _adUnitActivity.getIntent().getIntExtra(EXTRA_SYSTEM_UI_VISIBILITY, 0);
}
if (_adUnitActivity.getIntent().hasExtra(EXTRA_ACTIVITY_ID)) {
_activityId = _adUnitActivity.getIntent().getIntExtra(EXTRA_ACTIVITY_ID, -1);
}
if (_adUnitActivity.getIntent().hasExtra(EXTRA_DISPLAY_CUTOUT_MODE)) {
_displayCutoutMode = _adUnitActivity.getIntent().getIntExtra(EXTRA_DISPLAY_CUTOUT_MODE, 0);
}
event = AdUnitEvent.ON_CREATE;
} else {
_views = savedInstanceState.getStringArray(EXTRA_VIEWS);
_orientation = savedInstanceState.getInt(EXTRA_ORIENTATION, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
_systemUiVisibility = savedInstanceState.getInt(EXTRA_SYSTEM_UI_VISIBILITY, 0);
_keyEventList = savedInstanceState.getIntegerArrayList(EXTRA_KEY_EVENT_LIST);
_keepScreenOn = savedInstanceState.getBoolean(EXTRA_KEEP_SCREEN_ON);
_activityId = savedInstanceState.getInt(EXTRA_ACTIVITY_ID, -1);
_displayCutoutMode = savedInstanceState.getInt(EXTRA_DISPLAY_CUTOUT_MODE, 0);
setKeepScreenOn(_keepScreenOn);
event = AdUnitEvent.ON_RESTORE;
}
setOrientation(_orientation);
setSystemUiVisibility(_systemUiVisibility);
setLayoutInDisplayCutoutMode(_displayCutoutMode);
if(_views != null) {
for (String viewName : _views) {
IAdUnitViewHandler handler = getViewHandler(viewName);
if (handler != null) {
handler.onCreate(_adUnitActivity, savedInstanceState);
}
}
}
_eventSender.sendEvent(WebViewEventCategory.ADUNIT, event, _activityId);
}
public AdUnitRelativeLayout getLayout() {
return _layout;
}
public void onStart() {
if(!_eventSender.canSend()) {
if(!_adUnitActivity.isFinishing()) {
DeviceLog.error("Unity Ads web app is null, closing Unity Ads activity from onStart");
_adUnitActivity.finish();
}
return;
}
if (_viewHandlers != null) {
for (Map.Entry<String, IAdUnitViewHandler> entry : _viewHandlers.entrySet()) {
if (entry.getValue() != null) {
entry.getValue().onStart(_adUnitActivity);
}
}
}
_eventSender.sendEvent(WebViewEventCategory.ADUNIT, AdUnitEvent.ON_START, _activityId);
}
public void onStop() {
if(!_eventSender.canSend()) {
if(!_adUnitActivity.isFinishing()) {
DeviceLog.error("Unity Ads web app is null, closing Unity Ads activity from onStop");
_adUnitActivity.finish();
}
return;
}
if (_viewHandlers != null) {
for (Map.Entry<String, IAdUnitViewHandler> entry : _viewHandlers.entrySet()) {
if (entry.getValue() != null) {
entry.getValue().onStop(_adUnitActivity);
}
}
}
_eventSender.sendEvent(WebViewEventCategory.ADUNIT, AdUnitEvent.ON_STOP, _activityId);
}
public void onResume() {
if(!_eventSender.canSend()) {
if(!_adUnitActivity.isFinishing()) {
DeviceLog.error("Unity Ads web app is null, closing Unity Ads activity from onResume");
_adUnitActivity.finish();
}
return;
}
setViews(_views);
if (_viewHandlers != null) {
for (Map.Entry<String, IAdUnitViewHandler> entry : _viewHandlers.entrySet()) {
if (entry.getValue() != null) {
entry.getValue().onResume(_adUnitActivity);
}
}
}
_eventSender.sendEvent(WebViewEventCategory.ADUNIT, AdUnitEvent.ON_RESUME, _activityId);
}
public void onPause() {
if(!_eventSender.canSend()) {
if(!_adUnitActivity.isFinishing()) {
DeviceLog.error("Unity Ads web app is null, closing Unity Ads activity from onPause");
_adUnitActivity.finish();
}
return;
}
if (WebViewApp.getCurrentApp().getWebView() == null) {
DeviceLog.warning("Unity Ads web view is null, from onPause");
} else if (_adUnitActivity.isFinishing()) {
ViewUtilities.removeViewFromParent(WebViewApp.getCurrentApp().getWebView());
}
if (_viewHandlers != null) {
for (Map.Entry<String, IAdUnitViewHandler> entry : _viewHandlers.entrySet()) {
if (entry.getValue() != null) {
entry.getValue().onPause(_adUnitActivity);
}
}
}
_eventSender.sendEvent(WebViewEventCategory.ADUNIT, AdUnitEvent.ON_PAUSE, _adUnitActivity.isFinishing(), _activityId);
}
public void onSaveInstanceState(Bundle outState) {
outState.putInt(EXTRA_ORIENTATION, _orientation);
outState.putInt(EXTRA_SYSTEM_UI_VISIBILITY, _systemUiVisibility);
outState.putIntegerArrayList(EXTRA_KEY_EVENT_LIST, _keyEventList);
outState.putBoolean(EXTRA_KEEP_SCREEN_ON, _keepScreenOn);
outState.putStringArray(EXTRA_VIEWS, _views);
outState.putInt(EXTRA_ACTIVITY_ID, _activityId);
}
public void onDestroy() {
if(!_eventSender.canSend()) {
if(!_adUnitActivity.isFinishing()) {
DeviceLog.error("Unity Ads web app is null, closing Unity Ads activity from onDestroy");
_adUnitActivity.finish();
}
return;
}
_eventSender.sendEvent(WebViewEventCategory.ADUNIT, AdUnitEvent.ON_DESTROY, _adUnitActivity.isFinishing(), _activityId);
if (_viewHandlers != null) {
for (Map.Entry<String, IAdUnitViewHandler> entry : _viewHandlers.entrySet()) {
if (entry.getValue() != null) {
entry.getValue().onDestroy(_adUnitActivity);
}
}
}
if (AdUnit.getCurrentAdUnitActivityId() == _activityId) {
AdUnit.setAdUnitActivity(null);
}
Intent.removeActiveActivity(_adUnitActivity.getActivity());
}
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (_keyEventList != null) {
if (_keyEventList.contains(keyCode)) {
_eventSender.sendEvent(WebViewEventCategory.ADUNIT, AdUnitEvent.KEY_DOWN, keyCode, event.getEventTime(), event.getDownTime(), event.getRepeatCount(), _activityId);
return true;
}
}
return false;
}
public void onWindowFocusChanged(boolean hasFocus) {
if (hasFocus) {
_eventSender.sendEvent(WebViewEventCategory.ADUNIT, AdUnitEvent.ON_FOCUS_GAINED, _activityId);
} else {
_eventSender.sendEvent(WebViewEventCategory.ADUNIT, AdUnitEvent.ON_FOCUS_LOST, _activityId);
}
}
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
try {
JSONArray permissionsArray = new JSONArray();
JSONArray grantResultsArray = new JSONArray();
for (String permission : permissions) {
permissionsArray.put(permission);
}
for (int grantResult : grantResults) {
grantResultsArray.put(grantResult);
}
_eventSender.sendEvent(WebViewEventCategory.PERMISSIONS, PermissionsEvent.PERMISSIONS_RESULT, requestCode, permissionsArray, grantResultsArray);
}
catch (Exception e) {
_eventSender.sendEvent(WebViewEventCategory.PERMISSIONS, PermissionsEvent.PERMISSIONS_ERROR, e.getMessage());
}
}
/* API */
public void setViewFrame (String view, int x, int y, int width, int height) {
IAdUnitViewHandler handler = getViewHandler(view);
View targetView = null;
if (view.equals("adunit")) {
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(width, height);
params.setMargins(x, y, 0, 0);
_layout.setLayoutParams(params);
}
else if (handler != null) {
targetView = handler.getView();
}
if (targetView != null) {
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(width, height);
params.setMargins(x, y, 0, 0);
targetView.setLayoutParams(params);
}
}
public Map<String, Integer> getViewFrame (String view) {
IAdUnitViewHandler handler = getViewHandler(view);
View targetView = null;
if (view.equals("adunit")) {
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams)_layout.getLayoutParams();
HashMap<String, Integer> map = new HashMap<>();
map.put("x", params.leftMargin);
map.put("y", params.topMargin);
map.put("width", _layout.getWidth());
map.put("height", _layout.getHeight());
return map;
}
else if (handler != null) {
targetView = handler.getView();
}
if (targetView != null) {
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams)targetView.getLayoutParams();
HashMap<String, Integer> map = new HashMap<>();
map.put("x", params.leftMargin);
map.put("y", params.topMargin);
map.put("width", targetView.getWidth());
map.put("height", targetView.getHeight());
return map;
}
return null;
}
public void setViews (String[] views) {
String[] actualViews;
if (views == null)
actualViews = new String[0];
else
actualViews = views;
ArrayList<String> newViews = new ArrayList<>(Arrays.asList(actualViews));
if (_views == null) {
_views = new String[0];
}
ArrayList<String> removedViews = new ArrayList<>(Arrays.asList(_views));
removedViews.removeAll(newViews);
for (String view : removedViews) {
IAdUnitViewHandler handler = getViewHandler(view);
handler.destroy();
}
_views = actualViews;
for (String view : actualViews) {
if (view == null) {
continue;
}
IAdUnitViewHandler handler = getViewHandler(view);
handler.create(_adUnitActivity);
if (!handleViewPlacement(handler.getView())) {
return;
}
}
}
private boolean handleViewPlacement (View view) {
if (view == null) {
_adUnitActivity.finish();
DeviceLog.error("Could not place view because it is null, finishing activity");
return false;
}
if (view.getParent() != null && view.getParent().equals(_layout)) {
_layout.bringChildToFront(view);
}
else {
ViewUtilities.removeViewFromParent(view);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
params.addRule(RelativeLayout.CENTER_IN_PARENT);
params.setMargins(0, 0, 0, 0);
view.setPadding(0, 0, 0, 0);
_layout.addView(view, params);
}
return true;
}
public String[] getViews () {
return _views;
}
public void setOrientation (int orientation) {
_orientation = orientation;
_adUnitActivity.setRequestedOrientation(orientation);
}
// Returns true if successfully set, false if error
public boolean setKeepScreenOn(boolean keepScreenOn) {
_keepScreenOn = keepScreenOn;
// If activity is non-visual there is no window
if(_adUnitActivity.getWindow() == null)
return false;
if(keepScreenOn) {
_adUnitActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
} else {
_adUnitActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
return true;
}
public boolean setSystemUiVisibility (int flags) {
_systemUiVisibility = flags;
if (Build.VERSION.SDK_INT >= 11) {
try {
_adUnitActivity.getWindow().getDecorView().setSystemUiVisibility(flags);
return true;
}
catch (Exception e) {
DeviceLog.exception("Error while setting SystemUIVisibility", e);
return false;
}
}
return false;
}
public void setKeyEventList (ArrayList<Integer> keyevents) {
_keyEventList = keyevents;
}
public IAdUnitViewHandler getViewHandler(String name) {
IAdUnitViewHandler viewHandler;
if (_viewHandlers != null && _viewHandlers.containsKey(name)) {
viewHandler = _viewHandlers.get(name);
}
else {
viewHandler = createViewHandler(name);
if (viewHandler != null) {
if (_viewHandlers == null) {
_viewHandlers = new HashMap<>();
}
_viewHandlers.put(name, viewHandler);
}
}
return viewHandler;
}
public void setLayoutInDisplayCutoutMode(int flags) {
_displayCutoutMode = flags;
// LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES also needs system ui flags View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
if (Build.VERSION.SDK_INT >= 28 && _adUnitActivity.getWindow() != null) {
WindowManager.LayoutParams lp = _adUnitActivity.getWindow().getAttributes();
try {
Field layoutInDisplayCutoutMode = lp.getClass().getField("layoutInDisplayCutoutMode");
layoutInDisplayCutoutMode.setInt(lp, flags);
} catch (IllegalAccessException e) {
DeviceLog.debug("Error setting layoutInDisplayCutoutMode", e);
} catch (NoSuchFieldException e) {
DeviceLog.debug("Error getting layoutInDisplayCutoutMode", e);
}
}
}
/* LAYOUT */
protected void createLayout () {
if (_layout != null) {
return;
}
_layout = new AdUnitRelativeLayout(_adUnitActivity.getContext());
_layout.setLayoutParams(new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
ViewUtilities.setBackground(_layout, new ColorDrawable(Color.BLACK));
}
private IAdUnitViewHandler createViewHandler(String name) {
return _adUnitViewHandlerFactory.createViewHandler(name);
}
}

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

@ -3,9 +3,11 @@ package com.unity3d.services.ads.adunit;
import android.os.ConditionVariable;
import com.unity3d.services.core.configuration.Configuration;
import com.unity3d.services.core.misc.Utilities;
import com.unity3d.services.core.request.metrics.AdOperationError;
import com.unity3d.services.core.request.metrics.AdOperationMetric;
import com.unity3d.services.core.request.metrics.SDKMetrics;
import com.unity3d.services.core.request.metrics.SDKMetricsSender;
import com.unity3d.services.core.webview.WebViewApp;
import com.unity3d.services.core.webview.bridge.CallbackStatus;
@ -16,6 +18,7 @@ import java.lang.reflect.Method;
public class AdUnitOpen {
private static ConditionVariable _waitShowStatus;
private static Configuration _configuration;
private static final SDKMetricsSender _sdkMetricsSender = Utilities.getService(SDKMetricsSender.class);
public static synchronized boolean open(String placementId, JSONObject options) throws NoSuchMethodException {
Method showCallback = AdUnitOpen.class.getMethod("showCallback", CallbackStatus.class);
@ -27,7 +30,7 @@ public class AdUnitOpen {
boolean success = _waitShowStatus.block(_configuration.getShowTimeout());
_waitShowStatus = null;
if (!success) {
SDKMetrics.getInstance().sendMetric(AdOperationMetric.newAdShowFailure(AdOperationError.timeout, Long.valueOf(_configuration.getShowTimeout())));
_sdkMetricsSender.sendMetric(AdOperationMetric.newAdShowFailure(AdOperationError.timeout, Long.valueOf(_configuration.getShowTimeout())));
}
return success;
}

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

@ -1,9 +1,15 @@
package com.unity3d.services.ads.adunit;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_POINTER_DOWN;
import static android.view.MotionEvent.ACTION_POINTER_UP;
import static android.view.MotionEvent.ACTION_UP;
import android.annotation.TargetApi;
import android.content.Context;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.view.InputEvent;
import android.view.MotionEvent;
import android.widget.RelativeLayout;
@ -13,6 +19,7 @@ public class AdUnitRelativeLayout extends RelativeLayout {
private final ArrayList<AdUnitMotionEvent> _motionEvents = new ArrayList<>();
private int _maxEvents = 10000;
private boolean _shouldCapture = false;
private InputEvent _lastInputEvent;
public AdUnitRelativeLayout(Context context) {
super(context);
@ -22,6 +29,13 @@ public class AdUnitRelativeLayout extends RelativeLayout {
public boolean onInterceptTouchEvent(MotionEvent e) {
super.onInterceptTouchEvent(e);
if (e.getActionMasked() == ACTION_UP ||
e.getActionMasked() == ACTION_DOWN ||
e.getActionMasked() == ACTION_POINTER_UP ||
e.getActionMasked() == ACTION_POINTER_DOWN) {
_lastInputEvent = e;
}
if (_shouldCapture) {
if (_motionEvents.size() < _maxEvents) {
boolean isObscured = (e.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0;
@ -102,4 +116,8 @@ public class AdUnitRelativeLayout extends RelativeLayout {
return returnArray;
}
public InputEvent getLastInputEvent() {
return _lastInputEvent;
}
}

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

@ -6,17 +6,17 @@ import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import com.unity3d.services.core.misc.ViewUtilities;
import com.unity3d.services.core.webview.bridge.SharedInstances;
public class AdUnitTransparentActivity extends AdUnitActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ViewUtilities.setBackground(super._layout, new ColorDrawable(Color.TRANSPARENT));
ViewUtilities.setBackground(super._controller._layout, new ColorDrawable(Color.TRANSPARENT));
}
@Override
protected void createLayout() {
super.createLayout();
ViewUtilities.setBackground(_layout, new ColorDrawable(Color.TRANSPARENT));
}
@Override
protected AdUnitActivityController createController() {
return new AdUnitTransparentActivityController(this, SharedInstances.INSTANCE.getWebViewEventSender(), new AdUnitViewHandlerFactory());
}
}

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

@ -0,0 +1,19 @@
package com.unity3d.services.ads.adunit;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import com.unity3d.services.core.misc.ViewUtilities;
import com.unity3d.services.core.webview.bridge.IEventSender;
public class AdUnitTransparentActivityController extends AdUnitActivityController {
public AdUnitTransparentActivityController(IAdUnitActivity activity, IEventSender eventSender, IAdUnitViewHandlerFactory adUnitViewHandlerFactory) {
super(activity, eventSender, adUnitViewHandlerFactory);
}
@Override
protected void createLayout() {
super.createLayout();
ViewUtilities.setBackground(_layout, new ColorDrawable(Color.TRANSPARENT));
}
}

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

@ -13,10 +13,10 @@ public class AdUnitViewHandlerFactory implements IAdUnitViewHandlerFactory {
public IAdUnitViewHandler createViewHandler(String name) {
if (WebViewApp.getCurrentApp() != null) {
Configuration configuration = WebViewApp.getCurrentApp().getConfiguration();
String[] list = configuration.getModuleConfigurationList();
Class[] list = configuration.getModuleConfigurationList();
for (String moduleName : list) {
IModuleConfiguration moduleConfig = configuration.getModuleConfiguration(moduleName);
for (Class moduleClass : list) {
IModuleConfiguration moduleConfig = configuration.getModuleConfiguration(moduleClass);
if (moduleConfig instanceof IAdsModuleConfiguration) {
Map<String, Class> adUnitViewHandlers = ((IAdsModuleConfiguration) moduleConfig).getAdUnitViewHandlers();
if (adUnitViewHandlers != null && adUnitViewHandlers.containsKey(name)) {

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

@ -0,0 +1,53 @@
package com.unity3d.services.ads.adunit;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import java.util.ArrayList;
import java.util.Map;
public interface IAdUnitActivity {
void finish();
void addContentView(View view, ViewGroup.LayoutParams params);
Intent getIntent();
boolean isFinishing();
void setRequestedOrientation(int orientation);
Window getWindow();
Context getContext();
void requestPermissions(String[] permissions, int requestCode);
String[] getViews();
int getRequestedOrientation();
void setViews(String[] viewList);
void setOrientation(int orientation);
boolean setKeepScreenOn(boolean screenOn);
boolean setSystemUiVisibility(int systemUiVisibility);
void setKeyEventList(ArrayList<Integer> keyEventList);
void setViewFrame(String view, int x, int y, int width, int height);
Map<String, Integer> getViewFrame(String view);
AdUnitRelativeLayout getLayout();
void setLayoutInDisplayCutoutMode(int displayCutoutMode);
Activity getActivity();
}

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

@ -4,14 +4,14 @@ import android.os.Bundle;
import android.view.View;
public interface IAdUnitViewHandler {
boolean create(AdUnitActivity activity);
boolean create(IAdUnitActivity activity);
boolean destroy();
View getView();
void onCreate(AdUnitActivity activity, Bundle savedInstanceState);
void onStart(AdUnitActivity activity);
void onStop(AdUnitActivity activity);
void onResume(AdUnitActivity activity);
void onPause(AdUnitActivity activity);
void onDestroy(AdUnitActivity activity);
void onCreate(IAdUnitActivity activity, Bundle savedInstanceState);
void onStart(IAdUnitActivity activity);
void onStop(IAdUnitActivity activity);
void onResume(IAdUnitActivity activity);
void onPause(IAdUnitActivity activity);
void onDestroy(IAdUnitActivity activity);
}

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

@ -13,14 +13,14 @@ public class VideoPlayerHandler implements IAdUnitViewHandler {
private RelativeLayout _videoContainer;
private VideoPlayerView _videoView;
public boolean create(AdUnitActivity activity) {
public boolean create(IAdUnitActivity activity) {
DeviceLog.entered();
if (_videoContainer == null) {
_videoContainer = new RelativeLayout(activity);
_videoContainer = new RelativeLayout(activity.getContext());
}
if (_videoView == null) {
_videoView = new VideoPlayerView(activity);
_videoView = new VideoPlayerView(activity.getContext());
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
params.addRule(RelativeLayout.CENTER_IN_PARENT);
_videoView.setLayoutParams(params);
@ -57,23 +57,23 @@ public class VideoPlayerHandler implements IAdUnitViewHandler {
return _videoContainer;
}
public void onCreate(AdUnitActivity activity, Bundle savedInstanceState) {
public void onCreate(IAdUnitActivity activity, Bundle savedInstanceState) {
create(activity);
}
public void onStart(AdUnitActivity activity) {
public void onStart(IAdUnitActivity activity) {
}
public void onStop(AdUnitActivity activity) {
public void onStop(IAdUnitActivity activity) {
}
public void onResume(AdUnitActivity activity) {
public void onResume(IAdUnitActivity activity) {
}
public void onPause(AdUnitActivity activity) {
public void onPause(IAdUnitActivity activity) {
destroy();
}
public void onDestroy(AdUnitActivity activity) {
public void onDestroy(IAdUnitActivity activity) {
}
}

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

@ -13,10 +13,10 @@ public class WebPlayerHandler implements IAdUnitViewHandler {
private static String webPlayerViewId = "webplayer";
public boolean create(AdUnitActivity activity) {
public boolean create(IAdUnitActivity activity) {
if (_webPlayerView == null) {
WebPlayerSettingsCache webPlayerSettingsCache = WebPlayerSettingsCache.getInstance();
_webPlayerView = new WebPlayerView(activity, webPlayerViewId, webPlayerSettingsCache.getWebSettings(webPlayerViewId), webPlayerSettingsCache.getWebPlayerSettings(webPlayerViewId));
_webPlayerView = new WebPlayerView(activity.getContext(), webPlayerViewId, webPlayerSettingsCache.getWebSettings(webPlayerViewId), webPlayerSettingsCache.getWebPlayerSettings(webPlayerViewId));
_webPlayerView.setEventSettings(webPlayerSettingsCache.getWebPlayerEventSettings(webPlayerViewId));
WebPlayerViewCache.getInstance().addWebPlayer(webPlayerViewId, _webPlayerView);
}
@ -40,23 +40,23 @@ public class WebPlayerHandler implements IAdUnitViewHandler {
return _webPlayerView;
}
public void onCreate(AdUnitActivity activity, Bundle savedInstanceState) {
public void onCreate(IAdUnitActivity activity, Bundle savedInstanceState) {
this.create(activity);
}
public void onStart(AdUnitActivity activity) {
public void onStart(IAdUnitActivity activity) {
}
public void onStop(AdUnitActivity activity) {
public void onStop(IAdUnitActivity activity) {
}
public void onResume(AdUnitActivity activity) {
public void onResume(IAdUnitActivity activity) {
}
public void onPause(AdUnitActivity activity) {
public void onPause(IAdUnitActivity activity) {
}
public void onDestroy(AdUnitActivity activity) {
public void onDestroy(IAdUnitActivity activity) {
if (activity.isFinishing()) {
destroy();
}

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

@ -7,7 +7,7 @@ import com.unity3d.services.core.misc.ViewUtilities;
import com.unity3d.services.core.webview.WebViewApp;
public class WebViewHandler implements IAdUnitViewHandler {
public boolean create(AdUnitActivity activity) {
public boolean create(IAdUnitActivity activity) {
return true;
}
@ -26,22 +26,22 @@ public class WebViewHandler implements IAdUnitViewHandler {
return null;
}
public void onCreate(AdUnitActivity activity, Bundle savedInstanceState) {
public void onCreate(IAdUnitActivity activity, Bundle savedInstanceState) {
}
public void onStart(AdUnitActivity activity) {
public void onStart(IAdUnitActivity activity) {
}
public void onStop(AdUnitActivity activity) {
public void onStop(IAdUnitActivity activity) {
}
public void onResume(AdUnitActivity activity) {
public void onResume(IAdUnitActivity activity) {
}
public void onPause(AdUnitActivity activity) {
public void onPause(IAdUnitActivity activity) {
}
public void onDestroy(AdUnitActivity activity) {
public void onDestroy(IAdUnitActivity activity) {
destroy();
}
}

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

@ -12,6 +12,7 @@ import com.unity3d.services.ads.adunit.AdUnitMotionEvent;
import com.unity3d.services.ads.adunit.AdUnitSoftwareActivity;
import com.unity3d.services.ads.adunit.AdUnitTransparentActivity;
import com.unity3d.services.ads.adunit.AdUnitTransparentSoftwareActivity;
import com.unity3d.services.ads.adunit.IAdUnitActivity;
import com.unity3d.services.core.log.DeviceLog;
import com.unity3d.services.core.misc.Utilities;
import com.unity3d.services.core.properties.ClientProperties;
@ -30,17 +31,17 @@ import java.util.Iterator;
import java.util.Map;
public class AdUnit {
private static AdUnitActivity _adUnitActivity;
private static IAdUnitActivity _adUnitActivity;
private static int _currentActivityId = -1;
private AdUnit () {
}
public static void setAdUnitActivity (AdUnitActivity activity) {
public static void setAdUnitActivity (IAdUnitActivity activity) {
_adUnitActivity = activity;
}
public static AdUnitActivity getAdUnitActivity () {
public static IAdUnitActivity getAdUnitActivity () {
return _adUnitActivity;
}

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

@ -0,0 +1,47 @@
package com.unity3d.services.ads.api;
import android.view.InputEvent;
import com.unity3d.services.ads.measurements.MeasurementsErrors;
import com.unity3d.services.ads.measurements.MeasurementsService;
import com.unity3d.services.core.misc.Utilities;
import com.unity3d.services.core.webview.bridge.WebViewCallback;
import com.unity3d.services.core.webview.bridge.WebViewExposed;
public class Measurements {
private static final MeasurementsService measurementsService = Utilities.getService(MeasurementsService.class);
@WebViewExposed
public static void checkAvailability(WebViewCallback callback) {
measurementsService.checkAvailability();
callback.invoke();
}
@WebViewExposed
public static void registerView(final String url, WebViewCallback callback) {
measurementsService.registerView(url);
callback.invoke();
}
@WebViewExposed
public static void registerClick(final String url, WebViewCallback callback) {
if (AdUnit.getAdUnitActivity() == null) {
callback.error(MeasurementsErrors.ERROR_AD_UNIT_NULL);
return;
}
if (AdUnit.getAdUnitActivity().getLayout() == null) {
callback.error(MeasurementsErrors.ERROR_LAYOUT_NULL);
return;
}
InputEvent lastInputEvent = AdUnit.getAdUnitActivity().getLayout().getLastInputEvent();
if (lastInputEvent == null) {
callback.error(MeasurementsErrors.ERROR_LAST_INPUT_EVENT_NULL);
return;
}
measurementsService.registerClick(url, lastInputEvent);
callback.invoke();
}
}

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

@ -2,6 +2,7 @@ package com.unity3d.services.ads.api;
import com.unity3d.services.ads.token.TokenError;
import com.unity3d.services.ads.token.TokenStorage;
import com.unity3d.services.core.misc.Utilities;
import com.unity3d.services.core.webview.bridge.WebViewCallback;
import com.unity3d.services.core.webview.bridge.WebViewExposed;
@ -9,10 +10,12 @@ import org.json.JSONArray;
import org.json.JSONException;
public class Token {
private static final TokenStorage tokenStorage = Utilities.getService(TokenStorage.class);
@WebViewExposed
public static void createTokens(JSONArray tokens, WebViewCallback callback) {
try {
TokenStorage.getInstance().createTokens(tokens);
tokenStorage.createTokens(tokens);
} catch (JSONException e) {
callback.error(TokenError.JSON_EXCEPTION, e.getMessage());
return;
@ -24,7 +27,7 @@ public class Token {
@WebViewExposed
public static void appendTokens(JSONArray tokens, WebViewCallback callback) {
try {
TokenStorage.getInstance().appendTokens(tokens);
tokenStorage.appendTokens(tokens);
} catch (JSONException e) {
callback.error(TokenError.JSON_EXCEPTION, e.getMessage());
return;
@ -35,21 +38,14 @@ public class Token {
@WebViewExposed
public static void deleteTokens(WebViewCallback callback) {
TokenStorage.getInstance().deleteTokens();
callback.invoke();
}
@WebViewExposed
public static void setPeekMode(Boolean mode, WebViewCallback callback) {
TokenStorage.getInstance().setPeekMode(mode);
tokenStorage.deleteTokens();
callback.invoke();
}
@WebViewExposed
public static void getNativeGeneratedToken(WebViewCallback callback) {
TokenStorage.getInstance().getNativeGeneratedToken();
tokenStorage.getNativeGeneratedToken();
callback.invoke();
}

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

@ -0,0 +1,21 @@
package com.unity3d.services.ads.api;
import com.unity3d.services.ads.topics.TopicsService;
import com.unity3d.services.core.misc.Utilities;
import com.unity3d.services.core.webview.bridge.WebViewCallback;
import com.unity3d.services.core.webview.bridge.WebViewExposed;
public class Topics {
private static final TopicsService topicsService = Utilities.getService(TopicsService.class);
@WebViewExposed
public static void checkAvailability(WebViewCallback callback) {
callback.invoke(topicsService.checkAvailability());
}
@WebViewExposed
public static void getTopics(String adsSdkName, Boolean shouldRecordObservation, WebViewCallback callback) {
topicsService.getTopics(adsSdkName, shouldRecordObservation);
callback.invoke();
}
}

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

@ -9,6 +9,7 @@ import com.unity3d.services.ads.token.TokenStorage;
import com.unity3d.services.core.configuration.Configuration;
import com.unity3d.services.core.configuration.ErrorState;
import com.unity3d.services.core.log.DeviceLog;
import com.unity3d.services.core.misc.Utilities;
import java.net.InetAddress;
import java.net.MalformedURLException;
@ -18,6 +19,8 @@ import java.util.Map;
public class AdsModuleConfiguration implements IAdsModuleConfiguration {
private InetAddress _address;
private final TokenStorage tokenStorage = Utilities.getService(TokenStorage.class);
private final AsyncTokenStorage asyncTokenStorage = Utilities.getService(AsyncTokenStorage.class);
public Class[] getWebAppApiClassList() {
Class[] list = {
@ -27,7 +30,9 @@ public class AdsModuleConfiguration implements IAdsModuleConfiguration {
com.unity3d.services.ads.api.Load.class,
com.unity3d.services.ads.api.Show.class,
com.unity3d.services.ads.api.Token.class,
com.unity3d.services.ads.api.GMAScar.class
com.unity3d.services.ads.api.GMAScar.class,
com.unity3d.services.ads.api.Measurements.class,
com.unity3d.services.ads.api.Topics.class,
};
return list;
@ -36,59 +41,21 @@ public class AdsModuleConfiguration implements IAdsModuleConfiguration {
public boolean resetState(Configuration configuration) {
AdUnitOpen.setConfiguration(configuration);
UnityAdsImplementation.setConfiguration(configuration);
TokenStorage.getInstance().deleteTokens();
AsyncTokenStorage.getInstance().setConfiguration(configuration);
return true;
}
public boolean initModuleState(Configuration configuration) {
DeviceLog.debug("Unity Ads init: checking for ad blockers");
final String configHost;
try {
configHost = new URL(configuration.getConfigUrl()).getHost();
} catch(MalformedURLException e) {
return true;
}
final ConditionVariable cv = new ConditionVariable();
new Thread() {
@Override
public void run() {
try {
_address = InetAddress.getByName(configHost);
cv.open();
} catch(Exception e) {
DeviceLog.exception("Couldn't get address. Host: " + configHost, e);
cv.open();
}
}
}.start();
// This is checking if config url is in /etc/hosts or equivalent. No need for long wait.
boolean success = cv.block(2000);
if(success && _address != null && _address.isLoopbackAddress()) {
DeviceLog.error("Unity Ads init: halting init because Unity Ads config resolves to loopback address (due to ad blocker?)");
return false;
}
AdUnitOpen.setConfiguration(configuration);
UnityAdsImplementation.setConfiguration(configuration);
AsyncTokenStorage.getInstance().setConfiguration(configuration);
tokenStorage.deleteTokens();
asyncTokenStorage.setConfiguration(configuration);
return true;
}
public boolean initErrorState(Configuration configuration, ErrorState state, String errorMessage) {
TokenStorage.getInstance().setInitToken(null);
TokenStorage.getInstance().deleteTokens();
tokenStorage.setInitToken(null);
tokenStorage.deleteTokens();
return true;
}
public boolean initCompleteState(Configuration configuration) {
AdUnitOpen.setConfiguration(configuration);
UnityAdsImplementation.setConfiguration(configuration);
AsyncTokenStorage.getInstance().setConfiguration(configuration);
asyncTokenStorage.setConfiguration(configuration);
return true;
}

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

@ -3,13 +3,14 @@ package com.unity3d.services.ads.gmascar.adapters;
import com.unity3d.scar.adapter.common.GMAAdsError;
import com.unity3d.scar.adapter.common.IAdsErrorHandler;
import com.unity3d.scar.adapter.common.IScarAdapter;
import com.unity3d.scar.adapter.common.WebViewAdsError;
import com.unity3d.services.ads.gmascar.finder.ScarAdapterVersion;
import com.unity3d.services.core.log.DeviceLog;
import com.unity3d.services.core.properties.SdkProperties;
public class ScarAdapterFactory {
public IScarAdapter createScarAdapter(ScarAdapterVersion adapterVersion, IAdsErrorHandler adsErrorHandler) {
public IScarAdapter createScarAdapter(ScarAdapterVersion adapterVersion, IAdsErrorHandler<WebViewAdsError> adsErrorHandler) {
IScarAdapter scarAdapter = null;
switch (adapterVersion) {
@ -32,7 +33,7 @@ public class ScarAdapterFactory {
return scarAdapter;
}
private void reportAdapterFailure(ScarAdapterVersion adapterVersion, IAdsErrorHandler adsErrorHandler) {
private void reportAdapterFailure(ScarAdapterVersion adapterVersion, IAdsErrorHandler<WebViewAdsError> adsErrorHandler) {
String errorMessage = String.format("SCAR version %s is not supported.", adapterVersion.name());
adsErrorHandler.handleError(GMAAdsError.AdapterCreationError(errorMessage));
DeviceLog.debug(errorMessage);

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

@ -2,14 +2,24 @@ package com.unity3d.services.ads.gmascar.handlers;
import com.unity3d.scar.adapter.common.IAdsErrorHandler;
import com.unity3d.scar.adapter.common.WebViewAdsError;
import com.unity3d.services.core.webview.WebViewApp;
import com.unity3d.services.core.webview.WebViewEventCategory;
import com.unity3d.services.core.webview.bridge.IEventSender;
import com.unity3d.services.core.webview.bridge.SharedInstances;
public class WebViewErrorHandler implements IAdsErrorHandler<WebViewAdsError> {
private final IEventSender _eventSender;
public WebViewErrorHandler() {
this(SharedInstances.INSTANCE.getWebViewEventSender());
}
public WebViewErrorHandler(IEventSender eventSender) {
_eventSender = eventSender;
}
@Override
public void handleError(WebViewAdsError webViewAdsError) {
WebViewEventCategory category = WebViewEventCategory.valueOf(webViewAdsError.getDomain());
WebViewApp.getCurrentApp().sendEvent(category, webViewAdsError.getErrorCategory(), webViewAdsError.getErrorArguments());
_eventSender.sendEvent(category, webViewAdsError.getErrorCategory(), webViewAdsError.getErrorArguments());
}
}

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

@ -1,6 +1,7 @@
package com.unity3d.services.ads.gmascar.managers;
import static com.unity3d.services.ads.gmascar.utils.ScarConstants.TOKEN_WITH_SCAR_FORMAT;
import static com.unity3d.services.core.misc.Utilities.wrapCustomerListener;
import com.unity3d.ads.IUnityAdsTokenListener;
import com.unity3d.services.ads.gmascar.GMA;
@ -8,7 +9,8 @@ import com.unity3d.services.ads.gmascar.listeners.IBiddingSignalsListener;
import com.unity3d.services.ads.gmascar.models.BiddingSignals;
import com.unity3d.services.ads.gmascar.utils.ScarRequestHandler;
import com.unity3d.services.core.configuration.ConfigurationReader;
import com.unity3d.services.core.request.metrics.ISDKMetrics;
import com.unity3d.services.core.misc.Utilities;
import com.unity3d.services.core.request.metrics.SDKMetricsSender;
import com.unity3d.services.core.request.metrics.SDKMetrics;
import com.unity3d.services.core.request.metrics.ScarMetric;
@ -58,7 +60,7 @@ public abstract class BiddingBaseManager implements IBiddingManager {
@Override
public final void onUnityAdsTokenReady(String token) {
if (unityAdsTokenListener != null) {
unityAdsTokenListener.onUnityAdsTokenReady(token);
wrapCustomerListener(() -> unityAdsTokenListener.onUnityAdsTokenReady(token));
}
if (token != null && !token.isEmpty()) {
@ -142,7 +144,7 @@ public abstract class BiddingBaseManager implements IBiddingManager {
}).start();
}
public ISDKMetrics getMetricSender() {
return SDKMetrics.getInstance();
public SDKMetricsSender getMetricSender() {
return Utilities.getService(SDKMetricsSender.class);
}
}

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

@ -1,16 +1,26 @@
package com.unity3d.services.ads.gmascar.utils;
import com.unity3d.scar.adapter.common.GMAEvent;
import com.unity3d.services.core.webview.WebViewApp;
import com.unity3d.services.core.webview.WebViewEventCategory;
import com.unity3d.services.core.webview.bridge.IEventSender;
import com.unity3d.services.core.webview.bridge.SharedInstances;
public class GMAEventSender {
private final IEventSender _eventSender;
public GMAEventSender() {
this(SharedInstances.INSTANCE.getWebViewEventSender());
}
public GMAEventSender(IEventSender eventSender) {
_eventSender = eventSender;
}
public void send(GMAEvent event, Object... params) {
WebViewApp.getCurrentApp().sendEvent(WebViewEventCategory.GMA, event, params);
_eventSender.sendEvent(WebViewEventCategory.GMA, event, params);
}
public void sendVersion(String version) {
WebViewApp.getCurrentApp().sendEvent(WebViewEventCategory.INIT_GMA, GMAEvent.VERSION, version);
_eventSender.sendEvent(WebViewEventCategory.INIT_GMA, GMAEvent.VERSION, version);
}
}

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

@ -5,35 +5,41 @@ import static com.unity3d.services.ads.gmascar.utils.ScarConstants.TOKEN_ID_KEY;
import com.unity3d.services.ads.gmascar.models.BiddingSignals;
import com.unity3d.services.core.device.Device;
import com.unity3d.services.core.request.WebRequest;
import com.unity3d.services.core.misc.Utilities;
import com.unity3d.services.core.network.core.HttpClient;
import com.unity3d.services.core.network.model.HttpRequest;
import com.unity3d.services.core.network.model.RequestType;
import org.json.JSONObject;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ScarRequestHandler {
private final HttpClient httpClient = Utilities.getService(HttpClient.class);
public ScarRequestHandler() {};
public ScarRequestHandler() {
}
public void makeUploadRequest(String tokenIdentifier, BiddingSignals signals, String url) throws Exception {
Map<String, List<String>> headers = new HashMap<>();
headers.put("Content-Type",
Collections.singletonList("application/json"));
Map<String, List<String>> headers = new HashMap<>();
headers.put("Content-Type", Collections.singletonList("application/json"));
final WebRequest request = new WebRequest(
url,
"POST",
headers);
Map<String, String> body = new HashMap<>();
body.put(IDFI_KEY, Device.getIdfi());
body.put(TOKEN_ID_KEY, tokenIdentifier);
body.putAll(signals.getMap());
Map<String, String> body = new HashMap<>();
body.put(IDFI_KEY, Device.getIdfi());
body.put(TOKEN_ID_KEY, tokenIdentifier);
body.putAll(signals.getMap());
request.setBody(new JSONObject(body).toString());
request.makeRequest();
HttpRequest request = new HttpRequest(
url,
"",
RequestType.POST,
new JSONObject(body).toString().getBytes(StandardCharsets.UTF_8),
headers
);
httpClient.executeBlocking(request);
}
}

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

@ -0,0 +1,12 @@
package com.unity3d.services.ads.measurements
enum class MeasurementsErrors {
ERROR_AD_SERVICES_DISABLED,
ERROR_EXTENSION_BELOW_4,
ERROR_API_BELOW_33,
ERROR_MANAGER_NULL,
ERROR_EXCEPTION,
ERROR_AD_UNIT_NULL,
ERROR_LAYOUT_NULL,
ERROR_LAST_INPUT_EVENT_NULL,
}

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

@ -0,0 +1,10 @@
package com.unity3d.services.ads.measurements
enum class MeasurementsEvents {
NOT_AVAILABLE,
AVAILABLE,
VIEW_SUCCESSFUL,
VIEW_ERROR,
CLICK_SUCCESSFUL,
CLICK_ERROR,
}

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

@ -0,0 +1,21 @@
package com.unity3d.services.ads.measurements
import android.annotation.SuppressLint
import android.os.OutcomeReceiver
import com.unity3d.services.core.webview.WebViewEventCategory
import com.unity3d.services.core.webview.bridge.IEventSender
@SuppressLint("NewApi", "MissingPermission")
class MeasurementsReceiver(
private val eventSender: IEventSender,
private val successEvent: MeasurementsEvents,
private val errorEvent: MeasurementsEvents,
): OutcomeReceiver<Any, Exception> {
override fun onResult(p0: Any) {
eventSender.sendEvent(WebViewEventCategory.MEASUREMENTS, successEvent)
}
override fun onError(error: Exception) {
eventSender.sendEvent(WebViewEventCategory.MEASUREMENTS, errorEvent, error.toString())
}
}

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

@ -0,0 +1,76 @@
package com.unity3d.services.ads.measurements
import android.adservices.AdServicesState
import android.adservices.measurement.MeasurementManager
import android.annotation.SuppressLint
import android.content.Context
import android.net.Uri
import android.os.OutcomeReceiver
import android.os.ext.SdkExtensions
import android.view.InputEvent
import com.unity3d.services.core.device.Device
import com.unity3d.services.core.domain.ISDKDispatchers
import com.unity3d.services.core.webview.WebViewEventCategory
import com.unity3d.services.core.webview.bridge.IEventSender
import kotlinx.coroutines.asExecutor
@SuppressLint("NewApi", "MissingPermission")
class MeasurementsService(context: Context, private val dispatchers: ISDKDispatchers, private val eventSender: IEventSender) {
private val measurementManager: MeasurementManager? = getMeasurementManager(context)
fun checkAvailability() {
if (Device.getApiLevel() < 33) {
eventSender.sendEvent(WebViewEventCategory.MEASUREMENTS, MeasurementsEvents.NOT_AVAILABLE, MeasurementsErrors.ERROR_API_BELOW_33)
return
}
if (SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES) < 4) {
eventSender.sendEvent(WebViewEventCategory.MEASUREMENTS, MeasurementsEvents.NOT_AVAILABLE, MeasurementsErrors.ERROR_EXTENSION_BELOW_4)
return
}
if (measurementManager == null) {
eventSender.sendEvent(WebViewEventCategory.MEASUREMENTS, MeasurementsEvents.NOT_AVAILABLE, MeasurementsErrors.ERROR_MANAGER_NULL)
return
}
if (!AdServicesState.isAdServicesStateEnabled()) {
eventSender.sendEvent(WebViewEventCategory.MEASUREMENTS, MeasurementsEvents.NOT_AVAILABLE, MeasurementsErrors.ERROR_AD_SERVICES_DISABLED)
return
}
measurementManager.getMeasurementApiStatus(dispatchers.default.asExecutor(), MeasurementsStatusReceiver(eventSender))
}
fun registerView(url: String) {
measurementManager?.registerSource(
Uri.parse(url),
null,
dispatchers.default.asExecutor(),
MeasurementsReceiver(eventSender, MeasurementsEvents.VIEW_SUCCESSFUL, MeasurementsEvents.VIEW_ERROR)
)
}
fun registerClick(url: String, inputEvent: InputEvent) {
measurementManager?.registerSource(
Uri.parse(url),
inputEvent,
dispatchers.default.asExecutor(),
MeasurementsReceiver(eventSender, MeasurementsEvents.CLICK_SUCCESSFUL, MeasurementsEvents.CLICK_ERROR)
)
}
private fun getMeasurementManager(context: Context): MeasurementManager? {
// accessing MeasurementManager without API level and extension version checks can crash old Android devices
// also accessing SdkExtensions below API level 30 causes exception so check API level first
if (Device.getApiLevel() < 33) {
return null
}
if (SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES) < 4) {
return null
}
return context.getSystemService(MeasurementManager::class.java)
}
}

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

@ -0,0 +1,17 @@
package com.unity3d.services.ads.measurements
import android.annotation.SuppressLint
import android.os.OutcomeReceiver
import com.unity3d.services.core.webview.WebViewEventCategory
import com.unity3d.services.core.webview.bridge.IEventSender
@SuppressLint("NewApi", "MissingPermission")
class MeasurementsStatusReceiver(private val eventSender: IEventSender) : OutcomeReceiver<Int, Exception> {
override fun onResult(status: Int) {
eventSender.sendEvent(WebViewEventCategory.MEASUREMENTS, MeasurementsEvents.AVAILABLE, status)
}
override fun onError(error: Exception) {
eventSender.sendEvent(WebViewEventCategory.MEASUREMENTS, MeasurementsEvents.NOT_AVAILABLE, MeasurementsErrors.ERROR_EXCEPTION, error.toString())
}
}

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

@ -1,6 +1,6 @@
package com.unity3d.services.ads.operation;
import com.unity3d.services.core.request.metrics.ISDKMetrics;
import com.unity3d.services.core.request.metrics.SDKMetricsSender;
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;
@ -8,16 +8,16 @@ import com.unity3d.services.core.webview.bridge.invocation.WebViewBridgeInvocati
import java.util.concurrent.ExecutorService;
public abstract class AdModule<T extends IWebViewSharedObject, T2> extends WebViewBridgeSharedObjectStore<T> implements IAdModule<T, T2> {
protected ISDKMetrics _sdkMetrics;
protected SDKMetricsSender _sdkMetrics;
protected ExecutorService _executorService;
protected AdModule(ISDKMetrics sdkMetrics) {
protected AdModule(SDKMetricsSender sdkMetrics) {
super();
_sdkMetrics = sdkMetrics;
_executorService = WebViewBridgeInvocationSingleThreadedExecutor.getInstance().getExecutorService();
}
public ISDKMetrics getMetricSender() {
public SDKMetricsSender getMetricSender() {
return _sdkMetrics;
}
}

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

@ -1,11 +1,11 @@
package com.unity3d.services.ads.operation;
import com.unity3d.services.core.request.metrics.ISDKMetrics;
import com.unity3d.services.core.request.metrics.SDKMetricsSender;
import com.unity3d.services.core.webview.bridge.IWebViewBridgeInvoker;
import com.unity3d.services.core.webview.bridge.IWebViewBridgeSharedObjectStore;
import com.unity3d.services.core.webview.bridge.IWebViewSharedObject;
public interface IAdModule<T extends IWebViewSharedObject, T2> extends IWebViewBridgeSharedObjectStore<T> {
void executeAdOperation(final IWebViewBridgeInvoker webViewBridgeInvoker, final T2 state);
ISDKMetrics getMetricSender();
SDKMetricsSender getMetricSender();
}

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

@ -9,7 +9,7 @@ import com.unity3d.services.core.device.Device;
import com.unity3d.services.core.misc.Utilities;
import com.unity3d.services.core.request.metrics.AdOperationError;
import com.unity3d.services.core.request.metrics.AdOperationMetric;
import com.unity3d.services.core.request.metrics.ISDKMetrics;
import com.unity3d.services.core.request.metrics.SDKMetricsSender;
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;
@ -25,7 +25,7 @@ public abstract class BaseLoadModule extends AdModule<ILoadOperation, LoadOperat
static final String errorMsgPlacementIdNull = "[UnityAds] Placement ID cannot be null";
static final String errorMsgFailedToCreateLoadRequest = "[UnityAds] Failed to create load request";
public BaseLoadModule(ISDKMetrics sdkMetrics) {
public BaseLoadModule(SDKMetricsSender sdkMetrics) {
super(sdkMetrics);
}

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

@ -5,7 +5,8 @@ import com.unity3d.services.banners.UnityBannerSize;
import com.unity3d.services.banners.bridge.BannerBridge;
import com.unity3d.services.core.configuration.ConfigurationReader;
import com.unity3d.services.core.configuration.InitializationNotificationCenter;
import com.unity3d.services.core.request.metrics.ISDKMetrics;
import com.unity3d.services.core.misc.Utilities;
import com.unity3d.services.core.request.metrics.SDKMetricsSender;
import com.unity3d.services.core.request.metrics.SDKMetrics;
import org.json.JSONException;
@ -17,7 +18,7 @@ public class LoadBannerModule extends BaseLoadModule {
public static ILoadModule getInstance() {
if (_instance == null) {
LoadBannerModule loadModule = new LoadBannerModule(SDKMetrics.getInstance());
LoadBannerModule loadModule = new LoadBannerModule(Utilities.getService(SDKMetricsSender.class));
LoadModuleDecoratorInitializationBuffer bufferedLoadModule = new LoadModuleDecoratorInitializationBuffer(loadModule, InitializationNotificationCenter.getInstance());
LoadModuleDecoratorTimeout timedLoadModule = new LoadModuleDecoratorTimeout(bufferedLoadModule, new ConfigurationReader());
_instance = timedLoadModule;
@ -25,7 +26,7 @@ public class LoadBannerModule extends BaseLoadModule {
return _instance;
}
public LoadBannerModule(ISDKMetrics sdkMetrics) {
public LoadBannerModule(SDKMetricsSender sdkMetrics) {
super(sdkMetrics);
}

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

@ -3,7 +3,8 @@ package com.unity3d.services.ads.operation.load;
import com.unity3d.services.core.configuration.ConfigurationReader;
import com.unity3d.services.core.configuration.InitializationNotificationCenter;
import com.unity3d.services.core.request.metrics.ISDKMetrics;
import com.unity3d.services.core.misc.Utilities;
import com.unity3d.services.core.request.metrics.SDKMetricsSender;
import com.unity3d.services.core.request.metrics.SDKMetrics;
import org.json.JSONException;
@ -15,7 +16,7 @@ public class LoadModule extends BaseLoadModule {
public static ILoadModule getInstance() {
if (_instance == null) {
LoadModule loadModule = new LoadModule(SDKMetrics.getInstance());
LoadModule loadModule = new LoadModule(Utilities.getService(SDKMetricsSender.class));
LoadModuleDecoratorInitializationBuffer bufferedLoadModule = new LoadModuleDecoratorInitializationBuffer(loadModule, InitializationNotificationCenter.getInstance());
LoadModuleDecoratorTimeout timedLoadModule = new LoadModuleDecoratorTimeout(bufferedLoadModule, new ConfigurationReader());
_instance = timedLoadModule;
@ -23,12 +24,12 @@ public class LoadModule extends BaseLoadModule {
return _instance;
}
public LoadModule(ISDKMetrics sdkMetrics) {
public LoadModule(SDKMetricsSender sdkMetrics) {
super(sdkMetrics);
}
@Override
void addOptionalParameters(LoadOperationState state, JSONObject parameters) throws JSONException {
void addOptionalParameters(LoadOperationState state, JSONObject parameters) {
// none needed
}

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

@ -1,7 +1,7 @@
package com.unity3d.services.ads.operation.load;
import com.unity3d.ads.UnityAds;
import com.unity3d.services.core.request.metrics.ISDKMetrics;
import com.unity3d.services.core.request.metrics.SDKMetricsSender;
import com.unity3d.services.core.webview.bridge.IWebViewBridgeInvoker;
public class LoadModuleDecorator implements ILoadModule {
@ -17,7 +17,7 @@ public class LoadModuleDecorator implements ILoadModule {
}
@Override
public ISDKMetrics getMetricSender() {
public SDKMetricsSender getMetricSender() {
return _loadModule.getMetricSender();
}

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

@ -1,5 +1,7 @@
package com.unity3d.services.ads.operation.load;
import static com.unity3d.services.core.misc.Utilities.wrapCustomerListener;
import com.unity3d.ads.IUnityAdsLoadListener;
import com.unity3d.ads.UnityAds;
import com.unity3d.ads.UnityAdsLoadOptions;
@ -18,13 +20,15 @@ public class LoadOperationState extends OperationState {
public void onUnityAdsFailedToLoad(UnityAds.UnityAdsLoadError error, String message) {
if (listener != null) {
listener.onUnityAdsFailedToLoad(this.placementId, error, message);
wrapCustomerListener(() ->
listener.onUnityAdsFailedToLoad(this.placementId, error, message));
}
}
public void onUnityAdsAdLoaded() {
if (listener != null) {
listener.onUnityAdsAdLoaded(this.placementId);
wrapCustomerListener(() ->
listener.onUnityAdsAdLoaded(this.placementId));
}
}

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

@ -1,5 +1,7 @@
package com.unity3d.services.ads.operation.show;
import android.app.Activity;
import android.content.Context;
import android.graphics.Point;
import android.os.Build;
import android.text.TextUtils;
@ -14,7 +16,7 @@ import com.unity3d.services.core.misc.Utilities;
import com.unity3d.services.core.properties.ClientProperties;
import com.unity3d.services.core.request.metrics.AdOperationError;
import com.unity3d.services.core.request.metrics.AdOperationMetric;
import com.unity3d.services.core.request.metrics.ISDKMetrics;
import com.unity3d.services.core.request.metrics.SDKMetricsSender;
import com.unity3d.services.core.request.metrics.SDKMetrics;
import com.unity3d.services.core.webview.bridge.CallbackStatus;
import com.unity3d.services.core.webview.bridge.IWebViewBridgeInvoker;
@ -32,12 +34,12 @@ public class ShowModule extends AdModule<IShowOperation, ShowOperationState> imp
public static IShowModule getInstance() {
if (instance == null) {
instance = new ShowModuleDecoratorTimeout(new ShowModule(SDKMetrics.getInstance()), new ConfigurationReader());
instance = new ShowModuleDecoratorTimeout(new ShowModule(Utilities.getService(SDKMetricsSender.class)), new ConfigurationReader());
}
return instance;
}
public ShowModule(ISDKMetrics sdkMetrics) {
public ShowModule(SDKMetricsSender sdkMetrics) {
super(sdkMetrics);
}
@ -67,16 +69,17 @@ public class ShowModule extends AdModule<IShowOperation, ShowOperationState> imp
remove(state.id);
}
}));
Activity activity = state.activity.get();
ClientProperties.setActivity(state.activity);
ClientProperties.setActivity(activity);
Display defaultDisplay = ((WindowManager)state.activity.getSystemService(state.activity.WINDOW_SERVICE)).getDefaultDisplay();
Display defaultDisplay = ((WindowManager)activity.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
JSONObject parameters = new JSONObject();
JSONObject options = new JSONObject();
JSONObject display = new JSONObject();
try {
display.put("requestedOrientation", state.activity.getRequestedOrientation());
display.put("requestedOrientation", activity.getRequestedOrientation());
display.put("rotation", defaultDisplay.getRotation());
if (Build.VERSION.SDK_INT >= 13) {
Point displaySize = new Point();

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

@ -1,7 +1,7 @@
package com.unity3d.services.ads.operation.show;
import com.unity3d.ads.UnityAds;
import com.unity3d.services.core.request.metrics.ISDKMetrics;
import com.unity3d.services.core.request.metrics.SDKMetricsSender;
import com.unity3d.services.core.webview.bridge.IWebViewBridgeInvoker;
public class ShowModuleDecorator implements IShowModule {
@ -17,7 +17,7 @@ public class ShowModuleDecorator implements IShowModule {
}
@Override
public ISDKMetrics getMetricSender() {
public SDKMetricsSender getMetricSender() {
return _showModule.getMetricSender();
}

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

@ -1,5 +1,7 @@
package com.unity3d.services.ads.operation.show;
import static com.unity3d.services.core.misc.Utilities.wrapCustomerListener;
import android.app.Activity;
import com.unity3d.ads.IUnityAdsShowListener;
@ -8,39 +10,47 @@ import com.unity3d.ads.UnityAdsShowOptions;
import com.unity3d.services.ads.operation.OperationState;
import com.unity3d.services.core.configuration.Configuration;
import java.lang.ref.WeakReference;
public class ShowOperationState extends OperationState {
public Activity activity;
public WeakReference<Activity> activity;
public IUnityAdsShowListener listener;
public UnityAdsShowOptions showOptions;
public ShowOperationState(String placementId, IUnityAdsShowListener listener, Activity activity, UnityAdsShowOptions showOptions, Configuration configuration) {
super(placementId, configuration);
this.listener = listener;
this.activity = activity;
this.activity = new WeakReference<>(activity);
this.showOptions = showOptions;
}
public void onUnityAdsShowFailure(UnityAds.UnityAdsShowError error, String message) {
if (listener != null) {
listener.onUnityAdsShowFailure(this.placementId, error, message);
wrapCustomerListener(() ->
listener.onUnityAdsShowFailure(this.placementId, error, message));
}
}
public void onUnityAdsShowClick() {
if (listener != null) {
listener.onUnityAdsShowClick(this.placementId);
wrapCustomerListener(() ->
listener.onUnityAdsShowClick(this.placementId));
}
}
public void onUnityAdsShowStart(String placementId) {
if (listener != null) {
listener.onUnityAdsShowStart(placementId);
wrapCustomerListener(() ->
listener.onUnityAdsShowStart(placementId));
}
}
public void onUnityAdsShowComplete(UnityAds.UnityAdsShowCompletionState state) {
if (listener != null) {
listener.onUnityAdsShowComplete(this.placementId, state);
wrapCustomerListener(() ->
listener.onUnityAdsShowComplete(this.placementId, state));
}
}
}

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

@ -1,257 +0,0 @@
package com.unity3d.services.ads.token;
import static com.unity3d.services.core.device.TokenType.TOKEN_NATIVE;
import static com.unity3d.services.core.device.TokenType.TOKEN_REMOTE;
import android.os.Handler;
import android.os.Looper;
import com.unity3d.services.ads.gmascar.GMA;
import com.unity3d.services.ads.gmascar.managers.IBiddingManager;
import com.unity3d.services.ads.gmascar.utils.ScarConstants;
import com.unity3d.services.core.configuration.Configuration;
import com.unity3d.services.core.configuration.ConfigurationReader;
import com.unity3d.services.core.configuration.PrivacyConfigStorage;
import com.unity3d.services.core.device.TokenType;
import com.unity3d.services.core.device.reader.DeviceInfoReaderBuilderWithExtras;
import com.unity3d.services.core.device.reader.GameSessionIdReader;
import com.unity3d.services.core.log.DeviceLog;
import com.unity3d.services.core.properties.InitializationStatusReader;
import com.unity3d.services.core.properties.SdkProperties;
import com.unity3d.services.core.request.metrics.ISDKMetrics;
import com.unity3d.services.core.request.metrics.SDKMetrics;
import com.unity3d.services.core.request.metrics.TSIMetric;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class AsyncTokenStorage {
private final List<AsyncTokenStorage.TokenListenerState> _tokenListeners = new LinkedList<>();
private final Handler _handler;
private boolean _tokenAvailable = false;
private boolean _configurationWasSet = false;
private Configuration _configuration = new Configuration();
private INativeTokenGenerator _nativeTokenGenerator;
private final InitializationStatusReader _initStatusReader = new InitializationStatusReader();
private final ISDKMetrics _sdkMetrics;
private DeviceInfoReaderBuilderWithExtras _deviceInfoReaderBuilderWithExtras;
private TokenStorage _tokenStorage;
private static AsyncTokenStorage _instance;
public static AsyncTokenStorage getInstance() {
if (_instance == null) {
_instance = new AsyncTokenStorage(
null,
new Handler(Looper.getMainLooper()),
SDKMetrics.getInstance(),
TokenStorage.getInstance());
}
return _instance;
}
class TokenListenerState
{
public IBiddingManager biddingManager;
public Runnable runnable;
public boolean invoked;
public TokenType tokenType;
}
public AsyncTokenStorage(INativeTokenGenerator nativeTokenGenerator, Handler handler, ISDKMetrics sdkMetrics, TokenStorage tokenStorage) {
_handler = handler;
_nativeTokenGenerator = nativeTokenGenerator;
_sdkMetrics = sdkMetrics;
_tokenStorage = tokenStorage;
}
public synchronized void setConfiguration(Configuration configuration) {
_configuration = configuration;
_configurationWasSet = isValidConfig(_configuration);
if (!_configurationWasSet) {
return;
}
if (_nativeTokenGenerator == null) {
_deviceInfoReaderBuilderWithExtras = new DeviceInfoReaderBuilderWithExtras(new ConfigurationReader(), PrivacyConfigStorage.getInstance(), GameSessionIdReader.getInstance());
ExecutorService executorService = Executors.newSingleThreadExecutor();
_nativeTokenGenerator = new NativeTokenGenerator(executorService, _deviceInfoReaderBuilderWithExtras);
if (configuration.getExperiments().shouldNativeTokenAwaitPrivacy()) {
_nativeTokenGenerator = new NativeTokenGeneratorWithPrivacyAwait(executorService, _nativeTokenGenerator, configuration.getPrivacyRequestWaitTimeout());
}
}
ArrayList<TokenListenerState> tempList = new ArrayList<>(_tokenListeners);
for(TokenListenerState state: tempList) {
handleTokenInvocation(state);
}
}
public synchronized void onTokenAvailable() {
_tokenAvailable = true;
if (!_configurationWasSet) {
return;
}
notifyListenersTokenReady();
}
public synchronized void getToken(IBiddingManager biddingManager) {
if (SdkProperties.getCurrentInitializationState() == SdkProperties.InitializationState.INITIALIZED_FAILED) {
biddingManager.onUnityAdsTokenReady(null);
sendTokenMetrics(null, TOKEN_REMOTE);
return;
}
if (SdkProperties.getCurrentInitializationState() == SdkProperties.InitializationState.NOT_INITIALIZED) {
biddingManager.onUnityAdsTokenReady(null);
sendTokenMetrics(null, TOKEN_REMOTE);
return;
}
final AsyncTokenStorage.TokenListenerState state = addTimeoutHandler(biddingManager);
if (!_configurationWasSet) {
return;
}
handleTokenInvocation(state);
}
private synchronized AsyncTokenStorage.TokenListenerState addTimeoutHandler(IBiddingManager biddingManager) {
final AsyncTokenStorage.TokenListenerState state = new AsyncTokenStorage.TokenListenerState();
state.biddingManager = biddingManager;
state.tokenType = TOKEN_REMOTE;
state.runnable = new Runnable() {
@Override
public void run() {
notifyTokenReady(state, null);
}
};
_tokenListeners.add(state);
_handler.postDelayed(state.runnable, _configuration.getTokenTimeout());
return state;
}
private synchronized void notifyListenersTokenReady() {
while(!_tokenListeners.isEmpty()) {
String token = _tokenStorage.getToken();
if (token == null) {
break;
}
notifyTokenReady(_tokenListeners.get(0), token);
}
}
private void handleTokenInvocation(final AsyncTokenStorage.TokenListenerState state) {
if (state.invoked) {
return;
}
state.invoked = true;
if (!_tokenAvailable) {
state.tokenType = TOKEN_NATIVE;
if (GMA.getInstance().hasSCARBiddingSupport() && _deviceInfoReaderBuilderWithExtras != null) {
Map<String, String> extras = new HashMap<>();
extras.put(ScarConstants.TOKEN_ID_KEY, state.biddingManager.getTokenIdentifier());
_deviceInfoReaderBuilderWithExtras.setExtras(extras);
}
_nativeTokenGenerator.generateToken(new INativeTokenGeneratorListener() {
@Override
public void onReady(final String token) {
_handler.post(new Runnable() {
@Override
public void run() {
notifyTokenReady(state, token);
}
});
}
});
} else {
state.tokenType = TOKEN_REMOTE;
String token = _tokenStorage.getToken();
if (token == null || token.isEmpty()) {
return;
}
notifyTokenReady(state, token);
}
}
private synchronized void notifyTokenReady(AsyncTokenStorage.TokenListenerState state, String token) {
if (_tokenListeners.remove(state)) {
// If SCAR token identifier exists and token is generated by the webView, then the
// scar identifier is to be prepended to the token <ScarID>:<unityToken>. Otherwise
// scarID will be included in the token map<String, String> payload.
String formattedToken = state.tokenType == TOKEN_REMOTE
? state.biddingManager.getFormattedToken(token)
: token;
state.biddingManager.onUnityAdsTokenReady(formattedToken);
try {
_handler.removeCallbacks(state.runnable);
} catch (Exception ex) {
DeviceLog.exception("Failed to remove callback from a handler", ex);
}
}
sendTokenMetrics(token, state.tokenType);
}
private void sendTokenMetrics(String token, TokenType type) {
switch (type) {
case TOKEN_NATIVE:
sendNativeTokenMetrics(token);
break;
case TOKEN_REMOTE:
sendRemoteTokenMetrics(token);
break;
default:
DeviceLog.error("Unknown token type passed to sendTokenMetrics");
}
}
private void sendNativeTokenMetrics(String token) {
if (_sdkMetrics == null) return;
if (token == null) {
_sdkMetrics.sendMetric(TSIMetric.newNativeGeneratedTokenNull(getMetricTags()));
} else {
_sdkMetrics.sendMetric(TSIMetric.newNativeGeneratedTokenAvailable(getMetricTags()));
}
}
private void sendRemoteTokenMetrics(String token) {
if (_sdkMetrics == null) return;
if (token == null || token.isEmpty()) {
_sdkMetrics.sendMetric(TSIMetric.newAsyncTokenNull(getMetricTags()));
} else {
_sdkMetrics.sendMetric(TSIMetric.newAsyncTokenAvailable(getMetricTags()));
}
}
private Map<String, String> getMetricTags() {
Map<String, String> tags = new HashMap<>();
tags.put("state", _initStatusReader.getInitializationStateString(SdkProperties.getCurrentInitializationState()));
return tags;
}
private boolean isValidConfig(Configuration configuration) {
return configuration != null;
}
}

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

@ -0,0 +1,10 @@
package com.unity3d.services.ads.token
import com.unity3d.services.ads.gmascar.managers.IBiddingManager
import com.unity3d.services.core.configuration.Configuration
interface AsyncTokenStorage {
fun setConfiguration(configuration: Configuration?)
fun onTokenAvailable()
fun getToken(biddingManager: IBiddingManager?)
}

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

@ -0,0 +1,242 @@
package com.unity3d.services.ads.token;
import static com.unity3d.services.core.device.TokenType.TOKEN_NATIVE;
import static com.unity3d.services.core.device.TokenType.TOKEN_REMOTE;
import android.os.Handler;
import com.unity3d.services.ads.gmascar.GMA;
import com.unity3d.services.ads.gmascar.managers.IBiddingManager;
import com.unity3d.services.ads.gmascar.utils.ScarConstants;
import com.unity3d.services.core.configuration.Configuration;
import com.unity3d.services.core.configuration.ConfigurationReader;
import com.unity3d.services.core.configuration.PrivacyConfigStorage;
import com.unity3d.services.core.device.TokenType;
import com.unity3d.services.core.device.reader.builder.DeviceInfoReaderBuilderWithExtras;
import com.unity3d.services.core.device.reader.GameSessionIdReader;
import com.unity3d.services.core.log.DeviceLog;
import com.unity3d.services.core.properties.InitializationStatusReader;
import com.unity3d.services.core.properties.SdkProperties;
import com.unity3d.services.core.request.metrics.SDKMetricsSender;
import com.unity3d.services.core.request.metrics.TSIMetric;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class InMemoryAsyncTokenStorage implements AsyncTokenStorage {
private final List<InMemoryAsyncTokenStorage.TokenListenerState> _tokenListeners = new LinkedList<>();
private final Handler _handler;
private boolean _tokenAvailable = false;
private boolean _configurationWasSet = false;
private Configuration _configuration = new Configuration();
private INativeTokenGenerator _nativeTokenGenerator;
private final InitializationStatusReader _initStatusReader = new InitializationStatusReader();
private final SDKMetricsSender _sdkMetrics;
private DeviceInfoReaderBuilderWithExtras _deviceInfoReaderBuilderWithExtras;
private TokenStorage _tokenStorage;
class TokenListenerState
{
public IBiddingManager biddingManager;
public Runnable runnable;
public boolean invoked;
public TokenType tokenType;
}
public InMemoryAsyncTokenStorage(INativeTokenGenerator nativeTokenGenerator, Handler handler, SDKMetricsSender sdkMetrics, TokenStorage tokenStorage) {
_handler = handler;
_nativeTokenGenerator = nativeTokenGenerator;
_sdkMetrics = sdkMetrics;
_tokenStorage = tokenStorage;
}
public synchronized void setConfiguration(Configuration configuration) {
_configuration = configuration;
_configurationWasSet = isValidConfig(_configuration);
if (!_configurationWasSet) {
return;
}
if (_nativeTokenGenerator == null) {
_deviceInfoReaderBuilderWithExtras = new DeviceInfoReaderBuilderWithExtras(new ConfigurationReader(), PrivacyConfigStorage.getInstance(), GameSessionIdReader.getInstance());
ExecutorService executorService = Executors.newSingleThreadExecutor();
_nativeTokenGenerator = new NativeTokenGenerator(executorService, _deviceInfoReaderBuilderWithExtras);
if (configuration.getExperiments().shouldNativeTokenAwaitPrivacy()) {
_nativeTokenGenerator = new NativeTokenGeneratorWithPrivacyAwait(executorService, _nativeTokenGenerator, configuration.getPrivacyRequestWaitTimeout());
}
}
ArrayList<TokenListenerState> tempList = new ArrayList<>(_tokenListeners);
for(TokenListenerState state: tempList) {
handleTokenInvocation(state);
}
}
public synchronized void onTokenAvailable() {
_tokenAvailable = true;
if (!_configurationWasSet) {
return;
}
notifyListenersTokenReady();
}
public synchronized void getToken(IBiddingManager biddingManager) {
if (SdkProperties.getCurrentInitializationState() == SdkProperties.InitializationState.INITIALIZED_FAILED) {
biddingManager.onUnityAdsTokenReady(null);
sendTokenMetrics(null, TOKEN_REMOTE);
return;
}
if (SdkProperties.getCurrentInitializationState() == SdkProperties.InitializationState.NOT_INITIALIZED) {
biddingManager.onUnityAdsTokenReady(null);
sendTokenMetrics(null, TOKEN_REMOTE);
return;
}
final InMemoryAsyncTokenStorage.TokenListenerState state = addTimeoutHandler(biddingManager);
if (!_configurationWasSet) {
return;
}
handleTokenInvocation(state);
}
private synchronized InMemoryAsyncTokenStorage.TokenListenerState addTimeoutHandler(IBiddingManager biddingManager) {
final InMemoryAsyncTokenStorage.TokenListenerState state = new InMemoryAsyncTokenStorage.TokenListenerState();
state.biddingManager = biddingManager;
state.tokenType = TOKEN_REMOTE;
state.runnable = new Runnable() {
@Override
public void run() {
notifyTokenReady(state, null);
}
};
_tokenListeners.add(state);
_handler.postDelayed(state.runnable, _configuration.getTokenTimeout());
return state;
}
private synchronized void notifyListenersTokenReady() {
while(!_tokenListeners.isEmpty()) {
String token = _tokenStorage.getToken();
if (token == null) {
break;
}
notifyTokenReady(_tokenListeners.get(0), token);
}
}
private void handleTokenInvocation(final InMemoryAsyncTokenStorage.TokenListenerState state) {
if (state.invoked) {
return;
}
state.invoked = true;
if (!_tokenAvailable) {
state.tokenType = TOKEN_NATIVE;
if (GMA.getInstance().hasSCARBiddingSupport() && _deviceInfoReaderBuilderWithExtras != null) {
Map<String, String> extras = new HashMap<>();
extras.put(ScarConstants.TOKEN_ID_KEY, state.biddingManager.getTokenIdentifier());
_deviceInfoReaderBuilderWithExtras.setExtras(extras);
}
_nativeTokenGenerator.generateToken(new INativeTokenGeneratorListener() {
@Override
public void onReady(final String token) {
_handler.post(new Runnable() {
@Override
public void run() {
notifyTokenReady(state, token);
}
});
}
});
} else {
state.tokenType = TOKEN_REMOTE;
String token = _tokenStorage.getToken();
if (token == null || token.isEmpty()) {
return;
}
notifyTokenReady(state, token);
}
}
private synchronized void notifyTokenReady(InMemoryAsyncTokenStorage.TokenListenerState state, String token) {
if (_tokenListeners.remove(state)) {
// If SCAR token identifier exists and token is generated by the webView, then the
// scar identifier is to be prepended to the token <ScarID>:<unityToken>. Otherwise
// scarID will be included in the token map<String, String> payload.
String formattedToken = state.tokenType == TOKEN_REMOTE
? state.biddingManager.getFormattedToken(token)
: token;
state.biddingManager.onUnityAdsTokenReady(formattedToken);
try {
_handler.removeCallbacks(state.runnable);
} catch (Exception ex) {
DeviceLog.exception("Failed to remove callback from a handler", ex);
}
}
sendTokenMetrics(token, state.tokenType);
}
private void sendTokenMetrics(String token, TokenType type) {
switch (type) {
case TOKEN_NATIVE:
sendNativeTokenMetrics(token);
break;
case TOKEN_REMOTE:
sendRemoteTokenMetrics(token);
break;
default:
DeviceLog.error("Unknown token type passed to sendTokenMetrics");
}
}
private void sendNativeTokenMetrics(String token) {
if (_sdkMetrics == null) return;
if (token == null) {
_sdkMetrics.sendMetric(TSIMetric.newNativeGeneratedTokenNull(getMetricTags()));
} else {
_sdkMetrics.sendMetric(TSIMetric.newNativeGeneratedTokenAvailable(getMetricTags()));
}
}
private void sendRemoteTokenMetrics(String token) {
if (_sdkMetrics == null) return;
if (token == null || token.isEmpty()) {
_sdkMetrics.sendMetric(TSIMetric.newAsyncTokenNull(getMetricTags()));
} else {
_sdkMetrics.sendMetric(TSIMetric.newAsyncTokenAvailable(getMetricTags()));
}
}
private Map<String, String> getMetricTags() {
Map<String, String> tags = new HashMap<>();
tags.put("state", _initStatusReader.getInitializationStateString(SdkProperties.getCurrentInitializationState()));
return tags;
}
private boolean isValidConfig(Configuration configuration) {
return configuration != null;
}
}

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

@ -0,0 +1,98 @@
package com.unity3d.services.ads.token
import com.unity3d.services.core.configuration.ConfigurationReader
import com.unity3d.services.core.configuration.InitializeEventsMetricSender
import com.unity3d.services.core.configuration.PrivacyConfigStorage
import com.unity3d.services.core.device.reader.builder.DeviceInfoReaderBuilder
import com.unity3d.services.core.device.reader.GameSessionIdReader
import com.unity3d.services.core.di.IServiceComponent
import com.unity3d.services.core.di.inject
import com.unity3d.services.core.webview.WebViewApp
import com.unity3d.services.core.webview.WebViewEventCategory
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.getAndUpdate
import kotlinx.coroutines.flow.update
import org.json.JSONArray
import org.json.JSONException
import java.util.concurrent.ConcurrentLinkedQueue
import java.util.concurrent.Executors
class InMemoryTokenStorage : TokenStorage, IServiceComponent {
private val queue = ConcurrentLinkedQueue<String>()
private val accessCounter = MutableStateFlow(-1)
private val initToken = MutableStateFlow<String?>(null)
private val executorService = Executors.newSingleThreadExecutor()
private val asyncTokenStorage: AsyncTokenStorage by inject() // todo: remove this dependency when AsyncTokenStorage is rewrote to Kotlin (use flow instead of callback)
@Throws(JSONException::class)
override fun createTokens(tokens: JSONArray) {
deleteTokens()
appendTokens(tokens)
}
@Throws(JSONException::class)
override fun appendTokens(tokens: JSONArray) {
// -1 means deleteTokens was called before and queue should be considered as non initialized
accessCounter.compareAndSet(-1, 0)
val tokenLength = tokens.length()
for (i in 0 until tokenLength) {
queue.add(tokens.getString(i))
}
if (tokenLength > 0) {
triggerTokenAvailable(false)
asyncTokenStorage.onTokenAvailable()
}
}
override fun deleteTokens() {
queue.clear()
accessCounter.update { -1 }
}
override val token: String?
get() {
if (accessCounter.value == -1) {
return initToken.value
}
if (queue.isEmpty()) {
WebViewApp.getCurrentApp().sendEvent(WebViewEventCategory.TOKEN, TokenEvent.QUEUE_EMPTY)
return null
}
val accesses = accessCounter.getAndUpdate { it + 1 }
WebViewApp.getCurrentApp().sendEvent(WebViewEventCategory.TOKEN, TokenEvent.TOKEN_ACCESS, accesses)
return queue.poll()
}
override val nativeGeneratedToken: Unit
get() {
val nativeTokenGenerator = NativeTokenGenerator(
executorService,
DeviceInfoReaderBuilder(
ConfigurationReader(),
PrivacyConfigStorage.getInstance(),
GameSessionIdReader.getInstance()
),
null
)
nativeTokenGenerator.generateToken { token ->
WebViewApp.getCurrentApp().sendEvent(WebViewEventCategory.TOKEN, TokenEvent.TOKEN_NATIVE_DATA, token)
}
}
override fun setInitToken(value: String?) {
if (value == null) return
initToken.update { value }
triggerTokenAvailable(true)
asyncTokenStorage.onTokenAvailable()
}
private fun triggerTokenAvailable(withConfig: Boolean) {
InitializeEventsMetricSender.getInstance().sdkTokenDidBecomeAvailableWithConfig(withConfig)
}
}

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

@ -2,7 +2,7 @@ package com.unity3d.services.ads.token;
import android.util.Base64;
import com.unity3d.services.core.device.reader.DeviceInfoReaderBuilder;
import com.unity3d.services.core.device.reader.builder.DeviceInfoReaderBuilder;
import com.unity3d.services.core.device.reader.DeviceInfoReaderCompressor;
import com.unity3d.services.core.device.reader.IDeviceInfoReader;
import com.unity3d.services.core.log.DeviceLog;

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

@ -1,137 +0,0 @@
package com.unity3d.services.ads.token;
import com.unity3d.services.core.configuration.ConfigurationReader;
import com.unity3d.services.core.configuration.InitializeEventsMetricSender;
import com.unity3d.services.core.configuration.PrivacyConfigStorage;
import com.unity3d.services.core.device.reader.DeviceInfoReaderBuilder;
import com.unity3d.services.core.device.reader.GameSessionIdReader;
import com.unity3d.services.core.webview.WebViewApp;
import com.unity3d.services.core.webview.WebViewEventCategory;
import org.json.JSONArray;
import org.json.JSONException;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TokenStorage {
private static TokenStorage _instance;
public static TokenStorage getInstance() {
if (_instance == null) {
_instance = new TokenStorage();
}
return _instance;
}
private final Object _lock = new Object();
private ConcurrentLinkedQueue<String> _queue;
private int _accessCounter = 0;
private boolean _peekMode = false;
private String _initToken = null;
private final ExecutorService _executorService = Executors.newSingleThreadExecutor();
private TokenStorage() {
}
public void createTokens(JSONArray tokens) throws JSONException {
boolean shouldTriggerEvent;
synchronized (_lock) {
_queue = new ConcurrentLinkedQueue<>();
_accessCounter = 0;
for (int i = 0; i < tokens.length(); i++) {
_queue.add(tokens.getString(i));
}
shouldTriggerEvent = !_queue.isEmpty();
}
if (shouldTriggerEvent) {
triggerTokenAvailable(false);
AsyncTokenStorage.getInstance().onTokenAvailable();
}
}
public void appendTokens(JSONArray tokens) throws JSONException {
boolean shouldTriggerEvent;
synchronized (_lock) {
if (_queue == null) {
_queue = new ConcurrentLinkedQueue<>();
_accessCounter = 0;
}
for (int i = 0; i < tokens.length(); i++) {
_queue.add(tokens.getString(i));
}
shouldTriggerEvent = !_queue.isEmpty();
}
if (shouldTriggerEvent) {
triggerTokenAvailable(false);
AsyncTokenStorage.getInstance().onTokenAvailable();
}
}
public void deleteTokens() {
synchronized (_lock) {
_queue = null;
_accessCounter = 0;
}
}
public String getToken() {
synchronized (_lock) {
if (_queue == null) {
return _initToken;
}
if (_queue.isEmpty()) {
WebViewApp.getCurrentApp().sendEvent(WebViewEventCategory.TOKEN, TokenEvent.QUEUE_EMPTY);
return null;
} else if (_peekMode) {
WebViewApp.getCurrentApp().sendEvent(WebViewEventCategory.TOKEN, TokenEvent.TOKEN_ACCESS, _accessCounter++);
return _queue.peek();
} else {
WebViewApp.getCurrentApp().sendEvent(WebViewEventCategory.TOKEN, TokenEvent.TOKEN_ACCESS, _accessCounter++);
return _queue.poll();
}
}
}
public void setPeekMode(boolean mode) {
synchronized (_lock) {
_peekMode = mode;
}
}
public void getNativeGeneratedToken() {
NativeTokenGenerator nativeTokenGenerator = new NativeTokenGenerator(_executorService, new DeviceInfoReaderBuilder(new ConfigurationReader(), PrivacyConfigStorage.getInstance(), GameSessionIdReader.getInstance()), null);
nativeTokenGenerator.generateToken(new INativeTokenGeneratorListener() {
@Override
public void onReady(String token) {
WebViewApp.getCurrentApp().sendEvent(WebViewEventCategory.TOKEN, TokenEvent.TOKEN_NATIVE_DATA, token);
}
});
}
public void setInitToken(String value) {
boolean shouldTriggerEvent;
synchronized (_lock) {
_initToken = value;
shouldTriggerEvent = _initToken != null;
}
if (shouldTriggerEvent) {
triggerTokenAvailable(true);
AsyncTokenStorage.getInstance().onTokenAvailable();
}
}
private void triggerTokenAvailable(Boolean withConfig) {
InitializeEventsMetricSender.getInstance().sdkTokenDidBecomeAvailableWithConfig(withConfig);
}
}

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

@ -0,0 +1,16 @@
package com.unity3d.services.ads.token
import org.json.JSONArray
import org.json.JSONException
interface TokenStorage {
val token: String?
val nativeGeneratedToken: Unit
@Throws(JSONException::class)
fun createTokens(tokens: JSONArray)
@Throws(JSONException::class)
fun appendTokens(tokens: JSONArray)
fun deleteTokens()
fun setInitToken(value: String?)
}

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

@ -0,0 +1,5 @@
package com.unity3d.services.ads.topics
enum class TopicsErrors {
ERROR_EXCEPTION,
}

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

@ -0,0 +1,6 @@
package com.unity3d.services.ads.topics
enum class TopicsEvents {
NOT_AVAILABLE,
TOPICS_AVAILABLE,
}

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

@ -0,0 +1,35 @@
package com.unity3d.services.ads.topics
import android.adservices.topics.GetTopicsResponse
import android.adservices.topics.Topic
import android.annotation.SuppressLint
import android.os.OutcomeReceiver
import com.unity3d.services.core.log.DeviceLog
import com.unity3d.services.core.webview.WebViewEventCategory
import com.unity3d.services.core.webview.bridge.IEventSender
import org.json.JSONArray
import org.json.JSONObject
@SuppressLint("NewApi", "MissingPermission")
class TopicsReceiver(private val eventSender: IEventSender) : OutcomeReceiver<GetTopicsResponse, Exception> {
override fun onResult(result: GetTopicsResponse) {
val resultArray = JSONArray()
result.topics.forEach {
resultArray.put(formatTopic(it))
}
eventSender.sendEvent(WebViewEventCategory.TOPICS, TopicsEvents.TOPICS_AVAILABLE, resultArray.toString())
}
override fun onError(error: Exception) {
DeviceLog.debug("GetTopics exception: $error")
eventSender.sendEvent(WebViewEventCategory.TOPICS, TopicsEvents.NOT_AVAILABLE, TopicsErrors.ERROR_EXCEPTION, error.toString())
}
fun formatTopic(topic: Topic): JSONObject {
val resultObject = JSONObject()
resultObject.put("taxonomyVersion", topic.taxonomyVersion)
resultObject.put("modelVersion", topic.modelVersion)
resultObject.put("topicId", topic.topicId)
return resultObject
}
}

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

@ -0,0 +1,64 @@
package com.unity3d.services.ads.topics
import android.adservices.AdServicesState
import android.adservices.topics.GetTopicsRequest
import android.adservices.topics.TopicsManager
import android.annotation.SuppressLint
import android.content.Context
import android.os.ext.SdkExtensions
import com.unity3d.services.core.device.Device
import com.unity3d.services.core.domain.ISDKDispatchers
import com.unity3d.services.core.log.DeviceLog
import com.unity3d.services.core.webview.WebViewEventCategory
import com.unity3d.services.core.webview.bridge.IEventSender
import kotlinx.coroutines.asExecutor
@SuppressLint("NewApi", "MissingPermission")
class TopicsService(context: Context, private val dispatchers: ISDKDispatchers, private val eventSender: IEventSender) {
private val topicsManager: TopicsManager? = getTopicsManager(context)
fun checkAvailability(): TopicsStatus {
if (Device.getApiLevel() < 33) {
return TopicsStatus.ERROR_API_BELOW_33
}
if (SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES) < 4) {
return TopicsStatus.ERROR_EXTENSION_BELOW_4
}
if (topicsManager == null) {
return TopicsStatus.ERROR_TOPICSMANAGER_NULL
}
if (!AdServicesState.isAdServicesStateEnabled()) {
return TopicsStatus.ERROR_AD_SERVICES_DISABLED
}
return TopicsStatus.TOPICS_AVAILABLE
}
fun getTopics(adsSdkName: String, shouldRecordObservation: Boolean) {
val callback = TopicsReceiver(eventSender)
val topicsRequest = GetTopicsRequest.Builder().setAdsSdkName(adsSdkName).setShouldRecordObservation(shouldRecordObservation).build()
try {
topicsManager?.getTopics(topicsRequest, dispatchers.default.asExecutor(), callback)
} catch (error: Exception) {
eventSender.sendEvent(WebViewEventCategory.TOPICS, TopicsEvents.NOT_AVAILABLE, TopicsErrors.ERROR_EXCEPTION, error.toString())
DeviceLog.debug("Failed to get topics with error: $error")
}
}
private fun getTopicsManager(context: Context): TopicsManager? {
// accessing TopicsManager without API level and extension version checks can crash old Android devices
// also accessing SdkExtensions below API level 30 causes exception so check API level first
if (Device.getApiLevel() < 33) {
return null
}
if (SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES) < 4) {
return null
}
return context.getSystemService(TopicsManager::class.java)
}
}

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

@ -0,0 +1,9 @@
package com.unity3d.services.ads.topics
enum class TopicsStatus {
TOPICS_AVAILABLE,
ERROR_TOPICSMANAGER_NULL,
ERROR_API_BELOW_33,
ERROR_EXTENSION_BELOW_4,
ERROR_AD_SERVICES_DISABLED,
}

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

@ -479,7 +479,11 @@ public class WebPlayerView extends WebView {
// possible Google might reject the app as an unsafe implementation.
// https://support.google.com/faqs/answer/7071387?hl=en
super.onReceivedSslError(view, handler, error);
DeviceLog.error("Received SSL error for '%s': %s", error.getUrl(), error.toString());
if (error != null) {
DeviceLog.error("Received SSL error for '%s': %s", error.getUrl(), error.toString());
} else {
DeviceLog.error("Received unknown SSL error: SslError was null");
}
if (shouldSendEvent("onReceivedSslError")) {
String url = "";

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

@ -21,11 +21,6 @@ public class AnalyticsModuleConfiguration implements IModuleConfiguration {
return true;
}
@Override
public boolean initModuleState(Configuration configuration) {
return true;
}
@Override
public boolean initErrorState(Configuration configuration, ErrorState state, String message) {
return true;

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

@ -1,5 +1,8 @@
package com.unity3d.services.banners;
import com.unity3d.ads.UnityAds;
import com.unity3d.services.ads.operation.load.ILoadModule;
import com.unity3d.services.ads.operation.load.LoadBannerModule;
import com.unity3d.services.core.misc.Utilities;
import java.lang.ref.WeakReference;
@ -82,18 +85,7 @@ public class BannerViewCache {
}
public synchronized void triggerBannerErrorEvent(String bannerAdId, final BannerErrorInfo bannerErrorInfo) {
final BannerView bannerView = this.getBannerView(bannerAdId);
if (bannerView != null && bannerView.getListener() != null) {
final BannerView.IListener listener = bannerView.getListener();
Utilities.runOnUiThread(new Runnable() {
@Override
public void run() {
if (listener != null) {
listener.onBannerFailedToLoad(bannerView, bannerErrorInfo);
}
}
});
}
LoadBannerModule.getInstance().onUnityAdsFailedToLoad(bannerAdId, UnityAds.UnityAdsLoadError.INTERNAL_ERROR, bannerErrorInfo.errorMessage);
}
public synchronized void triggerBannerLeftApplicationEvent(String bannerAdId) {

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше