Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prevent a crash when the fragment is detached #5075

Merged
merged 3 commits into from May 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Expand Up @@ -5,6 +5,9 @@
* [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