#cynaed_code

1 messages ¡ Page 1 of 1 (latest)

sullen radishBOT
#

👋 Welcome to your new thread!

⏲️ We'll be here soon! Typically we respond in a few minutes, but sometimes we might take a bit longer if the server is busy or if you have a particularly tricky question.

⏱️ We close idle threads, which makes them read-only. Once a thread is closed it won't be reopened, but you can always start a new thread if you have another question.

🔗 This thread will always be available, even after it's closed. You can find it again using Discord's search, or you can save this link: https://discord.com/channels/841573134531821608/1451004618426548305

📝 Have more to share? Add more details, code, screenshots, videos, etc. below.

normal tusk
#

hi there, give me a moment to catch up

sage thicket
#

Alright for the mean time, I'll paste snippets here

#
    val logLevel = LogLevel.VERBOSE
    val tokenProvider = TokenProvider()

    val listener = object : TerminalListener {
      override fun onConnectionStatusChange(status: ConnectionStatus) {
        println("[CONNECTION STATUS CHANGE]: $status")
      }

      override fun onPaymentStatusChange(status: PaymentStatus) {
        println("[PAYMENT STATUS CHANGE]: $status")

        if (status == PaymentStatus.READY && !firstTime && !hasStartedTapToPay) {
          firstTime = true
          hasStartedTapToPay = true

          // Ensure logging runs sequentially on IO
          CoroutineScope(Dispatchers.IO).launch {
            postLoggingSequential("MyFloOffline | TapToPay", "First Time Payment")

            // Switch back to Main thread for UI action
            withContext(Dispatchers.Main) {
              val intent = Intent(this@MainActivity, TapToPayActivity::class.java)
              intent.putExtra("paymentIntentId", paymentIntentId)
              startActivityForResult(intent, 1234)
            }
          }
        }
      }
    }
    CoroutineScope(Dispatchers.IO).launch {
      postLoggingSequential("MyFloOffline | TapToPay", "Initialize Terminal")
    }

    // Initialize Terminal (this is OK on IO)
    if (!Terminal.isInitialized()) {
      Terminal.initTerminal(applicationContext, logLevel, tokenProvider, listener)
    }

    val terminal = Terminal.getInstance()
    println("STATUS IN INITIALIZATION ${terminal.paymentStatus}")

    if (terminal.paymentStatus == PaymentStatus.READY) {
      CoroutineScope(Dispatchers.IO).launch {
        postLoggingSequential("MyFloOffline | TapToPay", "2nd Condition Block")
      }

      val intent = Intent(this@MainActivity, TapToPayActivity::class.java)
      intent.putExtra("paymentIntentId", paymentIntentId)
      startActivityForResult(intent, 1234)
    }
  }```
#

postLoggingSequential is my way to create logs on this because only client have the Samsung Active Tab 5.

#

the logs is here

2025-12-18 10:58:31.9526|Info||[MyFloOffline | TapToPay : 12/18/2025 10:58:31 AM] : Started Payment |
2025-12-18 10:58:32.0297|Info||[MyFloOffline | TapToPay : 12/18/2025 10:58:32 AM] : 2nd Condition Block |
2025-12-18 10:58:32.0297|Info||[MyFloOffline | TapToPay : 12/18/2025 10:58:32 AM] : Initialize Terminal |
2025-12-18 10:58:32.0764|Info||[MyFloOffline | TapToPay : 12/18/2025 10:58:32 AM] : TapToPayActivity : pi_3SfUbwDFGfQzmzjw1Q81y7us |
2025-12-18 10:58:32.3670|Info||[MyFloOffline | TapToPay : 12/18/2025 10:58:32 AM] : TapToPayActivity : pi_3SfUbwDFGfQzmzjw1Q81y7us REQUIRES_PAYMENT_METHOD |
2025-12-18 10:58:56.0882|Info||[MyFloOffline | TapToPay : 12/18/2025 10:58:56 AM] : TapToPayActivity : pi_3SfUbwDFGfQzmzjw1Q81y7us |
2025-12-18 10:58:56.3885|Info||[MyFloOffline | TapToPay : 12/18/2025 10:58:56 AM] : TapToPayActivity : pi_3SfUbwDFGfQzmzjw1Q81y7us |
2025-12-18 10:58:56.4102|Info||[MyFloOffline | TapToPay : 12/18/2025 10:58:56 AM] : TapToPayActivity : pi_3SfUbwDFGfQzmzjw1Q81y7us REQUIRES_PAYMENT_METHOD |
2025-12-18 10:58:57.6190|Info||[MyFloOffline | TapToPay : 12/18/2025 10:58:57 AM] : Payment Successful |

#

TapToPayActivity onCreate

    super.onCreate(savedInstanceState)
    if (isRunning) {
      Log.w("TapToPay", "TapToPayActivity already running, ignoring duplicate")
      finish()
      return
    }
    isRunning = true

    setContentView(R.layout.activity_tap_to_pay)
    val paymentIntentId = intent.getStringExtra("paymentIntentId") ?: ""
    postLoggingSequential("MyFloOffline | TapToPay", "TapToPayActivity : " + paymentIntentId)
    val terminal = Terminal.getInstance()

    terminal.retrievePaymentIntent(
      paymentIntentId, // your PaymentIntent ID from backend
      object : PaymentIntentCallback {
        override fun onSuccess(paymentIntent: PaymentIntent) {
          if (paymentIntent.status == PaymentIntentStatus.SUCCEEDED) {
            postLoggingSequential(
              "MyFloOffline | TapToPay",
              "TapToPayActivity : ${paymentIntentId} ${paymentIntent.status}"
            )
            val resultIntent = Intent()
            resultIntent.putExtra("payment_intent_id", paymentIntent.id)
            setResult(Activity.RESULT_OK, resultIntent)
            finish()
            return
          }
          activePaymentIntent = paymentIntent
          postLoggingSequential(
            "MyFloOffline | TapToPay",
            "TapToPayActivity : ${paymentIntentId} ${paymentIntent.status}"
          )
          collectAndConfirm(paymentIntent) // continue with collect + confirm flow
        }

        override fun onFailure(e: TerminalException) {
          Log.e("TapToPay", "Retrieve PaymentIntent failed: ${e.message}")
          setResult(Activity.RESULT_CANCELED)
          finish()
        }
      }
    )```
