diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c00f1083..462b0847 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,7 +18,7 @@ jobs: with: java-version: 1.8 - name: Perform base checks - run: ./gradlew demo:assembleDebug cameraview:javadoc + run: ./gradlew demo:assembleDebug cameraview:publishToDirectory ANDROID_UNIT_TESTS: name: Unit Tests runs-on: ubuntu-latest @@ -28,12 +28,12 @@ jobs: with: java-version: 1.8 - name: Execute unit tests - run: ./gradlew cameraview:testDebugUnitTest + run: ./gradlew cameraview:runUnitTests - name: Upload unit tests artifact uses: actions/upload-artifact@v1 with: name: unit_tests - path: ./cameraview/build/jacoco/ + path: ./cameraview/build/coverage_input/unit_tests ANDROID_EMULATOR_TESTS: name: Emulator Tests runs-on: macOS-latest @@ -78,7 +78,7 @@ jobs: uses: actions/upload-artifact@v1 with: name: emulator_tests_${{ matrix.EMULATOR_API }} - path: ./cameraview/build/outputs/code_coverage/debugAndroidTest/connected + path: ./cameraview/build/coverage_input/android_tests CODE_COVERAGE: name: Code Coverage Report runs-on: ubuntu-latest @@ -92,23 +92,23 @@ jobs: uses: actions/download-artifact@v1 with: name: unit_tests - path: ./cameraview/build/jacoco/ + path: ./cameraview/build/coverage_input/unit_tests - name: Download emulator tests artifact uses: actions/download-artifact@v1 with: # 27 is the EMULATOR_API with less SdkExclude annotations, and should have # the best possible coverage. name: emulator_tests_27 - path: ./cameraview/build/outputs/code_coverage/debugAndroidTest/connected + path: ./cameraview/build/coverage_input/android_tests - name: Create merged coverage report - run: ./gradlew cameraview:mergeCoverageReports + run: ./gradlew cameraview:computeCoverage - name: Upload merged coverage report (GitHub) uses: actions/upload-artifact@v1 with: name: report - path: ./cameraview/build/reports/mergedCoverageReport + path: ./cameraview/build/coverage_output/xml - name: Upload merged coverage report (Codecov) uses: codecov/codecov-action@v1 with: - file: ./cameraview/build/reports/mergedCoverageReport/* + file: ./cameraview/build/coverage_output/xml/* fail_ci_if_error: true \ No newline at end of file diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 775f259d..8390af24 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -11,10 +11,11 @@ jobs: TRAVIS: true BINTRAY_USER: ${{ secrets.BINTRAY_USER }} BINTRAY_KEY: ${{ secrets.BINTRAY_KEY }} + BINTRAY_REPO: ${{ secrets.BINTRAY_REPO }} steps: - uses: actions/checkout@v2 - uses: actions/setup-java@v1 with: java-version: 1.8 - name: Perform bintray upload - run: ./gradlew bintrayUpload + run: ./gradlew cameraview:publishToBintray diff --git a/.github/workflows/emulator_script.sh b/.github/workflows/emulator_script.sh index 71307a36..3ffe9cdf 100755 --- a/.github/workflows/emulator_script.sh +++ b/.github/workflows/emulator_script.sh @@ -11,4 +11,4 @@ ADB_TAGS="$ADB_TAGS MediaEncoderEngine:I MediaEncoder:I AudioMediaEncoder:I Vide ADB_TAGS="$ADB_TAGS CameraIntegrationTest:I MessageQueue:W MPEG4Writer:I" adb logcat -c adb logcat $ADB_TAGS *:E -v color & -./gradlew cameraview:connectedCheck \ No newline at end of file +./gradlew cameraview:runAndroidTests \ No newline at end of file diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 3617d82c..00000000 --- a/build.gradle +++ /dev/null @@ -1,29 +0,0 @@ -buildscript { - repositories { - jcenter() - google() - } - - dependencies { - classpath 'com.android.tools.build:gradle:4.0.0' - classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1' - classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4' - } -} - -allprojects { - repositories { - jcenter() - google() - } -} - -ext { - compileSdkVersion = 29 - minSdkVersion = 15 - targetSdkVersion = 29 -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 00000000..4e783fc8 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,34 @@ + +buildscript { + + extra["minSdkVersion"] = 15 + extra["compileSdkVersion"] = 29 + extra["targetSdkVersion"] = 29 + extra["kotlinVersion"] = "1.3.72" + + repositories { + google() + mavenCentral() + jcenter() + } + + dependencies { + classpath("com.android.tools.build:gradle:4.0.0") + classpath("com.otaliastudios.tools:publisher:0.3.3") + val kotlinVersion = property("kotlinVersion") as String + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion") + + } +} + +allprojects { + repositories { + google() + mavenCentral() + jcenter() + } +} + +tasks.register("clean", Delete::class) { + delete(buildDir) +} \ No newline at end of file diff --git a/cameraview/build.gradle b/cameraview/build.gradle deleted file mode 100644 index deba5dca..00000000 --- a/cameraview/build.gradle +++ /dev/null @@ -1,271 +0,0 @@ -apply plugin: 'com.android.library' -apply plugin: 'com.github.dcendents.android-maven' -apply plugin: 'com.jfrog.bintray' - -// Required by bintray -version = '2.6.2' -group = 'com.otaliastudios' - -//region android dependencies - -android { - compileSdkVersion rootProject.ext.compileSdkVersion - - defaultConfig { - minSdkVersion rootProject.ext.minSdkVersion - targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 1 - versionName project.version - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - testInstrumentationRunnerArgument "filter", "" + - "com.otaliastudios.cameraview.tools.SdkExcludeFilter," + - "com.otaliastudios.cameraview.tools.SdkIncludeFilter" - } - - buildTypes { - debug { - testCoverageEnabled true - } - - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - } - } -} - -dependencies { - testImplementation 'junit:junit:4.12' - testImplementation 'org.mockito:mockito-inline:2.28.2' - - androidTestImplementation 'androidx.test:runner:1.2.0' - androidTestImplementation 'androidx.test:rules:1.2.0' - androidTestImplementation 'androidx.test.ext:junit:1.1.1' - androidTestImplementation 'org.mockito:mockito-android:2.28.2' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' - - api 'androidx.exifinterface:exifinterface:1.1.0' - api 'androidx.lifecycle:lifecycle-common:2.1.0' - api 'com.google.android.gms:play-services-tasks:17.0.0' - implementation 'androidx.annotation:annotation:1.1.0' - implementation 'com.otaliastudios.opengl:egloo:0.4.0' -} - -//endregion - -//region bintray - -// install is a task defined by the Gradle Maven plugin, which is used to -// publish a maven repo to a local repository. (we actually use the android version of the plugin, -// com.github.dcendents.android-maven, to support AARs) -// https://docs.gradle.org/current/userguide/maven_plugin.html#sec:maven_tasks -install { - // The repositories property is common to all tasks of type Upload and returns the repositories - // into which we will upload data. https://docs.gradle.org/current/dsl/org.gradle.api.tasks.Upload.html#org.gradle.api.tasks.Upload:repositories - // It returns a RepositoryHandler: https://docs.gradle.org/current/dsl/org.gradle.api.artifacts.dsl.RepositoryHandler.html - repositories { - // The maven plugin adds a mavenInstaller property to the RepositoryHandler which can be used to - // add and configure a local maven repository cache. - // https://docs.gradle.org/current/dsl/org.gradle.api.artifacts.dsl.RepositoryHandler.html#N11785 - mavenInstaller { - // The object here extends PomFilterContainer so we can configure the pom file here. - // https://docs.gradle.org/current/javadoc/org/gradle/api/artifacts/maven/PomFilterContainer.html#pom-groovy.lang.Closure- - pom { - // Now we are inside a MavenPom object that can be configured. We get the project and configure. - // https://docs.gradle.org/current/javadoc/org/gradle/api/artifacts/maven/MavenPom.html - project { - name 'CameraView' - description 'A well documented, high-level Android interface that makes capturing pictures ' + - 'and videos easy, addressing most of the common issues and needs.' - url 'https://github.com/natario1/CameraView' - packaging 'aar' - groupId project.group - artifactId 'cameraview' - version project.version - licenses { - license { - name 'The Apache Software License, Version 2.0' - url 'http://www.apache.org/licenses/LICENSE-2.0.txt' - } - } - scm { - connection 'https://github.com/natario1/CameraView.git' - developerConnection 'https://github.com/natario1/CameraView.git' - url 'https://github.com/natario1/CameraView' - - } - developers { - developer { - id = 'natario' - name 'Mattia Iavarone' - } - } - } - } - } - } -} - -def bintrayUser -def bintrayKey -def isCI = System.getenv("TRAVIS") -if (isCI) { - bintrayUser = System.getenv("BINTRAY_USER") - bintrayKey = System.getenv("BINTRAY_KEY") -} else { - Properties props = new Properties() - props.load(project.rootProject.file('local.properties').newDataInputStream()) - bintrayUser = props.getProperty('bintray.user') - bintrayKey = props.get('bintray.key') -} - -bintray { - // https://github.com/bintray/gradle-bintray-plugin - user = bintrayUser - key = bintrayKey - configurations = ['archives'] - pkg { - repo = 'android' - name = 'CameraView' - licenses = ['Apache-2.0'] - vcsUrl = 'https://github.com/natario1/CameraView.git' - publish = true - override = true - version { - name = project.version - desc = 'CameraView v. '+project.version - released = new Date() - vcsTag = 'v'+project.version - } - } -} - -//endregion - -//region javadoc and sources - -// From official sample https://github.com/bintray/bintray-examples/blob/master/gradle-aar-example/build.gradle -task sourcesJar(type: Jar) { - archiveClassifier.set('sources') - from android.sourceSets.main.java.sourceFiles -} - -task javadoc(type: Javadoc) { - source = android.sourceSets.main.java.srcDirs - classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) - classpath += project.files("${android.sdkDirectory}/platforms/${android.compileSdkVersion}/android.jar") - project.android.libraryVariants.all { variant -> - if (variant.name == 'release') { - classpath += files(variant.javaCompile.classpath) - } - } - exclude '**/BuildConfig.java' - exclude '**/R.java' - // This excludes our internal folder, which is nice, but also creates - // errors anytime we reference excluded classes in public classes javadocs, - // which is unfortunate. There might be a fix but I don't know any. - // exclude '**/internal/**' -} - -task javadocJar(type: Jar, dependsOn: javadoc) { - archiveClassifier.set('javadoc') - from javadoc.destinationDir -} - -artifacts { - archives javadocJar - archives sourcesJar -} - -//endregion - -//region code coverage - -// 1. running androidTests with connectedCheck will generate an .ec file -// in build/outputs/code-coverage/connected, plus the XML result in -// in build/reports/coverage/debug/report.xml . - -// 2. running unit tests with testDebugUnitTest will just generate the .exec file. -// The JacocoReport task from the jacoco plugin can create the XML report out of it. - -// to have a unified report, we just pass both the .exec and the .ec file -// to the jacoco task, so we get a unified XML report with total coverage. -// Reference: https://medium.com/@rafael_toledo/setting-up-an-unified-coverage-report-in-android-with-jacoco-robolectric-and-espresso-ffe239aaf3fa - -apply plugin: 'jacoco' - -def reportsDirectory = "$buildDir/reports/" -jacoco { - toolVersion = "0.8.1" - reportsDir = file(reportsDirectory) -} - -task createCoverageReports() { - dependsOn "testDebugUnitTest" - dependsOn "connectedCheck" -} - -task mergeCoverageReports(type: JacocoReport) { - // Let this be called without running the tests. - // dependsOn "createCoverageReports" - // However, ensure we have the compiled .class files. - dependsOn "compileDebugSources" - - // Merge unit tests and android tests data - executionData = fileTree(dir: "$buildDir", includes: [ - "jacoco/testDebugUnitTest.exec", // Unit tests - "outputs/code_coverage/debugAndroidTest/connected/*coverage.ec" // Android tests - ]) - - // Sources - sourceDirectories = files(android.sourceSets.main.java.sourceFiles) - additionalSourceDirs = files([ // Add BuildConfig and R. - "$buildDir/generated/source/buildConfig/debug", - "$buildDir/generated/source/r/debug" - ]) - - // Classes (.class files) - // Not everything in the filter relates to CameraView, - // but let's keep a generic filter - def classDir = "$buildDir/intermediates/javac/debug" - def classFilter = [ - '**/R.class', - '**/R$*.class', - '**/BuildConfig.*', - '**/Manifest*.*', - 'android/**', - 'androidx/**', - 'com/google/**', - '**/*$ViewInjector*.*', - '**/Dagger*Component.class', - '**/Dagger*Component$Builder.class', - '**/*Module_*Factory.class', - ] - if (isCI) { - // All these classes are tested by the integration tests that we are not able to - // run on the CI emulator. - // classFilter.add('**/com/otaliastudios/cameraview/engine/CameraEngine**.*') - // classFilter.add('**/com/otaliastudios/cameraview/engine/Camera1Engine**.*') - // classFilter.add('**/com/otaliastudios/cameraview/engine/Camera2Engine**.*') - // classFilter.add('**/com/otaliastudios/cameraview/engine/action/**.*') - // classFilter.add('**/com/otaliastudios/cameraview/engine/lock/**.*') - // classFilter.add('**/com/otaliastudios/cameraview/engine/meter/**.*') - // classFilter.add('**/com/otaliastudios/cameraview/picture/**.*') - // classFilter.add('**/com/otaliastudios/cameraview/video/**.*') - // classFilter.add('**/com/otaliastudios/cameraview/orchestrator/**.*') - // classFilter.add('**/com/otaliastudios/cameraview/video/encoding/**.*') - } - // We don't test OpenGL filters. - classFilter.add('**/com/otaliastudios/cameraview/filters/**.*') - - classDirectories = fileTree(dir: classDir, excludes: classFilter); - - reports.html.enabled = true - reports.xml.enabled = true - reports.xml.destination file("$reportsDirectory/mergedCoverageReport/report.xml") -} - -//endregion - -// To deploy ./gradlew bintrayUpload - diff --git a/cameraview/build.gradle.kts b/cameraview/build.gradle.kts new file mode 100644 index 00000000..f9d4c911 --- /dev/null +++ b/cameraview/build.gradle.kts @@ -0,0 +1,125 @@ +import com.otaliastudios.tools.publisher.common.License +import com.otaliastudios.tools.publisher.common.Release + +plugins { + id("com.android.library") + id("kotlin-android") + id("com.otaliastudios.tools.publisher") + id("jacoco") +} + +android { + setCompileSdkVersion(rootProject.property("compileSdkVersion") as Int) + defaultConfig { + setMinSdkVersion(rootProject.property("minSdkVersion") as Int) + setTargetSdkVersion(rootProject.property("targetSdkVersion") as Int) + versionCode = 1 + versionName = "2.6.2" + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + testInstrumentationRunnerArgument("filter", "" + + "com.otaliastudios.cameraview.tools.SdkExcludeFilter," + + "com.otaliastudios.cameraview.tools.SdkIncludeFilter") + } + buildTypes["debug"].isTestCoverageEnabled = true + buildTypes["release"].isMinifyEnabled = true +} + +dependencies { + testImplementation("junit:junit:4.12") + testImplementation("org.mockito:mockito-inline:2.28.2") + + androidTestImplementation("androidx.test:runner:1.2.0") + androidTestImplementation("androidx.test:rules:1.2.0") + androidTestImplementation("androidx.test.ext:junit:1.1.1") + androidTestImplementation("org.mockito:mockito-android:2.28.2") + androidTestImplementation("androidx.test.espresso:espresso-core:3.2.0") + + api("androidx.exifinterface:exifinterface:1.1.0") + api("androidx.lifecycle:lifecycle-common:2.1.0") + api("com.google.android.gms:play-services-tasks:17.0.0") + implementation("androidx.annotation:annotation:1.1.0") + implementation("com.otaliastudios.opengl:egloo:0.5.1") +} + +// Publishing + +publisher { + project.description = "A well documented, high-level Android interface that makes capturing " + + "pictures and videos easy, addressing all of the common issues and needs. " + + "Real-time filters, gestures, watermarks, frame processing, RAW, output of any size." + project.artifact = "cameraview" + project.group = "com.otaliastudios" + project.url = "https://github.com/natario1/CameraView" + project.addLicense(License.APACHE_2_0) + release.setSources(Release.SOURCES_AUTO) + release.setDocs(Release.DOCS_AUTO) + bintray { + auth.user = "BINTRAY_USER" + auth.key = "BINTRAY_KEY" + auth.repo = "BINTRAY_REPO" + } + directory { + directory = "build/local" + } +} + +// Code Coverage +val buildDir = project.buildDir.absolutePath +val coverageInputDir = "$buildDir/coverage_input" // changing? change github workflow +val coverageOutputDir = "$buildDir/coverage_output" // changing? change github workflow + +// Run unit tests, with coverage enabled in the android { } configuration. +// Output will be an .exec file in build/jacoco. +tasks.register("runUnitTests") { // changing name? change github workflow + dependsOn("testDebugUnitTest") + doLast { + copy { + from("$buildDir/jacoco/testDebugUnitTest.exec") + into("$coverageInputDir/unit_tests") // changing? change github workflow + } + } +} + +// Run android tests with coverage. +tasks.register("runAndroidTests") { // changing name? change github workflow + dependsOn("connectedDebugAndroidTest") + doLast { + copy { + from("$buildDir/outputs/code_coverage/debugAndroidTest/connected") + include("*coverage.ec") + into("$coverageInputDir/android_tests") // changing? change github workflow + } + } +} + +// Merge the two with a jacoco task. +jacoco { toolVersion = "0.8.1" } +tasks.register("computeCoverage", JacocoReport::class) { + dependsOn("compileDebugSources") // Compile sources, needed below + executionData.from(fileTree(coverageInputDir)) + sourceDirectories.from(android.sourceSets["main"].java.sourceFiles) + additionalSourceDirs.from("$buildDir/generated/source/buildConfig/debug") + additionalSourceDirs.from("$buildDir/generated/source/r/debug") + classDirectories.from(fileTree("$buildDir/intermediates/javac/debug") { + // Not everything here is relevant for CameraView, but let's keep it generic + exclude( + "**/R.class", + "**/R$*.class", + "**/BuildConfig.*", + "**/Manifest*.*", + "android/**", + "androidx/**", + "com/google/**", + "**/*\$ViewInjector*.*", + "**/Dagger*Component.class", + "**/Dagger*Component\$Builder.class", + "**/*Module_*Factory.class", + // We don"t test OpenGL filters. + "**/com/otaliastudios/cameraview/filters/**.*" + ) + }) + reports.html.isEnabled = true + reports.xml.isEnabled = true + reports.html.destination = file("$coverageOutputDir/html") + reports.xml.destination = file("$coverageOutputDir/xml/report.xml") +} \ No newline at end of file diff --git a/demo/build.gradle b/demo/build.gradle deleted file mode 100644 index 27790038..00000000 --- a/demo/build.gradle +++ /dev/null @@ -1,27 +0,0 @@ -apply plugin: 'com.android.application' - -android { - compileSdkVersion rootProject.ext.compileSdkVersion - - defaultConfig { - applicationId "com.otaliastudios.cameraview.demo" - minSdkVersion rootProject.ext.minSdkVersion - targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 1 - versionName "1.0" - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - vectorDrawables.useSupportLibrary = true - } - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - } - } -} - -dependencies { - implementation project(':cameraview') - implementation 'androidx.appcompat:appcompat:1.1.0' - implementation 'com.google.android.material:material:1.2.0' -} diff --git a/demo/build.gradle.kts b/demo/build.gradle.kts new file mode 100644 index 00000000..f65862d1 --- /dev/null +++ b/demo/build.gradle.kts @@ -0,0 +1,21 @@ +plugins { + id("com.android.application") +} + +android { + setCompileSdkVersion(rootProject.property("compileSdkVersion") as Int) + defaultConfig { + applicationId = "com.otaliastudios.cameraview.demo" + setMinSdkVersion(rootProject.property("minSdkVersion") as Int) + setTargetSdkVersion(rootProject.property("targetSdkVersion") as Int) + versionCode = 1 + versionName = "1.0" + vectorDrawables.useSupportLibrary = true + } +} + +dependencies { + implementation(project(":cameraview")) + implementation("androidx.appcompat:appcompat:1.1.0") + implementation("com.google.android.material:material:1.1.0") +} diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index 48f809fc..00000000 --- a/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -include ':demo', ':cameraview' diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 00000000..4100d446 --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,2 @@ +include(":cameraview") +include(":demo")