diff --git a/CHANGELOG.md b/CHANGELOG.md index b25057f..0f5ab3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,24 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [Unreleased] +### Upgraded +- keyple-demo-common-lib `2.0.0-SNAPSHOT` -> `2.0.1-SNAPSHOT` +- All Keyple components (compiled to java 8) + - keypop-reader-java-api `2.0.0` -> `2.0.1` + - keypop-calypso-card-java-api `2.0.0` -> `2.1.0` + - keypop-calypso-crypto-legacysam-java-api `0.3.0` -> `0.6.0` + - keyple-common-java-api `2.0.0` -> `2.0.1` + - keyple-util-java-lib `2.3.1` -> `2.4.0` + - keyple-service-java-lib `3.0.1` -> `3.2.1` + - keyple-distributed-network-java-lib `2.3.0` -> `2.3.1` + - keyple-distributed-local-java-lib `2.3.0` -> `2.3.1` + - keyple-distributed-local-java-lib `2.3.0` -> `2.3.1` + - keyple-card-calypso-java-lib `3.0.1` -> `3.1.1` + - keyple-card-calypso-crypto-legacysam-java-lib `0.4.0` -> `0.7.0` + - keyple-plugin-android-nfc-java-lib `2.0.1` -> `2.2.0` + - keyple-plugin-android-omapi-java-lib `2.0.1` -> `2.1.0` + - keyple-plugin-pcsc-java-lib `2.1.2` -> `2.2.1` +- Other components (Gradle wrapper, Android Gradle Plugin, etc.) ## [2023.12.06] ### Upgraded diff --git a/client/android/app/build.gradle.kts b/client/android/app/build.gradle.kts index 62452fa..f2d234a 100644 --- a/client/android/app/build.gradle.kts +++ b/client/android/app/build.gradle.kts @@ -5,7 +5,7 @@ import java.util.Properties plugins { id("com.android.application") id("kotlin-android") - kotlin("android.extensions") + id("kotlin-parcelize") kotlin("kapt") id("com.diffplug.spotless") } @@ -17,9 +17,24 @@ val kotlinVersion: String by project val archivesBaseName: String by project val signingPropertiesFile = File("signing.properties") android { - compileSdkVersion(29) - buildToolsVersion("30.0.3") - + /** + * The app's namespace. Used primarily to access app resources. + */ + namespace = "org.calypsonet.keyple.demo.reload.remote" + + /** + * compileSdk specifies the Android API level Gradle should use to + * compile your app. This means your app can use the API features included in + * this API level and lower. + */ + compileSdk = 34 + + /** + * The defaultConfig block encapsulates default settings and entries for all + * build variants and can override some attributes in main/AndroidManifest.xml + * dynamically from the build system. You can configure product flavors to override + * these values for different versions of your app. + */ signingConfigs { create("default") { // If the application has to be signed, the elements necessary for this operation @@ -37,16 +52,17 @@ android { } defaultConfig { - applicationId("org.calypsonet.keyple.demo.remote") - minSdkVersion(21) - targetSdkVersion(29) - versionCode(6) - versionName(project.version.toString()) + applicationId = "org.calypsonet.keyple.demo.reload.remote" + minSdk = 24 + //noinspection ExpiredTargetSdkVersion + targetSdk = 31 + versionCode = 6 + versionName = project.version.toString() } buildTypes { getByName("release") { - minifyEnabled(false) + isMinifyEnabled = true // Enables code shrinking for the release build type. proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" @@ -60,21 +76,19 @@ android { val javaSourceLevel: String by project val javaTargetLevel: String by project compileOptions { - // Flag to enable support for the new language APIs - isCoreLibraryDesugaringEnabled = true sourceCompatibility = JavaVersion.toVersion(javaSourceLevel) targetCompatibility = JavaVersion.toVersion(javaTargetLevel) } + kotlinOptions { + jvmTarget = javaTargetLevel + } + packagingOptions { exclude("META-INF/NOTICE.md") exclude("META-INF/plugin_release.kotlin_module") } - kotlinOptions { - jvmTarget = javaTargetLevel - } - lintOptions { isAbortOnError = false } @@ -88,6 +102,13 @@ android { } } + /** + * Build Features Configuration + */ + buildFeatures { + viewBinding = true + } + sourceSets { getByName("main").java.srcDirs("src/main/kotlin") } @@ -95,58 +116,55 @@ android { dependencies { // Demo common - implementation("org.calypsonet.keyple:keyple-demo-common-lib:2.0.0-SNAPSHOT") { isChanging = true } - - // Keyple core - implementation("org.eclipse.keypop:keypop-reader-java-api:2.0.0") - implementation("org.eclipse.keypop:keypop-calypso-card-java-api:2.0.0") - implementation("org.eclipse.keyple:keyple-common-java-api:2.0.0") - implementation("org.eclipse.keyple:keyple-util-java-lib:2.3.1") - implementation("org.eclipse.keyple:keyple-service-java-lib:3.0.1") - implementation("org.eclipse.keyple:keyple-card-calypso-java-lib:3.0.1") - - // Keyple reader plugins - implementation("org.eclipse.keyple:keyple-plugin-android-nfc-java-lib:2.0.1") - implementation("org.eclipse.keyple:keyple-plugin-android-omapi-java-lib:2.0.1") - - // Keyple distributed - implementation("org.eclipse.keyple:keyple-distributed-network-java-lib:2.3.0") - implementation("org.eclipse.keyple:keyple-distributed-local-java-lib:2.3.0") + implementation("org.calypsonet.keyple:keyple-demo-common-lib:2.0.1-SNAPSHOT") { isChanging = true } + + // Begin Keyple configuration (generated by 'https://keyple.org/components/overview/configuration-wizard/') + implementation("org.eclipse.keypop:keypop-reader-java-api:2.0.1") + implementation("org.eclipse.keypop:keypop-calypso-card-java-api:2.1.0") + implementation("org.eclipse.keyple:keyple-common-java-api:2.0.1") + implementation("org.eclipse.keyple:keyple-util-java-lib:2.4.0") + implementation("org.eclipse.keyple:keyple-service-java-lib:3.2.1") + implementation("org.eclipse.keyple:keyple-distributed-network-java-lib:2.3.1") + implementation("org.eclipse.keyple:keyple-distributed-local-java-lib:2.3.1") + implementation("org.eclipse.keyple:keyple-card-calypso-java-lib:3.1.1") + implementation("org.eclipse.keyple:keyple-plugin-android-nfc-java-lib:2.2.0") + implementation("org.eclipse.keyple:keyple-plugin-android-omapi-java-lib:2.1.0") + // End Keyple configuration // Network - implementation("org.java-websocket:Java-WebSocket:1.3.9") + implementation("org.java-websocket:Java-WebSocket:1.5.5") // Retrofit - implementation("com.squareup.retrofit2:retrofit:2.4.0") + implementation("com.squareup.retrofit2:retrofit:2.9.0") implementation("com.squareup.retrofit2:converter-gson:2.4.0") implementation("com.squareup.retrofit2:converter-scalars:2.4.0") implementation("com.squareup.retrofit2:adapter-rxjava2:2.4.0") implementation("com.squareup.okhttp3:logging-interceptor:3.9.1") // WorkManager - implementation("androidx.work:work-runtime-ktx:2.5.0") + implementation("androidx.work:work-runtime-ktx:2.9.0") implementation("org.greenrobot:eventbus:3.2.0") // to easily handle server status change // Android components - implementation("androidx.appcompat:appcompat:1.2.0") - implementation("com.google.android.material:material:1.3.0") - implementation("androidx.constraintlayout:constraintlayout:2.0.2") - implementation("androidx.activity:activity-ktx:1.2.1") - implementation("androidx.fragment:fragment-ktx:1.3.1") + implementation("androidx.appcompat:appcompat:1.6.1") + implementation("com.google.android.material:material:1.10.0") + implementation("androidx.constraintlayout:constraintlayout:2.1.4") + implementation("androidx.activity:activity-ktx:1.8.1") + implementation("androidx.fragment:fragment-ktx:1.6.2") // Log implementation("org.slf4j:slf4j-api:1.7.32") - implementation("com.jakewharton.timber:timber:4.7.1") + implementation("com.jakewharton.timber:timber:5.0.1") implementation("com.arcao:slf4j-timber:3.1@aar") //SLF4J binding for Timber // Kotlin - implementation("androidx.core:core-ktx:1.3.2") + implementation("androidx.core:core-ktx:1.12.0") implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion") implementation("org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion") // Coroutines - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.3") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.3") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4") implementation("androidx.multidex:multidex:2.0.1") @@ -162,10 +180,6 @@ dependencies { exclude(group = "org.slf4j") } - implementation("org.slf4j:slf4j-api:1.7.32") - implementation("com.jakewharton.timber:timber:4.7.1") //Android - implementation("com.arcao:slf4j-timber:3.1@aar") //SLF4J binding for Timber - // Dagger dependencies kapt("com.google.dagger:dagger-compiler:2.19") annotationProcessor("com.google.dagger:dagger-compiler:2.19") diff --git a/client/android/app/src/androidTest/AndroidManifest.xml b/client/android/app/src/androidTest/AndroidManifest.xml new file mode 100644 index 0000000..644b5f4 --- /dev/null +++ b/client/android/app/src/androidTest/AndroidManifest.xml @@ -0,0 +1,10 @@ + + + + + + + diff --git a/client/android/app/src/main/AndroidManifest.xml b/client/android/app/src/main/AndroidManifest.xml index 9e1f2f4..f3d6828 100644 --- a/client/android/app/src/main/AndroidManifest.xml +++ b/client/android/app/src/main/AndroidManifest.xml @@ -1,126 +1,130 @@ - - - - + + - - + - - + - + android:name="android.hardware.nfc" + android:required="true"/> - + android:allowBackup="true" + android:icon="@mipmap/ic_launcher" + android:roundIcon="@mipmap/ic_launcher_round" + android:supportsRtl="true" + android:theme="@style/AppTheme" + android:usesCleartextTraffic="true" + android:label="@string/app_name" + android:name="org.calypsonet.keyple.demo.reload.remote.Application"> + android:name="org.calypsonet.keyple.demo.reload.remote.ui.MainActivity" + android:theme="@style/AppTheme.NoActionBar" + android:screenOrientation="portrait" + android:launchMode="singleTop" + android:configChanges="orientation|keyboardHidden" + android:exported="true"> - - - + + + - + android:name="org.calypsonet.keyple.demo.reload.remote.ui.HomeActivity" + android:theme="@style/AppTheme.NoActionBar" + android:screenOrientation="portrait" + android:launchMode="singleTop" + android:configChanges="orientation|keyboardHidden" + android:exported="false"> + android:name="org.calypsonet.keyple.demo.reload.remote.ui.SettingsMenuActivity" + android:theme="@style/AppTheme.NoActionBar" + android:screenOrientation="portrait" + android:launchMode="singleTop" + android:configChanges="orientation|keyboardHidden" + android:exported="false"> + android:name="org.calypsonet.keyple.demo.reload.remote.ui.ServerSettingsActivity" + android:theme="@style/AppTheme.NoActionBar" + android:screenOrientation="portrait" + android:launchMode="singleTop" + android:configChanges="orientation|keyboardHidden" + android:exported="false"> + android:name="org.calypsonet.keyple.demo.reload.remote.ui.ConfigurationSettingsActivity" + android:theme="@style/AppTheme.NoActionBar" + android:screenOrientation="portrait" + android:launchMode="singleTop" + android:configChanges="orientation|keyboardHidden" + android:exported="false"> + android:name="org.calypsonet.keyple.demo.reload.remote.ui.CardReaderActivity" + android:theme="@style/AppTheme.NoActionBar" + android:screenOrientation="portrait" + android:launchMode="singleTop" + android:configChanges="orientation|keyboardHidden" + android:exported="false"> + android:name="org.calypsonet.keyple.demo.reload.remote.ui.cardsummary.CardSummaryActivity" + android:theme="@style/AppTheme.NoActionBar" + android:screenOrientation="portrait" + android:launchMode="singleTop" + android:configChanges="orientation|keyboardHidden" + android:exported="false"> + android:name="org.calypsonet.keyple.demo.reload.remote.ui.SelectTicketsActivity" + android:theme="@style/AppTheme.NoActionBar" + android:screenOrientation="portrait" + android:launchMode="singleTop" + android:configChanges="orientation|keyboardHidden" + android:exported="false"> + android:name="org.calypsonet.keyple.demo.reload.remote.ui.CheckoutActivity" + android:theme="@style/AppTheme.NoActionBar" + android:screenOrientation="portrait" + android:launchMode="singleTop" + android:configChanges="orientation|keyboardHidden" + android:exported="false"> + android:name="org.calypsonet.keyple.demo.reload.remote.ui.PaymentValidatedActivity" + android:theme="@style/AppTheme.NoActionBar" + android:screenOrientation="portrait" + android:launchMode="singleTop" + android:configChanges="orientation|keyboardHidden" + android:exported="false"> + android:name="org.calypsonet.keyple.demo.reload.remote.ui.ReloadActivity" + android:theme="@style/AppTheme.NoActionBar" + android:screenOrientation="portrait" + android:launchMode="singleTop" + android:configChanges="orientation|keyboardHidden" + android:exported="false"> + android:name="org.calypsonet.keyple.demo.reload.remote.ui.ReloadResultActivity" + android:theme="@style/AppTheme.NoActionBar" + android:screenOrientation="portrait" + android:launchMode="singleTop" + android:configChanges="orientation|keyboardHidden" + android:exported="false"> + android:name="org.calypsonet.keyple.demo.reload.remote.ui.PersonalizationActivity" + android:theme="@style/AppTheme.NoActionBar" + android:screenOrientation="portrait" + android:launchMode="singleTop" + android:configChanges="orientation|keyboardHidden" + android:exported="false"> - diff --git a/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/data/SharedPrefDataRepository.kt b/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/data/SharedPrefDataRepository.kt index dbb28c3..13e96f6 100644 --- a/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/data/SharedPrefDataRepository.kt +++ b/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/data/SharedPrefDataRepository.kt @@ -74,8 +74,9 @@ class SharedPrefDataRepository @Inject constructor(private var prefs: SharedPref fun loadContactlessConfigurationVisibility(): Visibility { return Visibility.valueOf( - prefs.getString(SETTING_CONTACTLESS_VISIBILITY, Visibility.ENABLE.text)!!.uppercase( - Locale.ROOT)) + prefs + .getString(SETTING_CONTACTLESS_VISIBILITY, Visibility.ENABLE.text)!! + .uppercase(Locale.ROOT)) } fun saveSimConfigurationVisibility(visibility: Visibility) { @@ -97,8 +98,9 @@ class SharedPrefDataRepository @Inject constructor(private var prefs: SharedPref fun loadWearableConfigurationVisibility(): Visibility { return Visibility.valueOf( - prefs.getString(SETTING_WEARABLE_VISIBILITY, Visibility.DISABLE.text)!!.uppercase( - Locale.ROOT)) + prefs + .getString(SETTING_WEARABLE_VISIBILITY, Visibility.DISABLE.text)!! + .uppercase(Locale.ROOT)) } fun saveEmbeddedConfigurationVisibility(visibility: Visibility) { @@ -109,8 +111,9 @@ class SharedPrefDataRepository @Inject constructor(private var prefs: SharedPref fun loadEmbeddedConfigurationVisibility(): Visibility { return Visibility.valueOf( - prefs.getString(SETTING_EMBEDDED_VISIBILITY, Visibility.DISABLE.text)!!.uppercase( - Locale.ROOT)) + prefs + .getString(SETTING_EMBEDDED_VISIBILITY, Visibility.DISABLE.text)!! + .uppercase(Locale.ROOT)) } fun saveLastStatus(up: Boolean) { diff --git a/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/AbstractDemoActivity.kt b/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/AbstractDemoActivity.kt index 61f306d..ace2267 100644 --- a/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/AbstractDemoActivity.kt +++ b/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/AbstractDemoActivity.kt @@ -15,12 +15,12 @@ import android.os.AsyncTask import android.os.Bundle import dagger.android.support.DaggerAppCompatActivity import javax.inject.Inject -import kotlinx.android.synthetic.main.toolbar.* import org.calypsonet.keyple.demo.reload.remote.R import org.calypsonet.keyple.demo.reload.remote.data.SharedPrefDataRepository import org.calypsonet.keyple.demo.reload.remote.data.model.SamStatus import org.calypsonet.keyple.demo.reload.remote.data.model.ServerStatusEvent import org.calypsonet.keyple.demo.reload.remote.data.network.RestClient +import org.calypsonet.keyple.demo.reload.remote.databinding.ToolbarBinding import org.eclipse.keyple.core.util.json.JsonUtil import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe @@ -33,6 +33,7 @@ import retrofit2.converter.scalars.ScalarsConverterFactory abstract class AbstractDemoActivity : DaggerAppCompatActivity() { private lateinit var client: RestClient + protected lateinit var toolbarBinding: ToolbarBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -73,8 +74,9 @@ abstract class AbstractDemoActivity : DaggerAppCompatActivity() { } private fun updateServerStatusIndicator() { - if (prefData.loadLastStatus()) serverStatus.setImageResource(R.drawable.ic_connection_success) - else serverStatus.setImageResource(R.drawable.ic_connection_wait) + if (prefData.loadLastStatus()) + toolbarBinding.serverStatus.setImageResource(R.drawable.ic_connection_success) + else toolbarBinding.serverStatus.setImageResource(R.drawable.ic_connection_wait) } private fun checkServerStatus() { diff --git a/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/CardReaderActivity.kt b/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/CardReaderActivity.kt index 9f5195d..d177cdf 100644 --- a/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/CardReaderActivity.kt +++ b/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/CardReaderActivity.kt @@ -21,9 +21,6 @@ import java.time.format.DateTimeFormatter import java.util.Locale import javax.inject.Inject import kotlin.Exception -import kotlinx.android.synthetic.main.activity_card_reader.cardAnimation -import kotlinx.android.synthetic.main.activity_card_reader.loadingAnimation -import kotlinx.android.synthetic.main.activity_card_reader.presentTxt import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch @@ -35,6 +32,7 @@ import org.calypsonet.keyple.demo.common.model.ContractStructure import org.calypsonet.keyple.demo.common.model.type.PriorityCode import org.calypsonet.keyple.demo.reload.remote.R import org.calypsonet.keyple.demo.reload.remote.data.model.* +import org.calypsonet.keyple.demo.reload.remote.databinding.ActivityCardReaderBinding import org.calypsonet.keyple.demo.reload.remote.di.scopes.ActivityScoped import org.calypsonet.keyple.demo.reload.remote.domain.TicketingService import org.calypsonet.keyple.demo.reload.remote.ui.cardsummary.CardSummaryActivity @@ -50,10 +48,13 @@ class CardReaderActivity : AbstractCardActivity() { @Inject lateinit var ticketingService: TicketingService private val dateTimeFormatter = DateTimeFormatter.ofPattern("d MMMM yyyy", Locale.ENGLISH) + private lateinit var activityCardReaderBinding: ActivityCardReaderBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_card_reader) + activityCardReaderBinding = ActivityCardReaderBinding.inflate(layoutInflater) + toolbarBinding = activityCardReaderBinding.appBarLayout + setContentView(activityCardReaderBinding.root) } override fun initReaders() { @@ -94,8 +95,8 @@ class CardReaderActivity : AbstractCardActivity() { } override fun onPause() { - cardAnimation.cancelAnimation() - loadingAnimation.cancelAnimation() + activityCardReaderBinding.cardAnimation.cancelAnimation() + activityCardReaderBinding.loadingAnimation.cancelAnimation() try { if (DeviceEnum.getDeviceEnum(prefData.loadDeviceType()!!) == DeviceEnum.CONTACTLESS_CARD) { deactivateAndClearAndroidKeypleNfcReader() @@ -238,8 +239,8 @@ class CardReaderActivity : AbstractCardActivity() { applicationSerialNumber: String?, finishActivity: Boolean? ) { - loadingAnimation?.cancelAnimation() - cardAnimation?.cancelAnimation() + activityCardReaderBinding.loadingAnimation?.cancelAnimation() + activityCardReaderBinding.cardAnimation?.cancelAnimation() val intent = Intent(this, CardSummaryActivity::class.java) intent.putExtra(CARD_CONTENT, cardReaderResponse) intent.putExtra(CARD_APPLICATION_NUMBER, applicationSerialNumber) @@ -250,18 +251,18 @@ class CardReaderActivity : AbstractCardActivity() { } private fun showPresentNfcCardInstructions() { - presentTxt.text = getString(R.string.present_travel_card_label) - cardAnimation.visibility = View.VISIBLE - cardAnimation.playAnimation() - loadingAnimation.cancelAnimation() - loadingAnimation.visibility = View.INVISIBLE + activityCardReaderBinding.presentTxt.text = getString(R.string.present_travel_card_label) + activityCardReaderBinding.cardAnimation.visibility = View.VISIBLE + activityCardReaderBinding.cardAnimation.playAnimation() + activityCardReaderBinding.loadingAnimation.cancelAnimation() + activityCardReaderBinding.loadingAnimation.visibility = View.INVISIBLE } private fun showNowLoadingInformation() { - presentTxt.text = getString(R.string.read_in_progress) - loadingAnimation.visibility = View.VISIBLE - loadingAnimation.playAnimation() - cardAnimation.cancelAnimation() - cardAnimation.visibility = View.INVISIBLE + activityCardReaderBinding.presentTxt.text = getString(R.string.read_in_progress) + activityCardReaderBinding.loadingAnimation.visibility = View.VISIBLE + activityCardReaderBinding.loadingAnimation.playAnimation() + activityCardReaderBinding.cardAnimation.cancelAnimation() + activityCardReaderBinding.cardAnimation.visibility = View.INVISIBLE } } diff --git a/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/CheckoutActivity.kt b/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/CheckoutActivity.kt index d9473ab..f20d203 100644 --- a/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/CheckoutActivity.kt +++ b/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/CheckoutActivity.kt @@ -15,18 +15,19 @@ import android.content.Intent import android.os.Bundle import java.text.SimpleDateFormat import java.util.Calendar -import kotlinx.android.synthetic.main.activity_checkout.expiryValue -import kotlinx.android.synthetic.main.activity_checkout.selectionLabel -import kotlinx.android.synthetic.main.activity_checkout.selectionPrice -import kotlinx.android.synthetic.main.activity_checkout.validateBtn import org.calypsonet.keyple.demo.common.model.type.PriorityCode import org.calypsonet.keyple.demo.reload.remote.R +import org.calypsonet.keyple.demo.reload.remote.databinding.ActivityCheckoutBinding class CheckoutActivity : AbstractDemoActivity() { + private lateinit var activityCheckoutBinding: ActivityCheckoutBinding + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_checkout) + activityCheckoutBinding = ActivityCheckoutBinding.inflate(layoutInflater) + toolbarBinding = activityCheckoutBinding.appBarLayout + setContentView(activityCheckoutBinding.root) val selectedTicketPriorityCode = PriorityCode.findEnumByKey( @@ -35,14 +36,15 @@ class CheckoutActivity : AbstractDemoActivity() { val ticketNumberCount: Int = intent.getIntExtra(SelectTicketsActivity.TICKETS_NUMBER, 0) if (selectedTicketPriorityCode == PriorityCode.SEASON_PASS) { - selectionLabel.text = getString(R.string.season_pass_title) - selectionPrice.text = getString(R.string.ticket_price, 20) + activityCheckoutBinding.selectionLabel.text = getString(R.string.season_pass_title) + activityCheckoutBinding.selectionPrice.text = getString(R.string.ticket_price, 20) } else { - selectionLabel.text = + activityCheckoutBinding.selectionLabel.text = resources.getQuantityString(R.plurals.x_tickets, ticketNumberCount, ticketNumberCount) - selectionPrice.text = getString(R.string.ticket_price, ticketNumberCount) + activityCheckoutBinding.selectionPrice.text = + getString(R.string.ticket_price, ticketNumberCount) } - validateBtn.setOnClickListener { + activityCheckoutBinding.validateBtn.setOnClickListener { val intent = Intent(this, PaymentValidatedActivity::class.java) intent.putExtras(getIntent()) startActivity(intent) @@ -51,6 +53,6 @@ class CheckoutActivity : AbstractDemoActivity() { val now = Calendar.getInstance().time val sdf = SimpleDateFormat("MM/yy") - expiryValue.text = sdf.format(now) + activityCheckoutBinding.expiryValue.text = sdf.format(now) } } diff --git a/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/ConfigurationSettingsActivity.kt b/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/ConfigurationSettingsActivity.kt index c2e3838..5c4d7c6 100644 --- a/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/ConfigurationSettingsActivity.kt +++ b/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/ConfigurationSettingsActivity.kt @@ -14,47 +14,42 @@ package org.calypsonet.keyple.demo.reload.remote.ui import android.os.Bundle import android.view.View import android.widget.RadioButton -import kotlinx.android.synthetic.main.activity_configuration_settings.backBtn -import kotlinx.android.synthetic.main.activity_configuration_settings.contactlessCardDisable -import kotlinx.android.synthetic.main.activity_configuration_settings.contactlessCardEnable -import kotlinx.android.synthetic.main.activity_configuration_settings.contactlessCardHide -import kotlinx.android.synthetic.main.activity_configuration_settings.embeddedCardDisable -import kotlinx.android.synthetic.main.activity_configuration_settings.embeddedCardEnable -import kotlinx.android.synthetic.main.activity_configuration_settings.embeddedCardHide -import kotlinx.android.synthetic.main.activity_configuration_settings.simCardDisable -import kotlinx.android.synthetic.main.activity_configuration_settings.simCardEnable -import kotlinx.android.synthetic.main.activity_configuration_settings.simCardHide -import kotlinx.android.synthetic.main.activity_configuration_settings.wearableCardDisable -import kotlinx.android.synthetic.main.activity_configuration_settings.wearableCardEnable -import kotlinx.android.synthetic.main.activity_configuration_settings.wearableCardHide import org.calypsonet.keyple.demo.reload.remote.R import org.calypsonet.keyple.demo.reload.remote.data.SharedPrefDataRepository +import org.calypsonet.keyple.demo.reload.remote.databinding.ActivityConfigurationSettingsBinding class ConfigurationSettingsActivity : AbstractDemoActivity() { + private lateinit var activityConfigurationSettingsBinding: ActivityConfigurationSettingsBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_configuration_settings) + activityConfigurationSettingsBinding = + ActivityConfigurationSettingsBinding.inflate(layoutInflater) + toolbarBinding = activityConfigurationSettingsBinding.appBarLayout + setContentView(activityConfigurationSettingsBinding.root) - backBtn.setOnClickListener { onBackPressed() } + activityConfigurationSettingsBinding.backBtn.setOnClickListener { onBackPressed() } setupRadioBtn( prefData.loadContactlessConfigurationVisibility(), - contactlessCardEnable, - contactlessCardDisable, - contactlessCardHide) + activityConfigurationSettingsBinding.contactlessCardEnable, + activityConfigurationSettingsBinding.contactlessCardDisable, + activityConfigurationSettingsBinding.contactlessCardHide) setupRadioBtn( - prefData.loadSimConfigurationVisibility(), simCardEnable, simCardDisable, simCardHide) + prefData.loadSimConfigurationVisibility(), + activityConfigurationSettingsBinding.simCardEnable, + activityConfigurationSettingsBinding.simCardDisable, + activityConfigurationSettingsBinding.simCardHide) setupRadioBtn( prefData.loadWearableConfigurationVisibility(), - wearableCardEnable, - wearableCardDisable, - wearableCardHide) + activityConfigurationSettingsBinding.wearableCardEnable, + activityConfigurationSettingsBinding.wearableCardDisable, + activityConfigurationSettingsBinding.wearableCardHide) setupRadioBtn( prefData.loadEmbeddedConfigurationVisibility(), - embeddedCardEnable, - embeddedCardDisable, - embeddedCardHide) + activityConfigurationSettingsBinding.embeddedCardEnable, + activityConfigurationSettingsBinding.embeddedCardDisable, + activityConfigurationSettingsBinding.embeddedCardHide) } private fun setupRadioBtn( @@ -118,9 +113,9 @@ class ConfigurationSettingsActivity : AbstractDemoActivity() { // Update layout setupRadioBtn( prefData.loadContactlessConfigurationVisibility(), - contactlessCardEnable, - contactlessCardDisable, - contactlessCardHide) + activityConfigurationSettingsBinding.contactlessCardEnable, + activityConfigurationSettingsBinding.contactlessCardDisable, + activityConfigurationSettingsBinding.contactlessCardHide) } } @@ -148,7 +143,10 @@ class ConfigurationSettingsActivity : AbstractDemoActivity() { } } setupRadioBtn( - prefData.loadSimConfigurationVisibility(), simCardEnable, simCardDisable, simCardHide) + prefData.loadSimConfigurationVisibility(), + activityConfigurationSettingsBinding.simCardEnable, + activityConfigurationSettingsBinding.simCardDisable, + activityConfigurationSettingsBinding.simCardHide) } } @@ -177,9 +175,9 @@ class ConfigurationSettingsActivity : AbstractDemoActivity() { } setupRadioBtn( prefData.loadWearableConfigurationVisibility(), - wearableCardEnable, - wearableCardDisable, - wearableCardHide) + activityConfigurationSettingsBinding.wearableCardEnable, + activityConfigurationSettingsBinding.wearableCardDisable, + activityConfigurationSettingsBinding.wearableCardHide) } } @@ -208,9 +206,9 @@ class ConfigurationSettingsActivity : AbstractDemoActivity() { } setupRadioBtn( prefData.loadEmbeddedConfigurationVisibility(), - embeddedCardEnable, - embeddedCardDisable, - embeddedCardHide) + activityConfigurationSettingsBinding.embeddedCardEnable, + activityConfigurationSettingsBinding.embeddedCardDisable, + activityConfigurationSettingsBinding.embeddedCardHide) } } } diff --git a/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/HomeActivity.kt b/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/HomeActivity.kt index ce779c3..ff2b4e2 100644 --- a/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/HomeActivity.kt +++ b/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/HomeActivity.kt @@ -15,34 +15,46 @@ import android.content.Intent import android.os.Bundle import android.view.View import androidx.core.content.ContextCompat -import kotlinx.android.synthetic.main.activity_home.* -import kotlinx.android.synthetic.main.toolbar.* import org.calypsonet.keyple.demo.reload.remote.R import org.calypsonet.keyple.demo.reload.remote.data.SharedPrefDataRepository import org.calypsonet.keyple.demo.reload.remote.data.model.DeviceEnum +import org.calypsonet.keyple.demo.reload.remote.databinding.ActivityHomeBinding class HomeActivity : AbstractDemoActivity() { + private lateinit var activityHomeBinding: ActivityHomeBinding + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_home) + activityHomeBinding = ActivityHomeBinding.inflate(layoutInflater) + toolbarBinding = activityHomeBinding.appBarLayout + setContentView(activityHomeBinding.root) if (intent.getBooleanExtra(CHOOSE_DEVICE_FOR_PERSO, false)) { - chooseDeviceTv.append(" ") - chooseDeviceTv.append(getString(R.string.to_be_personalized)) + activityHomeBinding.chooseDeviceTv.append(" ") + activityHomeBinding.chooseDeviceTv.append(getString(R.string.to_be_personalized)) + } + toolbarBinding.menuBtn.visibility = View.VISIBLE + toolbarBinding.menuBtn.setOnClickListener { + startActivity(Intent(this, SettingsMenuActivity::class.java)) } - menuBtn.visibility = View.VISIBLE - menuBtn.setOnClickListener { startActivity(Intent(this, SettingsMenuActivity::class.java)) } } override fun onResume() { super.onResume() setupBtn( - contactlessCardBtn, + activityHomeBinding.contactlessCardBtn, prefData.loadContactlessConfigurationVisibility(), DeviceEnum.CONTACTLESS_CARD) - setupBtn(simCardBtn, prefData.loadSimConfigurationVisibility(), DeviceEnum.SIM) - setupBtn(wearableBtn, prefData.loadWearableConfigurationVisibility(), DeviceEnum.WEARABLE) - setupBtn(embeddedElemBtn, prefData.loadEmbeddedConfigurationVisibility(), DeviceEnum.EMBEDDED) + setupBtn( + activityHomeBinding.simCardBtn, prefData.loadSimConfigurationVisibility(), DeviceEnum.SIM) + setupBtn( + activityHomeBinding.wearableBtn, + prefData.loadWearableConfigurationVisibility(), + DeviceEnum.WEARABLE) + setupBtn( + activityHomeBinding.embeddedElemBtn, + prefData.loadEmbeddedConfigurationVisibility(), + DeviceEnum.EMBEDDED) } private fun setupBtn( diff --git a/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/MainActivity.kt b/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/MainActivity.kt index 2ded8ea..5509c0b 100644 --- a/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/MainActivity.kt +++ b/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/MainActivity.kt @@ -16,14 +16,17 @@ import android.os.Bundle import dagger.android.support.DaggerAppCompatActivity import java.util.Timer import java.util.TimerTask -import org.calypsonet.keyple.demo.reload.remote.R +import org.calypsonet.keyple.demo.reload.remote.databinding.ActivityMainBinding class MainActivity : DaggerAppCompatActivity() { + private lateinit var activityMainBinding: ActivityMainBinding + override fun onCreate(savedInstanceState: Bundle?) { // Make sure this is before calling super.onCreate super.onCreate(savedInstanceState) - setContentView(R.layout.activity_main) + activityMainBinding = ActivityMainBinding.inflate(layoutInflater) + setContentView(activityMainBinding.root) // Wait for Wizway Device to be connected Timer() .schedule( diff --git a/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/PaymentValidatedActivity.kt b/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/PaymentValidatedActivity.kt index 5c8d5f4..9d6bada 100644 --- a/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/PaymentValidatedActivity.kt +++ b/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/PaymentValidatedActivity.kt @@ -13,17 +13,20 @@ package org.calypsonet.keyple.demo.reload.remote.ui import android.content.Intent import android.os.Bundle -import kotlinx.android.synthetic.main.activity_payment_validated.animation -import kotlinx.android.synthetic.main.activity_payment_validated.chargeBtn import org.calypsonet.keyple.demo.reload.remote.R +import org.calypsonet.keyple.demo.reload.remote.databinding.ActivityPaymentValidatedBinding class PaymentValidatedActivity : AbstractDemoActivity() { + private lateinit var activityPaymentValidatedBinding: ActivityPaymentValidatedBinding + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_payment_validated) - chargeBtn.text = getString(R.string.load_card) - chargeBtn.setOnClickListener { + activityPaymentValidatedBinding = ActivityPaymentValidatedBinding.inflate(layoutInflater) + toolbarBinding = activityPaymentValidatedBinding.appBarLayout + setContentView(activityPaymentValidatedBinding.root) + activityPaymentValidatedBinding.chargeBtn.text = getString(R.string.load_card) + activityPaymentValidatedBinding.chargeBtn.setOnClickListener { val intent = Intent(this, ReloadActivity::class.java) intent.putExtras(getIntent()) startActivity(intent) @@ -33,8 +36,8 @@ class PaymentValidatedActivity : AbstractDemoActivity() { override fun onResume() { super.onResume() - animation.setAnimation("tick_anim.json") - animation.repeatCount = 0 - animation.playAnimation() + activityPaymentValidatedBinding.animation.setAnimation("tick_anim.json") + activityPaymentValidatedBinding.animation.repeatCount = 0 + activityPaymentValidatedBinding.animation.playAnimation() } } diff --git a/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/PersonalizationActivity.kt b/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/PersonalizationActivity.kt index 73f9550..f4d2653 100644 --- a/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/PersonalizationActivity.kt +++ b/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/PersonalizationActivity.kt @@ -17,7 +17,6 @@ import android.view.View import java.lang.Exception import java.lang.IllegalStateException import javax.inject.Inject -import kotlinx.android.synthetic.main.activity_card_reader.* import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch @@ -30,6 +29,7 @@ import org.calypsonet.keyple.demo.reload.remote.data.model.AppSettings import org.calypsonet.keyple.demo.reload.remote.data.model.CardReaderResponse import org.calypsonet.keyple.demo.reload.remote.data.model.DeviceEnum import org.calypsonet.keyple.demo.reload.remote.data.model.Status +import org.calypsonet.keyple.demo.reload.remote.databinding.ActivityPersonalizationBinding import org.calypsonet.keyple.demo.reload.remote.di.scopes.ActivityScoped import org.calypsonet.keyple.demo.reload.remote.domain.TicketingService import org.eclipse.keyple.core.util.HexUtil @@ -40,10 +40,13 @@ import timber.log.Timber class PersonalizationActivity : AbstractCardActivity() { @Inject lateinit var ticketingService: TicketingService + private lateinit var activityPersonalizationBinding: ActivityPersonalizationBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_personalization) + activityPersonalizationBinding = ActivityPersonalizationBinding.inflate(layoutInflater) + toolbarBinding = activityPersonalizationBinding.appBarLayout + setContentView(activityPersonalizationBinding.root) } override fun initReaders() { @@ -65,8 +68,8 @@ class PersonalizationActivity : AbstractCardActivity() { } override fun onPause() { - cardAnimation.cancelAnimation() - loadingAnimation.cancelAnimation() + activityPersonalizationBinding.cardAnimation.cancelAnimation() + activityPersonalizationBinding.loadingAnimation.cancelAnimation() try { if (DeviceEnum.getDeviceEnum(prefData.loadDeviceType()!!) == DeviceEnum.CONTACTLESS_CARD) { deactivateAndClearAndroidKeypleNfcReader() @@ -80,19 +83,20 @@ class PersonalizationActivity : AbstractCardActivity() { } private fun showPresentNfcCardInstructions() { - presentTxt.text = getString(R.string.present_card_personalization) - cardAnimation.visibility = View.VISIBLE - cardAnimation.playAnimation() - loadingAnimation.cancelAnimation() - loadingAnimation.visibility = View.INVISIBLE + activityPersonalizationBinding.presentTxt.text = + getString(R.string.present_card_personalization) + activityPersonalizationBinding.cardAnimation.visibility = View.VISIBLE + activityPersonalizationBinding.cardAnimation.playAnimation() + activityPersonalizationBinding.loadingAnimation.cancelAnimation() + activityPersonalizationBinding.loadingAnimation.visibility = View.INVISIBLE } private fun showNowPersonalizingInformation() { - presentTxt.text = getString(R.string.personalization_in_progress) - loadingAnimation.visibility = View.VISIBLE - loadingAnimation.playAnimation() - cardAnimation.cancelAnimation() - cardAnimation.visibility = View.INVISIBLE + activityPersonalizationBinding.presentTxt.text = getString(R.string.personalization_in_progress) + activityPersonalizationBinding.loadingAnimation.visibility = View.VISIBLE + activityPersonalizationBinding.loadingAnimation.playAnimation() + activityPersonalizationBinding.cardAnimation.cancelAnimation() + activityPersonalizationBinding.cardAnimation.visibility = View.INVISIBLE } override fun changeDisplay( diff --git a/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/ReloadActivity.kt b/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/ReloadActivity.kt index 9e0c4e4..1164dae 100644 --- a/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/ReloadActivity.kt +++ b/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/ReloadActivity.kt @@ -17,9 +17,6 @@ import android.view.View import java.lang.Exception import java.lang.IllegalStateException import javax.inject.Inject -import kotlinx.android.synthetic.main.activity_card_reader.cardAnimation -import kotlinx.android.synthetic.main.activity_card_reader.loadingAnimation -import kotlinx.android.synthetic.main.activity_card_reader.presentTxt import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch @@ -35,6 +32,7 @@ import org.calypsonet.keyple.demo.reload.remote.data.model.AppSettings import org.calypsonet.keyple.demo.reload.remote.data.model.CardReaderResponse import org.calypsonet.keyple.demo.reload.remote.data.model.DeviceEnum import org.calypsonet.keyple.demo.reload.remote.data.model.Status +import org.calypsonet.keyple.demo.reload.remote.databinding.ActivityCardReaderBinding import org.calypsonet.keyple.demo.reload.remote.di.scopes.ActivityScoped import org.calypsonet.keyple.demo.reload.remote.domain.TicketingService import org.eclipse.keyple.core.util.HexUtil @@ -45,10 +43,13 @@ import timber.log.Timber class ReloadActivity : AbstractCardActivity() { @Inject lateinit var ticketingService: TicketingService + private lateinit var activityCardReaderBinding: ActivityCardReaderBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_charge) + activityCardReaderBinding = ActivityCardReaderBinding.inflate(layoutInflater) + toolbarBinding = activityCardReaderBinding.appBarLayout + setContentView(activityCardReaderBinding.root) } override fun initReaders() { @@ -71,8 +72,8 @@ class ReloadActivity : AbstractCardActivity() { } override fun onPause() { - cardAnimation.cancelAnimation() - loadingAnimation.cancelAnimation() + activityCardReaderBinding.cardAnimation.cancelAnimation() + activityCardReaderBinding.loadingAnimation.cancelAnimation() try { if (DeviceEnum.getDeviceEnum(prefData.loadDeviceType()!!) == DeviceEnum.CONTACTLESS_CARD) { deactivateAndClearAndroidKeypleNfcReader() @@ -169,8 +170,8 @@ class ReloadActivity : AbstractCardActivity() { applicationSerialNumber: String?, finishActivity: Boolean? ) { - loadingAnimation.cancelAnimation() - cardAnimation.cancelAnimation() + activityCardReaderBinding.loadingAnimation.cancelAnimation() + activityCardReaderBinding.cardAnimation.cancelAnimation() val intent = Intent(this, ReloadResultActivity::class.java) intent.putExtra(ReloadResultActivity.TICKETS_NUMBER, 0) intent.putExtra(ReloadResultActivity.STATUS, cardReaderResponse.status.toString()) @@ -182,18 +183,18 @@ class ReloadActivity : AbstractCardActivity() { } private fun showPresentNfcCardInstructions() { - presentTxt.text = getString(R.string.present_card) - cardAnimation.visibility = View.VISIBLE - cardAnimation.playAnimation() - loadingAnimation.cancelAnimation() - loadingAnimation.visibility = View.INVISIBLE + activityCardReaderBinding.presentTxt.text = getString(R.string.present_card) + activityCardReaderBinding.cardAnimation.visibility = View.VISIBLE + activityCardReaderBinding.cardAnimation.playAnimation() + activityCardReaderBinding.loadingAnimation.cancelAnimation() + activityCardReaderBinding.loadingAnimation.visibility = View.INVISIBLE } private fun showNowLoadingInformation() { - presentTxt.text = getString(R.string.loading_in_progress) - loadingAnimation.visibility = View.VISIBLE - loadingAnimation.playAnimation() - cardAnimation.cancelAnimation() - cardAnimation.visibility = View.INVISIBLE + activityCardReaderBinding.presentTxt.text = getString(R.string.loading_in_progress) + activityCardReaderBinding.loadingAnimation.visibility = View.VISIBLE + activityCardReaderBinding.loadingAnimation.playAnimation() + activityCardReaderBinding.cardAnimation.cancelAnimation() + activityCardReaderBinding.cardAnimation.visibility = View.INVISIBLE } } diff --git a/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/ReloadResultActivity.kt b/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/ReloadResultActivity.kt index d08f7cc..b4ff7ea 100644 --- a/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/ReloadResultActivity.kt +++ b/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/ReloadResultActivity.kt @@ -18,53 +18,51 @@ import android.view.View import com.airbnb.lottie.LottieDrawable import java.util.Timer import java.util.TimerTask -import kotlinx.android.synthetic.main.activity_charge_result.animation -import kotlinx.android.synthetic.main.activity_charge_result.bigText -import kotlinx.android.synthetic.main.activity_charge_result.btnLayout -import kotlinx.android.synthetic.main.activity_charge_result.cancelBtn -import kotlinx.android.synthetic.main.activity_charge_result.mainBackground -import kotlinx.android.synthetic.main.activity_charge_result.tryBtn -import kotlinx.android.synthetic.main.toolbar.toolbarLogo import org.calypsonet.keyple.demo.reload.remote.R import org.calypsonet.keyple.demo.reload.remote.data.model.Status +import org.calypsonet.keyple.demo.reload.remote.databinding.ActivityChargeResultBinding class ReloadResultActivity : AbstractDemoActivity() { private val timer = Timer() + private lateinit var activityChargeResultBinding: ActivityChargeResultBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_charge_result) - toolbarLogo.setImageResource(R.drawable.ic_logo_white) + activityChargeResultBinding = ActivityChargeResultBinding.inflate(layoutInflater) + toolbarBinding = activityChargeResultBinding.appBarLayout + setContentView(activityChargeResultBinding.root) + toolbarBinding.toolbarLogo.setImageResource(R.drawable.ic_logo_white) val status = Status.getStatus(intent.getStringExtra(STATUS)) - tryBtn.setOnClickListener { onBackPressed() } - cancelBtn.setOnClickListener { + activityChargeResultBinding.tryBtn.setOnClickListener { onBackPressed() } + activityChargeResultBinding.cancelBtn.setOnClickListener { val intent = Intent(this, HomeActivity::class.java) startActivity(intent) } when (status) { Status.LOADING -> { - animation.setAnimation("loading_anim.json") - animation.repeatCount = LottieDrawable.INFINITE - bigText.visibility = View.INVISIBLE - btnLayout.visibility = View.INVISIBLE + activityChargeResultBinding.animation.setAnimation("loading_anim.json") + activityChargeResultBinding.animation.repeatCount = LottieDrawable.INFINITE + activityChargeResultBinding.bigText.visibility = View.INVISIBLE + activityChargeResultBinding.btnLayout.visibility = View.INVISIBLE } Status.SUCCESS -> { - mainBackground.setBackgroundColor(resources.getColor(R.color.green)) - animation.setAnimation("tick_white.json") - animation.repeatCount = 0 - animation.playAnimation() - bigText.setText(R.string.charging_success_label) - bigText.visibility = View.VISIBLE - btnLayout.visibility = View.INVISIBLE + activityChargeResultBinding.mainBackground.setBackgroundColor( + resources.getColor(R.color.green)) + activityChargeResultBinding.animation.setAnimation("tick_white.json") + activityChargeResultBinding.animation.repeatCount = 0 + activityChargeResultBinding.animation.playAnimation() + activityChargeResultBinding.bigText.setText(R.string.charging_success_label) + activityChargeResultBinding.bigText.visibility = View.VISIBLE + activityChargeResultBinding.btnLayout.visibility = View.INVISIBLE if (intent.getBooleanExtra(IS_PERSONALIZATION_RESULT, false)) { - bigText.setText(R.string.perso_success_label) + activityChargeResultBinding.bigText.setText(R.string.perso_success_label) } else { - bigText.setText(R.string.charging_success_label) + activityChargeResultBinding.bigText.setText(R.string.charging_success_label) } Intent(this, HomeActivity::class.java) @@ -77,23 +75,24 @@ class ReloadResultActivity : AbstractDemoActivity() { RETURN_DELAY_MS.toLong()) } else -> { - mainBackground.setBackgroundColor(resources.getColor(R.color.red)) - animation.setAnimation("error_white.json") - animation.repeatCount = 0 - animation.playAnimation() + activityChargeResultBinding.mainBackground.setBackgroundColor( + resources.getColor(R.color.red)) + activityChargeResultBinding.animation.setAnimation("error_white.json") + activityChargeResultBinding.animation.repeatCount = 0 + activityChargeResultBinding.animation.playAnimation() val message = intent.getStringExtra(MESSAGE) if (intent.getBooleanExtra(IS_PERSONALIZATION_RESULT, false)) { - bigText.setText(R.string.perso_failed_label) - bigText.append(":\n") - bigText.append(message) + activityChargeResultBinding.bigText.setText(R.string.perso_failed_label) + activityChargeResultBinding.bigText.append(":\n") + activityChargeResultBinding.bigText.append(message) } else { - bigText.setText(R.string.transaction_cancelled_label) - bigText.append(":\n") - bigText.append(message) + activityChargeResultBinding.bigText.setText(R.string.transaction_cancelled_label) + activityChargeResultBinding.bigText.append(":\n") + activityChargeResultBinding.bigText.append(message) } - bigText.visibility = View.VISIBLE - btnLayout.visibility = View.VISIBLE + activityChargeResultBinding.bigText.visibility = View.VISIBLE + activityChargeResultBinding.btnLayout.visibility = View.VISIBLE } } diff --git a/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/SelectTicketsActivity.kt b/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/SelectTicketsActivity.kt index 3b40476..4acba08 100644 --- a/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/SelectTicketsActivity.kt +++ b/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/SelectTicketsActivity.kt @@ -13,45 +13,50 @@ package org.calypsonet.keyple.demo.reload.remote.ui import android.content.Intent import android.os.Bundle -import kotlinx.android.synthetic.main.activity_select_tickets.seasonPassBtn -import kotlinx.android.synthetic.main.activity_select_tickets.seasonPassPrice -import kotlinx.android.synthetic.main.activity_select_tickets.ticket1Btn -import kotlinx.android.synthetic.main.activity_select_tickets.ticket1Label -import kotlinx.android.synthetic.main.activity_select_tickets.ticket1Price -import kotlinx.android.synthetic.main.activity_select_tickets.ticket2Btn -import kotlinx.android.synthetic.main.activity_select_tickets.ticket2Label -import kotlinx.android.synthetic.main.activity_select_tickets.ticket2Price -import kotlinx.android.synthetic.main.activity_select_tickets.ticket3Btn -import kotlinx.android.synthetic.main.activity_select_tickets.ticket3Label -import kotlinx.android.synthetic.main.activity_select_tickets.ticket3Price -import kotlinx.android.synthetic.main.activity_select_tickets.ticket4Btn -import kotlinx.android.synthetic.main.activity_select_tickets.ticket4Label -import kotlinx.android.synthetic.main.activity_select_tickets.ticket4Price import org.calypsonet.keyple.demo.common.model.type.PriorityCode import org.calypsonet.keyple.demo.reload.remote.R +import org.calypsonet.keyple.demo.reload.remote.databinding.ActivitySelectTicketsBinding class SelectTicketsActivity : AbstractDemoActivity() { + private lateinit var activitySelectTicketsBinding: ActivitySelectTicketsBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_select_tickets) - ticket1Label.text = resources.getQuantityString(R.plurals.x_tickets, 1, 1) - ticket2Label.text = resources.getQuantityString(R.plurals.x_tickets, 2, 2) - ticket3Label.text = resources.getQuantityString(R.plurals.x_tickets, 3, 3) - ticket4Label.text = resources.getQuantityString(R.plurals.x_tickets, 4, 4) - ticket1Price.text = getString(R.string.ticket_price, 1) - ticket2Price.text = getString(R.string.ticket_price, 2) - ticket3Price.text = getString(R.string.ticket_price, 3) - ticket4Price.text = getString(R.string.ticket_price, 4) - seasonPassPrice.text = getString(R.string.ticket_price, 20) + activitySelectTicketsBinding = ActivitySelectTicketsBinding.inflate(layoutInflater) + toolbarBinding = activitySelectTicketsBinding.appBarLayout + setContentView(activitySelectTicketsBinding.root) - ticket1Btn.setOnClickListener { startCheckoutActivity(PriorityCode.MULTI_TRIP, 1) } - ticket2Btn.setOnClickListener { startCheckoutActivity(PriorityCode.MULTI_TRIP, 2) } - ticket3Btn.setOnClickListener { startCheckoutActivity(PriorityCode.MULTI_TRIP, 3) } - ticket4Btn.setOnClickListener { startCheckoutActivity(PriorityCode.MULTI_TRIP, 4) } + activitySelectTicketsBinding.ticket1Label.text = + resources.getQuantityString(R.plurals.x_tickets, 1, 1) + activitySelectTicketsBinding.ticket2Label.text = + resources.getQuantityString(R.plurals.x_tickets, 2, 2) + activitySelectTicketsBinding.ticket3Label.text = + resources.getQuantityString(R.plurals.x_tickets, 3, 3) + activitySelectTicketsBinding.ticket4Label.text = + resources.getQuantityString(R.plurals.x_tickets, 4, 4) + activitySelectTicketsBinding.ticket1Price.text = getString(R.string.ticket_price, 1) + activitySelectTicketsBinding.ticket2Price.text = getString(R.string.ticket_price, 2) + activitySelectTicketsBinding.ticket3Price.text = getString(R.string.ticket_price, 3) + activitySelectTicketsBinding.ticket4Price.text = getString(R.string.ticket_price, 4) + activitySelectTicketsBinding.seasonPassPrice.text = getString(R.string.ticket_price, 20) - seasonPassBtn.setOnClickListener { startCheckoutActivity(PriorityCode.SEASON_PASS) } + activitySelectTicketsBinding.ticket1Btn.setOnClickListener { + startCheckoutActivity(PriorityCode.MULTI_TRIP, 1) + } + activitySelectTicketsBinding.ticket2Btn.setOnClickListener { + startCheckoutActivity(PriorityCode.MULTI_TRIP, 2) + } + activitySelectTicketsBinding.ticket3Btn.setOnClickListener { + startCheckoutActivity(PriorityCode.MULTI_TRIP, 3) + } + activitySelectTicketsBinding.ticket4Btn.setOnClickListener { + startCheckoutActivity(PriorityCode.MULTI_TRIP, 4) + } + + activitySelectTicketsBinding.seasonPassBtn.setOnClickListener { + startCheckoutActivity(PriorityCode.SEASON_PASS) + } } private fun startCheckoutActivity(priorityCode: PriorityCode, ticketNumber: Int? = null) { diff --git a/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/ServerSettingsActivity.kt b/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/ServerSettingsActivity.kt index b806b02..9864ae1 100644 --- a/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/ServerSettingsActivity.kt +++ b/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/ServerSettingsActivity.kt @@ -20,10 +20,10 @@ import io.reactivex.disposables.CompositeDisposable import io.reactivex.schedulers.Schedulers import java.lang.NumberFormatException import kotlin.system.exitProcess -import kotlinx.android.synthetic.main.activity_server_settings.* import org.calypsonet.keyple.demo.reload.remote.R import org.calypsonet.keyple.demo.reload.remote.data.network.KeypleSyncEndPointClient import org.calypsonet.keyple.demo.reload.remote.data.network.RestClient +import org.calypsonet.keyple.demo.reload.remote.databinding.ActivityServerSettingsBinding import org.calypsonet.keyple.demo.reload.remote.di.scopes.ActivityScoped import retrofit2.Retrofit import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory @@ -34,26 +34,31 @@ import timber.log.Timber class ServerSettingsActivity : AbstractDemoActivity() { private lateinit var disposables: CompositeDisposable + private lateinit var activityServerSettingsBinding: ActivityServerSettingsBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_server_settings) + activityServerSettingsBinding = ActivityServerSettingsBinding.inflate(layoutInflater) + toolbarBinding = activityServerSettingsBinding.appBarLayout + setContentView(activityServerSettingsBinding.root) disposables = CompositeDisposable() - server_ip_edit.text.append(prefData.loadServerIP() ?: "") - server_port_edit.text.append(prefData.loadServerPort().toString()) - server_protocol_edit.text.append(prefData.loadServerProtocol()) + activityServerSettingsBinding.serverIpEdit.text.append(prefData.loadServerIP() ?: "") + activityServerSettingsBinding.serverPortEdit.text.append(prefData.loadServerPort().toString()) + activityServerSettingsBinding.serverProtocolEdit.text.append(prefData.loadServerProtocol()) - restart.setOnClickListener { if (validateEntries(true)) restartApp() } + activityServerSettingsBinding.restart.setOnClickListener { + if (validateEntries(true)) restartApp() + } - ping_btn.setOnClickListener { + activityServerSettingsBinding.pingBtn.setOnClickListener { if (validateEntries(false)) { val serverUrl = - server_protocol_edit.text.toString() + - server_ip_edit.text.toString() + + activityServerSettingsBinding.serverProtocolEdit.text.toString() + + activityServerSettingsBinding.serverIpEdit.text.toString() + ":" + - server_port_edit.text.toString() + activityServerSettingsBinding.serverPortEdit.text.toString() Timber.i("Loaded Rest client with URL: $serverUrl") val testKeypleEndpointClient = KeypleSyncEndPointClient( @@ -70,20 +75,22 @@ class ServerSettingsActivity : AbstractDemoActivity() { .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .doOnSubscribe { - ping_progress_bar.visibility = View.VISIBLE - ping_result_text.visibility = View.INVISIBLE + activityServerSettingsBinding.pingProgressBar.visibility = View.VISIBLE + activityServerSettingsBinding.pingResultText.visibility = View.INVISIBLE } .subscribe( { - ping_progress_bar.visibility = View.INVISIBLE - ping_result_text.visibility = View.VISIBLE - ping_result_text.text = getString(R.string.ping_success) + activityServerSettingsBinding.pingProgressBar.visibility = View.INVISIBLE + activityServerSettingsBinding.pingResultText.visibility = View.VISIBLE + activityServerSettingsBinding.pingResultText.text = + getString(R.string.ping_success) }, { Timber.e(it) - ping_progress_bar.visibility = View.INVISIBLE - ping_result_text.visibility = View.VISIBLE - ping_result_text.text = getString(R.string.ping_failed) + activityServerSettingsBinding.pingProgressBar.visibility = View.INVISIBLE + activityServerSettingsBinding.pingResultText.visibility = View.VISIBLE + activityServerSettingsBinding.pingResultText.text = + getString(R.string.ping_failed) })) } } @@ -100,7 +107,7 @@ class ServerSettingsActivity : AbstractDemoActivity() { } private fun validateEntries(saveOnSuccess: Boolean): Boolean { - with(server_ip_edit) { + with(activityServerSettingsBinding.serverIpEdit) { if (this.text.isNotBlank() && Patterns.IP_ADDRESS.matcher(this.text.toString()).matches()) { if (saveOnSuccess) prefData.saveServerIP(this.text.toString()) } else { @@ -108,7 +115,7 @@ class ServerSettingsActivity : AbstractDemoActivity() { return false } } - with(server_port_edit) { + with(activityServerSettingsBinding.serverPortEdit) { try { if (this.text.isNotBlank()) { if (saveOnSuccess) prefData.saveServerPort(Integer.valueOf(this.text.toString())) @@ -120,7 +127,7 @@ class ServerSettingsActivity : AbstractDemoActivity() { return false } } - with(server_protocol_edit) { + with(activityServerSettingsBinding.serverProtocolEdit) { if (this.text.isNotBlank() && arrayOf("http://", "https://").contains(this.text.toString())) { if (saveOnSuccess) prefData.saveServerProtocol(this.text.toString()) } else { diff --git a/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/SettingsMenuActivity.kt b/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/SettingsMenuActivity.kt index 3e8c555..9a424b2 100644 --- a/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/SettingsMenuActivity.kt +++ b/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/SettingsMenuActivity.kt @@ -13,32 +13,36 @@ package org.calypsonet.keyple.demo.reload.remote.ui import android.content.Intent import android.os.Bundle -import kotlinx.android.synthetic.main.activity_settings_menu.* import org.calypsonet.keyple.demo.reload.remote.BuildConfig import org.calypsonet.keyple.demo.reload.remote.R +import org.calypsonet.keyple.demo.reload.remote.databinding.ActivitySettingsMenuBinding class SettingsMenuActivity : AbstractDemoActivity() { + private lateinit var activitySettingsMenuBinding: ActivitySettingsMenuBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_settings_menu) + activitySettingsMenuBinding = ActivitySettingsMenuBinding.inflate(layoutInflater) + toolbarBinding = activitySettingsMenuBinding.appBarLayout + setContentView(activitySettingsMenuBinding.root) - serverBtn.setOnClickListener { + activitySettingsMenuBinding.serverBtn.setOnClickListener { val intent = Intent(this, ServerSettingsActivity::class.java) startActivity(intent) } - configurationBtn.setOnClickListener { + activitySettingsMenuBinding.configurationBtn.setOnClickListener { val intent = Intent(this, ConfigurationSettingsActivity::class.java) startActivity(intent) } - personalizationBtn.setOnClickListener { + activitySettingsMenuBinding.personalizationBtn.setOnClickListener { val intent = Intent(this, HomeActivity::class.java) intent.putExtra(HomeActivity.CHOOSE_DEVICE_FOR_PERSO, true) startActivity(intent) } - versionName.text = getString(R.string.version, BuildConfig.VERSION_NAME) + activitySettingsMenuBinding.versionName.text = + getString(R.string.version, BuildConfig.VERSION_NAME) } } diff --git a/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/cardsummary/CardSummaryActivity.kt b/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/cardsummary/CardSummaryActivity.kt index e0f3ff4..986aaf9 100644 --- a/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/cardsummary/CardSummaryActivity.kt +++ b/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/cardsummary/CardSummaryActivity.kt @@ -16,16 +16,10 @@ import android.media.MediaPlayer import android.os.Bundle import android.view.View import androidx.recyclerview.widget.LinearLayoutManager -import kotlinx.android.synthetic.main.activity_card_summary.animation -import kotlinx.android.synthetic.main.activity_card_summary.bigText -import kotlinx.android.synthetic.main.activity_card_summary.buyBtn -import kotlinx.android.synthetic.main.activity_card_summary.contentTitle -import kotlinx.android.synthetic.main.activity_card_summary.lastValidationContent -import kotlinx.android.synthetic.main.activity_card_summary.smallDesc -import kotlinx.android.synthetic.main.activity_card_summary.titlesList import org.calypsonet.keyple.demo.reload.remote.R import org.calypsonet.keyple.demo.reload.remote.data.model.CardReaderResponse import org.calypsonet.keyple.demo.reload.remote.data.model.Status +import org.calypsonet.keyple.demo.reload.remote.databinding.ActivityCardSummaryBinding import org.calypsonet.keyple.demo.reload.remote.ui.AbstractCardActivity import org.calypsonet.keyple.demo.reload.remote.ui.AbstractDemoActivity import org.calypsonet.keyple.demo.reload.remote.ui.SelectTicketsActivity @@ -34,85 +28,90 @@ class CardSummaryActivity : AbstractDemoActivity() { private lateinit var titleLinearLayoutManager: LinearLayoutManager private lateinit var titlesAdapter: TitlesRecyclerAdapter + private lateinit var activityCardSummaryBinding: ActivityCardSummaryBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_card_summary) + activityCardSummaryBinding = ActivityCardSummaryBinding.inflate(layoutInflater) + toolbarBinding = activityCardSummaryBinding.appBarLayout + setContentView(activityCardSummaryBinding.root) val cardContent: CardReaderResponse = intent.getParcelableExtra(AbstractCardActivity.CARD_CONTENT)!! titleLinearLayoutManager = LinearLayoutManager(this) - titlesList.layoutManager = titleLinearLayoutManager + activityCardSummaryBinding.titlesList.layoutManager = titleLinearLayoutManager titlesAdapter = TitlesRecyclerAdapter(cardContent.titlesList) - titlesList.adapter = titlesAdapter + activityCardSummaryBinding.titlesList.adapter = titlesAdapter when (cardContent.status) { Status.INVALID_CARD -> { - animation.setAnimation("error_orange_anim.json") - animation.playAnimation() - bigText.setText(R.string.card_invalid_label) - bigText.setTextColor(resources.getColor(R.color.orange)) - smallDesc.text = cardContent.errorMessage - smallDesc.setTextColor(resources.getColor(R.color.orange)) - buyBtn.visibility = View.INVISIBLE - titlesList.visibility = View.GONE - lastValidationContent.visibility = View.GONE - contentTitle.visibility = View.GONE + activityCardSummaryBinding.animation.setAnimation("error_orange_anim.json") + activityCardSummaryBinding.animation.playAnimation() + activityCardSummaryBinding.bigText.setText(R.string.card_invalid_label) + activityCardSummaryBinding.bigText.setTextColor(resources.getColor(R.color.orange)) + activityCardSummaryBinding.smallDesc.text = cardContent.errorMessage + activityCardSummaryBinding.smallDesc.setTextColor(resources.getColor(R.color.orange)) + activityCardSummaryBinding.buyBtn.visibility = View.INVISIBLE + activityCardSummaryBinding.titlesList.visibility = View.GONE + activityCardSummaryBinding.lastValidationContent.visibility = View.GONE + activityCardSummaryBinding.contentTitle.visibility = View.GONE } - Status.TICKETS_FOUND, Status.SUCCESS -> { - titlesList.visibility = View.VISIBLE - animation.visibility = View.GONE - bigText.visibility = View.GONE - smallDesc.visibility = View.INVISIBLE - buyBtn.visibility = View.VISIBLE - lastValidationContent.visibility = View.VISIBLE - contentTitle.visibility = View.VISIBLE + Status.TICKETS_FOUND, + Status.SUCCESS -> { + activityCardSummaryBinding.titlesList.visibility = View.VISIBLE + activityCardSummaryBinding.animation.visibility = View.GONE + activityCardSummaryBinding.bigText.visibility = View.GONE + activityCardSummaryBinding.smallDesc.visibility = View.INVISIBLE + activityCardSummaryBinding.buyBtn.visibility = View.VISIBLE + activityCardSummaryBinding.lastValidationContent.visibility = View.VISIBLE + activityCardSummaryBinding.contentTitle.visibility = View.VISIBLE } Status.EMPTY_CARD -> { - animation.setAnimation("error_anim.json") - animation.playAnimation() - bigText.text = getString(R.string.no_valid_label) - bigText.setTextColor(resources.getColor(R.color.red)) - smallDesc.visibility = View.VISIBLE - smallDesc.setTextColor(resources.getColor(R.color.red)) - smallDesc.text = getString(R.string.no_valid_desc) - buyBtn.visibility = View.VISIBLE - titlesList.visibility = View.GONE - lastValidationContent.visibility = View.VISIBLE - contentTitle.visibility = View.GONE + activityCardSummaryBinding.animation.setAnimation("error_anim.json") + activityCardSummaryBinding.animation.playAnimation() + activityCardSummaryBinding.bigText.text = getString(R.string.no_valid_label) + activityCardSummaryBinding.bigText.setTextColor(resources.getColor(R.color.red)) + activityCardSummaryBinding.smallDesc.visibility = View.VISIBLE + activityCardSummaryBinding.smallDesc.setTextColor(resources.getColor(R.color.red)) + activityCardSummaryBinding.smallDesc.text = getString(R.string.no_valid_desc) + activityCardSummaryBinding.buyBtn.visibility = View.VISIBLE + activityCardSummaryBinding.titlesList.visibility = View.GONE + activityCardSummaryBinding.lastValidationContent.visibility = View.VISIBLE + activityCardSummaryBinding.contentTitle.visibility = View.GONE } Status.ERROR -> { - animation.setAnimation("error_anim.json") - animation.playAnimation() - if (cardContent.errorMessage != null) bigText.text = cardContent.errorMessage - else bigText.setText(R.string.error_label) - bigText.setTextColor(resources.getColor(R.color.red)) - smallDesc.visibility = View.INVISIBLE - buyBtn.visibility = View.INVISIBLE - titlesList.visibility = View.GONE - lastValidationContent.visibility = View.GONE - contentTitle.visibility = View.GONE + activityCardSummaryBinding.animation.setAnimation("error_anim.json") + activityCardSummaryBinding.animation.playAnimation() + if (cardContent.errorMessage != null) + activityCardSummaryBinding.bigText.text = cardContent.errorMessage + else activityCardSummaryBinding.bigText.setText(R.string.error_label) + activityCardSummaryBinding.bigText.setTextColor(resources.getColor(R.color.red)) + activityCardSummaryBinding.smallDesc.visibility = View.INVISIBLE + activityCardSummaryBinding.buyBtn.visibility = View.INVISIBLE + activityCardSummaryBinding.titlesList.visibility = View.GONE + activityCardSummaryBinding.lastValidationContent.visibility = View.GONE + activityCardSummaryBinding.contentTitle.visibility = View.GONE } else -> { - animation.setAnimation("error_anim.json") - animation.playAnimation() - bigText.setText(R.string.error_label) - bigText.setTextColor(resources.getColor(R.color.red)) - smallDesc.visibility = View.INVISIBLE - buyBtn.visibility = View.INVISIBLE - titlesList.visibility = View.GONE - lastValidationContent.visibility = View.GONE - contentTitle.visibility = View.GONE + activityCardSummaryBinding.animation.setAnimation("error_anim.json") + activityCardSummaryBinding.animation.playAnimation() + activityCardSummaryBinding.bigText.setText(R.string.error_label) + activityCardSummaryBinding.bigText.setTextColor(resources.getColor(R.color.red)) + activityCardSummaryBinding.smallDesc.visibility = View.INVISIBLE + activityCardSummaryBinding.buyBtn.visibility = View.INVISIBLE + activityCardSummaryBinding.titlesList.visibility = View.GONE + activityCardSummaryBinding.lastValidationContent.visibility = View.GONE + activityCardSummaryBinding.contentTitle.visibility = View.GONE } } - animation.playAnimation() + activityCardSummaryBinding.animation.playAnimation() // Play sound val mp: MediaPlayer = MediaPlayer.create(this, R.raw.reading_sound) mp.start() - buyBtn.setOnClickListener { + activityCardSummaryBinding.buyBtn.setOnClickListener { val intent = Intent(this, SelectTicketsActivity::class.java) getIntent().getStringExtra(AbstractCardActivity.CARD_APPLICATION_NUMBER)?.let { intent.putExtra(AbstractCardActivity.CARD_APPLICATION_NUMBER, it) diff --git a/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/cardsummary/TitlesRecyclerAdapter.kt b/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/cardsummary/TitlesRecyclerAdapter.kt index 8aff67f..049e4c9 100644 --- a/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/cardsummary/TitlesRecyclerAdapter.kt +++ b/client/android/app/src/main/kotlin/org/calypsonet/keyple/demo/reload/remote/ui/cardsummary/TitlesRecyclerAdapter.kt @@ -11,32 +11,31 @@ ************************************************************************************** */ package org.calypsonet.keyple.demo.reload.remote.ui.cardsummary -import android.view.View +import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView -import kotlinx.android.synthetic.main.title_recycler_row.view.titleDescription -import kotlinx.android.synthetic.main.title_recycler_row.view.titleName -import org.calypsonet.keyple.demo.reload.remote.R import org.calypsonet.keyple.demo.reload.remote.data.model.CardTitle +import org.calypsonet.keyple.demo.reload.remote.databinding.TitleRecyclerRowBinding import org.calypsonet.keyple.demo.reload.remote.inflate class TitlesRecyclerAdapter(private val titles: List) : RecyclerView.Adapter() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TitleHolder { - val inflatedView = parent.inflate(R.layout.title_recycler_row, false) - return TitleHolder(inflatedView) + val binding = + TitleRecyclerRowBinding.inflate(LayoutInflater.from(parent.context), parent, false) + return TitleHolder(binding) } - class TitleHolder(v: View) : RecyclerView.ViewHolder(v) { + class TitleHolder(private val binding: TitleRecyclerRowBinding) : + RecyclerView.ViewHolder(binding.root) { - private var view: View = v private var title: CardTitle? = null fun bindItem(title: CardTitle) { this.title = title - view.titleName.text = title.name - view.titleDescription.text = title.description + binding.titleName.text = title.name + binding.titleDescription.text = title.description } } diff --git a/client/android/build.gradle.kts b/client/android/build.gradle.kts index e9d7e22..bac90ba 100644 --- a/client/android/build.gradle.kts +++ b/client/android/build.gradle.kts @@ -2,19 +2,20 @@ // GRADLE CONFIGURATION /////////////////////////////////////////////////////////////////////////////// plugins { - id("com.diffplug.spotless") version "5.10.2" + id("com.diffplug.spotless") version "6.25.0" } buildscript { val kotlinVersion: String by project repositories { mavenLocal() - maven(url = "https://repo.eclipse.org/service/local/repositories/maven_central/content") mavenCentral() google() } dependencies { classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion") - classpath("com.android.tools.build:gradle:4.1.3") + classpath("com.android.tools.build:gradle:7.4.2") + classpath("javax.xml.bind:jaxb-api:2.3.1") + classpath("com.sun.xml.bind:jaxb-impl:2.3.9") classpath("org.eclipse.keyple:keyple-gradle:0.2.+") { isChanging = true } } } @@ -26,7 +27,6 @@ allprojects { group = "org.calypsonet.keyple" repositories { mavenLocal() - maven(url = "https://repo.eclipse.org/service/local/repositories/maven_central/content") mavenCentral() maven(url = "https://oss.sonatype.org/content/repositories/releases") maven(url = "https://s01.oss.sonatype.org/content/repositories/releases") diff --git a/client/android/gradle.properties b/client/android/gradle.properties index c44a126..f1f5547 100644 --- a/client/android/gradle.properties +++ b/client/android/gradle.properties @@ -1,4 +1,4 @@ -version = 2023.12.06 +version = 2024.04.23 archivesBaseName = keyple-demo-remote-client-android # Project-wide Gradle settings. @@ -13,7 +13,7 @@ org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 javaSourceLevel = 1.8 javaTargetLevel = 1.8 -kotlinVersion = 1.7.0 +kotlinVersion = 1.7.21 # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit @@ -26,4 +26,6 @@ android.useAndroidX=true # Automatically convert third-party libraries to use AndroidX android.enableJetifier=true # Kotlin code style for this project: "official" or "obsolete": -kotlin.code.style=official \ No newline at end of file +kotlin.code.style=official +# disable warning "This Android Gradle plugin (7.4.2) was tested up to compileSdk = 33" +android.suppressUnsupportedCompileSdk=34 \ No newline at end of file diff --git a/client/android/gradle/wrapper/gradle-wrapper.jar b/client/android/gradle/wrapper/gradle-wrapper.jar index 758de96..afba109 100644 Binary files a/client/android/gradle/wrapper/gradle-wrapper.jar and b/client/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/client/android/gradle/wrapper/gradle-wrapper.properties b/client/android/gradle/wrapper/gradle-wrapper.properties index d2f6d50..c7d437b 100644 --- a/client/android/gradle/wrapper/gradle-wrapper.properties +++ b/client/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Tue Jan 05 11:18:31 CET 2021 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.4-bin.zip +networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip diff --git a/client/android/gradlew b/client/android/gradlew index cccdd3d..65dcd68 100755 --- a/client/android/gradlew +++ b/client/android/gradlew @@ -1,78 +1,129 @@ -#!/usr/bin/env sh +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -81,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -89,84 +140,105 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=$((i+1)) + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" fi +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + exec "$JAVACMD" "$@" diff --git a/client/android/gradlew.bat b/client/android/gradlew.bat index f955316..93e3f59 100644 --- a/client/android/gradlew.bat +++ b/client/android/gradlew.bat @@ -1,4 +1,20 @@ -@if "%DEBUG%" == "" @echo off +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -9,19 +25,23 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -35,7 +55,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -45,38 +65,26 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/client/android/settings.gradle b/client/android/settings.gradle index 9a565fc..7e49066 100644 --- a/client/android/settings.gradle +++ b/client/android/settings.gradle @@ -1,7 +1,3 @@ rootProject.name = "keyple-demo-remote-client-android" -include ':app' - -// Fix resolution of dependencies with dynamic version in order to use SNAPSHOT first when available. -// See explanation here: https://docs.gradle.org/6.8.3/userguide/single_versions.html -enableFeaturePreview("VERSION_ORDERING_V2") \ No newline at end of file +include ':app' \ No newline at end of file diff --git a/server/build.gradle.kts b/server/build.gradle.kts index e6a9f68..0c12b12 100644 --- a/server/build.gradle.kts +++ b/server/build.gradle.kts @@ -4,13 +4,12 @@ import org.apache.tools.ant.taskdefs.condition.Os /////////////////////////////////////////////////////////////////////////////// plugins { java - id("com.diffplug.spotless") version "5.10.2" + id("com.diffplug.spotless") version "6.25.0" id("io.quarkus") version "1.8.1.Final" } buildscript { repositories { mavenLocal() - maven(url = "https://repo.eclipse.org/service/local/repositories/maven_central/content") mavenCentral() } dependencies { @@ -24,7 +23,6 @@ apply(plugin = "org.eclipse.keyple") /////////////////////////////////////////////////////////////////////////////// repositories { mavenLocal() - maven(url = "https://repo.eclipse.org/service/local/repositories/maven_central/content") mavenCentral() maven(url = "https://oss.sonatype.org/content/repositories/snapshots") maven(url = "https://s01.oss.sonatype.org/content/repositories/snapshots") @@ -43,21 +41,23 @@ java { dependencies { // Demo common - implementation("org.calypsonet.keyple:keyple-demo-common-lib:2.0.0-SNAPSHOT") { isChanging = true } + implementation("org.calypsonet.keyple:keyple-demo-common-lib:2.0.1-SNAPSHOT") { isChanging = true } + + // Begin Keyple configuration (generated by 'https://keyple.org/components/overview/configuration-wizard/') + implementation("org.eclipse.keypop:keypop-reader-java-api:2.0.1") + implementation("org.eclipse.keypop:keypop-calypso-card-java-api:2.1.0") + implementation("org.eclipse.keypop:keypop-calypso-crypto-legacysam-java-api:0.6.0") + implementation("org.eclipse.keyple:keyple-common-java-api:2.0.1") + implementation("org.eclipse.keyple:keyple-util-java-lib:2.4.0") + implementation("org.eclipse.keyple:keyple-service-java-lib:3.2.1") + implementation("org.eclipse.keyple:keyple-service-resource-java-lib:3.0.1") + implementation("org.eclipse.keyple:keyple-distributed-network-java-lib:2.3.1") + implementation("org.eclipse.keyple:keyple-distributed-remote-java-lib:2.3.1") + implementation("org.eclipse.keyple:keyple-card-calypso-java-lib:3.1.1") + implementation("org.eclipse.keyple:keyple-card-calypso-crypto-legacysam-java-lib:0.7.0") + implementation("org.eclipse.keyple:keyple-plugin-pcsc-java-lib:2.2.1") + // End Keyple configuration - // Keyple dependencies - implementation("org.eclipse.keypop:keypop-reader-java-api:2.0.0") - implementation("org.eclipse.keypop:keypop-calypso-card-java-api:2.0.0") - implementation("org.eclipse.keypop:keypop-calypso-crypto-legacysam-java-api:0.3.0") - implementation("org.eclipse.keyple:keyple-common-java-api:2.0.0") - implementation("org.eclipse.keyple:keyple-service-java-lib:3.0.1") - implementation("org.eclipse.keyple:keyple-service-resource-java-lib:3.0.0") - implementation("org.eclipse.keyple:keyple-distributed-network-java-lib:2.3.0") - implementation("org.eclipse.keyple:keyple-distributed-remote-java-lib:2.3.0") - implementation("org.eclipse.keyple:keyple-card-calypso-java-lib:3.0.1") - implementation("org.eclipse.keyple:keyple-card-calypso-crypto-legacysam-java-lib:0.4.0") - implementation("org.eclipse.keyple:keyple-plugin-pcsc-java-lib:2.1.2") - implementation("org.eclipse.keyple:keyple-util-java-lib:2.3.1") // Quarkus implementation(enforcedPlatform("io.quarkus:quarkus-universe-bom:1.8.1.Final")) implementation("io.quarkus:quarkus-resteasy-jsonb") diff --git a/server/dashboard-app/package.json b/server/dashboard-app/package.json index c48681f..2d3bcdc 100644 --- a/server/dashboard-app/package.json +++ b/server/dashboard-app/package.json @@ -1,6 +1,6 @@ { "name": "dashboard-app", - "version": "2023.12.06", + "version": "2024.04.23", "private": true, "dependencies": { "@material-ui/core": "^4.11.3", diff --git a/server/gradle.properties b/server/gradle.properties index 20c25c8..deaf10d 100644 --- a/server/gradle.properties +++ b/server/gradle.properties @@ -1,5 +1,5 @@ # don't forget to keep the version string in server/dashboard-app/src/package.json synchronized with the following -version = 2023.12.06 +version = 2024.04.23 title = "Keyple Reload Demo - Remote Server" archivesBaseName = keyple-demo-remote-server diff --git a/server/gradle/wrapper/gradle-wrapper.jar b/server/gradle/wrapper/gradle-wrapper.jar index e708b1c..afba109 100644 Binary files a/server/gradle/wrapper/gradle-wrapper.jar and b/server/gradle/wrapper/gradle-wrapper.jar differ diff --git a/server/gradle/wrapper/gradle-wrapper.properties b/server/gradle/wrapper/gradle-wrapper.properties index 60c76b3..c7d437b 100644 --- a/server/gradle/wrapper/gradle-wrapper.properties +++ b/server/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.4-bin.zip +networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists \ No newline at end of file +zipStorePath=wrapper/dists diff --git a/server/gradlew b/server/gradlew index cccdd3d..65dcd68 100755 --- a/server/gradlew +++ b/server/gradlew @@ -1,78 +1,129 @@ -#!/usr/bin/env sh +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -81,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -89,84 +140,105 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=$((i+1)) + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" fi +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + exec "$JAVACMD" "$@" diff --git a/server/gradlew.bat b/server/gradlew.bat index f955316..93e3f59 100644 --- a/server/gradlew.bat +++ b/server/gradlew.bat @@ -1,4 +1,20 @@ -@if "%DEBUG%" == "" @echo off +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -9,19 +25,23 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -35,7 +55,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -45,38 +65,26 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal