updated Commons, min Android OS to 5, removed Camera One implementation

This commit is contained in:
tibbi 2018-10-17 23:32:12 +02:00
parent d7a9002076
commit 39aba65589
23 changed files with 91 additions and 1206 deletions

View File

@ -3,13 +3,13 @@ apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 27
buildToolsVersion "27.0.3"
compileSdkVersion 28
buildToolsVersion "28.0.3"
defaultConfig {
applicationId "com.simplemobiletools.camera"
minSdkVersion 16
targetSdkVersion 27
minSdkVersion 21
targetSdkVersion 28
versionCode 63
versionName "4.2.0"
setProperty("archivesBaseName", "camera")
@ -41,7 +41,7 @@ android {
}
dependencies {
implementation 'com.simplemobiletools:commons:4.6.4'
implementation 'com.simplemobiletools:commons:5.1.4'
}
Properties props = new Properties()

View File

@ -102,7 +102,7 @@
</receiver>
<provider
android:name="android.support.v4.content.FileProvider"
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">

View File

@ -16,14 +16,12 @@ import com.bumptech.glide.request.RequestOptions
import com.simplemobiletools.camera.BuildConfig
import com.simplemobiletools.camera.R
import com.simplemobiletools.camera.extensions.config
import com.simplemobiletools.camera.extensions.getMyCamera
import com.simplemobiletools.camera.extensions.navBarHeight
import com.simplemobiletools.camera.helpers.*
import com.simplemobiletools.camera.interfaces.MyCamera
import com.simplemobiletools.camera.implementations.MyCameraImpl
import com.simplemobiletools.camera.interfaces.MyPreview
import com.simplemobiletools.camera.views.CameraPreview
import com.simplemobiletools.camera.views.FocusCircleView
import com.simplemobiletools.camera.views.PreviewCameraOne
import com.simplemobiletools.camera.views.PreviewCameraTwo
import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.*
import com.simplemobiletools.commons.models.Release
@ -36,7 +34,7 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener {
private lateinit var mOrientationEventListener: OrientationEventListener
private lateinit var mFocusCircleView: FocusCircleView
private lateinit var mFadeHandler: Handler
private lateinit var mCameraImpl: MyCamera
private lateinit var mCameraImpl: MyCameraImpl
private var mPreview: MyPreview? = null
private var mPreviewUri: Uri? = null
@ -116,7 +114,7 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener {
mIsHardwareShutterHandled = false
mCurrVideoRecTimer = 0
mLastHandledOrientation = 0
mCameraImpl = getMyCamera()
mCameraImpl = MyCameraImpl(applicationContext)
if (config.alwaysOpenBackCamera) {
config.lastUsedCamera = mCameraImpl.getBackCameraId().toString()
@ -193,13 +191,10 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener {
setContentView(R.layout.activity_main)
initButtons()
camera_surface_view.beVisibleIf(!isLollipopPlus())
camera_texture_view.beVisibleIf(isLollipopPlus())
(btn_holder.layoutParams as RelativeLayout.LayoutParams).setMargins(0, 0, 0, (navBarHeight + resources.getDimension(R.dimen.activity_margin)).toInt())
checkVideoCaptureIntent()
mPreview = if (isLollipopPlus()) PreviewCameraTwo(this, camera_texture_view, mIsInPhotoMode) else PreviewCameraOne(this, camera_surface_view)
mPreview = CameraPreview(this, camera_texture_view, mIsInPhotoMode)
view_holder.addView(mPreview as ViewGroup)
checkImageCaptureIntent()
mPreview?.setIsImageCaptureIntent(isImageCaptureIntent())
@ -373,7 +368,7 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener {
mPreviewUri = Uri.withAppendedPath(uri, lastMediaId.toString())
runOnUiThread {
if (!isActivityDestroyed()) {
if (!isDestroyed) {
val options = RequestOptions()
.centerCrop()
.diskCacheStrategy(DiskCacheStrategy.NONE)
@ -419,14 +414,6 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener {
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LOW_PROFILE
}
fun toggleTimer(show: Boolean) {
if (show) {
showTimer()
} else {
hideTimer()
}
}
private fun showTimer() {
video_rec_curr_timer.beVisible()
setupTimer()
@ -450,14 +437,10 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener {
private fun resumeCameraItems() {
showToggleCameraIfNeeded()
if (mPreview?.resumeCamera() == true) {
hideNavigationBarIcons()
hideNavigationBarIcons()
if (!mIsInPhotoMode) {
initVideoButtons()
}
} else {
toast(R.string.camera_switch_error)
if (!mIsInPhotoMode) {
initVideoButtons()
}
}
@ -470,7 +453,7 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener {
private fun setupOrientationEventListener() {
mOrientationEventListener = object : OrientationEventListener(this, SensorManager.SENSOR_DELAY_NORMAL) {
override fun onOrientationChanged(orientation: Int) {
if (isActivityDestroyed()) {
if (isDestroyed) {
mOrientationEventListener.disable()
return
}
@ -490,7 +473,6 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener {
animateViews(degrees)
mLastHandledOrientation = currOrient
mPreview?.deviceOrientationChanged()
}
}
}
@ -555,7 +537,6 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener {
fun drawFocusCircle(x: Float, y: Float) = mFocusCircleView.drawFocusCircle(x, y)
override fun mediaSaved(path: String) {
mPreview?.imageSaved()
rescanPaths(arrayListOf(path)) {
setupPreviewImage(true)
Intent(BROADCAST_REFRESH_MEDIA).apply {

View File

@ -10,7 +10,6 @@ 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.isLollipopPlus
import com.simplemobiletools.commons.models.FAQItem
import com.simplemobiletools.commons.models.RadioItem
import kotlinx.android.synthetic.main.activity_settings.*
@ -29,7 +28,6 @@ class SettingsActivity : SimpleActivity() {
setupCustomizeColors()
setupUseEnglish()
setupAvoidWhatsNew()
setupShowPreview()
setupSound()
setupFocusBeforeCapture()
setupVolumeButtonsAsShutter()
@ -111,15 +109,6 @@ class SettingsActivity : SimpleActivity() {
return humanized.substringAfterLast("/", humanized)
}
private fun setupShowPreview() {
settings_show_preview_holder.beVisibleIf(!isLollipopPlus())
settings_show_preview.isChecked = config.isShowPreviewEnabled
settings_show_preview_holder.setOnClickListener {
settings_show_preview.toggle()
config.isShowPreviewEnabled = settings_show_preview.isChecked
}
}
private fun setupSound() {
settings_sound.isChecked = config.isSoundEnabled
settings_sound_holder.setOnClickListener {

View File

@ -1,8 +1,8 @@
package com.simplemobiletools.camera.dialogs
import android.support.v7.app.AlertDialog
import android.view.LayoutInflater
import android.view.View
import androidx.appcompat.app.AlertDialog
import com.simplemobiletools.camera.R
import com.simplemobiletools.camera.activities.SimpleActivity
import com.simplemobiletools.camera.extensions.config

View File

@ -4,9 +4,6 @@ import android.content.Context
import android.graphics.Point
import android.view.WindowManager
import com.simplemobiletools.camera.helpers.Config
import com.simplemobiletools.camera.implementations.MyCameraOneImpl
import com.simplemobiletools.camera.implementations.MyCameraTwoImpl
import com.simplemobiletools.commons.helpers.isLollipopPlus
import java.io.File
import java.text.SimpleDateFormat
import java.util.*
@ -47,5 +44,3 @@ val Context.realScreenSize: Point
}
val Context.navBarHeight: Int get() = realScreenSize.y - usableScreenSize.y
fun Context.getMyCamera() = if (isLollipopPlus()) MyCameraTwoImpl(applicationContext) else MyCameraOneImpl(applicationContext)

View File

@ -1,6 +0,0 @@
package com.simplemobiletools.camera.extensions
import android.content.Context
import android.hardware.Camera
import com.simplemobiletools.camera.R

View File

@ -21,10 +21,6 @@ class Config(context: Context) : BaseConfig(context) {
}
set(path) = prefs.edit().putString(SAVE_PHOTOS, path).apply()
var isShowPreviewEnabled: Boolean
get() = prefs.getBoolean(SHOW_PREVIEW, false)
set(enabled) = prefs.edit().putBoolean(SHOW_PREVIEW, enabled).apply()
var isSoundEnabled: Boolean
get() = prefs.getBoolean(SOUND, true)
set(enabled) = prefs.edit().putBoolean(SOUND, enabled).apply()
@ -73,10 +69,6 @@ class Config(context: Context) : BaseConfig(context) {
get() = prefs.getInt(FRONT_VIDEO_RESOLUTION_INDEX, 0)
set(frontVideoResIndex) = prefs.edit().putInt(FRONT_VIDEO_RESOLUTION_INDEX, frontVideoResIndex).apply()
var wasPhotoPreviewHintShown: Boolean
get() = prefs.getBoolean(PHOTO_PREVIEW_HINT_SHOWN, false)
set(wasPhotoPreviewHintShown) = prefs.edit().putBoolean(PHOTO_PREVIEW_HINT_SHOWN, wasPhotoPreviewHintShown).apply()
var keepSettingsVisible: Boolean
get() = prefs.getBoolean(KEEP_SETTINGS_VISIBLE, false)
set(keepSettingsVisible) = prefs.edit().putBoolean(KEEP_SETTINGS_VISIBLE, keepSettingsVisible).apply()

View File

@ -6,7 +6,6 @@ const val ORIENT_LANDSCAPE_RIGHT = 2
// shared preferences
const val SAVE_PHOTOS = "save_photos"
const val SHOW_PREVIEW = "show_preview"
const val SOUND = "sound"
const val FOCUS_BEFORE_CAPTURE = "focus_before_capture_2"
const val VOLUME_BUTTONS_AS_SHUTTER = "volume_buttons_as_shutter"
@ -19,7 +18,6 @@ const val BACK_PHOTO_RESOLUTION_INDEX = "back_photo_resolution_index_2"
const val BACK_VIDEO_RESOLUTION_INDEX = "back_video_resolution_index_2"
const val FRONT_PHOTO_RESOLUTION_INDEX = "front_photo_resolution_index_2"
const val FRONT_VIDEO_RESOLUTION_INDEX = "front_video_resolution_index_2"
const val PHOTO_PREVIEW_HINT_SHOWN = "photo_preview_hint_shown"
const val KEEP_SETTINGS_VISIBLE = "keep_settings_visible"
const val ALWAYS_OPEN_BACK_CAMERA = "always_open_back_camera"
const val SAVE_PHOTO_METADATA = "save_photo_metadata"

View File

@ -0,0 +1,16 @@
package com.simplemobiletools.camera.implementations
import android.content.Context
import android.hardware.camera2.CameraCharacteristics
import android.hardware.camera2.CameraManager
class MyCameraImpl(val context: Context) {
fun getFrontCameraId() = CameraCharacteristics.LENS_FACING_FRONT
fun getBackCameraId() = CameraCharacteristics.LENS_FACING_BACK
fun getCountOfCameras(): Int {
val manager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
return manager.cameraIdList.size
}
}

View File

@ -1,13 +0,0 @@
package com.simplemobiletools.camera.implementations
import android.content.Context
import android.hardware.Camera
import com.simplemobiletools.camera.interfaces.MyCamera
class MyCameraOneImpl(val context: Context) : MyCamera() {
override fun getFrontCameraId() = Camera.CameraInfo.CAMERA_FACING_FRONT
override fun getBackCameraId() = Camera.CameraInfo.CAMERA_FACING_BACK
override fun getCountOfCameras() = Camera.getNumberOfCameras()
}

View File

@ -1,20 +0,0 @@
package com.simplemobiletools.camera.implementations
import android.annotation.TargetApi
import android.content.Context
import android.hardware.camera2.CameraCharacteristics
import android.hardware.camera2.CameraManager
import android.os.Build
import com.simplemobiletools.camera.interfaces.MyCamera
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
class MyCameraTwoImpl(val context: Context) : MyCamera() {
override fun getFrontCameraId() = CameraCharacteristics.LENS_FACING_FRONT
override fun getBackCameraId() = CameraCharacteristics.LENS_FACING_BACK
override fun getCountOfCameras(): Int {
val manager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
return manager.cameraIdList.size
}
}

View File

@ -1,9 +0,0 @@
package com.simplemobiletools.camera.interfaces
abstract class MyCamera {
abstract fun getFrontCameraId(): Int
abstract fun getBackCameraId(): Int
abstract fun getCountOfCameras(): Int
}

View File

@ -32,10 +32,4 @@ interface MyPreview {
fun initVideoMode(): Boolean
fun checkFlashlight()
fun deviceOrientationChanged()
fun resumeCamera(): Boolean
fun imageSaved()
}

View File

@ -1,8 +1,6 @@
package com.simplemobiletools.camera.models
import android.annotation.TargetApi
import android.content.Context
import android.os.Build
import android.util.Size
import com.simplemobiletools.camera.R
@ -45,6 +43,5 @@ data class MySize(val width: Int, val height: Int) {
else -> context.resources.getString(R.string.other)
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
fun toSize() = Size(width, height)
}

View File

@ -1,7 +1,6 @@
package com.simplemobiletools.camera.views
import android.annotation.SuppressLint
import android.annotation.TargetApi
import android.content.Context
import android.graphics.ImageFormat
import android.graphics.Matrix
@ -14,7 +13,6 @@ import android.media.ImageReader
import android.media.MediaActionSound
import android.media.MediaRecorder
import android.net.Uri
import android.os.Build
import android.os.Handler
import android.os.HandlerThread
import android.util.DisplayMetrics
@ -30,30 +28,22 @@ import com.simplemobiletools.camera.R
import com.simplemobiletools.camera.activities.MainActivity
import com.simplemobiletools.camera.dialogs.ChangeResolutionDialog
import com.simplemobiletools.camera.extensions.config
import com.simplemobiletools.camera.extensions.getMyCamera
import com.simplemobiletools.camera.extensions.getOutputMediaFile
import com.simplemobiletools.camera.helpers.*
import com.simplemobiletools.camera.implementations.MyCameraImpl
import com.simplemobiletools.camera.interfaces.MyPreview
import com.simplemobiletools.camera.models.FocusArea
import com.simplemobiletools.camera.models.MySize
import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.isJellyBean1Plus
import com.simplemobiletools.commons.models.FileDirItem
import java.io.File
import java.lang.IllegalArgumentException
import java.lang.InterruptedException
import java.lang.Math
import java.lang.System
import java.lang.Thread
import java.util.*
import java.util.concurrent.Semaphore
import java.util.concurrent.TimeUnit
import kotlin.RuntimeException
// based on the Android Camera2 photo sample at https://github.com/googlesamples/android-Camera2Basic
// and video sample at https://github.com/googlesamples/android-Camera2Video
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
class PreviewCameraTwo : ViewGroup, TextureView.SurfaceTextureListener, MyPreview {
class CameraPreview : ViewGroup, TextureView.SurfaceTextureListener, MyPreview {
private val FOCUS_TAG = "focus_tag"
private val MAX_PREVIEW_WIDTH = 1920
private val MAX_PREVIEW_HEIGHT = 1080
@ -129,7 +119,7 @@ class PreviewCameraTwo : ViewGroup, TextureView.SurfaceTextureListener, MyPrevie
null
}
val isFrontCamera = cameraCharacteristics?.get(CameraCharacteristics.LENS_FACING).toString() == activity.getMyCamera().getFrontCameraId().toString()
val isFrontCamera = cameraCharacteristics?.get(CameraCharacteristics.LENS_FACING).toString() == MyCameraImpl(activity).getFrontCameraId().toString()
mUseFrontCamera = !activity.config.alwaysOpenBackCamera && isFrontCamera
mIsInVideoMode = !initPhotoMode
loadSounds()
@ -417,13 +407,8 @@ class PreviewCameraTwo : ViewGroup, TextureView.SurfaceTextureListener, MyPrevie
private fun getRealDisplaySize(): MySize {
val metrics = DisplayMetrics()
return if (isJellyBean1Plus()) {
mActivity.windowManager.defaultDisplay.getRealMetrics(metrics)
MySize(metrics.widthPixels, metrics.heightPixels)
} else {
mActivity.windowManager.defaultDisplay.getMetrics(metrics)
MySize(metrics.widthPixels, metrics.heightPixels)
}
mActivity.windowManager.defaultDisplay.getRealMetrics(metrics)
return MySize(metrics.widthPixels, metrics.heightPixels)
}
private val cameraStateCallback = object : CameraDevice.StateCallback() {
@ -718,53 +703,6 @@ class PreviewCameraTwo : ViewGroup, TextureView.SurfaceTextureListener, MyPrevie
return FocusArea(rect, MeteringRectangle.METERING_WEIGHT_MAX)
}
// touch-to-focus stucks after capturing a photo without "Focus before capture" so just reset the whole session until fixed properly
private fun resetPreviewSession() {
val stateCallback = object : CameraCaptureSession.StateCallback() {
override fun onConfigured(cameraCaptureSession: CameraCaptureSession) {
if (mCameraDevice == null) {
return
}
mCaptureSession = cameraCaptureSession
try {
mPreviewRequestBuilder!!.apply {
set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE)
setFlashAndExposure(this)
mPreviewRequest = build()
}
mCaptureSession!!.setRepeatingRequest(mPreviewRequest, mCaptureCallback, mBackgroundHandler)
mCameraState = STATE_PREVIEW
Handler().postDelayed({
if (mLastFocusX != 0f && mLastFocusY != 0f) {
if (mCaptureSession != null) {
focusArea(mLastFocusX, mLastFocusY, false)
}
}
}, 200L)
} catch (e: Exception) {
}
}
override fun onConfigureFailed(cameraCaptureSession: CameraCaptureSession) {}
}
try {
closeCaptureSession()
val texture = mTextureView.surfaceTexture!!
texture.setDefaultBufferSize(mPreviewSize!!.width, mPreviewSize!!.height)
val currentResolution = getCurrentResolution()
mImageReader = ImageReader.newInstance(currentResolution.width, currentResolution.height, ImageFormat.JPEG, 2)
mImageReader!!.setOnImageAvailableListener(imageAvailableListener, mBackgroundHandler)
val surface = Surface(texture)
mCameraDevice!!.createCaptureSession(Arrays.asList(surface, mImageReader!!.surface), stateCallback, null)
} catch (e: Exception) {
}
}
private fun calculateCameraToPreviewMatrix() {
val yScale = if (mUseFrontCamera) -1 else 1
mCameraToPreviewMatrix.apply {
@ -1034,11 +972,5 @@ class PreviewCameraTwo : ViewGroup, TextureView.SurfaceTextureListener, MyPrevie
}
}
override fun deviceOrientationChanged() {}
override fun resumeCamera() = true
override fun imageSaved() {}
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {}
}

View File

@ -1,922 +0,0 @@
package com.simplemobiletools.camera.views
import android.annotation.SuppressLint
import android.annotation.TargetApi
import android.app.Activity
import android.content.Context
import android.graphics.Point
import android.graphics.Rect
import android.hardware.Camera
import android.media.AudioManager
import android.media.CamcorderProfile
import android.media.MediaPlayer
import android.media.MediaRecorder
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.os.Handler
import android.view.*
import com.simplemobiletools.camera.R
import com.simplemobiletools.camera.activities.MainActivity
import com.simplemobiletools.camera.dialogs.ChangeResolutionDialog
import com.simplemobiletools.camera.extensions.config
import com.simplemobiletools.camera.extensions.getMyCamera
import com.simplemobiletools.camera.extensions.getOutputMediaFile
import com.simplemobiletools.camera.extensions.realScreenSize
import com.simplemobiletools.camera.helpers.*
import com.simplemobiletools.camera.implementations.MyCameraOneImpl
import com.simplemobiletools.camera.interfaces.MyPreview
import com.simplemobiletools.camera.models.MySize
import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.isJellyBean1Plus
import java.io.File
import java.io.IOException
import java.util.*
class PreviewCameraOne : ViewGroup, SurfaceHolder.Callback, MyPreview {
private val FOCUS_AREA_SIZE = 100
private val PHOTO_PREVIEW_LENGTH = 500L
private val REFOCUS_PERIOD = 3000L
private lateinit var mSurfaceHolder: SurfaceHolder
private lateinit var mSurfaceView: SurfaceView
private lateinit var mScreenSize: Point
private lateinit var mConfig: Config
private var mSupportedPreviewSizes: List<Camera.Size>? = null
private var mPreviewSize: Camera.Size? = null
private var mParameters: Camera.Parameters? = null
private var mRecorder: MediaRecorder? = null
private var mScaleGestureDetector: ScaleGestureDetector? = null
private var mZoomRatios = ArrayList<Int>()
private var mFlashlightState = FLASH_OFF
private var mCamera: Camera? = null
private var mCameraImpl: MyCameraOneImpl? = null
private var mAutoFocusHandler = Handler()
private var mActivity: MainActivity? = null
private var mTargetUri: Uri? = null
private var mCameraState = STATE_PREVIEW
private var mCurrVideoPath = ""
private var mCanTakePicture = false
private var mIsRecording = false
private var mIsInVideoMode = false
private var mIsSurfaceCreated = false
private var mSwitchToVideoAsap = false
private var mSetupPreviewAfterMeasure = false
private var mIsSixteenToNine = false
private var mWasZooming = false
private var mIsPreviewShown = false
private var mWasCameraPreviewSet = false
private var mIsImageCaptureIntent = false
private var mIsFocusingBeforeCapture = false
private var mLastClickX = 0f
private var mLastClickY = 0f
private var mCurrCameraId = 0
private var mMaxZoom = 0
private var mRotationAtCapture = 0
constructor(context: Context) : super(context)
@SuppressLint("ClickableViewAccessibility")
constructor(activity: MainActivity, surfaceView: SurfaceView) : super(activity) {
mActivity = activity
mSurfaceView = surfaceView
mSurfaceHolder = mSurfaceView.holder
mSurfaceHolder.addCallback(this)
mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS)
mCameraImpl = MyCameraOneImpl(activity.applicationContext)
mConfig = activity.config
mScreenSize = getScreenSize()
initGestureDetector()
mSurfaceView.setOnTouchListener { view, event ->
mLastClickX = event.x
mLastClickY = event.y
if (mMaxZoom > 0 && mParameters?.isZoomSupported == true) {
mScaleGestureDetector!!.onTouchEvent(event)
}
false
}
mSurfaceView.setOnClickListener {
if (mIsPreviewShown) {
resumePreview()
} else {
if (!mWasZooming && !mIsPreviewShown) {
focusArea(false)
}
mWasZooming = false
mSurfaceView.isSoundEffectsEnabled = true
}
}
}
override fun onResumed() {}
override fun onPaused() {
releaseCamera()
}
override fun tryInitVideoMode() {
if (mIsSurfaceCreated) {
initVideoMode()
} else {
mSwitchToVideoAsap = true
}
}
override fun resumeCamera(): Boolean {
val newCamera: Camera
try {
newCamera = Camera.open(mCurrCameraId)
mActivity!!.setIsCameraAvailable(true)
} catch (e: Exception) {
mActivity!!.showErrorToast(e)
mActivity!!.setIsCameraAvailable(false)
return false
}
if (mCamera === newCamera) {
return false
}
releaseCamera()
mCamera = newCamera
if (initCamera() && mIsInVideoMode) {
initVideoMode()
}
if (!mWasCameraPreviewSet && mIsSurfaceCreated) {
mCamera!!.setPreviewDisplay(mSurfaceHolder)
mWasCameraPreviewSet = true
}
return true
}
override fun imageSaved() {}
private fun initCamera(): Boolean {
if (mCamera == null)
return false
mParameters = mCamera!!.parameters
mMaxZoom = mParameters!!.maxZoom
if (mParameters!!.isZoomSupported)
mZoomRatios = mParameters!!.zoomRatios as ArrayList<Int>
mSupportedPreviewSizes = mParameters!!.supportedPreviewSizes.sortedByDescending { it.width * it.height }
refreshPreview()
// hackfix for slow photo preview, more info at https://github.com/SimpleMobileTools/Simple-Camera/issues/120
if (Build.MODEL == "Nexus 4") {
mParameters!!.setRecordingHint(true)
}
val focusModes = mParameters!!.supportedFocusModes
if (focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
mParameters!!.focusMode = Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE
}
mCamera!!.setDisplayOrientation(getPreviewRotation(mCurrCameraId))
mParameters!!.zoom = 0
updateCameraParameters()
if (mCanTakePicture) {
try {
mCamera!!.setPreviewDisplay(mSurfaceHolder)
} catch (e: IOException) {
mActivity!!.showErrorToast(e)
return false
}
}
mActivity!!.setFlashAvailable(hasFlash(mCamera))
return true
}
override fun toggleFrontBackCamera() {
mCurrCameraId = if (mCurrCameraId == mCameraImpl!!.getBackCameraId()) {
mCameraImpl!!.getFrontCameraId()
} else {
mCameraImpl!!.getBackCameraId()
}
mConfig.lastUsedCamera = mCurrCameraId.toString()
releaseCamera()
if (resumeCamera()) {
setFlashlightState(FLASH_OFF)
mActivity?.updateCameraIcon(mCurrCameraId == mCameraImpl!!.getFrontCameraId())
mActivity?.toggleTimer(false)
} else {
mActivity?.toast(R.string.camera_switch_error)
}
}
override fun getCameraState() = mCameraState
private fun refreshPreview() {
mIsSixteenToNine = getSelectedResolution().isSixteenToNine()
mSetupPreviewAfterMeasure = true
requestLayout()
invalidate()
rescheduleAutofocus()
}
private fun getSelectedResolution(): MySize {
if (mParameters == null) {
mParameters = mCamera!!.parameters
}
var index = getResolutionIndex()
val resolutions = if (mIsInVideoMode) {
mParameters!!.supportedVideoSizes ?: mParameters!!.supportedPreviewSizes
} else {
mParameters!!.supportedPictureSizes
}.map { MySize(it.width, it.height) }.sortedByDescending { it.width * it.height }
if (index == -1) {
index = getDefaultFullscreenResolution(resolutions) ?: 0
}
return resolutions[index]
}
private fun getResolutionIndex(): Int {
val isBackCamera = mConfig.lastUsedCamera == Camera.CameraInfo.CAMERA_FACING_BACK.toString()
return if (mIsInVideoMode) {
if (isBackCamera) mConfig.backVideoResIndex else mConfig.frontVideoResIndex
} else {
if (isBackCamera) mConfig.backPhotoResIndex else mConfig.frontPhotoResIndex
}
}
private fun getDefaultFullscreenResolution(resolutions: List<MySize>): Int? {
val screenAspectRatio = mActivity!!.realScreenSize.y / mActivity!!.realScreenSize.x.toFloat()
resolutions.forEachIndexed { index, size ->
val diff = screenAspectRatio - (size.width / size.height.toFloat())
if (Math.abs(diff) < 0.1f) {
mConfig.backPhotoResIndex = index
return index
}
}
return null
}
private fun initGestureDetector() {
mScaleGestureDetector = ScaleGestureDetector(mActivity, object : ScaleGestureDetector.SimpleOnScaleGestureListener() {
override fun onScale(detector: ScaleGestureDetector): Boolean {
val zoomFactor = mParameters!!.zoom
var zoomRatio = mZoomRatios[zoomFactor] / 100f
zoomRatio *= detector.scaleFactor
var newZoomFactor = zoomFactor
if (zoomRatio <= 1f) {
newZoomFactor = 0
} else if (zoomRatio >= mZoomRatios[mMaxZoom] / 100f) {
newZoomFactor = mMaxZoom
} else {
if (detector.scaleFactor > 1f) {
for (i in zoomFactor until mZoomRatios.size) {
if (mZoomRatios[i] / 100.0f >= zoomRatio) {
newZoomFactor = i
break
}
}
} else {
for (i in zoomFactor downTo 0) {
if (mZoomRatios[i] / 100.0f <= zoomRatio) {
newZoomFactor = i
break
}
}
}
}
newZoomFactor = Math.max(newZoomFactor, 0)
newZoomFactor = Math.min(mMaxZoom, newZoomFactor)
mParameters!!.zoom = newZoomFactor
updateCameraParameters()
return true
}
override fun onScaleEnd(detector: ScaleGestureDetector) {
super.onScaleEnd(detector)
mWasZooming = true
mSurfaceView.isSoundEffectsEnabled = false
mParameters!!.focusAreas = null
}
})
}
override fun tryTakePicture() {
if (mConfig.focusBeforeCapture) {
focusArea(true)
} else {
takePicture()
}
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
private fun takePicture() {
if (mCanTakePicture) {
val selectedResolution = getSelectedResolution()
mParameters!!.setPictureSize(selectedResolution.width, selectedResolution.height)
val pictureSize = mParameters!!.pictureSize
if (selectedResolution.width != pictureSize.width || selectedResolution.height != pictureSize.height) {
mActivity!!.toast(R.string.setting_resolution_failed)
}
if (isJellyBean1Plus()) {
mCamera!!.enableShutterSound(false)
}
mRotationAtCapture = mActivity!!.mLastHandledOrientation
updateCameraParameters()
mCameraState = STATE_PICTURE_TAKEN
mIsPreviewShown = true
try {
Thread {
mCamera!!.takePicture(null, null, takePictureCallback)
if (mConfig.isSoundEnabled) {
val audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
val volume = audioManager.getStreamVolume(AudioManager.STREAM_SYSTEM)
if (volume != 0) {
val mp = MediaPlayer.create(context, Uri.parse("file:///system/media/audio/ui/camera_click.ogg"))
mp?.start()
}
}
}.start()
} catch (ignored: Exception) {
}
}
mCanTakePicture = false
mIsFocusingBeforeCapture = false
}
private val takePictureCallback = Camera.PictureCallback { data, cam ->
if (data.isEmpty()) {
mActivity!!.toast(R.string.unknown_error_occurred)
return@PictureCallback
}
mCameraState = STATE_PREVIEW
if (!mIsImageCaptureIntent) {
handlePreview()
}
if (mIsImageCaptureIntent) {
if (mTargetUri != null) {
storePhoto(data)
} else {
mActivity!!.apply {
setResult(Activity.RESULT_OK)
finish()
}
}
} else {
storePhoto(data)
}
}
private fun storePhoto(data: ByteArray) {
val previewRotation = getPreviewRotation(mCurrCameraId)
PhotoProcessor(mActivity!!, mTargetUri, mRotationAtCapture, previewRotation, getIsUsingFrontCamera(), mIsImageCaptureIntent).execute(data)
}
private fun getIsUsingFrontCamera() = mCurrCameraId == mActivity!!.getMyCamera().getFrontCameraId()
private fun handlePreview() {
if (mConfig.isShowPreviewEnabled) {
if (!mConfig.wasPhotoPreviewHintShown) {
mActivity!!.toast(R.string.click_to_resume_preview)
mConfig.wasPhotoPreviewHintShown = true
}
} else {
Handler().postDelayed({
mIsPreviewShown = false
resumePreview()
}, PHOTO_PREVIEW_LENGTH)
}
}
private fun resumePreview() {
mIsPreviewShown = false
mActivity!!.toggleBottomButtons(false)
try {
mCamera?.startPreview()
} catch (ignored: Exception) {
}
mCanTakePicture = true
focusArea(false, false)
}
private fun focusArea(takePictureAfter: Boolean, showFocusRect: Boolean = true) {
if (mCamera == null || (mIsFocusingBeforeCapture && !takePictureAfter)) {
return
}
if (takePictureAfter) {
mIsFocusingBeforeCapture = true
}
mCamera!!.cancelAutoFocus()
if (mParameters!!.maxNumFocusAreas > 0) {
if (mLastClickX == 0f && mLastClickY == 0f) {
mLastClickX = width / 2.toFloat()
mLastClickY = height / 2.toFloat()
}
val focusRect = calculateFocusArea(mLastClickX, mLastClickY)
val focusAreas = ArrayList<Camera.Area>(1)
focusAreas.add(Camera.Area(focusRect, 1000))
mParameters!!.focusAreas = focusAreas
if (showFocusRect) {
mActivity!!.drawFocusCircle(mLastClickX, mLastClickY)
}
}
try {
val focusModes = mParameters!!.supportedFocusModes
if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
mParameters!!.focusMode = Camera.Parameters.FOCUS_MODE_AUTO
}
updateCameraParameters()
mCamera!!.autoFocus { success, camera ->
if (camera == null || mCamera == null) {
return@autoFocus
}
mCamera!!.cancelAutoFocus()
if (focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
mParameters!!.focusMode = Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE
}
updateCameraParameters()
if (takePictureAfter) {
takePicture()
} else {
rescheduleAutofocus()
}
}
} catch (ignored: Exception) {
}
}
private fun calculateFocusArea(x: Float, y: Float): Rect {
var left = x / mSurfaceView.width * 2000 - 1000
var top = y / mSurfaceView.height * 2000 - 1000
val tmp = left
left = top
top = -tmp
val rectLeft = Math.max(left.toInt() - FOCUS_AREA_SIZE / 2, -1000)
val rectTop = Math.max(top.toInt() - FOCUS_AREA_SIZE / 2, -1000)
val rectRight = Math.min(left.toInt() + FOCUS_AREA_SIZE / 2, 1000)
val rectBottom = Math.min(top.toInt() + FOCUS_AREA_SIZE / 2, 1000)
return Rect(rectLeft, rectTop, rectRight, rectBottom)
}
private fun rescheduleAutofocus() {
mAutoFocusHandler.removeCallbacksAndMessages(null)
mAutoFocusHandler.postDelayed({
if (!mIsInVideoMode || !mIsRecording) {
focusArea(false, false)
}
}, REFOCUS_PERIOD)
}
override fun showChangeResolutionDialog() {
if (mCamera != null) {
val oldResolution = getSelectedResolution()
val photoResolutions = mCamera!!.parameters.supportedPictureSizes.map { MySize(it.width, it.height) } as ArrayList<MySize>
val videoSizes = mCamera!!.parameters.supportedVideoSizes ?: mCamera!!.parameters.supportedPreviewSizes
val videoResolutions = videoSizes.map { MySize(it.width, it.height) } as ArrayList<MySize>
ChangeResolutionDialog(mActivity!!, getIsUsingFrontCamera(), photoResolutions, videoResolutions, false) {
if (oldResolution != getSelectedResolution()) {
refreshPreview()
}
}
}
}
fun releaseCamera() {
stopRecording()
mCamera?.stopPreview()
mCamera?.release()
mCamera = null
cleanupRecorder()
}
override fun surfaceCreated(holder: SurfaceHolder) {
mIsSurfaceCreated = true
try {
mWasCameraPreviewSet = mCamera != null
mCamera?.setPreviewDisplay(mSurfaceHolder)
if (mSwitchToVideoAsap)
initVideoMode()
} catch (e: IOException) {
mActivity!!.showErrorToast(e)
}
}
override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
mIsSurfaceCreated = true
if (mIsInVideoMode) {
initVideoMode()
}
}
override fun surfaceDestroyed(holder: SurfaceHolder) {
mIsSurfaceCreated = false
mCamera?.stopPreview()
cleanupRecorder()
}
private fun setupPreview() {
mCanTakePicture = true
if (mCamera != null && mPreviewSize != null) {
if (mParameters == null)
mParameters = mCamera!!.parameters
mParameters!!.setPreviewSize(mPreviewSize!!.width, mPreviewSize!!.height)
updateCameraParameters()
try {
mCamera!!.startPreview()
} catch (e: RuntimeException) {
mActivity!!.showErrorToast(e)
}
}
}
private fun cleanupRecorder() {
if (mRecorder != null) {
if (mIsRecording) {
stopRecording()
}
mRecorder!!.release()
mRecorder = null
}
}
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {}
private fun getOptimalPreviewSize(sizes: List<Camera.Size>, width: Int, height: Int): Camera.Size {
var result: Camera.Size? = null
for (size in sizes) {
if (size.width <= width && size.height <= height) {
if (result == null) {
result = size
} else {
val resultArea = result.width * result.height
val newArea = size.width * size.height
if (newArea > resultArea) {
result = size
}
}
}
}
return result!!
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
setMeasuredDimension(mScreenSize.x, mScreenSize.y)
if (mSupportedPreviewSizes != null) {
// for simplicity lets assume that most displays are 16:9 and the remaining ones are 4:3
// always set 16:9 for videos as many devices support 4:3 only in low quality
mPreviewSize = if (mIsSixteenToNine || mIsInVideoMode) {
getOptimalPreviewSize(mSupportedPreviewSizes!!, mScreenSize.y, mScreenSize.x)
} else {
val newRatioHeight = (mScreenSize.x * (4.toDouble() / 3)).toInt()
setMeasuredDimension(mScreenSize.x, newRatioHeight)
getOptimalPreviewSize(mSupportedPreviewSizes!!, newRatioHeight, mScreenSize.x)
}
val lp = mSurfaceView.layoutParams
// make sure to occupy whole width in every case
if (mScreenSize.x > mPreviewSize!!.height) {
val ratio = mScreenSize.x.toFloat() / mPreviewSize!!.height
lp.width = (mPreviewSize!!.height * ratio).toInt()
if (mIsSixteenToNine || mIsInVideoMode) {
lp.height = mScreenSize.y
} else {
lp.height = (mPreviewSize!!.width * ratio).toInt()
}
} else {
lp.width = mPreviewSize!!.height
lp.height = mPreviewSize!!.width
}
if (mSetupPreviewAfterMeasure) {
if (mCamera != null) {
mSetupPreviewAfterMeasure = false
mCamera!!.stopPreview()
setupPreview()
}
}
}
}
override fun setFlashlightState(state: Int) {
mFlashlightState = state
checkFlashlight()
}
override fun toggleFlashlight() {
val newState = ++mFlashlightState % if (mIsInVideoMode) 2 else 3
setFlashlightState(newState)
}
override fun checkFlashlight() {
when (mFlashlightState) {
FLASH_OFF -> disableFlash()
FLASH_ON -> enableFlash()
FLASH_AUTO -> setAutoFlash()
}
mActivity?.updateFlashlightState(mFlashlightState)
}
private fun disableFlash() {
mFlashlightState = FLASH_OFF
mParameters?.flashMode = Camera.Parameters.FLASH_MODE_OFF
updateCameraParameters()
}
private fun enableFlash() {
mFlashlightState = FLASH_ON
mParameters?.flashMode = Camera.Parameters.FLASH_MODE_TORCH
updateCameraParameters()
}
private fun setAutoFlash() {
mFlashlightState = FLASH_AUTO
mParameters?.flashMode = Camera.Parameters.FLASH_MODE_OFF
updateCameraParameters()
Handler().postDelayed({
mActivity?.runOnUiThread {
mParameters?.flashMode = Camera.Parameters.FLASH_MODE_AUTO
}
}, 1000)
}
override fun initPhotoMode() {
stopRecording()
cleanupRecorder()
mIsRecording = false
mIsInVideoMode = false
refreshPreview()
}
// VIDEO RECORDING
override fun initVideoMode(): Boolean {
if (mCamera == null || mRecorder != null || !mIsSurfaceCreated) {
return false
}
refreshPreview()
mSwitchToVideoAsap = false
mIsRecording = false
mIsInVideoMode = true
mRecorder = MediaRecorder().apply {
setCamera(mCamera)
setVideoSource(MediaRecorder.VideoSource.DEFAULT)
setAudioSource(MediaRecorder.AudioSource.DEFAULT)
}
mCurrVideoPath = mActivity!!.getOutputMediaFile(false)
if (mCurrVideoPath.isEmpty()) {
mActivity?.toast(R.string.video_creating_error)
return false
}
if (mRecorder == null) {
mActivity?.toast(R.string.unknown_error_occurred)
return false
}
val resolution = getSelectedResolution()
val profile = if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_HIGH)) {
CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH)
} else {
CamcorderProfile.get(CamcorderProfile.QUALITY_LOW)
}
if (profile == null) {
mActivity?.toast(R.string.unknown_error_occurred)
return false
}
profile.apply {
videoFrameWidth = resolution.width
videoFrameHeight = resolution.height
mRecorder!!.setProfile(this)
}
checkPermissions()
if (mRecorder == null) {
return false
}
mRecorder!!.setPreviewDisplay(mSurfaceHolder.surface)
val rotation = getVideoRotation()
mRecorder!!.setOrientationHint(rotation)
try {
mRecorder!!.prepare()
} catch (e: Exception) {
setupFailed(e)
return false
}
return true
}
private fun checkPermissions(): Boolean {
if (mActivity!!.needsStupidWritePermissions(mCurrVideoPath)) {
if (mConfig.treeUri.isEmpty()) {
mActivity!!.toast(R.string.save_error_internal_storage)
mConfig.savePhotosFolder = Environment.getExternalStorageDirectory().toString()
releaseCamera()
return false
}
try {
var document = mActivity!!.getDocumentFile(mCurrVideoPath.getParentPath())
if (document == null) {
mActivity!!.toast(R.string.unknown_error_occurred)
return false
}
document = document.createFile("video/mp4", mCurrVideoPath.substring(mCurrVideoPath.lastIndexOf('/') + 1))
val fileDescriptor = context.contentResolver.openFileDescriptor(document.uri, "rw")
mRecorder!!.setOutputFile(fileDescriptor!!.fileDescriptor)
} catch (e: Exception) {
setupFailed(e)
}
} else {
mRecorder!!.setOutputFile(mCurrVideoPath)
}
return true
}
private fun setupFailed(e: Exception) {
mActivity!!.showErrorToast(e)
releaseCamera()
}
private fun updateCameraParameters() {
try {
mCamera?.parameters = mParameters
} catch (e: RuntimeException) {
}
}
override fun setTargetUri(uri: Uri) {
mTargetUri = uri
}
override fun setIsImageCaptureIntent(isImageCaptureIntent: Boolean) {
mIsImageCaptureIntent = isImageCaptureIntent
}
override fun toggleRecording() {
if (mIsRecording) {
stopRecording()
initVideoMode()
} else {
startRecording()
}
}
private fun getVideoRotation(): Int {
val deviceRot = compensateDeviceRotation(mActivity!!.mLastHandledOrientation, getIsUsingFrontCamera())
val previewRot = getPreviewRotation(mCurrCameraId)
return (deviceRot + previewRot) % 360
}
override fun deviceOrientationChanged() {
if (mIsInVideoMode && !mIsRecording) {
mRecorder = null
initVideoMode()
}
}
private fun startRecording() {
try {
mCamera!!.unlock()
toggleShutterSound(true)
mRecorder!!.start()
toggleShutterSound(false)
mIsRecording = true
mActivity!!.setRecordingState(true)
} catch (e: Exception) {
mActivity!!.showErrorToast(e)
releaseCamera()
}
}
private fun stopRecording() {
if (mRecorder != null && mIsRecording) {
try {
toggleShutterSound(true)
mRecorder!!.stop()
mActivity!!.rescanPaths(arrayListOf(mCurrVideoPath)) {
mActivity!!.videoSaved(Uri.fromFile(File(mCurrVideoPath)))
toggleShutterSound(false)
}
} catch (e: RuntimeException) {
mActivity!!.showErrorToast(e)
toggleShutterSound(false)
File(mCurrVideoPath).delete()
mRecorder = null
mIsRecording = false
releaseCamera()
}
}
mRecorder = null
if (mIsRecording) {
mActivity!!.setRecordingState(false)
}
mIsRecording = false
val file = File(mCurrVideoPath)
if (file.exists() && file.length() == 0L) {
file.delete()
}
}
private fun toggleShutterSound(mute: Boolean?) {
if (!mConfig.isSoundEnabled) {
(mActivity!!.getSystemService(Context.AUDIO_SERVICE) as AudioManager).setStreamMute(AudioManager.STREAM_SYSTEM, mute!!)
}
}
private fun hasFlash(camera: Camera?): Boolean {
if (camera == null) {
return false
}
if (camera.parameters.flashMode == null) {
return false
}
val supportedFlashModes = camera.parameters.supportedFlashModes
if (supportedFlashModes == null || supportedFlashModes.isEmpty() ||
supportedFlashModes.size == 1 && supportedFlashModes[0] == Camera.Parameters.FLASH_MODE_OFF) {
return false
}
return true
}
private fun getScreenSize(): Point {
val display = mActivity!!.windowManager.defaultDisplay
val size = Point()
display.getSize(size)
size.y += mActivity!!.resources.getNavBarHeight()
return size
}
private fun getPreviewRotation(cameraId: Int): Int {
val info = getCameraInfo(cameraId)
val degrees = when (mActivity!!.windowManager.defaultDisplay.rotation) {
Surface.ROTATION_90 -> 90
Surface.ROTATION_180 -> 180
Surface.ROTATION_270 -> 270
else -> 0
}
var result: Int
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360
result = 360 - result
} else {
result = info.orientation - degrees + 360
}
return result % 360
}
private fun getCameraInfo(cameraId: Int): Camera.CameraInfo {
val info = android.hardware.Camera.CameraInfo()
Camera.getCameraInfo(cameraId, info)
return info
}
}

View File

@ -6,12 +6,6 @@
android:layout_height="match_parent"
android:background="@android:color/black">
<SurfaceView
android:id="@+id/camera_surface_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"/>
<com.simplemobiletools.camera.views.AutoFitTextureView
android:id="@+id/camera_texture_view"
android:layout_width="wrap_content"
@ -29,8 +23,8 @@
android:id="@+id/toggle_photo_video"
android:layout_width="@dimen/icon_size"
android:layout_height="@dimen/icon_size"
android:layout_alignParentRight="true"
android:layout_below="@+id/settings"
android:layout_alignParentRight="true"
android:padding="@dimen/normal_margin"
android:src="@drawable/ic_video"/>
@ -38,8 +32,8 @@
android:id="@+id/change_resolution"
android:layout_width="@dimen/icon_size"
android:layout_height="@dimen/icon_size"
android:layout_alignParentRight="true"
android:layout_below="@+id/toggle_photo_video"
android:layout_alignParentRight="true"
android:padding="@dimen/normal_margin"
android:src="@drawable/ic_resolution"/>
@ -47,8 +41,8 @@
android:id="@+id/last_photo_video_preview"
android:layout_width="@dimen/icon_size"
android:layout_height="@dimen/icon_size"
android:layout_alignParentRight="true"
android:layout_below="@+id/change_resolution"
android:layout_alignParentRight="true"
android:padding="@dimen/medium_margin"/>
<LinearLayout

View File

@ -18,18 +18,18 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/medium_margin"
android:background="?attr/selectableItemBackground"
android:paddingBottom="@dimen/activity_margin"
android:paddingLeft="@dimen/normal_margin"
android:paddingTop="@dimen/activity_margin"
android:paddingRight="@dimen/normal_margin"
android:paddingTop="@dimen/activity_margin">
android:paddingBottom="@dimen/activity_margin">
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/settings_purchase_thank_you"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:paddingLeft="@dimen/medium_margin"
android:paddingStart="@dimen/medium_margin"
android:paddingLeft="@dimen/medium_margin"
android:text="@string/purchase_simple_thank_you"/>
</RelativeLayout>
@ -40,18 +40,18 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/medium_margin"
android:background="?attr/selectableItemBackground"
android:paddingBottom="@dimen/activity_margin"
android:paddingLeft="@dimen/normal_margin"
android:paddingTop="@dimen/activity_margin"
android:paddingRight="@dimen/normal_margin"
android:paddingTop="@dimen/activity_margin">
android:paddingBottom="@dimen/activity_margin">
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/settings_customize_colors"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:paddingLeft="@dimen/medium_margin"
android:paddingStart="@dimen/medium_margin"
android:paddingLeft="@dimen/medium_margin"
android:text="@string/customize_colors"/>
</RelativeLayout>
@ -62,10 +62,10 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/medium_margin"
android:background="?attr/selectableItemBackground"
android:paddingBottom="@dimen/activity_margin"
android:paddingLeft="@dimen/normal_margin"
android:paddingTop="@dimen/activity_margin"
android:paddingRight="@dimen/normal_margin"
android:paddingTop="@dimen/activity_margin">
android:paddingBottom="@dimen/activity_margin">
<com.simplemobiletools.commons.views.MySwitchCompat
android:id="@+id/settings_use_english"
@ -73,8 +73,8 @@
android:layout_height="wrap_content"
android:background="@null"
android:clickable="false"
android:paddingLeft="@dimen/medium_margin"
android:paddingStart="@dimen/medium_margin"
android:paddingLeft="@dimen/medium_margin"
android:text="@string/use_english_language"
app:switchPadding="@dimen/medium_margin"/>
@ -86,10 +86,10 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/medium_margin"
android:background="?attr/selectableItemBackground"
android:paddingBottom="@dimen/activity_margin"
android:paddingLeft="@dimen/normal_margin"
android:paddingTop="@dimen/activity_margin"
android:paddingRight="@dimen/normal_margin"
android:paddingTop="@dimen/activity_margin">
android:paddingBottom="@dimen/activity_margin">
<com.simplemobiletools.commons.views.MySwitchCompat
android:id="@+id/settings_avoid_whats_new"
@ -97,8 +97,8 @@
android:layout_height="wrap_content"
android:background="@null"
android:clickable="false"
android:paddingLeft="@dimen/medium_margin"
android:paddingStart="@dimen/medium_margin"
android:paddingLeft="@dimen/medium_margin"
android:text="@string/avoid_whats_new"
app:switchPadding="@dimen/medium_margin"/>
@ -110,10 +110,10 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/medium_margin"
android:background="?attr/selectableItemBackground"
android:paddingBottom="@dimen/activity_margin"
android:paddingLeft="@dimen/normal_margin"
android:paddingTop="@dimen/activity_margin"
android:paddingRight="@dimen/normal_margin"
android:paddingTop="@dimen/activity_margin">
android:paddingBottom="@dimen/activity_margin">
<com.simplemobiletools.commons.views.MySwitchCompat
android:id="@+id/settings_keep_settings_visible"
@ -121,8 +121,8 @@
android:layout_height="wrap_content"
android:background="@null"
android:clickable="false"
android:paddingLeft="@dimen/medium_margin"
android:paddingStart="@dimen/medium_margin"
android:paddingLeft="@dimen/medium_margin"
android:text="@string/keep_settings_visible"
app:switchPadding="@dimen/medium_margin"/>
@ -135,10 +135,10 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/medium_margin"
android:background="?attr/selectableItemBackground"
android:paddingBottom="@dimen/activity_margin"
android:paddingLeft="@dimen/normal_margin"
android:paddingTop="@dimen/activity_margin"
android:paddingRight="@dimen/normal_margin"
android:paddingTop="@dimen/activity_margin">
android:paddingBottom="@dimen/activity_margin">
<com.simplemobiletools.commons.views.MySwitchCompat
android:id="@+id/settings_focus_before_capture"
@ -146,8 +146,8 @@
android:layout_height="wrap_content"
android:background="@null"
android:clickable="false"
android:paddingLeft="@dimen/medium_margin"
android:paddingStart="@dimen/medium_margin"
android:paddingLeft="@dimen/medium_margin"
android:text="@string/focus_before_capture"
app:switchPadding="@dimen/medium_margin"/>
@ -164,8 +164,8 @@
android:id="@+id/shutter_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/bigger_margin"
android:layout_marginStart="@dimen/bigger_margin"
android:layout_marginLeft="@dimen/bigger_margin"
android:layout_marginTop="@dimen/activity_margin"
android:text="@string/shutter"
android:textAllCaps="true"
@ -177,10 +177,10 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/medium_margin"
android:background="?attr/selectableItemBackground"
android:paddingBottom="@dimen/activity_margin"
android:paddingLeft="@dimen/normal_margin"
android:paddingTop="@dimen/activity_margin"
android:paddingRight="@dimen/normal_margin"
android:paddingTop="@dimen/activity_margin">
android:paddingBottom="@dimen/activity_margin">
<com.simplemobiletools.commons.views.MySwitchCompat
android:id="@+id/settings_sound"
@ -188,8 +188,8 @@
android:layout_height="wrap_content"
android:background="@null"
android:clickable="false"
android:paddingLeft="@dimen/medium_margin"
android:paddingStart="@dimen/medium_margin"
android:paddingLeft="@dimen/medium_margin"
android:text="@string/shutter_sound"
app:switchPadding="@dimen/medium_margin"/>
@ -201,10 +201,10 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/medium_margin"
android:background="?attr/selectableItemBackground"
android:paddingBottom="@dimen/activity_margin"
android:paddingLeft="@dimen/normal_margin"
android:paddingTop="@dimen/activity_margin"
android:paddingRight="@dimen/normal_margin"
android:paddingTop="@dimen/activity_margin">
android:paddingBottom="@dimen/activity_margin">
<com.simplemobiletools.commons.views.MySwitchCompat
android:id="@+id/settings_volume_buttons_as_shutter"
@ -212,8 +212,8 @@
android:layout_height="wrap_content"
android:background="@null"
android:clickable="false"
android:paddingLeft="@dimen/medium_margin"
android:paddingStart="@dimen/medium_margin"
android:paddingLeft="@dimen/medium_margin"
android:text="@string/volume_buttons_as_shutter"
app:switchPadding="@dimen/medium_margin"/>
@ -230,8 +230,8 @@
android:id="@+id/startup_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/bigger_margin"
android:layout_marginStart="@dimen/bigger_margin"
android:layout_marginLeft="@dimen/bigger_margin"
android:layout_marginTop="@dimen/activity_margin"
android:text="@string/startup"
android:textAllCaps="true"
@ -243,10 +243,10 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/medium_margin"
android:background="?attr/selectableItemBackground"
android:paddingBottom="@dimen/activity_margin"
android:paddingLeft="@dimen/normal_margin"
android:paddingTop="@dimen/activity_margin"
android:paddingRight="@dimen/normal_margin"
android:paddingTop="@dimen/activity_margin">
android:paddingBottom="@dimen/activity_margin">
<com.simplemobiletools.commons.views.MySwitchCompat
android:id="@+id/settings_turn_flash_off_at_startup"
@ -254,8 +254,8 @@
android:layout_height="wrap_content"
android:background="@null"
android:clickable="false"
android:paddingLeft="@dimen/medium_margin"
android:paddingStart="@dimen/medium_margin"
android:paddingLeft="@dimen/medium_margin"
android:text="@string/turn_flash_off_at_startup"
app:switchPadding="@dimen/medium_margin"/>
@ -267,10 +267,10 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/medium_margin"
android:background="?attr/selectableItemBackground"
android:paddingBottom="@dimen/activity_margin"
android:paddingLeft="@dimen/normal_margin"
android:paddingTop="@dimen/activity_margin"
android:paddingRight="@dimen/normal_margin"
android:paddingTop="@dimen/activity_margin">
android:paddingBottom="@dimen/activity_margin">
<com.simplemobiletools.commons.views.MySwitchCompat
android:id="@+id/settings_always_open_back_camera"
@ -278,8 +278,8 @@
android:layout_height="wrap_content"
android:background="@null"
android:clickable="false"
android:paddingLeft="@dimen/medium_margin"
android:paddingStart="@dimen/medium_margin"
android:paddingLeft="@dimen/medium_margin"
android:text="@string/always_open_back_camera"
app:switchPadding="@dimen/medium_margin"/>
@ -296,8 +296,8 @@
android:id="@+id/saving_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/bigger_margin"
android:layout_marginStart="@dimen/bigger_margin"
android:layout_marginLeft="@dimen/bigger_margin"
android:layout_marginTop="@dimen/activity_margin"
android:text="@string/saving_label"
android:textAllCaps="true"
@ -309,10 +309,10 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/medium_margin"
android:background="?attr/selectableItemBackground"
android:paddingBottom="@dimen/activity_margin"
android:paddingLeft="@dimen/normal_margin"
android:paddingTop="@dimen/activity_margin"
android:paddingRight="@dimen/normal_margin"
android:paddingTop="@dimen/activity_margin">
android:paddingBottom="@dimen/activity_margin">
<com.simplemobiletools.commons.views.MySwitchCompat
android:id="@+id/settings_save_photo_metadata"
@ -320,47 +320,23 @@
android:layout_height="wrap_content"
android:background="@null"
android:clickable="false"
android:paddingLeft="@dimen/medium_margin"
android:paddingStart="@dimen/medium_margin"
android:paddingLeft="@dimen/medium_margin"
android:text="@string/save_photo_metadata"
app:switchPadding="@dimen/medium_margin"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/settings_show_preview_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/medium_margin"
android:background="?attr/selectableItemBackground"
android:paddingBottom="@dimen/activity_margin"
android:paddingLeft="@dimen/normal_margin"
android:paddingRight="@dimen/normal_margin"
android:paddingTop="@dimen/activity_margin">
<com.simplemobiletools.commons.views.MySwitchCompat
android:id="@+id/settings_show_preview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@null"
android:clickable="false"
android:paddingLeft="@dimen/medium_margin"
android:paddingStart="@dimen/medium_margin"
android:text="@string/show_preview"
app:switchPadding="@dimen/medium_margin"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/settings_flip_photos_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/medium_margin"
android:background="?attr/selectableItemBackground"
android:paddingBottom="@dimen/activity_margin"
android:paddingLeft="@dimen/normal_margin"
android:paddingTop="@dimen/activity_margin"
android:paddingRight="@dimen/normal_margin"
android:paddingTop="@dimen/activity_margin">
android:paddingBottom="@dimen/activity_margin">
<com.simplemobiletools.commons.views.MySwitchCompat
android:id="@+id/settings_flip_photos"
@ -368,8 +344,8 @@
android:layout_height="wrap_content"
android:background="@null"
android:clickable="false"
android:paddingLeft="@dimen/medium_margin"
android:paddingStart="@dimen/medium_margin"
android:paddingLeft="@dimen/medium_margin"
android:text="@string/flip_front_camera_photos_horizontally"
app:switchPadding="@dimen/medium_margin"/>
@ -381,18 +357,18 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/medium_margin"
android:background="?attr/selectableItemBackground"
android:paddingBottom="@dimen/bigger_margin"
android:paddingLeft="@dimen/normal_margin"
android:paddingTop="@dimen/bigger_margin"
android:paddingRight="@dimen/normal_margin"
android:paddingTop="@dimen/bigger_margin">
android:paddingBottom="@dimen/bigger_margin">
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/settings_save_photos_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toLeftOf="@+id/settings_save_photos"
android:layout_toStartOf="@+id/settings_save_photos"
android:layout_toLeftOf="@+id/settings_save_photos"
android:paddingLeft="@dimen/medium_margin"
android:paddingRight="@dimen/medium_margin"
android:text="@string/save_photos"/>
@ -416,18 +392,18 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/medium_margin"
android:background="?attr/selectableItemBackground"
android:paddingBottom="@dimen/bigger_margin"
android:paddingLeft="@dimen/normal_margin"
android:paddingTop="@dimen/bigger_margin"
android:paddingRight="@dimen/normal_margin"
android:paddingTop="@dimen/bigger_margin">
android:paddingBottom="@dimen/bigger_margin">
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/settings_photo_quality_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toLeftOf="@+id/settings_photo_quality"
android:layout_toStartOf="@+id/settings_photo_quality"
android:layout_toLeftOf="@+id/settings_photo_quality"
android:paddingLeft="@dimen/medium_margin"
android:paddingRight="@dimen/medium_margin"
android:text="@string/photo_compression_quality"/>

View File

@ -19,8 +19,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toLeftOf="@+id/change_resolution_photo"
android:layout_toStartOf="@+id/change_resolution_photo"
android:layout_toLeftOf="@+id/change_resolution_photo"
android:text="@string/photo"/>
<com.simplemobiletools.commons.views.MyTextView
@ -47,8 +47,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toLeftOf="@+id/change_resolution_video"
android:layout_toStartOf="@+id/change_resolution_video"
android:layout_toLeftOf="@+id/change_resolution_video"
android:text="@string/video"/>
<com.simplemobiletools.commons.views.MyTextView

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="FullScreenTheme" parent="AppTheme.Base">
<item name="android:windowTranslucentNavigation">true</item>
</style>
</resources>

View File

@ -3,10 +3,9 @@
<style name="AppTheme" parent="AppTheme.Base"/>
<style name="FullScreenTheme.Base" parent="AppTheme">
<style name="FullScreenTheme" parent="AppTheme">
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowTranslucentNavigation">true</item>
</style>
<style name="FullScreenTheme" parent="FullScreenTheme.Base"/>
</resources>

View File

@ -1,7 +1,7 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = '1.2.60'
ext.kotlin_version = '1.2.71'
repositories {
google()