Address edge-to-edge Google Play Store warnings (#1205)

* Handle camera overlay window insets

* Adopt AndroidX edge-to-edge helpers
This commit is contained in:
Justin Hernandez
2025-10-04 09:29:04 -07:00
committed by GitHub
parent efacb8db94
commit 073f77cc98
5 changed files with 148 additions and 9 deletions

View File

@@ -5,8 +5,9 @@ package com.proofofpassportapp
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.content.pm.ActivityInfo
import androidx.core.view.WindowCompat
import android.graphics.Color
import androidx.activity.SystemBarStyle
import androidx.activity.enableEdgeToEdge
import com.facebook.react.ReactActivity
import com.facebook.react.ReactActivityDelegate
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled
@@ -43,9 +44,12 @@ class MainActivity : ReactActivity() {
// Prevent fragment state restoration to avoid react-native-screens crash
// See: https://github.com/software-mansion/react-native-screens/issues/17#issuecomment-424704978
super.onCreate(null)
// Ensure edge-to-edge is enabled consistently across Android versions
// Android 15 enables by default; on earlier versions, opt-in for immersive layouts
WindowCompat.setDecorFitsSystemWindows(window, false)
// Ensure edge-to-edge is enabled consistently across Android versions using
// the AndroidX helper so deprecated window color APIs are avoided.
enableEdgeToEdge(
statusBarStyle = SystemBarStyle.auto(Color.TRANSPARENT, Color.TRANSPARENT),
navigationBarStyle = SystemBarStyle.auto(Color.TRANSPARENT, Color.TRANSPARENT)
)
// Allow system to manage orientation for large screens
}
}

View File

@@ -28,11 +28,13 @@ import android.graphics.Color
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.doOnAttach
import com.google.mlkit.vision.text.Text
@@ -77,6 +79,47 @@ class CameraMLKitFragment(cameraMLKitCallback: CameraMLKitCallback) : CameraFrag
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val fragmentBinding = binding ?: return
val statusTop = fragmentBinding.statusViewTop
val statusBottom = fragmentBinding.statusViewBottom
val initialTopStart = ViewCompat.getPaddingStart(statusTop)
val initialTopPadding = statusTop.paddingTop
val initialTopEnd = ViewCompat.getPaddingEnd(statusTop)
val initialTopBottom = statusTop.paddingBottom
val initialBottomStart = ViewCompat.getPaddingStart(statusBottom)
val initialBottomTop = statusBottom.paddingTop
val initialBottomEnd = ViewCompat.getPaddingEnd(statusBottom)
val initialBottomPadding = statusBottom.paddingBottom
ViewCompat.setOnApplyWindowInsetsListener(fragmentBinding.root) { _, insets ->
val statusInsets = insets.getInsets(
WindowInsetsCompat.Type.statusBars() or WindowInsetsCompat.Type.displayCutout()
)
ViewCompat.setPaddingRelative(
statusTop,
initialTopStart,
initialTopPadding + statusInsets.top,
initialTopEnd,
initialTopBottom
)
val navAndGesturesInsets = insets.getInsets(
WindowInsetsCompat.Type.navigationBars() or WindowInsetsCompat.Type.systemGestures()
)
val imeInsets = insets.getInsets(WindowInsetsCompat.Type.ime())
val bottomInset = maxOf(navAndGesturesInsets.bottom, imeInsets.bottom)
ViewCompat.setPaddingRelative(
statusBottom,
initialBottomStart,
initialBottomTop,
initialBottomEnd,
initialBottomPadding + bottomInset
)
insets
}
fragmentBinding.root.doOnAttach { ViewCompat.requestApplyInsets(it) }
}
@@ -96,9 +139,11 @@ class CameraMLKitFragment(cameraMLKitCallback: CameraMLKitCallback) : CameraFrag
}
override fun onDestroyView() {
binding?.root?.let { ViewCompat.setOnApplyWindowInsetsListener(it, null) }
if (!disposable.isDisposed()) {
disposable.dispose();
}
binding = null
super.onDestroyView()
// customView.onDestroy()
}

View File

