diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 36985190b..14c2c1842 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -185,6 +185,7 @@ android:theme="@style/Theme.App" android:taskAffinity=".ui.activities.InAppGallery" android:excludeFromRecents="true" + android:windowSoftInputMode="adjustResize" android:exported="false"/> Unit, +) : InputFilter { + + constructor(min: Int, max: Int, onOutOfRange: () -> Unit) : this(min.toFloat(), max.toFloat(), onOutOfRange) override fun filter( source: CharSequence, @@ -18,25 +24,20 @@ class NumInputFilter(private val settings: MoreSettings) : InputFilter { val input = (dest.subSequence(0, dstart).toString() + source + dest.subSequence( dend, dest.length - )).toInt() + )).toFloat() if (isInRange(input)) { return null } else { - settings.showMessage(settings.getString( - R.string.photo_quality_number_limit, min, max)) + this.onOutOfRange() } } catch (e: NumberFormatException) { e.printStackTrace() + return null } return "" } - private fun isInRange(value: Int): Boolean { - return value in min..max - } - - companion object { - const val min = 1 - const val max = 100 + private fun isInRange(value: Float): Boolean { + return value in this.min..this.max } } diff --git a/app/src/main/java/app/grapheneos/camera/capturer/ImageCapturer.kt b/app/src/main/java/app/grapheneos/camera/capturer/ImageCapturer.kt index 17d947264..2d0b12b3c 100644 --- a/app/src/main/java/app/grapheneos/camera/capturer/ImageCapturer.kt +++ b/app/src/main/java/app/grapheneos/camera/capturer/ImageCapturer.kt @@ -7,6 +7,7 @@ import android.app.NotificationManager import android.content.ClipData import android.content.ClipboardManager import android.graphics.Bitmap +import android.location.Location import android.os.Build import android.util.Log import android.view.View @@ -77,7 +78,14 @@ class ImageCapturer(val mActivity: MainActivity) { && camConfig.saveImageAsPreviewed if (camConfig.requireLocation) { - val location = (mActivity.applicationContext as App).getLocation() + val location = if (camConfig.mockLocationEnabled) { + val loc = Location("") + loc.latitude = camConfig.mockLocationLatitude.toDouble() + loc.longitude = camConfig.mockLocationLongitude.toDouble() + loc + } else { + (mActivity.applicationContext as App).getLocation() + } if (location == null) { mActivity.showMessage(R.string.location_unavailable) } else { diff --git a/app/src/main/java/app/grapheneos/camera/capturer/VideoCapturer.kt b/app/src/main/java/app/grapheneos/camera/capturer/VideoCapturer.kt index 6a505d0ca..8dc5aeb3c 100644 --- a/app/src/main/java/app/grapheneos/camera/capturer/VideoCapturer.kt +++ b/app/src/main/java/app/grapheneos/camera/capturer/VideoCapturer.kt @@ -134,7 +134,15 @@ class VideoCapturer(private val mActivity: MainActivity) { var location: Location? = null if (camConfig.requireLocation) { - location = (mActivity.applicationContext as App).getLocation() + val location = if (camConfig.mockLocationEnabled) { + val loc = Location("") + loc.latitude = camConfig.mockLocationLatitude.toDouble() + loc.longitude = camConfig.mockLocationLongitude.toDouble() + loc + } else { + (mActivity.applicationContext as App).getLocation() + } + if (location == null) { mActivity.showMessage(R.string.location_unavailable) } diff --git a/app/src/main/java/app/grapheneos/camera/ui/activities/MoreSettings.kt b/app/src/main/java/app/grapheneos/camera/ui/activities/MoreSettings.kt index 18b228fbf..e11adabb0 100644 --- a/app/src/main/java/app/grapheneos/camera/ui/activities/MoreSettings.kt +++ b/app/src/main/java/app/grapheneos/camera/ui/activities/MoreSettings.kt @@ -2,7 +2,6 @@ package app.grapheneos.camera.ui.activities import android.content.Context import android.content.Intent -import android.graphics.Color import android.graphics.Rect import android.os.Bundle import android.view.KeyEvent @@ -16,12 +15,11 @@ import android.widget.TextView import androidx.activity.enableEdgeToEdge import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AppCompatActivity -import androidx.core.view.OnApplyWindowInsetsListener import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat import app.grapheneos.camera.CamConfig import app.grapheneos.camera.CapturedItems -import app.grapheneos.camera.NumInputFilter +import app.grapheneos.camera.NumLimitFilter import app.grapheneos.camera.R import app.grapheneos.camera.databinding.MoreSettingsBinding import app.grapheneos.camera.util.storageLocationToUiString @@ -150,9 +148,99 @@ open class MoreSettings : AppCompatActivity(), TextView.OnEditorActionListener { pQField.setText(camConfig.photoQuality.toString()) } - pQField.filters = arrayOf(NumInputFilter(this)) + pQField.filters = arrayOf(NumLimitFilter( + min = PHOTO_QUALITY_MIN, + max = PHOTO_QUALITY_MAX, + onOutOfRange = { + showMessage(getString(R.string.photo_quality_number_limit, PHOTO_QUALITY_MIN, PHOTO_QUALITY_MAX)) + } + )) + + pQField.onFocusChangeListener = object: View.OnFocusChangeListener { + override fun onFocusChange(v: View, hasFocus: Boolean) { + if (!hasFocus) { + if (pQField.text.isEmpty()) { + camConfig.photoQuality = 0 + + showMessage( + getString(R.string.photo_quality_was_set_to_auto) + ) + } else { + try { + camConfig.photoQuality = + Integer.parseInt(pQField.text.toString()) + } catch (exception: Exception) { + camConfig.photoQuality = 0 + + } + } + } + } + } pQField.setOnEditorActionListener(this) + val latitudeField = binding.latitudeTextfield + latitudeField.setText(camConfig.mockLocationLatitude.toString()) + latitudeField.filters = arrayOf(NumLimitFilter( + min = LATITUDE_MIN, + max = LATITUDE_MAX, + onOutOfRange = { + showMessage(getString(R.string.latitude_number_limit, LATITUDE_MIN, LATITUDE_MAX)) + } + )) + latitudeField.onFocusChangeListener = object: View.OnFocusChangeListener { + override fun onFocusChange(v: View, hasFocus: Boolean) { + if (!hasFocus) { + if (latitudeField.text?.isEmpty() != false) { + latitudeField.setText(camConfig.mockLocationLatitude.toString()) + showMessage(getString(R.string.latitude_number_limit, LATITUDE_MIN, LATITUDE_MAX)) + } else { + try { + camConfig.mockLocationLatitude = latitudeField.text.toString().toFloat() + } catch (exception: Exception) { + camConfig.mockLocationLatitude = 0f + showMessage(getString(R.string.latitude_number_limit, LATITUDE_MIN, LATITUDE_MAX)) + + } + } + } + } + } + latitudeField.setOnEditorActionListener(this) + + val longitudeField = binding.longitudeTextfield + longitudeField.setText(camConfig.mockLocationLongitude.toString()) + longitudeField.filters = arrayOf(NumLimitFilter( + min = LONGITUDE_MIN.toFloat(), + max = LONGITUDE_MAX.toFloat(), + onOutOfRange = { + showMessage(getString(R.string.longitude_number_limit, LONGITUDE_MIN, LONGITUDE_MAX)) + } + )) + longitudeField.onFocusChangeListener = object: View.OnFocusChangeListener { + override fun onFocusChange(v: View, hasFocus: Boolean) { + if (!hasFocus) { + if (longitudeField.text?.isEmpty() != false) { + longitudeField.setText(camConfig.mockLocationLongitude.toString()) + showMessage(getString(R.string.longitude_number_limit, LONGITUDE_MIN, LONGITUDE_MAX)) + } else { + try { + camConfig.mockLocationLongitude = longitudeField.text.toString().toFloat() + } catch (exception: Exception) { + camConfig.mockLocationLongitude = 0f + showMessage(getString(R.string.longitude_number_limit, LONGITUDE_MIN, LONGITUDE_MAX)) + } + } + } + } + } + longitudeField.setOnEditorActionListener(this) + + binding.mockLocationSettingSwitch.isChecked = camConfig.mockLocationEnabled + binding.mockLocationSettingSwitch.setOnClickListener { + camConfig.mockLocationEnabled = !camConfig.mockLocationEnabled + } + iFField = binding.imageFormatSettingField iFField.setOnEditorActionListener(this) @@ -267,7 +355,7 @@ open class MoreSettings : AppCompatActivity(), TextView.OnEditorActionListener { v.getGlobalVisibleRect(outRect) if (!outRect.contains(event.rawX.toInt(), event.rawY.toInt())) { clearFocus() - dumpData() +// dumpData() } } } @@ -287,24 +375,10 @@ open class MoreSettings : AppCompatActivity(), TextView.OnEditorActionListener { private fun dumpData() { // Dump state of photo quality - if (pQField.text.isEmpty()) { - camConfig.photoQuality = 0 - showMessage( - getString(R.string.photo_quality_was_set_to_auto) - ) - } else { - try { - - camConfig.photoQuality = - Integer.parseInt(pQField.text.toString()) - } catch (exception: Exception) { + // Dump state of image format - camConfig.photoQuality = 0 - - } - } // // Dump state of image format // camConfig.imageFormat = iFField.text.toString() @@ -332,6 +406,15 @@ open class MoreSettings : AppCompatActivity(), TextView.OnEditorActionListener { } companion object { + const val PHOTO_QUALITY_MIN = 1 + const val PHOTO_QUALITY_MAX = 100 + + const val LATITUDE_MIN = -90f + const val LATITUDE_MAX = 90f + + const val LONGITUDE_MIN = -180f + const val LONGITUDE_MAX = 180f + private var camConfigId = 0L private var staticCamConfig: CamConfig? = null diff --git a/app/src/main/res/drawable/location.xml b/app/src/main/res/drawable/location.xml index e3446a9a0..9ddb83997 100644 --- a/app/src/main/res/drawable/location.xml +++ b/app/src/main/res/drawable/location.xml @@ -1,35 +1,12 @@ - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + diff --git a/app/src/main/res/drawable/location_toggle.xml b/app/src/main/res/drawable/location_toggle.xml new file mode 100644 index 000000000..e3446a9a0 --- /dev/null +++ b/app/src/main/res/drawable/location_toggle.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/more_settings.xml b/app/src/main/res/layout/more_settings.xml index c3b8117f2..847540b90 100644 --- a/app/src/main/res/layout/more_settings.xml +++ b/app/src/main/res/layout/more_settings.xml @@ -165,6 +165,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9aa6ae1eb..a1fc69863 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -193,4 +193,14 @@ The video\'s audio recording has been muted The video\'s audio recording has been unmuted + + Use Mock Location + When enabled uses below location over the location provided by device for geo-tagging + + ° + Latitude + Longitude + + Latitude can only be between %1$.1f and %2$.1f + Longitude can only be between %1$.1f and %2$.1f