do some optimisations for pre SDK 29 devices

This commit is contained in:
darthpaul
2022-07-13 16:39:18 +01:00
parent 6bc74d8066
commit 9c021c655b
7 changed files with 99 additions and 30 deletions

View File

@ -7,6 +7,7 @@ import android.hardware.SensorManager
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.os.Looper
import android.provider.MediaStore import android.provider.MediaStore
import android.util.Log import android.util.Log
import android.view.* import android.view.*
@ -31,9 +32,11 @@ import java.util.concurrent.TimeUnit
import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, CameraXPreviewListener { class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, CameraXPreviewListener {
private val TAG = "MainActivity" companion object {
private val FADE_DELAY = 5000L private const val TAG = "MainActivity"
private val CAPTURE_ANIMATION_DURATION = 100L private const val FADE_DELAY = 5000L
private const val CAPTURE_ANIMATION_DURATION = 100L
}
lateinit var mTimerHandler: Handler lateinit var mTimerHandler: Handler
private lateinit var mOrientationEventListener: OrientationEventListener private lateinit var mOrientationEventListener: OrientationEventListener
@ -49,14 +52,8 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
private var mCurrVideoRecTimer = 0 private var mCurrVideoRecTimer = 0
var mLastHandledOrientation = 0 var mLastHandledOrientation = 0
@Suppress("DEPRECATION")
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
window.addFlags(
WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON or
WindowManager.LayoutParams.FLAG_FULLSCREEN
)
useDynamicTheme = false useDynamicTheme = false
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
appLaunched(BuildConfig.APPLICATION_ID) appLaunched(BuildConfig.APPLICATION_ID)
@ -67,6 +64,22 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
supportActionBar?.hide() supportActionBar?.hide()
checkWhatsNewDialog() checkWhatsNewDialog()
setupOrientationEventListener() setupOrientationEventListener()
if (isRPlus()) {
setShowWhenLocked(true)
setTurnScreenOn(true)
window.insetsController?.hide(WindowInsets.Type.statusBars())
} else if (isOreoMr1Plus()) {
setShowWhenLocked(true)
setTurnScreenOn(true)
window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
} else {
window.addFlags(
WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON or
WindowManager.LayoutParams.FLAG_FULLSCREEN
)
}
} }
override fun onResume() { override fun onResume() {
@ -238,8 +251,8 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
mFocusCircleView = FocusCircleView(applicationContext) mFocusCircleView = FocusCircleView(applicationContext)
view_holder.addView(mFocusCircleView) view_holder.addView(mFocusCircleView)
mTimerHandler = Handler() mTimerHandler = Handler(Looper.getMainLooper())
mFadeHandler = Handler() mFadeHandler = Handler(Looper.getMainLooper())
setupPreviewImage(true) setupPreviewImage(true)
val initialFlashlightState = FLASH_OFF val initialFlashlightState = FLASH_OFF
@ -439,8 +452,13 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
view.isClickable = value != .0f view.isClickable = value != .0f
} }
@Suppress("DEPRECATION")
private fun hideNavigationBarIcons() { private fun hideNavigationBarIcons() {
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LOW_PROFILE if (isRPlus()) {
window.insetsController?.hide(WindowInsets.Type.systemBars())
} else {
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LOW_PROFILE
}
} }
private fun showTimer() { private fun showTimer() {

View File

@ -1,8 +1,10 @@
package com.simplemobiletools.camera.activities package com.simplemobiletools.camera.activities
import android.annotation.SuppressLint
import android.os.Bundle import android.os.Bundle
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import androidx.core.content.res.ResourcesCompat
import com.simplemobiletools.camera.BuildConfig import com.simplemobiletools.camera.BuildConfig
import com.simplemobiletools.camera.R import com.simplemobiletools.camera.R
import com.simplemobiletools.camera.extensions.config import com.simplemobiletools.camera.extensions.config
@ -14,6 +16,7 @@ import com.simplemobiletools.commons.helpers.NavigationIcon
import com.simplemobiletools.commons.models.FAQItem import com.simplemobiletools.commons.models.FAQItem
import com.simplemobiletools.commons.models.RadioItem import com.simplemobiletools.commons.models.RadioItem
import java.util.Locale import java.util.Locale
import kotlin.system.exitProcess
import kotlinx.android.synthetic.main.activity_settings.* import kotlinx.android.synthetic.main.activity_settings.*
class SettingsActivity : SimpleActivity() { class SettingsActivity : SimpleActivity() {
@ -77,7 +80,7 @@ class SettingsActivity : SimpleActivity() {
// make sure the corners at ripple fit the stroke rounded corners // make sure the corners at ripple fit the stroke rounded corners
if (settings_purchase_thank_you_holder.isGone()) { if (settings_purchase_thank_you_holder.isGone()) {
settings_use_english_holder.background = resources.getDrawable(R.drawable.ripple_top_corners, theme) settings_use_english_holder.background = ResourcesCompat.getDrawable(resources, R.drawable.ripple_top_corners, theme)
} }
settings_purchase_thank_you_holder.setOnClickListener { settings_purchase_thank_you_holder.setOnClickListener {
@ -97,13 +100,13 @@ class SettingsActivity : SimpleActivity() {
settings_use_english.isChecked = config.useEnglish settings_use_english.isChecked = config.useEnglish
if (settings_use_english_holder.isGone() && settings_purchase_thank_you_holder.isGone()) { if (settings_use_english_holder.isGone() && settings_purchase_thank_you_holder.isGone()) {
settings_keep_settings_visible_holder.background = resources.getDrawable(R.drawable.ripple_all_corners, theme) settings_keep_settings_visible_holder.background = ResourcesCompat.getDrawable(resources, R.drawable.ripple_all_corners, theme)
} }
settings_use_english_holder.setOnClickListener { settings_use_english_holder.setOnClickListener {
settings_use_english.toggle() settings_use_english.toggle()
config.useEnglish = settings_use_english.isChecked config.useEnglish = settings_use_english.isChecked
System.exit(0) exitProcess(0)
} }
} }
@ -172,8 +175,8 @@ class SettingsActivity : SimpleActivity() {
settings_save_photos_holder.setOnClickListener { settings_save_photos_holder.setOnClickListener {
FilePickerDialog(this, config.savePhotosFolder, false, showFAB = true) { FilePickerDialog(this, config.savePhotosFolder, false, showFAB = true) {
val path = it val path = it
handleSAFDialog(it) { handleSAFDialog(it) { success ->
if (it) { if (success) {
config.savePhotosFolder = path config.savePhotosFolder = path
settings_save_photos.text = getLastPart(config.savePhotosFolder) settings_save_photos.text = getLastPart(config.savePhotosFolder)
} }
@ -206,6 +209,7 @@ class SettingsActivity : SimpleActivity() {
} }
} }
@SuppressLint("SetTextI18n")
private fun updatePhotoQuality(quality: Int) { private fun updatePhotoQuality(quality: Int) {
settings_photo_quality.text = "$quality%" settings_photo_quality.text = "$quality%"
} }

View File

@ -90,7 +90,7 @@ class ChangeResolutionDialogX(
if (isFrontCamera) { if (isFrontCamera) {
config.frontVideoResIndex = selectionIndex config.frontVideoResIndex = selectionIndex
} else { } else {
config.backPhotoResIndex = selectionIndex config.backVideoResIndex = selectionIndex
} }
dialog?.dismiss() dialog?.dismiss()
callback.invoke() callback.invoke()

View File

@ -12,6 +12,8 @@ import com.simplemobiletools.camera.extensions.getRandomMediaName
import com.simplemobiletools.camera.models.MediaOutput import com.simplemobiletools.camera.models.MediaOutput
import com.simplemobiletools.commons.activities.BaseSimpleActivity import com.simplemobiletools.commons.activities.BaseSimpleActivity
import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.isOreoPlus
import com.simplemobiletools.commons.helpers.isQPlus
import java.io.File import java.io.File
import java.io.OutputStream import java.io.OutputStream
@ -25,6 +27,7 @@ class MediaOutputHelper(
companion object { companion object {
private const val TAG = "MediaOutputHelper" private const val TAG = "MediaOutputHelper"
private const val MODE = "rw" private const val MODE = "rw"
private const val EXTERNAL_VOLUME = "external"
private const val IMAGE_MIME_TYPE = "image/jpeg" private const val IMAGE_MIME_TYPE = "image/jpeg"
private const val VIDEO_MIME_TYPE = "video/mp4" private const val VIDEO_MIME_TYPE = "video/mp4"
} }
@ -53,37 +56,56 @@ class MediaOutputHelper(
fun getVideoMediaOutput(): MediaOutput { fun getVideoMediaOutput(): MediaOutput {
return if (is3rdPartyIntent) { return if (is3rdPartyIntent) {
if (outputUri != null) { if (outputUri != null) {
val fileDescriptor = openFileDescriptor(outputUri) if (isOreoPlus()) {
if (fileDescriptor != null) { val fileDescriptor = openFileDescriptor(outputUri)
MediaOutput.FileDescriptorMediaOutput(fileDescriptor, outputUri) if (fileDescriptor != null) {
MediaOutput.FileDescriptorMediaOutput(fileDescriptor, outputUri)
} else {
errorHandler.showSaveToInternalStorage()
getMediaStoreOutput(isPhoto = false)
}
} else { } else {
errorHandler.showSaveToInternalStorage() val path = activity.getRealPathFromURI(outputUri)
getMediaStoreOutput(isPhoto = false) if (path != null) {
MediaOutput.FileMediaOutput(File(path), outputUri)
} else {
errorHandler.showSaveToInternalStorage()
getMediaStoreOutput(isPhoto = false)
}
} }
} else { } else {
getMediaStoreOutput(isPhoto = false) getMediaStoreOutput(isPhoto = false)
} }
} else { } else {
getFileDescriptorMediaOutput() ?: getMediaStoreOutput(isPhoto = false) if (isOreoPlus()) {
getFileDescriptorMediaOutput() ?: getMediaStoreOutput(isPhoto = false)
} else {
getFileMediaOutput() ?: getMediaStoreOutput(isPhoto = false)
}
} }
} }
private fun getMediaStoreOutput(isPhoto: Boolean): MediaOutput.MediaStoreOutput { private fun getMediaStoreOutput(isPhoto: Boolean): MediaOutput.MediaStoreOutput {
val contentValues = getContentValues(isPhoto) val contentValues = getContentValues(isPhoto)
val contentUri = if (isPhoto) { val contentUri = if (isPhoto) {
MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY) MediaStore.Images.Media.getContentUri(EXTERNAL_VOLUME)
} else { } else {
MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY) MediaStore.Video.Media.getContentUri(EXTERNAL_VOLUME)
} }
return MediaOutput.MediaStoreOutput(contentValues, contentUri) return MediaOutput.MediaStoreOutput(contentValues, contentUri)
} }
@Suppress("DEPRECATION")
private fun getContentValues(isPhoto: Boolean): ContentValues { private fun getContentValues(isPhoto: Boolean): ContentValues {
val mimeType = if (isPhoto) IMAGE_MIME_TYPE else VIDEO_MIME_TYPE val mimeType = if (isPhoto) IMAGE_MIME_TYPE else VIDEO_MIME_TYPE
return ContentValues().apply { return ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, getRandomMediaName(isPhoto)) put(MediaStore.MediaColumns.DISPLAY_NAME, getRandomMediaName(isPhoto))
put(MediaStore.MediaColumns.MIME_TYPE, mimeType) put(MediaStore.MediaColumns.MIME_TYPE, mimeType)
put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM) if (isQPlus()) {
put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM)
} else {
put(MediaStore.MediaColumns.DATA, Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).toString())
}
} }
} }
@ -131,6 +153,21 @@ class MediaOutputHelper(
return mediaOutput return mediaOutput
} }
private fun getFileMediaOutput(): MediaOutput.FileMediaOutput? {
var mediaOutput: MediaOutput.FileMediaOutput? = null
val canWrite = canWriteToFilePath(mediaStorageDir)
Log.i(TAG, "getMediaOutput: canWrite=${canWrite}")
if (canWrite) {
val path = activity.getOutputMediaFile(false)
val uri = getUriForFilePath(path)
if (uri != null) {
mediaOutput = MediaOutput.FileMediaOutput(File(path), uri)
}
}
Log.i(TAG, "FileDescriptorMediaOutput: $mediaOutput")
return mediaOutput
}
private fun openFileDescriptor(uri: Uri): ParcelFileDescriptor? { private fun openFileDescriptor(uri: Uri): ParcelFileDescriptor? {
return try { return try {
Log.i(TAG, "uri: $uri") Log.i(TAG, "uri: $uri")

View File

@ -51,7 +51,7 @@ class VideoQualityManager(
fun getUserSelectedQuality(cameraSelector: CameraSelector): Quality { fun getUserSelectedQuality(cameraSelector: CameraSelector): Quality {
var selectionIndex = if (cameraSelector == CameraSelector.DEFAULT_FRONT_CAMERA) config.frontVideoResIndex else config.backVideoResIndex var selectionIndex = if (cameraSelector == CameraSelector.DEFAULT_FRONT_CAMERA) config.frontVideoResIndex else config.backVideoResIndex
selectionIndex = selectionIndex.coerceAtLeast(0) selectionIndex = selectionIndex.coerceAtLeast(0)
return getSupportedQualities(cameraSelector)[selectionIndex].toCameraXQuality() return getSupportedQualities(cameraSelector).getOrElse(selectionIndex) { VideoQuality.HD }.toCameraXQuality()
} }
fun getSupportedQualities(cameraSelector: CameraSelector): List<VideoQuality> { fun getSupportedQualities(cameraSelector: CameraSelector): List<VideoQuality> {

View File

@ -431,7 +431,7 @@ class CameraXPreview(
} }
} }
@SuppressLint("MissingPermission") @SuppressLint("MissingPermission", "NewApi")
private fun startRecording() { private fun startRecording() {
val videoCapture = videoCapture ?: throw IllegalStateException("Camera initialization failed.") val videoCapture = videoCapture ?: throw IllegalStateException("Camera initialization failed.")
@ -441,6 +441,10 @@ class CameraXPreview(
FileDescriptorOutputOptions.Builder(mediaOutput.fileDescriptor).build() FileDescriptorOutputOptions.Builder(mediaOutput.fileDescriptor).build()
.let { videoCapture.output.prepareRecording(activity, it) } .let { videoCapture.output.prepareRecording(activity, it) }
} }
is MediaOutput.FileMediaOutput -> {
FileOutputOptions.Builder(mediaOutput.file).build()
.let { videoCapture.output.prepareRecording(activity, it) }
}
is MediaOutput.MediaStoreOutput -> { is MediaOutput.MediaStoreOutput -> {
MediaStoreOutputOptions.Builder(contentResolver, mediaOutput.contentUri).setContentValues(mediaOutput.contentValues).build() MediaStoreOutputOptions.Builder(contentResolver, mediaOutput.contentUri).setContentValues(mediaOutput.contentValues).build()
.let { videoCapture.output.prepareRecording(activity, it) } .let { videoCapture.output.prepareRecording(activity, it) }

View File

@ -3,6 +3,7 @@ package com.simplemobiletools.camera.models
import android.content.ContentValues import android.content.ContentValues
import android.net.Uri import android.net.Uri
import android.os.ParcelFileDescriptor import android.os.ParcelFileDescriptor
import java.io.File
import java.io.OutputStream import java.io.OutputStream
sealed class MediaOutput( sealed class MediaOutput(
@ -23,5 +24,10 @@ sealed class MediaOutput(
override val uri: Uri, override val uri: Uri,
) : MediaOutput(uri) ) : MediaOutput(uri)
data class FileMediaOutput(
val file: File,
override val uri: Uri,
) : MediaOutput(uri)
object BitmapOutput : MediaOutput(null) object BitmapOutput : MediaOutput(null)
} }