@@ -27,11 +27,13 @@ import android.graphics.Bitmap
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.doOnAttach
import com.proofofpassportapp.utils.QrCodeDetectorProcessor
import example.jllarraz.com.passportreader.R
import example.jllarraz.com.passportreader.databinding.FragmentCameraMrzBinding
@@ -64,6 +66,47 @@ class QrCodeScannerFragment(callback: QRCodeScannerCallback) : CameraFragment()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val fragmentBinding = binding ?: return
val statusTop = fragmentBinding.statusViewTop
val statusBottom = fragmentBinding.statusViewBottom
val initialTopStart = ViewCompat.getPaddingStart(statusTop)
val initialTopPadding = statusTop.paddingTop
val initialTopEnd = ViewCompat.getPaddingEnd(statusTop)
val initialTopBottom = statusTop.paddingBottom
val initialBottomStart = ViewCompat.getPaddingStart(statusBottom)
val initialBottomTop = statusBottom.paddingTop
val initialBottomEnd = ViewCompat.getPaddingEnd(statusBottom)
val initialBottomPadding = statusBottom.paddingBottom
ViewCompat.setOnApplyWindowInsetsListener(fragmentBinding.root) { _, insets ->
val statusInsets = insets.getInsets(
WindowInsetsCompat.Type.statusBars() or WindowInsetsCompat.Type.displayCutout()
)
ViewCompat.setPaddingRelative(
statusTop,
initialTopStart,
initialTopPadding + statusInsets.top,
initialTopEnd,
initialTopBottom
)
val navAndGesturesInsets = insets.getInsets(
WindowInsetsCompat.Type.navigationBars() or WindowInsetsCompat.Type.systemGestures()
)
val imeInsets = insets.getInsets(WindowInsetsCompat.Type.ime())
val bottomInset = maxOf(navAndGesturesInsets.bottom, imeInsets.bottom)
ViewCompat.setPaddingRelative(
statusBottom,
initialBottomStart,
initialBottomTop,
initialBottomEnd,
initialBottomPadding + bottomInset
)
insets
}
fragmentBinding.root.doOnAttach { ViewCompat.requestApplyInsets(it) }
}
@@ -83,9 +126,11 @@ class QrCodeScannerFragment(callback: QRCodeScannerCallback) : CameraFragment()
}
override fun onDestroyView() {
binding?.root?.let { ViewCompat.setOnApplyWindowInsetsListener(it, null) }
if (!disposable.isDisposed) {
disposable.dispose();
}
binding = null
super.onDestroyView()
}

View File

@@ -28,11 +28,13 @@ import android.graphics.Color
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.doOnAttach
import com.google.mlkit.vision.text.Text
@@ -77,6 +79,47 @@ class CameraMLKitFragment(cameraMLKitCallback: CameraMLKitCallback) : CameraFrag
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val fragmentBinding = binding ?: return
val statusTop = fragmentBinding.statusViewTop
val statusBottom = fragmentBinding.statusViewBottom
val initialTopStart = ViewCompat.getPaddingStart(statusTop)
val initialTopPadding = statusTop.paddingTop
val initialTopEnd = ViewCompat.getPaddingEnd(statusTop)
val initialTopBottom = statusTop.paddingBottom
val initialBottomStart = ViewCompat.getPaddingStart(statusBottom)
val initialBottomTop = statusBottom.paddingTop
val initialBottomEnd = ViewCompat.getPaddingEnd(statusBottom)
val initialBottomPadding = statusBottom.paddingBottom
ViewCompat.setOnApplyWindowInsetsListener(fragmentBinding.root) { _, insets ->
val statusInsets = insets.getInsets(
WindowInsetsCompat.Type.statusBars() or WindowInsetsCompat.Type.displayCutout()
)
ViewCompat.setPaddingRelative(
statusTop,
initialTopStart,
initialTopPadding + statusInsets.top,
initialTopEnd,
initialTopBottom
)
val navAndGesturesInsets = insets.getInsets(
WindowInsetsCompat.Type.navigationBars() or WindowInsetsCompat.Type.systemGestures()
)
val imeInsets = insets.getInsets(WindowInsetsCompat.Type.ime())
val bottomInset = maxOf(navAndGesturesInsets.bottom, imeInsets.bottom)
ViewCompat.setPaddingRelative(
statusBottom,
initialBottomStart,
initialBottomTop,
initialBottomEnd,
initialBottomPadding + bottomInset
)
insets
}
fragmentBinding.root.doOnAttach { ViewCompat.requestApplyInsets(it) }
}
@@ -96,9 +139,11 @@ class CameraMLKitFragment(cameraMLKitCallback: CameraMLKitCallback) : CameraFrag
}
override fun onDestroyView() {
binding?.root?.let { ViewCompat.setOnApplyWindowInsetsListener(it, null) }
if (!disposable.isDisposed()) {
disposable.dispose();
}
binding = null
super.onDestroyView()
}

View File

@@ -27,7 +27,7 @@
<TextView android:id="@+id/status_view_top"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@+id/status_view_bottom"
android:layout_alignParentTop="true"
android:layout_margin="14dp"
android:background="#0000"
android:text=""