fix preview and capture resolutions

- adjust the preview so the image captured is what the user sees
- add method MySize.isSupported; current support is for full, 16:9, 4:3 and 1:1 of the highest resolution
- cleanup ImageQualityManager, add method to get the full screen resolution which is just the resolution with the largest width
- change the UI to move settings to the top and remove the auto fading
This commit is contained in:
darthpaul 2022-08-17 01:12:18 +01:00
parent f6235e3b96
commit d9193f7494
9 changed files with 249 additions and 177 deletions

View File

@ -10,7 +10,7 @@ import android.os.Handler
import android.os.Looper
import android.provider.MediaStore
import android.view.*
import android.widget.RelativeLayout
import androidx.constraintlayout.widget.ConstraintLayout
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
@ -32,7 +32,6 @@ import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, CameraXPreviewListener {
companion object {
private const val FADE_DELAY = 5000L
private const val CAPTURE_ANIMATION_DURATION = 100L
}
@ -84,7 +83,6 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
if (hasStorageAndCameraPermissions()) {
resumeCameraItems()
setupPreviewImage(mIsInPhotoMode)
scheduleFadeOut()
mFocusCircleView.setStrokeColor(getProperPrimaryColor())
if (isVideoCaptureIntent() && mIsInPhotoMode) {
@ -216,11 +214,11 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
setContentView(R.layout.activity_main)
initButtons()
(btn_holder.layoutParams as RelativeLayout.LayoutParams).setMargins(
(video_rec_curr_timer.layoutParams as ConstraintLayout.LayoutParams).setMargins(
0,
0,
0,
(navigationBarHeight + resources.getDimension(R.dimen.activity_margin)).toInt()
(navigationBarHeight + resources.getDimension(R.dimen.big_margin)).toInt()
)
checkVideoCaptureIntent()
@ -310,12 +308,8 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
}
private fun launchSettings() {
if (settings.alpha == 1f) {
val intent = Intent(applicationContext, SettingsActivity::class.java)
startActivity(intent)
} else {
fadeInButtons()
}
val intent = Intent(applicationContext, SettingsActivity::class.java)
startActivity(intent)
}
private fun handleTogglePhotoVideo() {
@ -415,34 +409,6 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
}
}
private fun scheduleFadeOut() {
if (!config.keepSettingsVisible) {
mFadeHandler.postDelayed({
fadeOutButtons()
}, FADE_DELAY)
}
}
private fun fadeOutButtons() {
fadeAnim(settings, .5f)
fadeAnim(toggle_photo_video, .0f)
fadeAnim(change_resolution, .0f)
fadeAnim(last_photo_video_preview, .0f)
}
private fun fadeInButtons() {
fadeAnim(settings, 1f)
fadeAnim(toggle_photo_video, 1f)
fadeAnim(change_resolution, 1f)
fadeAnim(last_photo_video_preview, 1f)
scheduleFadeOut()
}
private fun fadeAnim(view: View, value: Float) {
view.animate().alpha(value).start()
view.isClickable = value != .0f
}
private fun showTimer() {
video_rec_curr_timer.beVisible()
setupTimer()

View File

@ -47,7 +47,12 @@ class ChangeResolutionDialogX(
val items = photoResolutions.mapIndexed { index, resolution ->
val megapixels = resolution.megaPixels
val aspectRatio = resolution.getAspectRatio(activity)
RadioItem(index, "${resolution.width} x ${resolution.height} ($megapixels MP, $aspectRatio)")
if (resolution.isFullScreen) {
//TODO: Extract to string resource
RadioItem(index, "Full")
} else {
RadioItem(index, "${resolution.width} x ${resolution.height} ($megapixels MP, $aspectRatio)")
}
}
var selectionIndex = if (isFrontCamera) config.frontPhotoResIndex else config.backPhotoResIndex
selectionIndex = selectionIndex.coerceAtLeast(0)

View File

@ -66,6 +66,7 @@ class Config(context: Context) : BaseConfig(context) {
get() = prefs.getInt(FRONT_VIDEO_RESOLUTION_INDEX, 0)
set(frontVideoResIndex) = prefs.edit().putInt(FRONT_VIDEO_RESOLUTION_INDEX, frontVideoResIndex).apply()
//TODO: Remove keepSettingsVisible since the view has moved to the top
var keepSettingsVisible: Boolean
get() = prefs.getBoolean(KEEP_SETTINGS_VISIBLE, false)
set(keepSettingsVisible) = prefs.edit().putBoolean(KEEP_SETTINGS_VISIBLE, keepSettingsVisible).apply()

View File

@ -28,13 +28,12 @@ class ImageQualityManager(
for (cameraId in cameraManager.cameraIdList) {
try {
val characteristics = cameraManager.getCameraCharacteristics(cameraId)
for (lens in CAMERA_LENS) {
if (characteristics.get(CameraCharacteristics.LENS_FACING) == lens) {
val configMap = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP) ?: continue
val imageSizes = configMap.getOutputSizes(ImageFormat.JPEG).map { MySize(it.width, it.height) }
val cameraSelector = lens.toCameraSelector()
imageQualities.add(CameraSelectorImageQualities(cameraSelector, imageSizes))
}
val lensFacing = characteristics.get(CameraCharacteristics.LENS_FACING) ?: continue
if (lensFacing in CAMERA_LENS) {
val configMap = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP) ?: continue
val imageSizes = configMap.getOutputSizes(ImageFormat.JPEG).map { MySize(it.width, it.height) }
val cameraSelector = lensFacing.toCameraSelector()
imageQualities.add(CameraSelectorImageQualities(cameraSelector, imageSizes))
}
} catch (e: Exception) {
activity.showErrorToast(e)
@ -52,19 +51,26 @@ class ImageQualityManager(
}
fun getUserSelectedResolution(cameraSelector: CameraSelector): MySize {
val index = if (cameraSelector == CameraSelector.DEFAULT_FRONT_CAMERA) config.frontPhotoResIndex else config.backPhotoResIndex
return imageQualities.filter { it.camSelector == cameraSelector }
.flatMap { it.qualities }
.sortedWith(compareByDescending<MySize> { it.ratio }.thenByDescending { it.pixels })
.distinctBy { it.pixels }
.filter { it.megaPixels != "0.0" }[index]
val resolutions = getSupportedResolutions(cameraSelector)
var index = if (cameraSelector == CameraSelector.DEFAULT_FRONT_CAMERA) config.frontPhotoResIndex else config.backPhotoResIndex
index = index.coerceAtMost(resolutions.lastIndex)
return resolutions[index]
}
fun getSupportedResolutions(cameraSelector: CameraSelector): List<MySize> {
val fullScreenSize = getFullScreenResolution(cameraSelector)
return listOf(fullScreenSize) + imageQualities.filter { it.camSelector == cameraSelector }
.flatMap { it.qualities }
.sortedByDescending { it.pixels }
.distinctBy { it.getAspectRatio(activity) }
.filter { it.isSupported() }
}
private fun getFullScreenResolution(cameraSelector: CameraSelector): MySize {
return imageQualities.filter { it.camSelector == cameraSelector }
.flatMap { it.qualities }
.sortedWith(compareByDescending<MySize> { it.ratio }.thenByDescending { it.pixels })
.distinctBy { it.pixels }
.filter { it.megaPixels != "0.0" }
.sortedByDescending { it.width }
.first { it.isSupported() }
.copy(isFullScreen = true)
}
}

View File

@ -4,6 +4,7 @@ import android.annotation.SuppressLint
import android.content.Context
import android.hardware.SensorManager
import android.hardware.display.DisplayManager
import android.util.Rational
import android.util.Size
import android.view.*
import android.view.GestureDetector.SimpleOnGestureListener
@ -14,10 +15,12 @@ import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.video.*
import androidx.camera.video.VideoCapture
import androidx.camera.view.PreviewView
import androidx.camera.view.PreviewView.ScaleType
import androidx.core.content.ContextCompat
import androidx.core.view.doOnLayout
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.window.layout.WindowMetricsCalculator
import com.bumptech.glide.load.ImageHeaderParser.UNKNOWN_ORIENTATION
import com.simplemobiletools.camera.R
import com.simplemobiletools.camera.dialogs.ChangeResolutionDialogX
@ -49,6 +52,7 @@ class CameraXPreview(
private val mainExecutor = ContextCompat.getMainExecutor(activity)
private val displayManager = activity.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
private val mediaSoundHelper = MediaSoundHelper()
private val windowMetricsCalculator = WindowMetricsCalculator.getOrCreate()
private val videoQualityManager = VideoQualityManager(activity)
private val imageQualityManager = ImageQualityManager(activity)
private val exifRemover = ExifRemover(contentResolver)
@ -120,7 +124,7 @@ class CameraXPreview(
private fun bindCameraUseCases() {
val cameraProvider = cameraProvider ?: throw IllegalStateException("Camera initialization failed.")
val rotation = previewView.display.rotation
val resolution = if (isPhotoCapture) {
imageQualityManager.getUserSelectedResolution(cameraSelector)
} else {
@ -128,22 +132,94 @@ class CameraXPreview(
MySize(selectedQuality.width, selectedQuality.height)
}
val isFullSize = resolution.isFullScreen
previewView.scaleType = if (isFullSize) ScaleType.FILL_CENTER else ScaleType.FIT_CENTER
val rotation = previewView.display.rotation
val rotatedResolution = getRotatedResolution(resolution, rotation)
preview = buildPreview(rotatedResolution, rotation)
val previewUseCase = buildPreview(rotatedResolution, rotation)
val captureUseCase = getCaptureUseCase(rotatedResolution, rotation)
cameraProvider.unbindAll()
camera = cameraProvider.bindToLifecycle(
activity,
cameraSelector,
preview,
captureUseCase,
)
preview?.setSurfaceProvider(previewView.surfaceProvider)
cameraProvider.unbindAll()
camera = if (isFullSize) {
val metrics = windowMetricsCalculator.computeCurrentWindowMetrics(activity).bounds
val screenWidth = metrics.width()
val screenHeight = metrics.height()
val viewPort = ViewPort.Builder(Rational(screenWidth, screenHeight), rotation).build()
val useCaseGroup = UseCaseGroup.Builder()
.addUseCase(previewUseCase)
.addUseCase(captureUseCase)
.setViewPort(viewPort)
.build()
cameraProvider.bindToLifecycle(
activity,
cameraSelector,
useCaseGroup,
)
} else {
cameraProvider.bindToLifecycle(
activity,
cameraSelector,
previewUseCase,
captureUseCase,
)
}
previewUseCase.setSurfaceProvider(previewView.surfaceProvider)
preview = previewUseCase
setupZoomAndFocus()
}
private fun getRotatedResolution(resolution: MySize, rotationDegrees: Int): Size {
return if (rotationDegrees == Surface.ROTATION_0 || rotationDegrees == Surface.ROTATION_180) {
Size(resolution.height, resolution.width)
} else {
Size(resolution.width, resolution.height)
}
}
private fun buildPreview(resolution: Size, rotation: Int): Preview {
return Preview.Builder()
.setTargetRotation(rotation)
.setTargetResolution(resolution)
.build()
}
private fun getCaptureUseCase(resolution: Size, rotation: Int): UseCase {
return if (isPhotoCapture) {
buildImageCapture(resolution, rotation).also {
imageCapture = it
}
} else {
buildVideoCapture().also {
videoCapture = it
}
}
}
private fun buildImageCapture(resolution: Size, rotation: Int): ImageCapture {
return Builder()
.setCaptureMode(CAPTURE_MODE_MAXIMIZE_QUALITY)
.setFlashMode(flashMode)
.setJpegQuality(config.photoQuality)
.setTargetRotation(rotation)
.setTargetResolution(resolution)
.build()
}
private fun buildVideoCapture(): VideoCapture<Recorder> {
val qualitySelector = QualitySelector.from(
videoQualityManager.getUserSelectedQuality(cameraSelector).toCameraXQuality(),
FallbackStrategy.higherQualityOrLowerThan(Quality.SD),
)
val recorder = Recorder.Builder()
.setQualitySelector(qualitySelector)
.build()
return VideoCapture.withOutput(recorder)
}
private fun setupCameraObservers() {
listener.setFlashAvailable(camera?.cameraInfo?.hasFlashUnit() ?: false)
listener.onChangeCamera(isFrontCameraInUse())
@ -166,56 +242,6 @@ class CameraXPreview(
}
}
private fun getCaptureUseCase(resolution: Size, rotation: Int): UseCase {
return if (isPhotoCapture) {
cameraProvider?.unbind(videoCapture)
buildImageCapture(resolution, rotation).also {
imageCapture = it
}
} else {
cameraProvider?.unbind(imageCapture)
buildVideoCapture().also {
videoCapture = it
}
}
}
private fun buildImageCapture(resolution: Size, rotation: Int): ImageCapture {
return Builder()
.setCaptureMode(CAPTURE_MODE_MAXIMIZE_QUALITY)
.setFlashMode(flashMode)
.setJpegQuality(config.photoQuality)
.setTargetRotation(rotation)
.setTargetResolution(resolution)
.build()
}
private fun getRotatedResolution(resolution: MySize, rotationDegrees: Int): Size {
return if (rotationDegrees == Surface.ROTATION_0 || rotationDegrees == Surface.ROTATION_180) {
Size(resolution.height, resolution.width)
} else {
Size(resolution.width, resolution.height)
}
}
private fun buildPreview(resolution: Size, rotation: Int): Preview {
return Preview.Builder()
.setTargetRotation(rotation)
.setTargetResolution(resolution)
.build()
}
private fun buildVideoCapture(): VideoCapture<Recorder> {
val qualitySelector = QualitySelector.from(
videoQualityManager.getUserSelectedQuality(cameraSelector).toCameraXQuality(),
FallbackStrategy.higherQualityOrLowerThan(Quality.SD),
)
val recorder = Recorder.Builder()
.setQualitySelector(qualitySelector)
.build()
return VideoCapture.withOutput(recorder)
}
private fun hasBackCamera(): Boolean {
return cameraProvider?.hasCamera(CameraSelector.DEFAULT_BACK_CAMERA) ?: false
}

View File

@ -4,18 +4,19 @@ import android.content.Context
import android.util.Size
import com.simplemobiletools.camera.R
data class MySize(val width: Int, val height: Int) {
data class MySize(val width: Int, val height: Int, val isFullScreen: Boolean = false) {
companion object {
private const val ONE_MEGA_PIXEL = 1000000
private const val ZERO_MEGA_PIXEL = "0.0"
}
val ratio = width / height.toFloat()
private val ratio = width / height.toFloat()
val pixels: Int = width * height
val megaPixels: String = String.format("%.1f", (width * height.toFloat()) / ONE_MEGA_PIXEL)
val megaPixels: String = String.format("%.1f", (width * height.toFloat()) / ONE_MEGA_PIXEL)
fun isSixteenToNine() = ratio == 16 / 9f
private fun isSixteenToNine() = ratio == 16 / 9f
private fun isFiveToThree() = ratio == 5 / 3f
@ -37,6 +38,10 @@ data class MySize(val width: Int, val height: Int) {
private fun isSquare() = width == height
fun isSupported(): Boolean {
return (isFourToThree() || isSixteenToNine() || isSquare()) && megaPixels != ZERO_MEGA_PIXEL
}
fun getAspectRatio(context: Context) = when {
isSixteenToNine() -> "16:9"
isFiveToThree() -> "5:3"

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:angle="90"
android:endColor="@android:color/transparent"
android:startColor="@color/gradient_grey_start"/>
</shape>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:angle="270"
android:endColor="@android:color/transparent"
android:startColor="@color/gradient_grey_start"/>
</shape>

View File

@ -1,17 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/view_holder"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black">
android:background="@android:color/black"
android:fitsSystemWindows="true">
<androidx.camera.view.PreviewView
android:id="@+id/preview_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:scaleType="fitStart" />
android:layout_height="match_parent" />
<View
android:id="@+id/capture_black_screen"
@ -20,24 +20,28 @@
android:alpha="0"
android:background="@color/md_grey_black" />
<View
android:id="@+id/top_overlay"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="@drawable/gradient_background_flipped"
app:layout_constraintBottom_toBottomOf="@id/settings"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/settings"
android:layout_width="@dimen/icon_size"
android:layout_height="@dimen/icon_size"
android:layout_alignParentEnd="true"
android:contentDescription="@string/settings"
android:padding="@dimen/normal_margin"
android:src="@drawable/ic_settings_cog_vector" />
android:src="@drawable/ic_settings_cog_vector"
app:layout_constraintEnd_toStartOf="@id/change_resolution"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/toggle_photo_video"
android:layout_width="@dimen/icon_size"
android:layout_height="@dimen/icon_size"
android:layout_below="@+id/settings"
android:layout_alignParentEnd="true"
android:contentDescription="@string/toggle_photo_video"
android:padding="@dimen/normal_margin"
android:src="@drawable/ic_video_vector" />
<ImageView
android:id="@+id/change_resolution"
@ -47,61 +51,106 @@
android:layout_alignParentEnd="true"
android:contentDescription="@string/resolution"
android:padding="@dimen/normal_margin"
android:src="@drawable/ic_resolution_vector" />
android:src="@drawable/ic_resolution_vector"
app:layout_constraintEnd_toStartOf="@id/toggle_flash"
app:layout_constraintStart_toEndOf="@id/settings"
app:layout_constraintTop_toTopOf="@id/settings" />
<ImageView
android:id="@+id/toggle_flash"
android:layout_width="@dimen/icon_size"
android:layout_height="@dimen/icon_size"
android:layout_weight="1"
android:contentDescription="@string/toggle_flash"
android:padding="@dimen/normal_margin"
android:src="@drawable/ic_flash_off_vector"
app:layout_constraintEnd_toStartOf="@id/toggle_photo_video"
app:layout_constraintStart_toEndOf="@id/change_resolution"
app:layout_constraintTop_toTopOf="@id/settings" />
<ImageView
android:id="@+id/toggle_photo_video"
android:layout_width="@dimen/icon_size"
android:layout_height="@dimen/icon_size"
android:contentDescription="@string/toggle_photo_video"
android:padding="@dimen/normal_margin"
android:src="@drawable/ic_video_vector"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/toggle_flash"
app:layout_constraintTop_toTopOf="@id/settings" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/top_barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="bottom"
app:constraint_referenced_ids="settings,change_resolution,toggle_flash,toggle_photo_video" />
<View
android:id="@+id/bottom_overlay"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="@drawable/gradient_background"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/shutter" />
<ImageView
android:id="@+id/toggle_camera"
android:layout_width="@dimen/icon_size"
android:layout_height="@dimen/icon_size"
android:contentDescription="@string/toggle_camera"
android:padding="@dimen/normal_margin"
android:src="@drawable/ic_camera_front_vector"
app:layout_constraintBottom_toBottomOf="@id/shutter"
app:layout_constraintEnd_toStartOf="@id/shutter"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/shutter" />
<ImageView
android:id="@+id/shutter"
android:layout_width="@dimen/icon_size"
android:layout_height="@dimen/icon_size"
android:layout_marginBottom="@dimen/small_margin"
android:contentDescription="@string/shutter"
android:src="@drawable/ic_shutter_vector"
app:layout_constraintBottom_toTopOf="@id/video_rec_curr_timer"
app:layout_constraintEnd_toStartOf="@id/last_photo_video_preview"
app:layout_constraintStart_toEndOf="@id/toggle_camera"
app:layout_constraintVertical_bias="1"
app:layout_goneMarginBottom="@dimen/big_margin" />
<ImageView
android:id="@+id/last_photo_video_preview"
android:layout_width="@dimen/icon_size"
android:layout_height="@dimen/icon_size"
android:layout_below="@+id/change_resolution"
android:layout_alignParentEnd="true"
android:contentDescription="@string/view_last_media"
android:padding="@dimen/medium_margin" />
android:padding="@dimen/medium_margin"
app:layout_constraintBottom_toBottomOf="@id/shutter"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/shutter"
app:layout_constraintTop_toTopOf="@id/shutter"
tools:src="@tools:sample/backgrounds/scenic" />
<LinearLayout
android:id="@+id/btn_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:gravity="center_horizontal|bottom">
<ImageView
android:id="@+id/toggle_camera"
android:layout_width="@dimen/icon_size"
android:layout_height="@dimen/icon_size"
android:layout_weight="1"
android:contentDescription="@string/toggle_camera"
android:padding="@dimen/normal_margin"
android:src="@drawable/ic_camera_front_vector" />
<ImageView
android:id="@+id/shutter"
android:layout_width="@dimen/icon_size"
android:layout_height="@dimen/icon_size"
android:layout_weight="1"
android:contentDescription="@string/shutter"
android:src="@drawable/ic_shutter_vector" />
<ImageView
android:id="@+id/toggle_flash"
android:layout_width="@dimen/icon_size"
android:layout_height="@dimen/icon_size"
android:layout_weight="1"
android:contentDescription="@string/toggle_flash"
android:padding="@dimen/normal_margin"
android:src="@drawable/ic_flash_off_vector" />
</LinearLayout>
<TextView
android:id="@+id/video_rec_curr_timer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@+id/btn_holder"
android:layout_centerHorizontal="true"
android:layout_marginTop="@dimen/small_margin"
android:layout_marginBottom="@dimen/big_margin"
android:textColor="@android:color/white"
android:visibility="gone"
tools:text="00:00" />
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:text="00:00"
tools:visibility="gone" />
</RelativeLayout>
</androidx.constraintlayout.widget.ConstraintLayout>