From ed1191937b07479e2d9eebee7d987926955a21cb Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Sun, 18 Jun 2023 10:31:42 +0000 Subject: [PATCH 01/23] Update dependency org.mockito:mockito-core to v5.4.0 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a18ca95a..9208e19c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ picasso = "2.8" junit4 = "4.13.2" junit5 = "5.9.3" -mockito = "5.3.1" +mockito = "5.4.0" mockitoKotlin = "5.0.0" kluent = "1.73" apacheCodecs = "1.15" From f931c906c0927bdbfae5a984788e5c614190d553 Mon Sep 17 00:00:00 2001 From: tzugen Date: Sun, 18 Jun 2023 14:11:57 +0200 Subject: [PATCH 02/23] Reallow cleartext communication --- ultrasonic/src/main/res/xml/network_security_config.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ultrasonic/src/main/res/xml/network_security_config.xml b/ultrasonic/src/main/res/xml/network_security_config.xml index e0690d2f..b3a39028 100644 --- a/ultrasonic/src/main/res/xml/network_security_config.xml +++ b/ultrasonic/src/main/res/xml/network_security_config.xml @@ -1,5 +1,6 @@ - + From 9a2a9599728358dbbc6bc9daabe653c82b57eebb Mon Sep 17 00:00:00 2001 From: birdbird <6892457-tzugen@users.noreply.gitlab.com> Date: Sun, 18 Jun 2023 12:44:27 +0000 Subject: [PATCH 03/23] Add RoboTest when releasing --- .gitlab-ci.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 3f9d9721..04ddc650 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -129,6 +129,17 @@ Publish Signed APK: rules: - if: $CI_COMMIT_TAG && $CI_PROJECT_ID == $ROOT_PROJECT_ID +RoboTest: + stage: Publish + image: gcr.io/google.com/cloudsdktool/google-cloud-cli:latest + script: + - curl --silent "https://gitlab.com/gitlab-org/incubation-engineering/mobile-devops/download-secure-files/-/raw/main/installer" | bash + - gcloud auth activate-service-account --key-file .secure_files/ultrasonic-61089-8ab2ad46c8a8.json + - gcloud firebase test android run --token $FIREBASE_TOKEN --type robo --app ultrasonic-release/${PACKAGE_APK} --device model=Nexus6,version=21,locale=en,orientation=portrait --device model=Nexus7,version=19,locale=fr,orientation=landscape + rules: + - if: $CI_COMMIT_TAG && $CI_PROJECT_ID == $ROOT_PROJECT_ID + + Release: stage: Release image: registry.gitlab.com/gitlab-org/release-cli:latest @@ -138,3 +149,5 @@ Release: --assets-link "{\"name\":\"${PACKAGE_APK_IDSIG}\",\"url\":\"${PACKAGE_REGISTRY_URL}/${PACKAGE_APK_IDSIG}\"}" rules: - if: $CI_COMMIT_TAG && $CI_PROJECT_ID == $ROOT_PROJECT_ID + + From e6441f13449c79aca2a48197458515363ed4eaa5 Mon Sep 17 00:00:00 2001 From: birdbird <6892457-tzugen@users.noreply.gitlab.com> Date: Sun, 18 Jun 2023 12:58:17 +0000 Subject: [PATCH 04/23] CI: Try to merge two steps to remove code duplication --- .gitlab-ci.yml | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 04ddc650..5dc51dec 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -84,39 +84,30 @@ Assemble Release: rules: - if: $CI_COMMIT_REF_NAME == "develop" || $CI_COMMIT_REF_NAME == "master" || $CI_COMMIT_TAG || $CI_PROJECT_ID != $ROOT_PROJECT_ID +# We generate a signed package for each commit to develop as well as when making a release. +# Since the develop signed apk are not persistent they can be downloaded for around 3 weeks before Gitlab deletes them. Generate Signed Develop APK: + variables: + APK_NAME: ultrasonic-${CI_COMMIT_SHA} stage: Sign APK # We don't need the gradle cache here cache: [] script: - openssl aes-256-cbc -K ${ULTRASONIC_KEYSTORE_KEY} -iv ${ULTRASONIC_KEYSTORE_IV} -in ultrasonic-keystore.enc -out ultrasonic-keystore -d - mkdir -p ${CI_PROJECT_DIR}/ultrasonic-release - - ${ANDROID_HOME}/build-tools/*/zipalign -v 4 ultrasonic/build/outputs/apk/release/ultrasonic-release-unsigned.apk ${CI_PROJECT_DIR}/ultrasonic-release/ultrasonic-${CI_COMMIT_SHA}.apk - - ${ANDROID_HOME}/build-tools/*/apksigner sign --verbose --ks ${CI_PROJECT_DIR}/ultrasonic-keystore --ks-pass pass:${ULTRASONIC_KEYSTORE_STOREPASS} --key-pass pass:${ULTRASONIC_KEYSTORE_KEYPASS} ${CI_PROJECT_DIR}/ultrasonic-release/ultrasonic-${CI_COMMIT_SHA}.apk - - ${ANDROID_HOME}/build-tools/*/apksigner verify --verbose ${CI_PROJECT_DIR}/ultrasonic-release/ultrasonic-${CI_COMMIT_SHA}.apk + - ${ANDROID_HOME}/build-tools/*/zipalign -v 4 ultrasonic/build/outputs/apk/release/ultrasonic-release-unsigned.apk ${CI_PROJECT_DIR}/ultrasonic-release/${APK_NAME}.apk + - ${ANDROID_HOME}/build-tools/*/apksigner sign --verbose --ks ${CI_PROJECT_DIR}/ultrasonic-keystore --ks-pass pass:${ULTRASONIC_KEYSTORE_STOREPASS} --key-pass pass:${ULTRASONIC_KEYSTORE_KEYPASS} ${CI_PROJECT_DIR}/ultrasonic-release/${APK_NAME}.apk + - ${ANDROID_HOME}/build-tools/*/apksigner verify --verbose ${CI_PROJECT_DIR}/ultrasonic-release/${APK_NAME}.apk artifacts: - name: ultrasonic-${CI_COMMIT_SHA} + name: $APK_NAME paths: - ultrasonic-release/ rules: - if: $CI_COMMIT_REF_NAME == "develop" && $CI_PROJECT_ID == $ROOT_PROJECT_ID - -Generate Signed APK: - stage: Sign APK - # We don't need the gradle cache here - cache: [] - script: - - openssl aes-256-cbc -K ${ULTRASONIC_KEYSTORE_KEY} -iv ${ULTRASONIC_KEYSTORE_IV} -in ultrasonic-keystore.enc -out ultrasonic-keystore -d - - mkdir -p ${CI_PROJECT_DIR}/ultrasonic-release - - ${ANDROID_HOME}/build-tools/*/zipalign -v 4 ultrasonic/build/outputs/apk/release/ultrasonic-release-unsigned.apk ${CI_PROJECT_DIR}/ultrasonic-release/${PACKAGE_APK} - - ${ANDROID_HOME}/build-tools/*/apksigner sign --verbose --ks ${CI_PROJECT_DIR}/ultrasonic-keystore --ks-pass pass:${ULTRASONIC_KEYSTORE_STOREPASS} --key-pass pass:${ULTRASONIC_KEYSTORE_KEYPASS} ${CI_PROJECT_DIR}/ultrasonic-release/${PACKAGE_APK} - - ${ANDROID_HOME}/build-tools/*/apksigner verify --verbose ${CI_PROJECT_DIR}/ultrasonic-release/${PACKAGE_APK} - artifacts: - name: ultrasonic-${CI_COMMIT_TAG} - paths: - - ultrasonic-release/ - rules: - if: $CI_COMMIT_TAG && $CI_PROJECT_ID == $ROOT_PROJECT_ID + variables: + APK_NAME: ultrasonic-${CI_COMMIT_TAG} + Publish Signed APK: stage: Publish From fbec7610f3c8febf56f2560b592522762b07a87a Mon Sep 17 00:00:00 2001 From: birdbird <6892457-tzugen@users.noreply.gitlab.com> Date: Sun, 18 Jun 2023 13:00:37 +0000 Subject: [PATCH 05/23] [SkipCI] Rename step --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5dc51dec..85da3284 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -86,7 +86,7 @@ Assemble Release: # We generate a signed package for each commit to develop as well as when making a release. # Since the develop signed apk are not persistent they can be downloaded for around 3 weeks before Gitlab deletes them. -Generate Signed Develop APK: +Generate Signed APK: variables: APK_NAME: ultrasonic-${CI_COMMIT_SHA} stage: Sign APK From ecfa17762cb85bef26ece5ce5f1d6ae71f0d7ce0 Mon Sep 17 00:00:00 2001 From: birdbird <6892457-tzugen@users.noreply.gitlab.com> Date: Sun, 18 Jun 2023 13:45:20 +0000 Subject: [PATCH 06/23] Update .gitlab-ci.yml file --- .gitlab-ci.yml | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 85da3284..7da73c57 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -120,17 +120,6 @@ Publish Signed APK: rules: - if: $CI_COMMIT_TAG && $CI_PROJECT_ID == $ROOT_PROJECT_ID -RoboTest: - stage: Publish - image: gcr.io/google.com/cloudsdktool/google-cloud-cli:latest - script: - - curl --silent "https://gitlab.com/gitlab-org/incubation-engineering/mobile-devops/download-secure-files/-/raw/main/installer" | bash - - gcloud auth activate-service-account --key-file .secure_files/ultrasonic-61089-8ab2ad46c8a8.json - - gcloud firebase test android run --token $FIREBASE_TOKEN --type robo --app ultrasonic-release/${PACKAGE_APK} --device model=Nexus6,version=21,locale=en,orientation=portrait --device model=Nexus7,version=19,locale=fr,orientation=landscape - rules: - - if: $CI_COMMIT_TAG && $CI_PROJECT_ID == $ROOT_PROJECT_ID - - Release: stage: Release image: registry.gitlab.com/gitlab-org/release-cli:latest @@ -141,4 +130,13 @@ Release: rules: - if: $CI_COMMIT_TAG && $CI_PROJECT_ID == $ROOT_PROJECT_ID +RoboTest: + stage: Release + image: gcr.io/google.com/cloudsdktool/google-cloud-cli:latest + script: + - curl --silent "https://gitlab.com/gitlab-org/incubation-engineering/mobile-devops/download-secure-files/-/raw/main/installer" | bash + - gcloud auth activate-service-account --key-file .secure_files/ultrasonic-61089-8ab2ad46c8a8.json + - gcloud firebase test android run --token $FIREBASE_TOKEN --type robo --app ultrasonic-release/${PACKAGE_APK} --device model=Nexus6,version=21,locale=en,orientation=portrait --device model=Nexus7,version=19,locale=fr,orientation=landscape + rules: + - if: $CI_COMMIT_TAG && $CI_PROJECT_ID == $ROOT_PROJECT_ID From df3dc4221f51aec80a3a36684f3f1e603c65f62a Mon Sep 17 00:00:00 2001 From: birdbird <6892457-tzugen@users.noreply.gitlab.com> Date: Sun, 18 Jun 2023 13:55:16 +0000 Subject: [PATCH 07/23] Don't run sign step when merging dev into master --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 7da73c57..c3be5606 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -103,7 +103,7 @@ Generate Signed APK: paths: - ultrasonic-release/ rules: - - if: $CI_COMMIT_REF_NAME == "develop" && $CI_PROJECT_ID == $ROOT_PROJECT_ID + - if: $CI_COMMIT_REF_NAME == "develop" && $CI_PROJECT_ID == $ROOT_PROJECT_ID && $CI_PIPELINE_SOURCE != "merge_request_event" - if: $CI_COMMIT_TAG && $CI_PROJECT_ID == $ROOT_PROJECT_ID variables: APK_NAME: ultrasonic-${CI_COMMIT_TAG} From f3152c5e4db123f494dcb821300130e61865aedd Mon Sep 17 00:00:00 2001 From: birdbird <6892457-tzugen@users.noreply.gitlab.com> Date: Tue, 20 Jun 2023 06:48:06 +0000 Subject: [PATCH 08/23] allow failure for now for the robotest --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c3be5606..0e63dc64 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -139,4 +139,5 @@ RoboTest: - gcloud firebase test android run --token $FIREBASE_TOKEN --type robo --app ultrasonic-release/${PACKAGE_APK} --device model=Nexus6,version=21,locale=en,orientation=portrait --device model=Nexus7,version=19,locale=fr,orientation=landscape rules: - if: $CI_COMMIT_TAG && $CI_PROJECT_ID == $ROOT_PROJECT_ID + allow_failure: true From ea2048babfac1e38c00f39ca13d8a1ab03bfbf58 Mon Sep 17 00:00:00 2001 From: birdbird <6892457-tzugen@users.noreply.gitlab.com> Date: Tue, 20 Jun 2023 08:43:44 +0000 Subject: [PATCH 09/23] Enable [ROBO] annotation to manually trigger a robo test --- .gitlab-ci.yml | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0e63dc64..e045954c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -87,26 +87,26 @@ Assemble Release: # We generate a signed package for each commit to develop as well as when making a release. # Since the develop signed apk are not persistent they can be downloaded for around 3 weeks before Gitlab deletes them. Generate Signed APK: - variables: - APK_NAME: ultrasonic-${CI_COMMIT_SHA} stage: Sign APK # We don't need the gradle cache here cache: [] script: - openssl aes-256-cbc -K ${ULTRASONIC_KEYSTORE_KEY} -iv ${ULTRASONIC_KEYSTORE_IV} -in ultrasonic-keystore.enc -out ultrasonic-keystore -d - mkdir -p ${CI_PROJECT_DIR}/ultrasonic-release - - ${ANDROID_HOME}/build-tools/*/zipalign -v 4 ultrasonic/build/outputs/apk/release/ultrasonic-release-unsigned.apk ${CI_PROJECT_DIR}/ultrasonic-release/${APK_NAME}.apk - - ${ANDROID_HOME}/build-tools/*/apksigner sign --verbose --ks ${CI_PROJECT_DIR}/ultrasonic-keystore --ks-pass pass:${ULTRASONIC_KEYSTORE_STOREPASS} --key-pass pass:${ULTRASONIC_KEYSTORE_KEYPASS} ${CI_PROJECT_DIR}/ultrasonic-release/${APK_NAME}.apk - - ${ANDROID_HOME}/build-tools/*/apksigner verify --verbose ${CI_PROJECT_DIR}/ultrasonic-release/${APK_NAME}.apk + - ${ANDROID_HOME}/build-tools/*/zipalign -v 4 ultrasonic/build/outputs/apk/release/ultrasonic-release-unsigned.apk ${CI_PROJECT_DIR}/ultrasonic-release/${PACKAGE_APK}.apk + - ${ANDROID_HOME}/build-tools/*/apksigner sign --verbose --ks ${CI_PROJECT_DIR}/ultrasonic-keystore --ks-pass pass:${ULTRASONIC_KEYSTORE_STOREPASS} --key-pass pass:${ULTRASONIC_KEYSTORE_KEYPASS} ${CI_PROJECT_DIR}/ultrasonic-release/${PACKAGE_APK}.apk + - ${ANDROID_HOME}/build-tools/*/apksigner verify --verbose ${CI_PROJECT_DIR}/ultrasonic-release/${PACKAGE_APK}.apk artifacts: - name: $APK_NAME + name: $PACKAGE_APK paths: - ultrasonic-release/ rules: - - if: $CI_COMMIT_REF_NAME == "develop" && $CI_PROJECT_ID == $ROOT_PROJECT_ID && $CI_PIPELINE_SOURCE != "merge_request_event" + # Run when releasing a new tag - if: $CI_COMMIT_TAG && $CI_PROJECT_ID == $ROOT_PROJECT_ID + # Or when adding a new commit to develop (but never inside merge events) + - if: $CI_COMMIT_REF_NAME == "develop" && $CI_PROJECT_ID == $ROOT_PROJECT_ID && $CI_PIPELINE_SOURCE != "merge_request_event" variables: - APK_NAME: ultrasonic-${CI_COMMIT_TAG} + PACKAGE_APK: ultrasonic-${CI_COMMIT_SHA} Publish Signed APK: @@ -133,11 +133,19 @@ Release: RoboTest: stage: Release image: gcr.io/google.com/cloudsdktool/google-cloud-cli:latest + # We don't need the gradle cache here + cache: [] script: - curl --silent "https://gitlab.com/gitlab-org/incubation-engineering/mobile-devops/download-secure-files/-/raw/main/installer" | bash - gcloud auth activate-service-account --key-file .secure_files/ultrasonic-61089-8ab2ad46c8a8.json - - gcloud firebase test android run --token $FIREBASE_TOKEN --type robo --app ultrasonic-release/${PACKAGE_APK} --device model=Nexus6,version=21,locale=en,orientation=portrait --device model=Nexus7,version=19,locale=fr,orientation=landscape + - gcloud firebase test android run --type robo --app ultrasonic-release/${PACKAGE_APK} --robo-directives click:button1= --device model=Nexus6,version=21,locale=en,orientation=portrait --device model=Nexus7,version=19,locale=fr,orientation=landscape rules: + # Run when releasing a new tag - if: $CI_COMMIT_TAG && $CI_PROJECT_ID == $ROOT_PROJECT_ID - allow_failure: true + # or when requested by using [ROBO] inside the commit message and merging to develop + # Would be nice to be able to run it in a MR as well, but currently not possible + # Because it would not have access to the protected keys + - if: $CI_COMMIT_MESSAGE =~ /^\[ROBO\].*/ && $CI_PROJECT_ID == $ROOT_PROJECT_ID && $CI_COMMIT_REF_NAME == "develop" && $CI_PIPELINE_SOURCE != "merge_request_event" + variables: + PACKAGE_APK: ultrasonic-${CI_COMMIT_SHA} From 8469a099b0a13372d1adb39ff8b9a7df0e986cd4 Mon Sep 17 00:00:00 2001 From: birdbird <6892457-tzugen@users.noreply.gitlab.com> Date: Tue, 20 Jun 2023 08:44:38 +0000 Subject: [PATCH 10/23] [ROBO] test --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e045954c..caff9a9b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -144,7 +144,7 @@ RoboTest: - if: $CI_COMMIT_TAG && $CI_PROJECT_ID == $ROOT_PROJECT_ID # or when requested by using [ROBO] inside the commit message and merging to develop # Would be nice to be able to run it in a MR as well, but currently not possible - # Because it would not have access to the protected keys + # Because it would not have access to the protected keys. - if: $CI_COMMIT_MESSAGE =~ /^\[ROBO\].*/ && $CI_PROJECT_ID == $ROOT_PROJECT_ID && $CI_COMMIT_REF_NAME == "develop" && $CI_PIPELINE_SOURCE != "merge_request_event" variables: PACKAGE_APK: ultrasonic-${CI_COMMIT_SHA} From 24fb2e4f438b56712e8c1a68c5ae332ba4bf17b4 Mon Sep 17 00:00:00 2001 From: birdbird <6892457-tzugen@users.noreply.gitlab.com> Date: Tue, 20 Jun 2023 09:29:00 +0000 Subject: [PATCH 11/23] [ROBO] Use higher privileged key, specify project --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index caff9a9b..8725269e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -137,8 +137,8 @@ RoboTest: cache: [] script: - curl --silent "https://gitlab.com/gitlab-org/incubation-engineering/mobile-devops/download-secure-files/-/raw/main/installer" | bash - - gcloud auth activate-service-account --key-file .secure_files/ultrasonic-61089-8ab2ad46c8a8.json - - gcloud firebase test android run --type robo --app ultrasonic-release/${PACKAGE_APK} --robo-directives click:button1= --device model=Nexus6,version=21,locale=en,orientation=portrait --device model=Nexus7,version=19,locale=fr,orientation=landscape + - gcloud auth activate-service-account --key-file .secure_files/firebase-key.json + - gcloud firebase test android run --project ultrasonic-61089 --type robo --app ultrasonic-release/${PACKAGE_APK} --robo-directives click:button1= --device model=Nexus6,version=21,locale=en,orientation=portrait --device model=Nexus7,version=19,locale=fr,orientation=landscape rules: # Run when releasing a new tag - if: $CI_COMMIT_TAG && $CI_PROJECT_ID == $ROOT_PROJECT_ID From 3da9097c6bfd37c2ad6ad5b7866091e578208c39 Mon Sep 17 00:00:00 2001 From: birdbird <6892457-tzugen@users.noreply.gitlab.com> Date: Tue, 20 Jun 2023 10:13:36 +0000 Subject: [PATCH 12/23] [ROBO] Correct apk path --- .gitlab-ci.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8725269e..10219433 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -93,9 +93,9 @@ Generate Signed APK: script: - openssl aes-256-cbc -K ${ULTRASONIC_KEYSTORE_KEY} -iv ${ULTRASONIC_KEYSTORE_IV} -in ultrasonic-keystore.enc -out ultrasonic-keystore -d - mkdir -p ${CI_PROJECT_DIR}/ultrasonic-release - - ${ANDROID_HOME}/build-tools/*/zipalign -v 4 ultrasonic/build/outputs/apk/release/ultrasonic-release-unsigned.apk ${CI_PROJECT_DIR}/ultrasonic-release/${PACKAGE_APK}.apk - - ${ANDROID_HOME}/build-tools/*/apksigner sign --verbose --ks ${CI_PROJECT_DIR}/ultrasonic-keystore --ks-pass pass:${ULTRASONIC_KEYSTORE_STOREPASS} --key-pass pass:${ULTRASONIC_KEYSTORE_KEYPASS} ${CI_PROJECT_DIR}/ultrasonic-release/${PACKAGE_APK}.apk - - ${ANDROID_HOME}/build-tools/*/apksigner verify --verbose ${CI_PROJECT_DIR}/ultrasonic-release/${PACKAGE_APK}.apk + - ${ANDROID_HOME}/build-tools/*/zipalign -v 4 ultrasonic/build/outputs/apk/release/ultrasonic-release-unsigned.apk ${CI_PROJECT_DIR}/ultrasonic-release/${PACKAGE_APK} + - ${ANDROID_HOME}/build-tools/*/apksigner sign --verbose --ks ${CI_PROJECT_DIR}/ultrasonic-keystore --ks-pass pass:${ULTRASONIC_KEYSTORE_STOREPASS} --key-pass pass:${ULTRASONIC_KEYSTORE_KEYPASS} ${CI_PROJECT_DIR}/ultrasonic-release/${PACKAGE_APK} + - ${ANDROID_HOME}/build-tools/*/apksigner verify --verbose ${CI_PROJECT_DIR}/ultrasonic-release/${PACKAGE_APK} artifacts: name: $PACKAGE_APK paths: @@ -106,7 +106,7 @@ Generate Signed APK: # Or when adding a new commit to develop (but never inside merge events) - if: $CI_COMMIT_REF_NAME == "develop" && $CI_PROJECT_ID == $ROOT_PROJECT_ID && $CI_PIPELINE_SOURCE != "merge_request_event" variables: - PACKAGE_APK: ultrasonic-${CI_COMMIT_SHA} + PACKAGE_APK: ultrasonic-${CI_COMMIT_SHA}.apk Publish Signed APK: @@ -147,5 +147,5 @@ RoboTest: # Because it would not have access to the protected keys. - if: $CI_COMMIT_MESSAGE =~ /^\[ROBO\].*/ && $CI_PROJECT_ID == $ROOT_PROJECT_ID && $CI_COMMIT_REF_NAME == "develop" && $CI_PIPELINE_SOURCE != "merge_request_event" variables: - PACKAGE_APK: ultrasonic-${CI_COMMIT_SHA} + PACKAGE_APK: ultrasonic-${CI_COMMIT_SHA}.apk From dc4e85b21db5397e6b5e6353c3af46c7c3c0a1f5 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Wed, 21 Jun 2023 18:31:46 +0000 Subject: [PATCH 13/23] Update dependency commons-codec:commons-codec to v1.16.0 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9208e19c..cefb2194 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -33,7 +33,7 @@ junit5 = "5.9.3" mockito = "5.4.0" mockitoKotlin = "5.0.0" kluent = "1.73" -apacheCodecs = "1.15" +apacheCodecs = "1.16.0" robolectric = "4.10.3" timber = "5.0.1" fastScroll = "2.0.1" From 11a30a15d93f24f52fb289bca21ffdf30e21bf6f Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Wed, 21 Jun 2023 21:31:42 +0000 Subject: [PATCH 14/23] Update room to v2.5.2 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9208e19c..c47efd5e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ androidSupport = "1.6.0" materialDesign = "1.9.0" constraintLayout = "2.1.4" multidex = "2.0.1" -room = "2.5.1" +room = "2.5.2" kotlin = "1.8.22" kotlinxCoroutines = "1.7.1" viewModelKtx = "2.6.1" From ae306e6eb3b7704d169e085d29e4018abd221629 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 22 Jun 2023 20:31:51 +0000 Subject: [PATCH 15/23] Update dependency org.jlleitschuh.gradle:ktlint-gradle to v11.4.2 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9208e19c..61709d5f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -6,7 +6,7 @@ navigation = "2.6.0" gradlePlugin = "8.0.2" androidxcore = "1.10.1" ktlint = "0.43.2" -ktlintGradle = "11.4.0" +ktlintGradle = "11.4.2" detekt = "1.23.0" preferences = "1.2.0" media3 = "1.0.2" From e3917466254b74b03d7788dd85b5786ab9f2ab91 Mon Sep 17 00:00:00 2001 From: birdbird <6892457-tzugen@users.noreply.gitlab.com> Date: Fri, 23 Jun 2023 09:52:13 +0000 Subject: [PATCH 16/23] Add some more devices for robotest --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 10219433..67f84832 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -138,7 +138,7 @@ RoboTest: script: - curl --silent "https://gitlab.com/gitlab-org/incubation-engineering/mobile-devops/download-secure-files/-/raw/main/installer" | bash - gcloud auth activate-service-account --key-file .secure_files/firebase-key.json - - gcloud firebase test android run --project ultrasonic-61089 --type robo --app ultrasonic-release/${PACKAGE_APK} --robo-directives click:button1= --device model=Nexus6,version=21,locale=en,orientation=portrait --device model=Nexus7,version=19,locale=fr,orientation=landscape + - gcloud firebase test android run --project ultrasonic-61089 --type robo --app ultrasonic-release/${PACKAGE_APK} --robo-directives click:button1= --device model=Nexus6,version=21,locale=en,orientation=portrait --device model=Pixel3,version=28,locale=fr,orientation=landscape --device model=Pixel5,version=30,locale=zh,orientation=portrait rules: # Run when releasing a new tag - if: $CI_COMMIT_TAG && $CI_PROJECT_ID == $ROOT_PROJECT_ID From e8c56b1a060df32f8ef5bc3719250576a3d17022 Mon Sep 17 00:00:00 2001 From: birdbird <6892457-tzugen@users.noreply.gitlab.com> Date: Mon, 26 Jun 2023 16:33:11 +0000 Subject: [PATCH 17/23] Hide search in now playing screen --- .../main/kotlin/org/moire/ultrasonic/fragment/PlayerFragment.kt | 2 ++ ultrasonic/src/main/res/menu/nowplaying.xml | 2 +- ultrasonic/src/main/res/menu/search_view_menu.xml | 2 +- ultrasonic/src/main/res/values/strings.xml | 1 + 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/PlayerFragment.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/PlayerFragment.kt index 7f50a870..a1c3ee81 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/PlayerFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/PlayerFragment.kt @@ -536,8 +536,10 @@ class PlayerFragment : if (update.success == true && update.rating is HeartRating) { if (update.rating.isHeart) { starMenuItem.setIcon(fullStar) + starMenuItem.setTitle(R.string.download_menu_unstar) } else { starMenuItem.setIcon(hollowStar) + starMenuItem.setTitle(R.string.download_menu_star) } } else if (update.success == false) { Toast.makeText(context, "Setting rating failed", Toast.LENGTH_SHORT) diff --git a/ultrasonic/src/main/res/menu/nowplaying.xml b/ultrasonic/src/main/res/menu/nowplaying.xml index 39126689..d3bc8b59 100644 --- a/ultrasonic/src/main/res/menu/nowplaying.xml +++ b/ultrasonic/src/main/res/menu/nowplaying.xml @@ -12,7 +12,7 @@ + app:showAsAction="ifRoom|collapseActionView" /> \ No newline at end of file diff --git a/ultrasonic/src/main/res/values/strings.xml b/ultrasonic/src/main/res/values/strings.xml index f8d91b62..08db0901 100644 --- a/ultrasonic/src/main/res/values/strings.xml +++ b/ultrasonic/src/main/res/values/strings.xml @@ -346,6 +346,7 @@ Set Bookmark Delete Bookmark Star + Unstar Clear Playlist Shares No shares available on server From 9b9e552b9581c9c2fc162417480902f8f476073f Mon Sep 17 00:00:00 2001 From: birdbird <6892457-tzugen@users.noreply.gitlab.com> Date: Mon, 26 Jun 2023 17:10:05 +0000 Subject: [PATCH 18/23] Don't assume Stable ids for playlist --- .../org/moire/ultrasonic/adapters/BaseAdapter.kt | 5 +++-- .../moire/ultrasonic/adapters/TrackViewBinder.kt | 13 +++---------- .../org/moire/ultrasonic/fragment/PlayerFragment.kt | 2 +- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/BaseAdapter.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/BaseAdapter.kt index fb48151a..bca2e0b5 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/BaseAdapter.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/BaseAdapter.kt @@ -26,7 +26,8 @@ import timber.log.Timber * It should be kept generic enough that it can be used a Base for all lists in the app. */ @Suppress("unused", "UNUSED_PARAMETER") -class BaseAdapter : MultiTypeAdapter(), FastScrollRecyclerView.SectionedAdapter { +class BaseAdapter(allowDuplicateEntries: Boolean = false) : + MultiTypeAdapter(), FastScrollRecyclerView.SectionedAdapter { // Update the BoundedTreeSet if selection type is changed internal var selectionType: SelectionType = SelectionType.MULTIPLE @@ -41,7 +42,7 @@ class BaseAdapter : MultiTypeAdapter(), FastScrollRecyclerView private val diffCallback = GenericDiffCallback() init { - setHasStableIds(true) + setHasStableIds(!allowDuplicateEntries) } override fun getItemId(position: Int): Long { diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/TrackViewBinder.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/TrackViewBinder.kt index bca305aa..91bcb09d 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/TrackViewBinder.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/TrackViewBinder.kt @@ -43,14 +43,7 @@ class TrackViewBinder( override fun onBindViewHolder(holder: TrackViewHolder, item: Identifiable) { val diffAdapter = adapter as BaseAdapter<*> - val track: Track = when (item) { - is Track -> { - item - } - else -> { - return - } - } + val track = (item as? Track) ?: return // Remove observer before binding holder.observableChecked.removeObservers(lifecycleOwner) @@ -59,7 +52,7 @@ class TrackViewBinder( song = track, checkable = checkable, draggable = draggable, - diffAdapter.isSelected(item.longId) + diffAdapter.isSelected(track.longId) ) holder.itemView.setOnLongClickListener { @@ -110,7 +103,7 @@ class TrackViewBinder( diffAdapter.selectionRevision.observe( lifecycleOwner ) { - val newStatus = diffAdapter.isSelected(item.longId) + val newStatus = diffAdapter.isSelected(track.longId) if (newStatus != holder.check.isChecked) holder.check.isChecked = newStatus } diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/PlayerFragment.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/PlayerFragment.kt index a1c3ee81..adcffd95 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/PlayerFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/PlayerFragment.kt @@ -176,7 +176,7 @@ class PlayerFragment : private val binding get() = _binding!! private val viewAdapter: BaseAdapter by lazy { - BaseAdapter() + BaseAdapter(allowDuplicateEntries = true) } override fun onCreate(savedInstanceState: Bundle?) { From d420f7022574446224bc0aa098a34b6c51f26c8e Mon Sep 17 00:00:00 2001 From: birdbird <6892457-tzugen@users.noreply.gitlab.com> Date: Tue, 27 Jun 2023 08:22:57 +0000 Subject: [PATCH 19/23] Prevent a media3 crash --- .../org/moire/ultrasonic/fragment/EntryListFragment.kt | 3 --- .../ultrasonic/fragment/TrackCollectionFragment.kt | 2 -- .../org/moire/ultrasonic/service/MediaPlayerManager.kt | 10 ++++++++-- .../org/moire/ultrasonic/subsonic/DownloadHandler.kt | 4 ++-- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/EntryListFragment.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/EntryListFragment.kt index dca68e30..48815367 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/EntryListFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/EntryListFragment.kt @@ -135,7 +135,6 @@ abstract class EntryListFragment : MultiListFragment() { item.id, append = false, autoPlay = true, - shuffle = false, playNext = false, isArtist = isArtist ) @@ -145,7 +144,6 @@ abstract class EntryListFragment : MultiListFragment() { item.id, append = false, autoPlay = true, - shuffle = true, playNext = true, isArtist = isArtist ) @@ -155,7 +153,6 @@ abstract class EntryListFragment : MultiListFragment() { item.id, append = true, autoPlay = false, - shuffle = false, playNext = false, isArtist = isArtist ) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/TrackCollectionFragment.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/TrackCollectionFragment.kt index cd71ee7c..9b923e95 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/TrackCollectionFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/TrackCollectionFragment.kt @@ -316,7 +316,6 @@ open class TrackCollectionFragment( append = append, playNext = false, autoPlay = !append, - shuffle = false, playlistName = null, fragment = this ) @@ -616,7 +615,6 @@ open class TrackCollectionFragment( append = true, playNext = true, autoPlay = false, - shuffle = false, playlistName = navArgs.playlistName, fragment = this@TrackCollectionFragment ) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerManager.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerManager.kt index dba110ec..d1ffd067 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerManager.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerManager.kt @@ -429,7 +429,10 @@ class MediaPlayerManager( when (insertionMode) { InsertionMode.CLEAR -> clear() InsertionMode.APPEND -> insertAt = mediaItemCount - InsertionMode.AFTER_CURRENT -> insertAt = currentMediaItemIndex + 1 + InsertionMode.AFTER_CURRENT -> { + // Must never be larger than the count of items (especially when empty) + insertAt = (currentMediaItemIndex + 1).coerceAtMost(mediaItemCount) + } } val mediaItems: List = songs.map { @@ -437,10 +440,13 @@ class MediaPlayerManager( result } - if (shuffle) isShufflePlayEnabled = true Timber.w("Adding ${mediaItems.size} media items") controller?.addMediaItems(insertAt, mediaItems) + // There is a bug in media3 ( https://github.com/androidx/media/issues/480 ), + // so we must first add the tracks, and then enable shuffle + if (shuffle) isShufflePlayEnabled = true + prepare() // Playback doesn't start correctly when the player is in STATE_ENDED. diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/subsonic/DownloadHandler.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/subsonic/DownloadHandler.kt index 1a653a50..55bceca2 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/subsonic/DownloadHandler.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/subsonic/DownloadHandler.kt @@ -98,7 +98,7 @@ class DownloadHandler( isDirectory: Boolean = true, append: Boolean, autoPlay: Boolean, - shuffle: Boolean, + shuffle: Boolean = false, playNext: Boolean, isArtist: Boolean = false ) { @@ -141,7 +141,7 @@ class DownloadHandler( append: Boolean, playNext: Boolean, autoPlay: Boolean, - shuffle: Boolean, + shuffle: Boolean = false, playlistName: String? = null, fragment: Fragment ) { From 69b83fe5380fa3d31841f6e8e4dde45322ca3f85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20Garc=C3=ADa=20Amor?= Date: Tue, 27 Jun 2023 06:48:01 +0000 Subject: [PATCH 20/23] Translated using Weblate (Spanish) Currently translated at 100.0% (428 of 428 strings) Translation: Ultrasonic/app Translate-URL: https://hosted.weblate.org/projects/ultrasonic/app/es/ --- ultrasonic/src/main/res/values-es/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/ultrasonic/src/main/res/values-es/strings.xml b/ultrasonic/src/main/res/values-es/strings.xml index 0f66c28f..50aab0a1 100644 --- a/ultrasonic/src/main/res/values-es/strings.xml +++ b/ultrasonic/src/main/res/values-es/strings.xml @@ -454,4 +454,5 @@ Tasa de bits máxima: al fijar una canción de forma permanente Canciones aleatorias Reproducir las canciones aleatoriamente + No me gusta \ No newline at end of file From f202febb4d7343adb9e2897fe73a1ad199065b1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20Garc=C3=ADa=20Amor?= Date: Tue, 27 Jun 2023 07:35:23 +0000 Subject: [PATCH 21/23] Translated using Weblate (Spanish) Currently translated at 100.0% (428 of 428 strings) Translation: Ultrasonic/app Translate-URL: https://hosted.weblate.org/projects/ultrasonic/app/es/ --- ultrasonic/src/main/res/values-es/strings.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ultrasonic/src/main/res/values-es/strings.xml b/ultrasonic/src/main/res/values-es/strings.xml index 50aab0a1..9d4d3466 100644 --- a/ultrasonic/src/main/res/values-es/strings.xml +++ b/ultrasonic/src/main/res/values-es/strings.xml @@ -44,7 +44,7 @@ Reproducir a continuación Reproducir ahora Reproducción aleatoria - Public + Público Guardar Seleccionar todo Título @@ -57,14 +57,14 @@ Marcador añadido a %s. Nada se esta descargando La lista de reproducción esta vacía - El control remoto no esta habilitado. Por favor habilita el modo jukebox en Configuración > Usuarios en tu servidor de Subsonic. + El control remoto no esta habilitado. Por favor habilita el modo gramola (jukebox) en Configuración > Usuarios en tu servidor de Subsonic. Control remoto apagado. La música se reproduce en tu dispositivo. Control remoto no disponible en modo fuera de línea. Control remoto encendido. La música se reproduce en el servidor. Control remoto no soportado. Por favor actualiza tu servidor de Subsonic. Ecualizador - Apagar Jukebox - Encender Jukebox + Apagar gramola + Encender gramola Letras Guardar lista de reproducción Pantalla apagada @@ -87,7 +87,7 @@ Ecualizador Seleccionar preajuste Error - Jukebox por defecto + Gramola por defecto No se encontraron letras Predeterminado del sistema Chino (China) @@ -446,7 +446,7 @@ 100 canciones 50 canciones 1000 canciones - Jukebox + Gramola 500 canciones Funciones soportadas No se puede reanudar la reproducción From c032d32e02e50484370af3e0a307a416befc8ba6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20Garc=C3=ADa=20Amor?= Date: Tue, 27 Jun 2023 07:04:32 +0000 Subject: [PATCH 22/23] Translated using Weblate (Galician) Currently translated at 13.3% (57 of 428 strings) Translation: Ultrasonic/app Translate-URL: https://hosted.weblate.org/projects/ultrasonic/app/gl/ --- ultrasonic/src/main/res/values-gl/strings.xml | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/ultrasonic/src/main/res/values-gl/strings.xml b/ultrasonic/src/main/res/values-gl/strings.xml index 86dcf5c1..36cb490a 100644 --- a/ultrasonic/src/main/res/values-gl/strings.xml +++ b/ultrasonic/src/main/res/values-gl/strings.xml @@ -24,4 +24,40 @@ Podcast Buscar Enviar unha mensaxe + Marcadores + Enviar + Imaxe do avatar + Álbum + Comentar + Confirmar + Borrar + Descargar + Detalles + Múltiples xéneros + Nome + OK + Reproducir a continuación + Reproducir agora + Reproducir aleatoriamente + Público + Gardar + Seleccionar todo + Desancorar + ¿Realmente queres desancorar a selección actual\? + Ultrasonic + Título + Artista + Cancelar + Reproducir última + Ancorar + Mostra un cadro de diálogo de confirmación antes de eliminar ou desancorar as cancións + + %d canción seleccionada para ser ancorada + %d cancións seleccionadas para ser ancoradas + + Tasa de bits máxima: ao fixar unha canción de forma permanente + + %d canción desancorada + %d cancións desancoradas + \ No newline at end of file From b40b0048da0735650f505d586d6c49e36f1cb1c0 Mon Sep 17 00:00:00 2001 From: tzugen Date: Tue, 27 Jun 2023 12:11:53 +0200 Subject: [PATCH 23/23] 4.6.1 Release canditate --- .../metadata/android/en-US/changelogs/124.txt | 15 +++++++++++++++ ultrasonic/build.gradle | 4 ++-- 2 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 fastlane/metadata/android/en-US/changelogs/124.txt diff --git a/fastlane/metadata/android/en-US/changelogs/124.txt b/fastlane/metadata/android/en-US/changelogs/124.txt new file mode 100644 index 00000000..9850d96c --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/124.txt @@ -0,0 +1,15 @@ +Features: +- Search is accessible through a new icon on the main screen +- Modernize Back Handling +- Reenable R8 Code minification +- Add a "Play Random Songs" shortcut + +Bug fixes: +- Readd the "Star" button to the Now Playing screen +- Fix a rare crash when shuffling playlists with duplicate entries +- Fix a crash when choosing "Play next" on an empty playlist. +- Tracks buttons flash a scrollbar sometimes in Android 13 +- Fix EndlessScrolling in genre listing +- Couldn't delete a track when shuffle was active +- Upgrade material to 1.9.0 + diff --git a/ultrasonic/build.gradle b/ultrasonic/build.gradle index a437074b..07af3496 100644 --- a/ultrasonic/build.gradle +++ b/ultrasonic/build.gradle @@ -9,8 +9,8 @@ android { defaultConfig { applicationId "org.moire.ultrasonic" - versionCode 123 - versionName "4.6.0" + versionCode 124 + versionName "4.6.1-RC" minSdkVersion versions.minSdk targetSdkVersion versions.targetSdk