mirror of
https://github.com/SimpleMobileTools/Simple-Camera.git
synced 2025-06-27 09:02:59 +02:00
do some optimisations for pre SDK 29 devices
This commit is contained in:
@ -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() {
|
||||||
|
@ -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%"
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
|
@ -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")
|
||||||
|
@ -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> {
|
||||||
|
@ -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) }
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user