Merge pull request #330 from KryptKode/feat/camera-x

Updates/Fixes for CameraX implementation
This commit is contained in:
Tibor Kaputa 2022-07-13 08:54:12 +02:00 committed by GitHub
commit 91bc6ccf60
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 363 additions and 319 deletions

View File

@ -63,13 +63,13 @@ android {
}
dependencies {
implementation 'com.github.SimpleMobileTools:Simple-Commons:d1d5402388'
implementation 'com.github.SimpleMobileTools:Simple-Commons:7c48da6bef'
implementation 'androidx.documentfile:documentfile:1.0.1'
implementation "androidx.exifinterface:exifinterface:1.3.3"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.4.1"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.5.0"
implementation 'androidx.window:window:1.1.0-alpha02'
def camerax_version = '1.1.0-rc02'
def camerax_version = '1.1.0'
implementation "androidx.camera:camera-core:$camerax_version"
implementation "androidx.camera:camera-camera2:$camerax_version"
implementation "androidx.camera:camera-video:$camerax_version"

View File

@ -10,10 +10,11 @@ import com.simplemobiletools.commons.dialogs.FilePickerDialog
import com.simplemobiletools.commons.dialogs.RadioGroupDialog
import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.LICENSE_GLIDE
import com.simplemobiletools.commons.helpers.NavigationIcon
import com.simplemobiletools.commons.models.FAQItem
import com.simplemobiletools.commons.models.RadioItem
import java.util.Locale
import kotlinx.android.synthetic.main.activity_settings.*
import java.util.*
class SettingsActivity : SimpleActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
@ -23,7 +24,7 @@ class SettingsActivity : SimpleActivity() {
override fun onResume() {
super.onResume()
setupToolbar(settings_toolbar, NavigationIcon.Arrow)
setupPurchaseThankYou()
setupCustomizeColors()
setupUseEnglish()

View File

@ -8,13 +8,19 @@ import com.simplemobiletools.camera.activities.SimpleActivity
import com.simplemobiletools.camera.extensions.config
import com.simplemobiletools.camera.models.MySize
import com.simplemobiletools.commons.dialogs.RadioGroupDialog
import com.simplemobiletools.commons.extensions.getAlertDialogBuilder
import com.simplemobiletools.commons.extensions.setupDialogStuff
import com.simplemobiletools.commons.models.RadioItem
import kotlinx.android.synthetic.main.dialog_change_resolution.view.*
import kotlinx.android.synthetic.main.dialog_change_resolution.view.change_resolution_photo
import kotlinx.android.synthetic.main.dialog_change_resolution.view.change_resolution_photo_holder
import kotlinx.android.synthetic.main.dialog_change_resolution.view.change_resolution_video
import kotlinx.android.synthetic.main.dialog_change_resolution.view.change_resolution_video_holder
class ChangeResolutionDialog(val activity: SimpleActivity, val isFrontCamera: Boolean, val photoResolutions: ArrayList<MySize>,
val videoResolutions: ArrayList<MySize>, val openVideoResolutions: Boolean, val callback: () -> Unit) {
private var dialog: AlertDialog
class ChangeResolutionDialog(
val activity: SimpleActivity, val isFrontCamera: Boolean, val photoResolutions: ArrayList<MySize>,
val videoResolutions: ArrayList<MySize>, val openVideoResolutions: Boolean, val callback: () -> Unit
) {
private var dialog: AlertDialog? = null
private val config = activity.config
init {
@ -23,16 +29,18 @@ class ChangeResolutionDialog(val activity: SimpleActivity, val isFrontCamera: Bo
setupVideoResolutionPicker(this)
}
dialog = AlertDialog.Builder(activity)
.setPositiveButton(R.string.ok, null)
.setOnDismissListener { callback() }
.create().apply {
activity.setupDialogStuff(view, this, if (isFrontCamera) R.string.front_camera else R.string.back_camera) {
if (openVideoResolutions) {
view.change_resolution_video_holder.performClick()
}
activity.getAlertDialogBuilder()
.setPositiveButton(R.string.ok, null)
.setOnDismissListener { callback() }
.apply {
val titleId = if (isFrontCamera) R.string.front_camera else R.string.back_camera
activity.setupDialogStuff(view, this, titleId) { alertDialog ->
dialog = alertDialog
if (openVideoResolutions) {
view.change_resolution_video_holder.performClick()
}
}
}
}
private fun setupPhotoResolutionPicker(view: View) {
@ -49,7 +57,7 @@ class ChangeResolutionDialog(val activity: SimpleActivity, val isFrontCamera: Bo
} else {
config.backPhotoResIndex = it
}
dialog.dismiss()
dialog?.dismiss()
}
}
view.change_resolution_photo.text = items.getOrNull(selectionIndex)?.title
@ -68,7 +76,7 @@ class ChangeResolutionDialog(val activity: SimpleActivity, val isFrontCamera: Bo
} else {
config.backVideoResIndex = it
}
dialog.dismiss()
dialog?.dismiss()
}
}
view.change_resolution_video.text = items.getOrNull(selectionIndex)?.title

View File

@ -10,6 +10,7 @@ import com.simplemobiletools.camera.extensions.config
import com.simplemobiletools.camera.models.MySize
import com.simplemobiletools.camera.models.VideoQuality
import com.simplemobiletools.commons.dialogs.RadioGroupDialog
import com.simplemobiletools.commons.extensions.getAlertDialogBuilder
import com.simplemobiletools.commons.extensions.setupDialogStuff
import com.simplemobiletools.commons.models.RadioItem
import kotlinx.android.synthetic.main.dialog_change_resolution.view.change_resolution_photo
@ -22,9 +23,9 @@ class ChangeResolutionDialogX(
private val isFrontCamera: Boolean,
private val photoResolutions: List<MySize> = listOf(),
private val videoResolutions: List<VideoQuality>,
private val callback: () -> Unit
private val callback: () -> Unit,
) {
private var dialog: AlertDialog
private var dialog: AlertDialog? = null
private val config = activity.config
private val TAG = "ChangeResolutionDialogX"
@ -34,20 +35,27 @@ class ChangeResolutionDialogX(
setupVideoResolutionPicker(this)
}
dialog = AlertDialog.Builder(activity)
activity.getAlertDialogBuilder()
.setPositiveButton(R.string.ok, null)
.create().apply {
activity.setupDialogStuff(view, this, if (isFrontCamera) R.string.front_camera else R.string.back_camera)
.apply {
val titleId = if (isFrontCamera) R.string.front_camera else R.string.back_camera
activity.setupDialogStuff(view, this, titleId) { alertDialog ->
dialog = alertDialog
}
}
}
private fun setupPhotoResolutionPicker(view: View) {
val items = getFormattedResolutions(photoResolutions)
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)")
}
var selectionIndex = if (isFrontCamera) config.frontPhotoResIndex else config.backPhotoResIndex
selectionIndex = Math.max(selectionIndex, 0)
selectionIndex = selectionIndex.coerceAtLeast(0)
view.change_resolution_photo_holder.setOnClickListener {
RadioGroupDialog(activity, items, selectionIndex) {
RadioGroupDialog(activity, ArrayList(items), selectionIndex) {
selectionIndex = it as Int
Log.w(TAG, "setupPhotoResolutionPicker: selectionIndex=$it")
view.change_resolution_photo.text = items[selectionIndex].title
@ -56,7 +64,7 @@ class ChangeResolutionDialogX(
} else {
config.backPhotoResIndex = it
}
dialog.dismiss()
dialog?.dismiss()
callback.invoke()
}
}
@ -70,35 +78,27 @@ class ChangeResolutionDialogX(
RadioItem(index, "${videoQuality.width} x ${videoQuality.height} ($megapixels MP, $aspectRatio)")
}
val videoQuality = if (isFrontCamera) config.frontVideoQuality else config.backVideoQuality
var selectionIndex = videoResolutions.indexOf(videoQuality)
var selectionIndex = if (isFrontCamera) config.frontVideoResIndex else config.backVideoResIndex
selectionIndex = selectionIndex.coerceAtLeast(0)
Log.i(TAG, "videoResolutions=$videoResolutions")
Log.i(TAG, "setupVideoResolutionPicker: selectionIndex=$selectionIndex")
view.change_resolution_video_holder.setOnClickListener {
RadioGroupDialog(activity, ArrayList(items), selectionIndex) {
selectionIndex = it as Int
val selectedItem = items[selectionIndex]
val selectedQuality = videoResolutions[selectionIndex]
view.change_resolution_video.text = selectedItem.title
if (isFrontCamera) {
config.frontVideoQuality = selectedQuality
config.frontVideoResIndex = selectionIndex
} else {
config.backVideoQuality = selectedQuality
config.backPhotoResIndex = selectionIndex
}
dialog.dismiss()
dialog?.dismiss()
callback.invoke()
}
}
view.change_resolution_video.text = items.getOrNull(selectionIndex)?.title
}
private fun getFormattedResolutions(resolutions: List<MySize>): ArrayList<RadioItem> {
val items = ArrayList<RadioItem>(resolutions.size)
val sorted = resolutions.sortedByDescending { it.width * it.height }
sorted.forEachIndexed { index, size ->
val megapixels = String.format("%.1f", (size.width * size.height.toFloat()) / 1000000)
val aspectRatio = size.getAspectRatio(activity)
items.add(RadioItem(index, "${size.width} x ${size.height} ($megapixels MP, $aspectRatio)"))
}
return items
val selectedItem = items.getOrNull(selectionIndex)
view.change_resolution_video.text = selectedItem?.title
Log.i(TAG, "setupVideoResolutionPicker: selectedItem=$selectedItem")
}
}

View File

@ -3,7 +3,6 @@ package com.simplemobiletools.camera.helpers
import android.content.Context
import android.os.Environment
import androidx.camera.core.CameraSelector
import com.simplemobiletools.camera.models.VideoQuality
import com.simplemobiletools.commons.helpers.BaseConfig
import java.io.File
@ -63,20 +62,6 @@ class Config(context: Context) : BaseConfig(context) {
get() = prefs.getInt(FRONT_PHOTO_RESOLUTION_INDEX, 0)
set(frontPhotoResIndex) = prefs.edit().putInt(FRONT_PHOTO_RESOLUTION_INDEX, frontPhotoResIndex).apply()
var backVideoQuality: VideoQuality
get() {
val backQuality = prefs.getString(BACK_VIDEO_QUALITY, VideoQuality.UHD.name)
return VideoQuality.values().first { it.name == backQuality }
}
set(backVideoQuality) = prefs.edit().putString(BACK_VIDEO_QUALITY, backVideoQuality.name).apply()
var frontVideoQuality: VideoQuality
get() {
val frontQuality = prefs.getString(FRONT_VIDEO_QUALITY, VideoQuality.UHD.name)
return VideoQuality.values().first { it.name == frontQuality }
}
set(frontVideoQuality) = prefs.edit().putString(FRONT_VIDEO_QUALITY, frontVideoQuality.name).apply()
var frontVideoResIndex: Int
get() = prefs.getInt(FRONT_VIDEO_RESOLUTION_INDEX, 0)
set(frontVideoResIndex) = prefs.edit().putInt(FRONT_VIDEO_RESOLUTION_INDEX, frontVideoResIndex).apply()

View File

@ -10,11 +10,8 @@ import android.util.Log
import android.util.Size
import androidx.appcompat.app.AppCompatActivity
import androidx.camera.core.CameraSelector
import androidx.camera.video.Quality
import com.simplemobiletools.camera.extensions.config
import com.simplemobiletools.camera.extensions.toCameraXQuality
import com.simplemobiletools.camera.models.CameraSelectorImageQualities
import com.simplemobiletools.camera.models.CameraSelectorVideoQualities
import com.simplemobiletools.camera.models.MySize
class ImageQualityManager(
@ -69,7 +66,7 @@ class ImageQualityManager(
val index = if (cameraSelector == CameraSelector.DEFAULT_FRONT_CAMERA) config.frontPhotoResIndex else config.backPhotoResIndex
return imageQualities.filter { it.camSelector == cameraSelector }
.flatMap { it.qualities }
.sortedByDescending { it.pixels}
.sortedByDescending { it.pixels }
.distinctBy { it.pixels }
.map { Size(it.width, it.height) }
.also {
@ -85,5 +82,6 @@ class ImageQualityManager(
.flatMap { it.qualities }
.sortedByDescending { it.pixels }
.distinctBy { it.pixels }
.filter { it.megaPixels != "0.0" }
}
}

View File

@ -1,17 +1,20 @@
package com.simplemobiletools.camera.helpers
import android.util.Log
import androidx.camera.core.Camera
import androidx.appcompat.app.AppCompatActivity
import androidx.camera.core.CameraSelector
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.video.Quality
import androidx.camera.video.QualitySelector
import com.simplemobiletools.camera.extensions.config
import com.simplemobiletools.camera.extensions.toCameraXQuality
import com.simplemobiletools.camera.extensions.toVideoQuality
import com.simplemobiletools.camera.models.CameraSelectorVideoQualities
import com.simplemobiletools.camera.models.VideoQuality
class VideoQualityManager(private val config: Config) {
class VideoQualityManager(
private val activity: AppCompatActivity,
) {
companion object {
private const val TAG = "VideoQualityHelper"
@ -19,14 +22,14 @@ class VideoQualityManager(private val config: Config) {
private val CAMERA_SELECTORS = arrayOf(CameraSelector.DEFAULT_BACK_CAMERA, CameraSelector.DEFAULT_FRONT_CAMERA)
}
private val config = activity.config
private val videoQualities = mutableListOf<CameraSelectorVideoQualities>()
fun initSupportedQualities(
cameraProvider: ProcessCameraProvider,
camera: Camera,
) {
fun initSupportedQualities(cameraProvider: ProcessCameraProvider) {
if (videoQualities.isEmpty()) {
for (camSelector in CAMERA_SELECTORS) {
cameraProvider.unbindAll()
val camera = cameraProvider.bindToLifecycle(activity, camSelector)
try {
if (cameraProvider.hasCamera(camSelector)) {
QualitySelector.getSupportedQualities(camera.cameraInfo)
@ -34,6 +37,7 @@ class VideoQualityManager(private val config: Config) {
.also { allQualities ->
val qualities = allQualities.map { it.toVideoQuality() }
videoQualities.add(CameraSelectorVideoQualities(camSelector, qualities))
}
Log.i(TAG, "bindCameraUseCases: videoQualities=$videoQualities")
}
@ -45,11 +49,9 @@ class VideoQualityManager(private val config: Config) {
}
fun getUserSelectedQuality(cameraSelector: CameraSelector): Quality {
return if (cameraSelector == CameraSelector.DEFAULT_FRONT_CAMERA) {
config.frontVideoQuality.toCameraXQuality()
} else {
config.backVideoQuality.toCameraXQuality()
}
var selectionIndex = if (cameraSelector == CameraSelector.DEFAULT_FRONT_CAMERA) config.frontVideoResIndex else config.backVideoResIndex
selectionIndex = selectionIndex.coerceAtLeast(0)
return getSupportedQualities(cameraSelector)[selectionIndex].toCameraXQuality()
}
fun getSupportedQualities(cameraSelector: CameraSelector): List<VideoQuality> {

View File

@ -5,6 +5,7 @@ import android.content.Context
import android.hardware.SensorManager
import android.hardware.display.DisplayManager
import android.util.Log
import android.util.Size
import android.view.*
import android.view.GestureDetector.SimpleOnGestureListener
import androidx.appcompat.app.AppCompatActivity
@ -57,7 +58,7 @@ class CameraXPreview(
private val displayManager = activity.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
private val mediaSoundHelper = MediaSoundHelper()
private val windowMetricsCalculator = WindowMetricsCalculator.getOrCreate()
private val videoQualityManager = VideoQualityManager(config)
private val videoQualityManager = VideoQualityManager(activity)
private val imageQualityManager = ImageQualityManager(activity)
private val exifRemover = ExifRemover(contentResolver)
@ -74,7 +75,7 @@ class CameraXPreview(
in 225 until 315 -> Surface.ROTATION_90
else -> Surface.ROTATION_0
}
Log.i(TAG, "onOrientationChanged: rotation=$rotation")
preview?.targetRotation = rotation
imageCapture?.targetRotation = rotation
videoCapture?.targetRotation = rotation
@ -109,10 +110,13 @@ class CameraXPreview(
private fun startCamera(switching: Boolean = false) {
Log.i(TAG, "startCamera: ")
imageQualityManager.initSupportedQualities()
val cameraProviderFuture = ProcessCameraProvider.getInstance(activity)
cameraProviderFuture.addListener({
try {
cameraProvider = cameraProviderFuture.get()
val provider = cameraProviderFuture.get()
cameraProvider = provider
videoQualityManager.initSupportedQualities(provider)
bindCameraUseCases()
setupCameraObservers()
} catch (e: Exception) {
@ -142,9 +146,7 @@ class CameraXPreview(
cameraSelector,
preview,
captureUseCase,
).also {
videoQualityManager.initSupportedQualities(cameraProvider, it)
}
)
preview?.setSurfaceProvider(previewView.surfaceProvider)
setupZoomAndFocus()
@ -187,20 +189,31 @@ class CameraXPreview(
}
private fun buildImageCapture(aspectRatio: Int, rotation: Int): ImageCapture {
return ImageCapture.Builder()
return Builder()
.setCaptureMode(CAPTURE_MODE_MAXIMIZE_QUALITY)
.setFlashMode(flashMode)
.setJpegQuality(config.photoQuality)
.setTargetRotation(rotation)
.apply {
imageQualityManager.getUserSelectedResolution(cameraSelector)?.let { resolution ->
val rotatedResolution = getRotatedResolution(rotation, resolution)
Log.i(TAG, "buildImageCapture: rotation=$rotation")
Log.i(TAG, "buildImageCapture: resolution=$resolution")
setTargetResolution(resolution)
Log.i(TAG, "buildImageCapture: rotatedResolution=$rotatedResolution")
setTargetResolution(rotatedResolution)
} ?: setTargetAspectRatio(aspectRatio)
}
.build()
}
private fun getRotatedResolution(rotationDegrees: Int, resolution: Size): 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(aspectRatio: Int, rotation: Int): Preview {
return Preview.Builder()
.setTargetRotation(rotation)
@ -211,7 +224,7 @@ class CameraXPreview(
private fun buildVideoCapture(): VideoCapture<Recorder> {
val qualitySelector = QualitySelector.from(
videoQualityManager.getUserSelectedQuality(cameraSelector),
FallbackStrategy.lowerQualityOrHigherThan(Quality.SD),
FallbackStrategy.higherQualityOrLowerThan(Quality.SD),
)
val recorder = Recorder.Builder()
.setQualitySelector(qualitySelector)
@ -350,7 +363,7 @@ class CameraXPreview(
if (bitmap != null) {
listener.onImageCaptured(bitmap)
} else {
cameraErrorHandler.handleImageCaptureError(ImageCapture.ERROR_CAPTURE_FAILED)
cameraErrorHandler.handleImageCaptureError(ERROR_CAPTURE_FAILED)
}
}

View File

@ -5,8 +5,16 @@ import android.util.Size
import com.simplemobiletools.camera.R
data class MySize(val width: Int, val height: Int) {
companion object {
private const val ONE_MEGA_PIXEL = 1000000
}
val ratio = width / height.toFloat()
val pixels: Int = width * height
val megaPixels: String = String.format("%.1f", (width * height.toFloat()) / ONE_MEGA_PIXEL)
fun isSixteenToNine() = ratio == 16 / 9f
private fun isFiveToThree() = ratio == 5 / 3f

View File

@ -1,254 +1,283 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.coordinatorlayout.widget.CoordinatorLayout 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/settings_scrollview"
android:id="@+id/settings_coordinator"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/settings_holder"
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/settings_app_bar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
android:layout_height="wrap_content">
<TextView
android:id="@+id/settings_color_customization_label"
style="@style/SettingsSectionLabelStyle"
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/settings_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/color_customization" />
android:layout_height="?attr/actionBarSize"
android:background="@color/color_primary"
app:layout_scrollFlags="scroll|enterAlways"
app:title="@string/settings"
app:titleTextAppearance="@style/AppTheme.ActionBar.TitleTextStyle" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:id="@+id/settings_nested_scrollview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:scrollbars="none"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:id="@+id/settings_color_customization_holder"
android:id="@+id/settings_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/medium_margin"
android:background="@drawable/section_holder_stroke"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/settings_customize_colors_holder"
style="@style/SettingsHolderTextViewOneLinerStyle"
<TextView
android:id="@+id/settings_color_customization_label"
style="@style/SettingsSectionLabelStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/ripple_all_corners">
android:text="@string/color_customization" />
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/settings_customize_colors_label"
style="@style/SettingsTextLabelStyle"
android:layout_width="wrap_content"
<LinearLayout
android:id="@+id/settings_color_customization_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/medium_margin"
android:background="@drawable/section_holder_stroke"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/settings_customize_colors_holder"
style="@style/SettingsHolderTextViewOneLinerStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/customize_colors" />
android:background="@drawable/ripple_all_corners">
</RelativeLayout>
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/settings_customize_colors_label"
style="@style/SettingsTextLabelStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/customize_colors" />
</RelativeLayout>
</LinearLayout>
<TextView
android:id="@+id/settings_general_settings_label"
style="@style/SettingsSectionLabelStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/general_settings" />
<LinearLayout
android:id="@+id/settings_general_settings_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/medium_margin"
android:background="@drawable/section_holder_stroke"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/settings_purchase_thank_you_holder"
style="@style/SettingsHolderTextViewOneLinerStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/ripple_top_corners">
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/settings_purchase_thank_you"
style="@style/SettingsTextLabelStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/purchase_simple_thank_you" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/settings_use_english_holder"
style="@style/SettingsHolderCheckboxStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/ripple_background">
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/settings_use_english"
style="@style/SettingsCheckboxStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/use_english_language" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/settings_keep_settings_visible_holder"
style="@style/SettingsHolderCheckboxStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/ripple_bottom_corners">
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/settings_keep_settings_visible"
style="@style/SettingsCheckboxStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/keep_settings_visible" />
</RelativeLayout>
</LinearLayout>
<TextView
android:id="@+id/settings_shutter_label"
style="@style/SettingsSectionLabelStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/shutter" />
<LinearLayout
android:id="@+id/settings_shutter_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/medium_margin"
android:background="@drawable/section_holder_stroke"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/settings_sound_holder"
style="@style/SettingsHolderCheckboxStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/ripple_top_corners">
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/settings_sound"
style="@style/SettingsCheckboxStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/shutter_sound" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/settings_volume_buttons_as_shutter_holder"
style="@style/SettingsHolderCheckboxStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/ripple_bottom_corners">
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/settings_volume_buttons_as_shutter"
style="@style/SettingsCheckboxStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/volume_buttons_as_shutter" />
</RelativeLayout>
</LinearLayout>
<TextView
android:id="@+id/settings_saving_label"
style="@style/SettingsSectionLabelStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/saving_label" />
<LinearLayout
android:id="@+id/settings_saving_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/medium_margin"
android:background="@drawable/section_holder_stroke"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/settings_save_photo_metadata_holder"
style="@style/SettingsHolderCheckboxStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/ripple_top_corners">
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/settings_save_photo_metadata"
style="@style/SettingsCheckboxStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/save_photo_metadata" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/settings_flip_photos_holder"
style="@style/SettingsHolderCheckboxStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/ripple_background">
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/settings_flip_photos"
style="@style/SettingsCheckboxStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/flip_front_camera_photos_horizontally" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/settings_save_photos_holder"
style="@style/SettingsHolderTextViewStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/ripple_background">
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/settings_save_photos_label"
style="@style/SettingsTextLabelStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/save_photos" />
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/settings_save_photos"
style="@style/SettingsTextValueStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/settings_save_photos_label"
tools:text="Internal/DCIM" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/settings_photo_quality_holder"
style="@style/SettingsHolderTextViewStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/ripple_bottom_corners">
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/settings_photo_quality_label"
style="@style/SettingsTextLabelStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/photo_compression_quality" />
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/settings_photo_quality"
style="@style/SettingsTextValueStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/settings_photo_quality_label"
tools:text="80%" />
</RelativeLayout>
</LinearLayout>
</LinearLayout>
<TextView
android:id="@+id/settings_general_settings_label"
style="@style/SettingsSectionLabelStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/general_settings" />
</androidx.core.widget.NestedScrollView>
<LinearLayout
android:id="@+id/settings_general_settings_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/medium_margin"
android:background="@drawable/section_holder_stroke"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/settings_purchase_thank_you_holder"
style="@style/SettingsHolderTextViewOneLinerStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/ripple_top_corners">
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/settings_purchase_thank_you"
style="@style/SettingsTextLabelStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/purchase_simple_thank_you" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/settings_use_english_holder"
style="@style/SettingsHolderCheckboxStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/ripple_background">
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/settings_use_english"
style="@style/SettingsCheckboxStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/use_english_language" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/settings_keep_settings_visible_holder"
style="@style/SettingsHolderCheckboxStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/ripple_bottom_corners">
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/settings_keep_settings_visible"
style="@style/SettingsCheckboxStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/keep_settings_visible" />
</RelativeLayout>
</LinearLayout>
<TextView
android:id="@+id/settings_shutter_label"
style="@style/SettingsSectionLabelStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/shutter" />
<LinearLayout
android:id="@+id/settings_shutter_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/medium_margin"
android:background="@drawable/section_holder_stroke"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/settings_sound_holder"
style="@style/SettingsHolderCheckboxStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/ripple_top_corners">
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/settings_sound"
style="@style/SettingsCheckboxStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/shutter_sound" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/settings_volume_buttons_as_shutter_holder"
style="@style/SettingsHolderCheckboxStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/ripple_bottom_corners">
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/settings_volume_buttons_as_shutter"
style="@style/SettingsCheckboxStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/volume_buttons_as_shutter" />
</RelativeLayout>
</LinearLayout>
<TextView
android:id="@+id/settings_saving_label"
style="@style/SettingsSectionLabelStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/saving_label" />
<LinearLayout
android:id="@+id/settings_saving_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/medium_margin"
android:background="@drawable/section_holder_stroke"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/settings_save_photo_metadata_holder"
style="@style/SettingsHolderCheckboxStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/ripple_top_corners">
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/settings_save_photo_metadata"
style="@style/SettingsCheckboxStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/save_photo_metadata" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/settings_flip_photos_holder"
style="@style/SettingsHolderCheckboxStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/ripple_background">
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/settings_flip_photos"
style="@style/SettingsCheckboxStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/flip_front_camera_photos_horizontally" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/settings_save_photos_holder"
style="@style/SettingsHolderTextViewStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/ripple_background">
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/settings_save_photos_label"
style="@style/SettingsTextLabelStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/save_photos" />
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/settings_save_photos"
style="@style/SettingsTextValueStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/settings_save_photos_label"
tools:text="Internal/DCIM" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/settings_photo_quality_holder"
style="@style/SettingsHolderTextViewStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/ripple_bottom_corners">
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/settings_photo_quality_label"
style="@style/SettingsTextLabelStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/photo_compression_quality" />
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/settings_photo_quality"
style="@style/SettingsTextValueStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/settings_photo_quality_label"
tools:text="80%" />
</RelativeLayout>
</LinearLayout>
</LinearLayout>
</ScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>