diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index f7d81810..5b8fefd1 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -12,10 +12,23 @@ jobs: uses: actions/setup-ruby@v1 with: ruby-version: '2.7' - - name: set up JDK 1.8 + - name: set up JDK 11 uses: actions/setup-java@v1 with: - java-version: 1.8 + distribution: 'zulu' + java-version: '11' + - name: set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.10' + - name: generate ksProp file + run: python scripts/generateKsPropFile.py + - name: create google-services.json file + run: cat app/google-services.json | base64 + - name: update google-services.json file + env: + DATA: ${{ secrets.GOOGLE_SERVICES_JSON }} + run: echo $DATA > app/google-services.json - name: setup fastlane run: bundle install - name: run unit tests @@ -30,23 +43,53 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - - name: set up JDK 1.8 + - name: set up JDK 11 uses: actions/setup-java@v1 with: - java-version: 1.8 + distribution: 'zulu' + java-version: '11' + - name: set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.10' + - name: generate ksProp file + run: python scripts/generateKsPropFile.py + - name: create google-services.json file + run: cat app/google-services.json | base64 + - name: update google-services.json file + env: + DATA: ${{ secrets.GOOGLE_SERVICES_JSON }} + run: echo $DATA > app/google-services.json - name: Lint - run: bash ./gradlew lint --stacktrace + run: bash ./gradlew lintDebug - name: Lint results uses: actions/upload-artifact@v1 with: name: app - path: app/build/reports/lint-results.html + path: app/build/reports/lint-results-debug.html ui-test: runs-on: macOS-latest steps: - name: checkout uses: actions/checkout@v2 + - name: set up JDK 11 + uses: actions/setup-java@v1 + with: + distribution: 'zulu' + java-version: '11' + - name: set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.10' + - name: generate ksProp file + run: python scripts/generateKsPropFile.py + - name: create google-services.json file + run: cat app/google-services.json | base64 + - name: update google-services.json file + env: + DATA: ${{ secrets.GOOGLE_SERVICES_JSON }} + run: echo $DATA > app/google-services.json - name: run tests uses: reactivecircus/android-emulator-runner@v2 with: diff --git a/.idea/androidTestResultsUserPreferences.xml b/.idea/androidTestResultsUserPreferences.xml new file mode 100644 index 00000000..c1bfc262 --- /dev/null +++ b/.idea/androidTestResultsUserPreferences.xml @@ -0,0 +1,24 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 33782299..669e0711 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -5,10 +5,18 @@ - + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml deleted file mode 100644 index 7f68460d..00000000 --- a/.idea/runConfigurations.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/Gemfile.lock b/Gemfile.lock index 40f07aee..9f5be1e3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,62 +1,80 @@ GEM remote: https://rubygems.org/ specs: - CFPropertyList (3.0.3) - addressable (2.7.0) - public_suffix (>= 2.0.2, < 5.0) + CFPropertyList (3.0.5) + rexml + addressable (2.8.1) + public_suffix (>= 2.0.2, < 6.0) artifactory (3.0.15) atomos (0.1.3) - aws-eventstream (1.1.0) - aws-partitions (1.416.0) - aws-sdk-core (3.111.0) + aws-eventstream (1.2.0) + aws-partitions (1.642.0) + aws-sdk-core (3.158.0) aws-eventstream (~> 1, >= 1.0.2) - aws-partitions (~> 1, >= 1.239.0) + aws-partitions (~> 1, >= 1.525.0) aws-sigv4 (~> 1.1) - jmespath (~> 1.0) - aws-sdk-kms (1.41.0) - aws-sdk-core (~> 3, >= 3.109.0) + jmespath (~> 1, >= 1.6.1) + aws-sdk-kms (1.58.0) + aws-sdk-core (~> 3, >= 3.127.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.87.0) - aws-sdk-core (~> 3, >= 3.109.0) + aws-sdk-s3 (1.114.0) + aws-sdk-core (~> 3, >= 3.127.0) aws-sdk-kms (~> 1) - aws-sigv4 (~> 1.1) - aws-sigv4 (1.2.2) + aws-sigv4 (~> 1.4) + aws-sigv4 (1.5.2) aws-eventstream (~> 1, >= 1.0.2) babosa (1.0.4) - claide (1.0.3) + claide (1.1.0) colored (1.2) colored2 (3.1.2) - commander-fastlane (4.4.6) - highline (~> 1.7.2) + commander (4.6.0) + highline (~> 2.0.0) declarative (0.0.20) - declarative-option (0.1.0) - digest-crc (0.6.3) + digest-crc (0.6.4) rake (>= 12.0.0, < 14.0.0) domain_name (0.5.20190701) unf (>= 0.0.5, < 1.0.0) - dotenv (2.7.6) - emoji_regex (3.2.1) - excon (0.78.1) - faraday (1.3.0) + dotenv (2.8.1) + emoji_regex (3.2.3) + excon (0.93.0) + faraday (1.10.2) + faraday-em_http (~> 1.0) + faraday-em_synchrony (~> 1.0) + faraday-excon (~> 1.1) + faraday-httpclient (~> 1.0) + faraday-multipart (~> 1.0) faraday-net_http (~> 1.0) - multipart-post (>= 1.2, < 3) - ruby2_keywords + faraday-net_http_persistent (~> 1.0) + faraday-patron (~> 1.0) + faraday-rack (~> 1.0) + faraday-retry (~> 1.0) + ruby2_keywords (>= 0.0.4) faraday-cookie_jar (0.0.7) faraday (>= 0.8.0) http-cookie (~> 1.0.0) + faraday-em_http (1.0.0) + faraday-em_synchrony (1.0.0) + faraday-excon (1.1.0) + faraday-httpclient (1.0.1) + faraday-multipart (1.0.4) + multipart-post (~> 2) faraday-net_http (1.0.1) - faraday_middleware (1.0.0) + faraday-net_http_persistent (1.2.0) + faraday-patron (1.0.0) + faraday-rack (1.0.0) + faraday-retry (1.0.3) + faraday_middleware (1.2.0) faraday (~> 1.0) - fastimage (2.2.1) - fastlane (2.172.0) + fastimage (2.2.6) + fastlane (2.210.1) CFPropertyList (>= 2.3, < 4.0.0) - addressable (>= 2.3, < 3.0.0) + addressable (>= 2.8, < 3.0.0) artifactory (~> 3.0) aws-sdk-s3 (~> 1.0) babosa (>= 1.0.3, < 2.0.0) bundler (>= 1.12.0, < 3.0.0) colored - commander-fastlane (>= 4.4.6, < 5.0.0) + commander (~> 4.6) dotenv (>= 2.1.1, < 3.0.0) emoji_regex (>= 0.1, < 4.0) excon (>= 0.71.0, < 1.0.0) @@ -65,18 +83,20 @@ GEM faraday_middleware (~> 1.0) fastimage (>= 2.1.0, < 3.0.0) gh_inspector (>= 1.1.2, < 2.0.0) - google-api-client (>= 0.37.0, < 0.39.0) - google-cloud-storage (>= 1.15.0, < 2.0.0) - highline (>= 1.7.2, < 2.0.0) + google-apis-androidpublisher_v3 (~> 0.3) + google-apis-playcustomapp_v1 (~> 0.1) + google-cloud-storage (~> 1.31) + highline (~> 2.0) json (< 3.0.0) jwt (>= 2.1.0, < 3) mini_magick (>= 4.9.4, < 5.0.0) multipart-post (~> 2.0.0) + naturally (~> 2.2) + optparse (~> 0.1.1) plist (>= 3.1.0, < 4.0.0) rubyzip (>= 2.0.0, < 3.0.0) security (= 0.1.3) simctl (~> 1.6.3) - slack-notifier (>= 2.0.0, < 3.0.0) terminal-notifier (>= 2.0.0, < 3.0.0) terminal-table (>= 1.4.5, < 2.0.0) tty-screen (>= 0.6.3, < 1.0.0) @@ -86,73 +106,85 @@ GEM xcpretty (~> 0.3.0) xcpretty-travis-formatter (>= 0.0.3) gh_inspector (1.1.3) - google-api-client (0.38.0) + google-apis-androidpublisher_v3 (0.29.0) + google-apis-core (>= 0.9.0, < 2.a) + google-apis-core (0.9.0) addressable (~> 2.5, >= 2.5.1) - googleauth (~> 0.9) - httpclient (>= 2.8.1, < 3.0) + googleauth (>= 0.16.2, < 2.a) + httpclient (>= 2.8.1, < 3.a) mini_mime (~> 1.0) representable (~> 3.0) - retriable (>= 2.0, < 4.0) - signet (~> 0.12) - google-cloud-core (1.5.0) + retriable (>= 2.0, < 4.a) + rexml + webrick + google-apis-iamcredentials_v1 (0.15.0) + google-apis-core (>= 0.9.0, < 2.a) + google-apis-playcustomapp_v1 (0.11.0) + google-apis-core (>= 0.9.0, < 2.a) + google-apis-storage_v1 (0.19.0) + google-apis-core (>= 0.9.0, < 2.a) + google-cloud-core (1.6.0) google-cloud-env (~> 1.0) google-cloud-errors (~> 1.0) - google-cloud-env (1.4.0) - faraday (>= 0.17.3, < 2.0) - google-cloud-errors (1.0.1) - google-cloud-storage (1.29.2) - addressable (~> 2.5) + google-cloud-env (1.6.0) + faraday (>= 0.17.3, < 3.0) + google-cloud-errors (1.3.0) + google-cloud-storage (1.43.0) + addressable (~> 2.8) digest-crc (~> 0.4) - google-api-client (~> 0.33) - google-cloud-core (~> 1.2) - googleauth (~> 0.9) + google-apis-iamcredentials_v1 (~> 0.1) + google-apis-storage_v1 (~> 0.19.0) + google-cloud-core (~> 1.6) + googleauth (>= 0.16.2, < 2.a) mini_mime (~> 1.0) - googleauth (0.14.0) - faraday (>= 0.17.3, < 2.0) + googleauth (1.2.0) + faraday (>= 0.17.3, < 3.a) jwt (>= 1.4, < 3.0) memoist (~> 0.16) multi_json (~> 1.11) os (>= 0.9, < 2.0) - signet (~> 0.14) - highline (1.7.10) - http-cookie (1.0.3) + signet (>= 0.16, < 2.a) + highline (2.0.3) + http-cookie (1.0.5) domain_name (~> 0.5) httpclient (2.8.3) - jmespath (1.4.0) - json (2.5.1) - jwt (2.2.2) + jmespath (1.6.1) + json (2.6.2) + jwt (2.5.0) memoist (0.16.2) mini_magick (4.11.0) - mini_mime (1.0.2) + mini_mime (1.1.2) multi_json (1.15.0) multipart-post (2.0.0) nanaimo (0.3.0) - naturally (2.2.0) - os (1.1.1) + naturally (2.2.1) + optparse (0.1.1) + os (1.1.4) plist (3.6.0) - public_suffix (4.0.6) - rake (13.0.3) - representable (3.0.4) + public_suffix (5.0.0) + rake (13.0.6) + representable (3.2.0) declarative (< 0.1.0) - declarative-option (< 0.2.0) + trailblazer-option (>= 0.1.1, < 0.2.0) uber (< 0.2.0) retriable (3.1.2) + rexml (3.2.5) rouge (2.0.7) - ruby2_keywords (0.0.2) - rubyzip (2.3.0) + ruby2_keywords (0.0.5) + rubyzip (2.3.2) security (0.1.3) - signet (0.14.0) - addressable (~> 2.3) - faraday (>= 0.17.3, < 2.0) + signet (0.17.0) + addressable (~> 2.8) + faraday (>= 0.17.5, < 3.a) jwt (>= 1.5, < 3.0) multi_json (~> 1.10) simctl (1.6.8) CFPropertyList naturally - slack-notifier (2.3.2) terminal-notifier (2.0.0) terminal-table (1.8.0) unicode-display_width (~> 1.1, >= 1.1.1) + trailblazer-option (0.1.2) tty-cursor (0.7.1) tty-screen (0.8.1) tty-spinner (0.9.3) @@ -160,25 +192,29 @@ GEM uber (0.1.0) unf (0.1.4) unf_ext - unf_ext (0.0.7.7-x64-mingw32) - unicode-display_width (1.7.0) + unf_ext (0.0.8.2) + unf_ext (0.0.8.2-x64-mingw32) + unicode-display_width (1.8.0) + webrick (1.7.0) word_wrap (1.0.0) - xcodeproj (1.19.0) + xcodeproj (1.22.0) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) colored2 (~> 3.1) nanaimo (~> 0.3.0) + rexml (~> 3.2.4) xcpretty (0.3.0) rouge (~> 2.0.7) xcpretty-travis-formatter (1.0.1) xcpretty (~> 0.2, >= 0.0.7) PLATFORMS + universal-darwin-21 x64-mingw32 DEPENDENCIES fastlane BUNDLED WITH - 2.1.4 + 2.3.7 diff --git a/app/.gitignore b/app/.gitignore index 796b96d1..c8f0d7e9 100644 --- a/app/.gitignore +++ b/app/.gitignore @@ -1 +1,3 @@ /build +keystore.properties +google-services.json \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index e876ce33..0b8c67e4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,12 +1,17 @@ -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply plugin: 'koin' +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' +} repositories { } android { - compileSdkVersion 30 + compileSdkVersion 33 compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 @@ -16,58 +21,90 @@ android { defaultConfig { applicationId "org.kabiri.android.usbterminal" minSdkVersion 23 - targetSdkVersion 30 - versionCode 9 - versionName "0.7.9" + targetSdkVersion 33 + versionCode 10 + versionName "0.8.0" 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' } } - buildFeatures { - viewBinding true - } + namespace 'org.kabiri.android.usbterminal' } +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 "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - implementation 'androidx.appcompat:appcompat:1.2.0' - implementation 'androidx.core:core-ktx:1.3.2' - implementation 'androidx.constraintlayout:constraintlayout:2.0.4' + implementation 'androidx.appcompat:appcompat:1.5.1' + implementation 'androidx.core:core-ktx:1.9.0' + implementation 'androidx.constraintlayout:constraintlayout:2.1.4' - // Sentry Tracking - implementation 'io.sentry:sentry-android-core:2.0.2' + // 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' - // Koin for Android - ViewModel features - implementation "org.koin:koin-android-viewmodel:$koin_version" + // Dependency Injection + implementation "com.google.dagger:hilt-android:$hilt_version" + kapt "com.google.dagger:hilt-compiler:$hilt_version" // Coroutines - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0" + implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.1' + implementation 'androidx.activity:activity-compose:1.6.0' + 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.4.2' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.2' -// testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.0-RC2' + 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.1' - testImplementation "com.google.truth:truth:1.1.2" + testImplementation 'junit:junit:4.13.2' + testImplementation "com.google.truth:truth:1.1.3" // instrumented test libs - androidTestImplementation 'androidx.test.ext:junit:1.1.2' + androidTestImplementation 'androidx.test:core:1.5.0-alpha02' + androidTestImplementation 'androidx.test.ext:junit:1.1.3' + androidTestImplementation 'androidx.test.ext:junit-ktx:1.1.3' // Espresso - androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' // Hamcrest for view matching - androidTestImplementation 'org.hamcrest:hamcrest-library:1.3' - androidTestImplementation 'androidx.test:runner:1.3.0' - androidTestImplementation 'androidx.test:rules:1.3.0' + androidTestImplementation 'org.hamcrest:hamcrest-library:2.2' + androidTestImplementation 'androidx.test:runner:1.4.0' + androidTestImplementation 'androidx.test:rules:1.4.0' /** * This library helps to automate some parts of the USB serial connection. diff --git a/app/src/androidTest/java/org/kabiri/android/usbterminal/MainActivityTest.kt b/app/src/androidTest/java/org/kabiri/android/usbterminal/MainActivityTest.kt index f49d7fbe..5a9c56a9 100644 --- a/app/src/androidTest/java/org/kabiri/android/usbterminal/MainActivityTest.kt +++ b/app/src/androidTest/java/org/kabiri/android/usbterminal/MainActivityTest.kt @@ -5,14 +5,18 @@ import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.matcher.ViewMatchers.isDisplayed import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.ext.junit.rules.ActivityScenarioRule +import androidx.test.ext.junit.rules.activityScenarioRule +import androidx.test.ext.junit.runners.AndroidJUnit4 import org.junit.Rule import org.junit.Test +import org.junit.runner.RunWith +@RunWith(AndroidJUnit4::class) class MainActivityTest { @get:Rule - var rule = ActivityScenarioRule(MainActivity::class.java) + var rule = activityScenarioRule() @Test fun checkUiViewsAreDisplayed() { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f89a8e95..c87c749d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,6 +1,5 @@ - + @@ -9,7 +8,6 @@ - + diff --git a/app/src/main/java/org/kabiri/android/usbterminal/MainActivity.kt b/app/src/main/java/org/kabiri/android/usbterminal/MainActivity.kt index dd5d9661..cb0cd4d0 100644 --- a/app/src/main/java/org/kabiri/android/usbterminal/MainActivity.kt +++ b/app/src/main/java/org/kabiri/android/usbterminal/MainActivity.kt @@ -7,49 +7,59 @@ import android.util.Log import android.view.Menu import android.view.MenuInflater import android.view.MenuItem +import android.widget.Button +import android.widget.EditText +import android.widget.TextView +import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity -import org.kabiri.android.usbterminal.databinding.ActivityMainBinding +import dagger.hilt.android.AndroidEntryPoint import org.kabiri.android.usbterminal.viewmodel.MainActivityViewModel -import org.koin.android.viewmodel.ext.android.viewModel - +@AndroidEntryPoint class MainActivity : AppCompatActivity() { companion object { private const val TAG = "MainActivity" } - private val viewModel: MainActivityViewModel by viewModel() - private lateinit var binding: ActivityMainBinding + private val viewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_main) - binding = ActivityMainBinding.inflate(layoutInflater) + + val etInput = findViewById(R.id.etInput) + val tvOutput = findViewById(R.id.tvOutput) + val btEnter = findViewById