normal tusk
#

Could you share how you declared isRunning?

sage thicket
#

companion object {
private var isRunning = false
private var activePaymentIntent: PaymentIntent? = null
}

override fun onDestroy() {
super.onDestroy()
Log.d("TapToPay", "Destroyed Activity")
isRunning = false
}

#

what I firgured just now is that upon changing of orientation it recreates the Activity again. since i'm using a tab it automatically do the collection of payment in landscape but my application is on portrait

#

do you think this is a possible reason?

normal tusk
#

Could you reproduce the same behavior on an Android phone device? If yes then it likely is it. When you mentioned orientation, I looked up Android docs [0] and it does say

*The system recreates an Activity when a configuration change occurs. To do this, the system calls onDestroy() and destroys the existing Activity instance. It then creates a new instance using onCreate(), and this new Activity instance is initialized with the new, updated configuration. This also means that the system also recreates the UI with the new configuration.
*

[0] https://developer.android.com/guide/topics/resources/runtime-changes

sage thicket
#

I recreated the issue on phone by rotating my phone while the collection of payment is happening. and it reappears, so it recreates the activity upon changing of orientation this is confirmed since I did side by side testing just now with the client. and we run the application on landscape and it didn't re appear.

#

but the problem is we locked the device into portrait now but the collection of payment is still turning in landscape

#

is there a way in stripe to lock the collection in portrait orientation in tablet?

#

when I say client they're testing it on Samsung Active Tab 5

#
      paymentIntentId, // your PaymentIntent ID from backend
      object : PaymentIntentCallback {
        override fun onSuccess(paymentIntent: PaymentIntent) {
          if (paymentIntent.status == PaymentIntentStatus.SUCCEEDED) {
            postLoggingSequential(
              "MyFloOffline | TapToPay",
              "TapToPayActivity : ${paymentIntentId} ${paymentIntent.status}"
            )
            val resultIntent = Intent()
            resultIntent.putExtra("payment_intent_id", paymentIntent.id)
            setResult(Activity.RESULT_OK, resultIntent)
            finish()
            return
          }
          activePaymentIntent = paymentIntent
          postLoggingSequential(
            "MyFloOffline | TapToPay",
            "TapToPayActivity : ${paymentIntentId} ${paymentIntent.status}"
          )
          collectAndConfirm(paymentIntent) // continue with collect + confirm flow
        }```

```collectAndConfirm(paymentIntent) // continue with collect + confirm flow```
#
    val terminal = Terminal.getInstance()
    terminal.collectPaymentMethod(paymentIntent, object : PaymentIntentCallback {
      override fun onSuccess(paymentIntent: PaymentIntent) {
        terminal.confirmPaymentIntent(paymentIntent, object : PaymentIntentCallback {
          override fun onSuccess(paymentIntent: PaymentIntent) {
            Log.d("TapToPay", "Payment success")
            activePaymentIntent = null
            val resultIntent = Intent()
            resultIntent.putExtra("payment_intent_id", paymentIntent.id)
            setResult(Activity.RESULT_OK, resultIntent)
            finish()
          }

          override fun onFailure(e: TerminalException) {
            Log.e("TapToPay", "Payment confirm failed: ${e.message}")
            setResult(Activity.RESULT_CANCELED)
            finish()
          }
        })
      }

      override fun onFailure(e: TerminalException) {
        Log.e("TapToPay", "Payment method failed: ${e.message}")
        setResult(Activity.RESULT_CANCELED)
        finish()
      }
    })
  }```
normal tusk
#

which Stripe SDK version are you currently on?

#

and what is the Android version on the Samsung Tab 5 device?

sage thicket
#

implementation("com.stripe:stripeterminal-taptopay:4.3.1")
implementation("com.stripe:stripeterminal-core:4.3.1")

Androind Version 16

normal tusk
sage thicket
#

alright will change it to 4.6 now. I think this helps

#

thank you so much!

normal tusk
#

you're welcome. feel free to reach out again if the same issue persist after the upgrade

sage thicket
#

alright.