do some optimisations for pre SDK 29 devices
This commit is contained in:
parent
6bc74d8066
commit
9c021c655b
|
@ -7,6 +7,7 @@ import android.hardware.SensorManager
|
|||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.provider.MediaStore
|
||||
import android.util.Log
|
||||
import android.view.*
|
||||
|
@ -31,9 +32,11 @@ import java.util.concurrent.TimeUnit
|
|||
import kotlinx.android.synthetic.main.activity_main.*
|
||||
|
||||
class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, CameraXPreviewListener {
|
||||
private val TAG = "MainActivity"
|
||||
private val FADE_DELAY = 5000L
|
||||
private val CAPTURE_ANIMATION_DURATION = 100L
|
||||
companion object {
|
||||
private const val TAG = "MainActivity"
|
||||
private const val FADE_DELAY = 5000L
|
||||
private const val CAPTURE_ANIMATION_DURATION = 100L
|
||||
}
|
||||
|
||||
lateinit var mTimerHandler: Handler
|
||||
private lateinit var mOrientationEventListener: OrientationEventListener
|
||||
|
@ -49,14 +52,8 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
|
|||
private var mCurrVideoRecTimer = 0
|
||||
var mLastHandledOrientation = 0
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
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
|
||||
super.onCreate(savedInstanceState)
|
||||
appLaunched(BuildConfig.APPLICATION_ID)
|
||||
|
@ -67,6 +64,22 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
|
|||
supportActionBar?.hide()
|
||||
checkWhatsNewDialog()
|
||||
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() {
|
||||
|
@ -238,8 +251,8 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
|
|||
mFocusCircleView = FocusCircleView(applicationContext)
|
||||
view_holder.addView(mFocusCircleView)
|
||||
|
||||
mTimerHandler = Handler()
|
||||
mFadeHandler = Handler()
|
||||
mTimerHandler = Handler(Looper.getMainLooper())
|
||||
mFadeHandler = Handler(Looper.getMainLooper())
|
||||
setupPreviewImage(true)
|
||||
|
||||
val initialFlashlightState = FLASH_OFF
|
||||
|
@ -439,8 +452,13 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
|
|||
view.isClickable = value != .0f
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
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() {
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
package com.simplemobiletools.camera.activities
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import com.simplemobiletools.camera.BuildConfig
|
||||
import com.simplemobiletools.camera.R
|
||||
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.RadioItem
|
||||
import java.util.Locale
|
||||
import kotlin.system.exitProcess
|
||||
import kotlinx.android.synthetic.main.activity_settings.*
|
||||
|
||||
class SettingsActivity : SimpleActivity() {
|
||||
|
@ -77,7 +80,7 @@ class SettingsActivity : SimpleActivity() {
|
|||
|
||||
// make sure the corners at ripple fit the stroke rounded corners
|
||||
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 {
|
||||
|
@ -97,13 +100,13 @@ class SettingsActivity : SimpleActivity() {
|
|||
settings_use_english.isChecked = config.useEnglish
|
||||
|
||||
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.toggle()
|
||||
config.useEnglish = settings_use_english.isChecked
|
||||
System.exit(0)
|
||||
exitProcess(0)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -172,8 +175,8 @@ class SettingsActivity : SimpleActivity() {
|
|||
settings_save_photos_holder.setOnClickListener {
|
||||
FilePickerDialog(this, config.savePhotosFolder, false, showFAB = true) {
|
||||
val path = it
|
||||
handleSAFDialog(it) {
|
||||
if (it) {
|
||||
handleSAFDialog(it) { success ->
|
||||
if (success) {
|
||||
config.savePhotosFolder = path
|
||||
settings_save_photos.text = getLastPart(config.savePhotosFolder)
|
||||
}
|
||||
|
@ -206,6 +209,7 @@ class SettingsActivity : SimpleActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
private fun updatePhotoQuality(quality: Int) {
|
||||
settings_photo_quality.text = "$quality%"
|
||||
}
|
||||
|
|
|
@ -90,7 +90,7 @@ class ChangeResolutionDialogX(
|
|||
if (isFrontCamera) {
|
||||
config.frontVideoResIndex = selectionIndex
|
||||
} else {
|
||||
config.backPhotoResIndex = selectionIndex
|
||||
config.backVideoResIndex = selectionIndex
|
||||
}
|
||||
dialog?.dismiss()
|
||||
callback.invoke()
|
||||
|
|
|
@ -12,6 +12,8 @@ import com.simplemobiletools.camera.extensions.getRandomMediaName
|
|||
import com.simplemobiletools.camera.models.MediaOutput
|
||||
import com.simplemobiletools.commons.activities.BaseSimpleActivity
|
||||
import com.simplemobiletools.commons.extensions.*
|
||||
import com.simplemobiletools.commons.helpers.isOreoPlus
|
||||
import com.simplemobiletools.commons.helpers.isQPlus
|
||||
import java.io.File
|
||||
import java.io.OutputStream
|
||||
|
||||
|
@ -25,6 +27,7 @@ class MediaOutputHelper(
|
|||
companion object {
|
||||
private const val TAG = "MediaOutputHelper"
|
||||
private const val MODE = "rw"
|
||||
private const val EXTERNAL_VOLUME = "external"
|
||||
private const val IMAGE_MIME_TYPE = "image/jpeg"
|
||||
private const val VIDEO_MIME_TYPE = "video/mp4"
|
||||
}
|
||||
|
@ -53,37 +56,56 @@ class MediaOutputHelper(
|
|||
fun getVideoMediaOutput(): MediaOutput {
|
||||
return if (is3rdPartyIntent) {
|
||||
if (outputUri != null) {
|
||||
val fileDescriptor = openFileDescriptor(outputUri)
|
||||
if (fileDescriptor != null) {
|
||||
MediaOutput.FileDescriptorMediaOutput(fileDescriptor, outputUri)
|
||||
if (isOreoPlus()) {
|
||||
val fileDescriptor = openFileDescriptor(outputUri)
|
||||
if (fileDescriptor != null) {
|
||||
MediaOutput.FileDescriptorMediaOutput(fileDescriptor, outputUri)
|
||||
} else {
|
||||
errorHandler.showSaveToInternalStorage()
|
||||
getMediaStoreOutput(isPhoto = false)
|
||||
}
|
||||
} else {
|
||||
errorHandler.showSaveToInternalStorage()
|
||||
getMediaStoreOutput(isPhoto = false)
|
||||
val path = activity.getRealPathFromURI(outputUri)
|
||||
if (path != null) {
|
||||
MediaOutput.FileMediaOutput(File(path), outputUri)
|
||||
} else {
|
||||
errorHandler.showSaveToInternalStorage()
|
||||
getMediaStoreOutput(isPhoto = false)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
getMediaStoreOutput(isPhoto = false)
|
||||
}
|
||||
} else {
|
||||
getFileDescriptorMediaOutput() ?: getMediaStoreOutput(isPhoto = false)
|
||||
if (isOreoPlus()) {
|
||||
getFileDescriptorMediaOutput() ?: getMediaStoreOutput(isPhoto = false)
|
||||
} else {
|
||||
getFileMediaOutput() ?: getMediaStoreOutput(isPhoto = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getMediaStoreOutput(isPhoto: Boolean): MediaOutput.MediaStoreOutput {
|
||||
val contentValues = getContentValues(isPhoto)
|
||||
val contentUri = if (isPhoto) {
|
||||
MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
|
||||
MediaStore.Images.Media.getContentUri(EXTERNAL_VOLUME)
|
||||
} else {
|
||||
MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
|
||||
MediaStore.Video.Media.getContentUri(EXTERNAL_VOLUME)
|
||||
}
|
||||
return MediaOutput.MediaStoreOutput(contentValues, contentUri)
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
private fun getContentValues(isPhoto: Boolean): ContentValues {
|
||||
val mimeType = if (isPhoto) IMAGE_MIME_TYPE else VIDEO_MIME_TYPE
|
||||
return ContentValues().apply {
|
||||
put(MediaStore.MediaColumns.DISPLAY_NAME, getRandomMediaName(isPhoto))
|
||||
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
|
||||
}
|
||||
|
||||
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? {
|
||||
return try {
|
||||
Log.i(TAG, "uri: $uri")
|
||||
|
|
|
@ -51,7 +51,7 @@ class VideoQualityManager(
|
|||
fun getUserSelectedQuality(cameraSelector: CameraSelector): Quality {
|
||||
var selectionIndex = if (cameraSelector == CameraSelector.DEFAULT_FRONT_CAMERA) config.frontVideoResIndex else config.backVideoResIndex
|
||||
selectionIndex = selectionIndex.coerceAtLeast(0)
|
||||
return getSupportedQualities(cameraSelector)[selectionIndex].toCameraXQuality()
|
||||
return getSupportedQualities(cameraSelector).getOrElse(selectionIndex) { VideoQuality.HD }.toCameraXQuality()
|
||||
}
|
||||
|
||||
fun getSupportedQualities(cameraSelector: CameraSelector): List<VideoQuality> {
|
||||
|
|
|
@ -431,7 +431,7 @@ class CameraXPreview(
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
@SuppressLint("MissingPermission", "NewApi")
|
||||
private fun startRecording() {
|
||||
val videoCapture = videoCapture ?: throw IllegalStateException("Camera initialization failed.")
|
||||
|
||||
|
@ -441,6 +441,10 @@ class CameraXPreview(
|
|||
FileDescriptorOutputOptions.Builder(mediaOutput.fileDescriptor).build()
|
||||
.let { videoCapture.output.prepareRecording(activity, it) }
|
||||
}
|
||||
is MediaOutput.FileMediaOutput -> {
|
||||
FileOutputOptions.Builder(mediaOutput.file).build()
|
||||
.let { videoCapture.output.prepareRecording(activity, it) }
|
||||
}
|
||||
is MediaOutput.MediaStoreOutput -> {
|
||||
MediaStoreOutputOptions.Builder(contentResolver, mediaOutput.contentUri).setContentValues(mediaOutput.contentValues).build()
|
||||
.let { videoCapture.output.prepareRecording(activity, it) }
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.simplemobiletools.camera.models
|
|||
import android.content.ContentValues
|
||||
import android.net.Uri
|
||||
import android.os.ParcelFileDescriptor
|
||||
import java.io.File
|
||||
import java.io.OutputStream
|
||||
|
||||
sealed class MediaOutput(
|
||||
|
@ -23,5 +24,10 @@ sealed class MediaOutput(
|
|||
override val uri: Uri,
|
||||
) : MediaOutput(uri)
|
||||
|
||||
data class FileMediaOutput(
|
||||
val file: File,
|
||||
override val uri: Uri,
|
||||
) : MediaOutput(uri)
|
||||
|
||||
object BitmapOutput : MediaOutput(null)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue