From f50cf443f210339bc5004ce6d89c29195aae2d34 Mon Sep 17 00:00:00 2001 From: Ali Kabiri Date: Sun, 19 Feb 2023 12:09:58 +0100 Subject: [PATCH 1/9] Create generateGoogleServicesJson.py load google-services.json file from environment variables --- scripts/generateGoogleServicesJson.py | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 scripts/generateGoogleServicesJson.py diff --git a/scripts/generateGoogleServicesJson.py b/scripts/generateGoogleServicesJson.py new file mode 100644 index 00000000..3cd613ce --- /dev/null +++ b/scripts/generateGoogleServicesJson.py @@ -0,0 +1,9 @@ +import os + +outputPath = "app/google-services.json" + +fileContent = os.getenv('GOOGLE_SERVICES_JSON') + +fhand = open(outputPath, 'w') +fhand.write(str(fileContent)) +fhand.close() \ No newline at end of file From e4dfe2054cf996d9aaeeb695ec4cfe37ae28392c Mon Sep 17 00:00:00 2001 From: Ali Kabiri Date: Sun, 19 Feb 2023 12:10:24 +0100 Subject: [PATCH 2/9] Update build.gradle update AGP version; add jacoco_version to ext --- build.gradle | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 462fec47..2e395f32 100644 --- a/build.gradle +++ b/build.gradle @@ -5,13 +5,14 @@ buildscript { kotlin_version = '1.7.10' hilt_version = '2.44' firebase_bom_version = '30.5.0' + jacoco_version = '0.8.8' } repositories { google() mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:7.4.0-rc01' + classpath 'com.android.tools.build:gradle:7.4.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version" classpath 'com.google.gms:google-services:4.3.14' From 798cf4c9ac9b1d2d3f19b758bdffcfdd62b2cedf Mon Sep 17 00:00:00 2001 From: Ali Kabiri Date: Sun, 19 Feb 2023 12:12:58 +0100 Subject: [PATCH 3/9] Update build.gradle - activate test coverage for debug builds - add gradle managed device - automated test device (api-30; google_atd) - apply jacoco and require xml and html reports - merge unit and instrumented test reports and export result under `/mergedReportDir` in build directory --- app/build.gradle | 45 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 01e6fc54..d8e1c896 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,7 @@ plugins { id 'org.jetbrains.kotlin.android' id 'kotlin-kapt' id 'dagger.hilt.android.plugin' + id "jacoco" } repositories { @@ -46,12 +47,54 @@ android { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } + debug { + testCoverageEnabled = true + } + } + + testOptions { + + animationsDisabled = true + + managedDevices { + devices { + pixel2api30 (com.android.build.api.dsl.ManagedVirtualDevice) { + device = "Pixel 2" + apiLevel = 30 + systemImageSource = "google_atd" + } + } + } } namespace 'org.kabiri.android.usbterminal' } +jacoco { + toolVersion = jacoco_version + reportsDirectory.set(layout.buildDirectory.dir("mergedReportDir")) +} + +task jacocoTestReport(type: JacocoReport, dependsOn: ['testDebugUnitTest', 'pixel2api30DebugAndroidTest']) { + reports { + xml.required.set(true) + html.required.set(true) + csv.required.set(false) + } + + def fileFilter = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*', '**/*Test*.*', 'android/**/*.*'] + def debugTree = fileTree(dir: "${buildDir}/tmp/kotlin-classes/debug", excludes: fileFilter) + def mainSrc = "${project.projectDir}/src/main/kotlin" + + sourceDirectories.from(files([mainSrc])) + classDirectories.from(files([debugTree])) + executionData.from(fileTree(dir: "$buildDir", includes: [ + "outputs/unit_test_code_coverage/debugUnitTest/testDebugUnitTest.exec", + "outputs/managed_device_code_coverage/pixel2api30/coverage.ec" + ])) +} + private void loadKeyStore(Properties ksProp) { def ksPropFile = file("keystore.properties") if (ksPropFile.exists()) { @@ -111,4 +154,4 @@ dependencies { * For more information, visit: https://github.com/felHR85/UsbSerial */ implementation 'com.github.felHR85:UsbSerial:6.1.0' -} +} \ No newline at end of file From 8cb90517ad084f6cae95a40e98f1f47b35e5824b Mon Sep 17 00:00:00 2001 From: Ali Kabiri Date: Sun, 19 Feb 2023 12:17:16 +0100 Subject: [PATCH 4/9] Update config.yml - use circleci android machine executor to run the tests - generate ksPropFile and google-services.json - download emulator image for android emulator (google automated test device) - accept sdkmanager licenses after download - run the instrumented tests using gradle managed device `system-images;android-30;google_atd;x86` with coverage - run unit tests with coverage - store test results in the artifacts directory of circleci --- .circleci/config.yml | 81 ++++++++++++++++++++------------------------ 1 file changed, 36 insertions(+), 45 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 02d75bf9..b9249f1c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,57 +1,48 @@ version: 2.1 -jobs: - android-test: - macos: - xcode: "11.2.0" - working_directory: ~/repo/App +commands: + restore_gradle_cache: steps: - - checkout: - path: ~/repo - - - run: - name: set ANDROID_SDK_ROOT - command: | - echo 'export ANDROID_SDK_ROOT=$HOME/android-tools' >> $BASH_ENV - - restore_cache: - key: android=tools-v1-{{ checksum "scripts/install-android-tools.sh" }}-{{ arch }} - - - run: - name: install android tools - command: | - sh scripts/install-android-tools.sh - echo 'export PATH=$ANDROID_SDK_ROOT/tools/bin:$PATH' >> $BASH_ENV - echo 'export PATH=$ANDROID_SDK_ROOT/tools:$PATH' >> $BASH_ENV - echo 'export PATH=$ANDROID_SDK_ROOT/platform-tools:$PATH' >> $BASH_ENV - echo 'export PATH=$ANDROID_SDK_ROOT/emulator:$PATH' >> $BASH_ENV - source $BASH_ENV - sdkmanager --list + key: v1-gradle-wrapper-{{ arch }}-{{ checksum "gradle/wrapper/gradle-wrapper.properties" }} + - restore_cache: + key: v1-gradle-cache-{{ arch }}-{{ checksum "build.gradle" }} + save_gradle_cache: + steps: - save_cache: - key: android=tools-v1-{{ checksum "scripts/install-android-tools.sh" }}-{{ arch }} paths: - - /Users/distiller/android-tools - - - run: - name: create AVD - command: make create-avd - - - run: - name: start AVD - command: emulator-headless -avd android-tablet - background: true - - - run: - name: wait for emulator - command: adb wait-for-device shell 'while [[ -z $(getprop dev.bootcomplete) ]]; do sleep 1; done;' - - - run: adb shell screencap -p > screenshots/before.png - - # (insert testing here) + - ~/.gradle/wrapper + key: v1-gradle-wrapper-{{ arch }}-{{ checksum "gradle/wrapper/gradle-wrapper.properties" }} + - save_cache: + paths: + - ~/.gradle/caches + key: v1-gradle-cache-{{ arch }}-{{ checksum "build.gradle" }} +jobs: + android-test: + machine: + image: android:2022.12.1 + resource_class: large + steps: + - run: lsb_release -a + - checkout + - run: python3 scripts/generateKsPropFile.py + - run: python3 scripts/generateGoogleServicesJson.py + - restore_gradle_cache + - run: ./gradlew tasks + - save_gradle_cache + - run: sdkmanager --list + - run: (yes || true) | sdkmanager "tools" "platform-tools" "build-tools;33.0.2" "platforms;android-33" "system-images;android-30;google_atd;x86" + - run: (yes || true) | sdkmanager --licenses + - run: ./gradlew assembleDebug --stacktrace + - run: ./gradlew pixel2api30DebugAndroidTest --stacktrace + - run: ./gradlew testDebugUnitTest --stacktrace + - run: ./gradlew jacocoTestReport --stacktrace - store_artifacts: - path: screenshots + path: app/build/mergedReportDir + - store_test_results: + path: app/build/test-results/testDebugUnitTest workflows: workflow: From 9503e9ea6d8a84be08e3236e89ade592e21fde1e Mon Sep 17 00:00:00 2001 From: Ali Kabiri Date: Sun, 19 Feb 2023 12:33:35 +0100 Subject: [PATCH 5/9] use codecov orb to upload jacoco coverage file --- .circleci/config.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index b9249f1c..64864519 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,4 +1,6 @@ version: 2.1 +orbs: + codecov: codecov/codecov@3.2.4 commands: restore_gradle_cache: @@ -39,6 +41,8 @@ jobs: - run: ./gradlew pixel2api30DebugAndroidTest --stacktrace - run: ./gradlew testDebugUnitTest --stacktrace - run: ./gradlew jacocoTestReport --stacktrace + - codecov/upload: + file: app/build/mergedReportDir/jacocoTestReport/jacocoTestReport.xml - store_artifacts: path: app/build/mergedReportDir - store_test_results: From b01c46a159ab27716bc2a0f2bf07f68ed9d63ddd Mon Sep 17 00:00:00 2001 From: Ali Kabiri Date: Sun, 19 Feb 2023 12:39:00 +0100 Subject: [PATCH 6/9] Update config.yml --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 64864519..0e3fe664 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -51,4 +51,4 @@ jobs: workflows: workflow: jobs: - - android-test \ No newline at end of file + - android-test From 3d6e438102e4722d0165efcc2b0d2a5cec3573c4 Mon Sep 17 00:00:00 2001 From: Ali Kabiri Date: Sun, 19 Feb 2023 12:46:13 +0100 Subject: [PATCH 7/9] Update config.yml --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 0e3fe664..aca01a1e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -43,10 +43,10 @@ jobs: - run: ./gradlew jacocoTestReport --stacktrace - codecov/upload: file: app/build/mergedReportDir/jacocoTestReport/jacocoTestReport.xml - - store_artifacts: - path: app/build/mergedReportDir - store_test_results: path: app/build/test-results/testDebugUnitTest + - store_artifacts: + path: app/build/mergedReportDir workflows: workflow: From 3debdf1263ac17b89fc42afe6e14b195036e6c10 Mon Sep 17 00:00:00 2001 From: Ali Kabiri Date: Sun, 19 Feb 2023 13:06:21 +0100 Subject: [PATCH 8/9] Update README.md - add circleci and codecov badges --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c75c331a..e0102fa7 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,8 @@ Terminal-like app to send commands to Arduino through USB ![Android CI](https://github.com/k4biri/arduino-usb-terminal/workflows/Android%20CI/badge.svg) - +[![superus8r](https://circleci.com/gh/superus8r/arduino-usb-terminal.svg?style=shield)](https://circleci.com/gh/superus8r/arduino-usb-terminal) +[![codecov](https://codecov.io/gh/superus8r/arduino-usb-terminal/branch/develop/graph/badge.svg?token=RYIUU345QG)](https://codecov.io/gh/superus8r/arduino-usb-terminal) This app simplifies testing your Arduino components that work with direct usb commands by giving you the ability to send custom commands and view the returned message from your Arduino device. From 890667facff5b3a83ae8febb577dd2f24dca746f Mon Sep 17 00:00:00 2001 From: Ali Kabiri Date: Sun, 19 Feb 2023 13:40:35 +0100 Subject: [PATCH 9/9] migrate build.gradle to build.gradle.kts --- app/build.gradle | 157 -------------------------------------- app/build.gradle.kts | 167 +++++++++++++++++++++++++++++++++++++++++ app/proguard-rules.pro | 2 +- 3 files changed, 168 insertions(+), 158 deletions(-) delete mode 100644 app/build.gradle create mode 100644 app/build.gradle.kts diff --git a/app/build.gradle b/app/build.gradle deleted file mode 100644 index d8e1c896..00000000 --- a/app/build.gradle +++ /dev/null @@ -1,157 +0,0 @@ -plugins { - id 'com.android.application' - id 'com.google.gms.google-services' - id 'com.google.firebase.crashlytics' - id 'org.jetbrains.kotlin.android' - id 'kotlin-kapt' - id 'dagger.hilt.android.plugin' - id "jacoco" -} - -repositories { -} - -android { - compileSdkVersion 33 - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - - defaultConfig { - applicationId "org.kabiri.android.usbterminal" - minSdkVersion 23 - targetSdkVersion 33 - versionCode 13 - versionName "0.9.12" - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - } - - signingConfigs { - // read release credentials from keystore.properties file - def ksProp = new Properties() - // load keys inside the ksProp file - loadKeyStore(ksProp) - release { - keyAlias ksProp.getProperty("release.keyAlias") - keyPassword ksProp.getProperty("release.keyPassword") - storeFile file(ksProp.getProperty("release.file")) - storePassword ksProp.getProperty("release.storePassword") - } - } - - buildTypes { - release { - signingConfig signingConfigs.release - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } - debug { - testCoverageEnabled = true - } - } - - testOptions { - - animationsDisabled = true - - managedDevices { - devices { - pixel2api30 (com.android.build.api.dsl.ManagedVirtualDevice) { - device = "Pixel 2" - apiLevel = 30 - systemImageSource = "google_atd" - } - } - } - } - - namespace 'org.kabiri.android.usbterminal' - -} - -jacoco { - toolVersion = jacoco_version - reportsDirectory.set(layout.buildDirectory.dir("mergedReportDir")) -} - -task jacocoTestReport(type: JacocoReport, dependsOn: ['testDebugUnitTest', 'pixel2api30DebugAndroidTest']) { - reports { - xml.required.set(true) - html.required.set(true) - csv.required.set(false) - } - - def fileFilter = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*', '**/*Test*.*', 'android/**/*.*'] - def debugTree = fileTree(dir: "${buildDir}/tmp/kotlin-classes/debug", excludes: fileFilter) - def mainSrc = "${project.projectDir}/src/main/kotlin" - - sourceDirectories.from(files([mainSrc])) - classDirectories.from(files([debugTree])) - executionData.from(fileTree(dir: "$buildDir", includes: [ - "outputs/unit_test_code_coverage/debugUnitTest/testDebugUnitTest.exec", - "outputs/managed_device_code_coverage/pixel2api30/coverage.ec" - ])) -} - -private void loadKeyStore(Properties ksProp) { - def ksPropFile = file("keystore.properties") - if (ksPropFile.exists()) { - ksProp.load(new FileInputStream(ksPropFile)) - } else { - println 'ERROR: local keystore file not found' - } -} - -dependencies { - - implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'androidx.appcompat:appcompat:1.6.0' - implementation 'androidx.core:core-ktx:1.9.0' - implementation 'androidx.constraintlayout:constraintlayout:2.1.4' - - // Firebase - implementation platform("com.google.firebase:firebase-bom:$firebase_bom_version") - implementation 'com.google.firebase:firebase-analytics-ktx' - implementation 'com.google.firebase:firebase-crashlytics-ktx' - - // Dependency Injection - implementation "com.google.dagger:hilt-android:$hilt_version" - kapt "com.google.dagger:hilt-compiler:$hilt_version" - - // Coroutines - implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.1' - implementation 'androidx.activity:activity-compose:1.6.1' - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1" - implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4' - - // hilt testing - // more info: - // https://developer.android.com/training/dependency-injection/hilt-testing - androidTestImplementation "com.google.dagger:hilt-android-testing:$hilt_version" - kaptAndroidTest "com.google.dagger:hilt-android-compiler:$hilt_version" - - // unit test libs - testImplementation 'junit:junit:4.13.2' - testImplementation "com.google.truth:truth:1.1.3" - - // instrumented test libs - androidTestImplementation 'androidx.test:core:1.5.0' - androidTestImplementation 'androidx.test.ext:junit:1.1.5' - androidTestImplementation 'androidx.test.ext:junit-ktx:1.1.5' - // Espresso - androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' - // Hamcrest for view matching - androidTestImplementation 'org.hamcrest:hamcrest-library:2.2' - androidTestImplementation 'androidx.test:runner:1.5.2' - androidTestImplementation 'androidx.test:rules:1.5.0' - - /** - * This library helps to automate some parts of the USB serial connection. - * For more information, visit: https://github.com/felHR85/UsbSerial - */ - implementation 'com.github.felHR85:UsbSerial:6.1.0' -} \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 00000000..23b09bd3 --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,167 @@ +import java.io.FileInputStream +import java.util.* + +plugins { + id("com.android.application") + id("com.google.gms.google-services") + id("com.google.firebase.crashlytics") + id("org.jetbrains.kotlin.android") + id("kotlin-kapt") + id("dagger.hilt.android.plugin") + id("jacoco") +} + +repositories { +} + +android { + compileSdkVersion(33) + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + + defaultConfig { + applicationId = "org.kabiri.android.usbterminal" + minSdkVersion(23) + targetSdkVersion(33) + versionCode = 13 + versionName = "0.9.12" + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + signingConfigs { + // read release credentials from keystore.properties file + val ksProp = Properties() + // load keys inside the ksProp file + loadKeyStore(ksProp) + create("release") { + keyAlias = ksProp.getProperty("release.keyAlias") + keyPassword = ksProp.getProperty("release.keyPassword") + storeFile = file(ksProp.getProperty("release.file")) + storePassword = ksProp.getProperty("release.storePassword") + } + } + + buildTypes { + named("release") { + signingConfig = signingConfigs.getByName("release") + isMinifyEnabled = false + proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") + } + named("debug") { + isTestCoverageEnabled = true + } + } + + testOptions { + + animationsDisabled = true + + managedDevices { + devices { + maybeCreate("pixel2api30").apply { + device = "Pixel 2" + apiLevel = 30 + systemImageSource = "google_atd" + } + } + } + } + + namespace = "org.kabiri.android.usbterminal" + +} + +jacoco { + val jacoco_version: String by project + toolVersion = jacoco_version + reportsDirectory.set(layout.buildDirectory.dir("mergedReportDir")) +} + +tasks.register("jacocoTestReport") { + + dependsOn("testDebugUnitTest") + dependsOn("pixel2api30DebugAndroidTest") + + reports { + xml.required.set(true) + html.required.set(true) + csv.required.set(false) + } + + val fileFilter = listOf("**/R.class", "**/R$*.class", "**/BuildConfig.*", "**/Manifest*.*", "**/*Test*.*", "android/**/*.*") + val debugTree = fileTree("${buildDir}/tmp/kotlin-classes/debug") { exclude(fileFilter) } + val mainSrc = "${project.projectDir}/src/main/kotlin" + + sourceDirectories.from(files(setOf(mainSrc))) + classDirectories.from(files(setOf(debugTree))) + executionData.from(fileTree(buildDir) { include(setOf( + "outputs/unit_test_code_coverage/debugUnitTest/testDebugUnitTest.exec", + "outputs/managed_device_code_coverage/pixel2api30/coverage.ec" + ))}) +} + +fun loadKeyStore(ksProp: Properties) { + val ksPropFile = file("keystore.properties") + if (ksPropFile.exists()) { + ksProp.load(FileInputStream(ksPropFile)) + } else { + println("ERROR: local keystore file not found") + } +} + +val firebase_bom_version: String by project +val hilt_version: String by project +dependencies { + +// implementation fileTree("libs") { include(setOf("*.jar")) } + implementation("androidx.appcompat:appcompat:1.6.0") + implementation("androidx.core:core-ktx:1.9.0") + implementation("androidx.constraintlayout:constraintlayout:2.1.4") + + // Firebase + implementation(platform("com.google.firebase:firebase-bom:$firebase_bom_version")) + implementation("com.google.firebase:firebase-analytics-ktx") + implementation("com.google.firebase:firebase-crashlytics-ktx") + + // Dependency Injection + implementation("com.google.dagger:hilt-android:$hilt_version") + kapt("com.google.dagger:hilt-compiler:$hilt_version") + + // Coroutines + implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.5.1") + implementation("androidx.activity:activity-compose:1.6.1") + implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1") + implementation("androidx.lifecycle:lifecycle-extensions:2.2.0") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4") + + // hilt testing + // more info: + // https://developer.android.com/training/dependency-injection/hilt-testing + androidTestImplementation("com.google.dagger:hilt-android-testing:$hilt_version") + kaptAndroidTest("com.google.dagger:hilt-android-compiler:$hilt_version") + + // unit test libs + testImplementation("junit:junit:4.13.2") + testImplementation("com.google.truth:truth:1.1.3") + + // instrumented test libs + androidTestImplementation("androidx.test:core:1.5.0") + androidTestImplementation("androidx.test.ext:junit:1.1.5") + androidTestImplementation("androidx.test.ext:junit-ktx:1.1.5") + // Espresso + androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") + // Hamcrest for view matching + androidTestImplementation("org.hamcrest:hamcrest-library:2.2") + androidTestImplementation("androidx.test:runner:1.5.2") + androidTestImplementation("androidx.test:rules:1.5.0") + + /** + * This library helps to automate some parts of the USB serial connection. + * For more information, visit: https://github.com/felHR85/UsbSerial + */ + implementation("com.github.felHR85:UsbSerial:6.1.0") +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index f1b42451..2f9dc5a4 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -1,6 +1,6 @@ # Add project specific ProGuard rules here. # You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. +# proguardFiles setting in build.gradle.kts. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html