Skip to content

Commit

Permalink
Prevent a crash when the fragment is detached (#5075)
Browse files Browse the repository at this point in the history
* Prevent a crash when the fragment is detached

* Update changelog

* Fix lint
  • Loading branch information
awush-stripe committed May 26, 2022
1 parent 61df560 commit f3c4dc9
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 39 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Expand Up @@ -70,6 +70,9 @@ This release includes several Payments and PaymentSheet bug fixes.
* [FIXED] [4861](https://github.com/stripe/stripe-android/pull/4861) Remove font resource to save space and default to system default
* [CHANGED] [4855](https://github.com/stripe/stripe-android/pull/4855) Remove force portrait mode in PaymentLauncher.

### CardScan
* [FIXED] [5075](https://github.com/stripe/stripe-android/pull/5075) Prevent a crash when the fragment is detached.

## 20.0.1 - 2022-04-11
This release includes several PaymentSheet bug fixes.

Expand Down
Expand Up @@ -124,7 +124,7 @@ class CardScanFragment : ScanFragment(), SimpleScanStateful<CardScanState> {
) {
launch(Dispatchers.Main) {
changeScanState(CardScanState.Correct)
cameraAdapter.unbindFromLifecycle(requireActivity())
activity?.let { cameraAdapter.unbindFromLifecycle(it) }
resultListener.cardScanComplete(ScannedCard(result.pan))
}.let { }
}
Expand Down Expand Up @@ -203,13 +203,13 @@ class CardScanFragment : ScanFragment(), SimpleScanStateful<CardScanState> {
* Set up viewFinderWindowView and viewFinderBorderView centered with predefined margins
*/
private fun setupViewFinderConstraints() {

val screenSize = Resources.getSystem().displayMetrics.let {
Size(it.widthPixels, it.heightPixels)
}

val viewFinderMargin = (
min(screenSize.width, screenSize.height) *
requireActivity().getFloatResource(R.dimen.stripeViewFinderMargin)
(context?.getFloatResource(R.dimen.stripeViewFinderMargin) ?: 0F)
).roundToInt()

listOf(viewBinding.viewFinderWindow, viewBinding.viewFinderBorder).forEach { view ->
Expand Down Expand Up @@ -241,14 +241,16 @@ class CardScanFragment : ScanFragment(), SimpleScanStateful<CardScanState> {
* Once the camera stream is available, start processing images.
*/
override suspend fun onCameraStreamAvailable(cameraStream: Flow<CameraPreviewImage<Bitmap>>) {
scanFlow.startFlow(
context = requireActivity(),
imageStream = cameraStream,
viewFinder = viewBinding.viewFinderWindow.asRect(),
lifecycleOwner = this,
coroutineScope = this,
parameters = null
)
context?.let {
scanFlow.startFlow(
context = it,
imageStream = cameraStream,
viewFinder = viewBinding.viewFinderWindow.asRect(),
lifecycleOwner = this,
coroutineScope = this,
parameters = null
)
}
}

/**
Expand All @@ -267,20 +269,24 @@ class CardScanFragment : ScanFragment(), SimpleScanStateful<CardScanState> {
override fun displayState(newState: CardScanState, previousState: CardScanState?) {
when (newState) {
is CardScanState.NotFound, CardScanState.Found -> {
viewBinding.viewFinderBackground
.setBackgroundColor(
requireActivity().getColorByRes(R.color.stripeNotFoundBackground)
)
context?.let {
viewBinding.viewFinderBackground
.setBackgroundColor(
it.getColorByRes(R.color.stripeNotFoundBackground)
)
}
viewBinding.viewFinderWindow
.setBackgroundResource(R.drawable.stripe_card_background_not_found)
viewBinding.viewFinderBorder
.startAnimation(R.drawable.stripe_paymentsheet_card_border_not_found)
}
is CardScanState.Correct -> {
viewBinding.viewFinderBackground
.setBackgroundColor(
requireActivity().getColorByRes(R.color.stripeCorrectBackground)
)
context?.let {
viewBinding.viewFinderBackground
.setBackgroundColor(
it.getColorByRes(R.color.stripeCorrectBackground)
)
}
viewBinding.viewFinderWindow
.setBackgroundResource(R.drawable.stripe_card_background_correct)
viewBinding.viewFinderBorder.startAnimation(R.drawable.stripe_card_border_correct)
Expand All @@ -293,8 +299,8 @@ class CardScanFragment : ScanFragment(), SimpleScanStateful<CardScanState> {
stripePublishableKey = params.stripePublishableKey,
instanceId = Stats.instanceId,
scanId = Stats.scanId,
device = Device.fromContext(requireActivity()),
appDetails = AppDetails.fromContext(requireActivity()),
device = Device.fromContext(context),
appDetails = AppDetails.fromContext(context),
scanStatistics = ScanStatistics.fromStats(),
scanConfig = ScanConfig(0),
)
Expand Down
Expand Up @@ -14,7 +14,7 @@ internal data class AppDetails(
) {
companion object {
@JvmStatic
fun fromContext(context: Context) = AppDetails(
fun fromContext(context: Context?) = AppDetails(
appPackageName = getAppPackageName(context),
applicationId = getApplicationId(),
libraryPackageName = getLibraryPackageName(),
Expand All @@ -26,7 +26,8 @@ internal data class AppDetails(
}
}

internal fun getAppPackageName(context: Context): String? = context.applicationContext.packageName
internal fun getAppPackageName(context: Context?): String? =
context?.applicationContext?.packageName

private fun getApplicationId(): String = "" // no longer available in later versions of gradle.

Expand Down
Expand Up @@ -21,7 +21,7 @@ internal data class Device(
val platform: String
) {
companion object {
private val getDeviceDetails = cacheFirstResult { context: Context ->
private val getDeviceDetails = cacheFirstResult { context: Context? ->
Device(
android_id = getAndroidId(),
name = getDeviceName(),
Expand All @@ -37,7 +37,7 @@ internal data class Device(
}

@JvmStatic
fun fromContext(context: Context) = getDeviceDetails(context.applicationContext)
fun fromContext(context: Context?) = getDeviceDetails(context?.applicationContext)
}
}

Expand All @@ -51,10 +51,12 @@ internal data class Device(
@SuppressLint("HardwareIds")
private fun getAndroidId() = "Redacted"

private fun getDeviceBootCount(context: Context): Int =
private fun getDeviceBootCount(context: Context?): Int =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
try {
Settings.Global.getInt(context.contentResolver, Settings.Global.BOOT_COUNT)
context?.let {
Settings.Global.getInt(it.contentResolver, Settings.Global.BOOT_COUNT)
} ?: -1
} catch (t: Throwable) {
-1
}
Expand All @@ -65,27 +67,27 @@ private fun getDeviceBootCount(context: Context): Int =
private fun getDeviceLocale(): String =
"${Locale.getDefault().isO3Language}_${Locale.getDefault().isO3Country}"

private fun getDeviceCarrier(context: Context) = try {
(context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager?)?.networkOperatorName
private fun getDeviceCarrier(context: Context?) = try {
(context?.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager?)?.networkOperatorName
} catch (t: Throwable) {
null
}

private fun getDevicePhoneType(context: Context) = try {
(context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager?)?.phoneType
private fun getDevicePhoneType(context: Context?) = try {
(context?.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager?)?.phoneType
} catch (t: Throwable) {
null
}

private fun getDevicePhoneCount(context: Context) =
private fun getDevicePhoneCount(context: Context?) =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
(context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager?)
(context?.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager?)
?.activeModemCount ?: -1
} else {
@Suppress("deprecation")
(context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager?)
(context?.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager?)
?.phoneCount ?: -1
}
} catch (t: Throwable) {
Expand All @@ -95,8 +97,8 @@ private fun getDevicePhoneCount(context: Context) =
-1
}

private fun getNetworkOperator(context: Context) =
(context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager?)?.networkOperator
private fun getNetworkOperator(context: Context?) =
(context?.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager?)?.networkOperator

internal fun getOsVersion() = Build.VERSION.SDK_INT

Expand Down
Expand Up @@ -73,8 +73,10 @@ abstract class ScanFragment : Fragment(), CoroutineScope {
super.onStart()
Stats.startScan()

if (!CameraAdapter.isCameraSupported(requireActivity())) {
showCameraNotSupported()
context?.let {
if (!CameraAdapter.isCameraSupported(it)) {
showCameraNotSupported()
}
}
}

Expand All @@ -94,7 +96,7 @@ abstract class ScanFragment : Fragment(), CoroutineScope {

protected open fun hideSystemUi() {
// Prevent screenshots and keep the screen on while scanning.
requireActivity().window.setFlags(
activity?.window?.setFlags(
WindowManager.LayoutParams.FLAG_SECURE +
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
WindowManager.LayoutParams.FLAG_SECURE +
Expand Down

0 comments on commit f3c4dc9

Please sign in to comment.