diff --git a/app/src/main/java/sushi/hardcore/droidfs/CameraActivity.kt b/app/src/main/java/sushi/hardcore/droidfs/CameraActivity.kt index 179d435..c0a0447 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/CameraActivity.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/CameraActivity.kt @@ -6,7 +6,11 @@ import android.os.Bundle import android.text.InputType import android.view.View import android.view.WindowManager +import android.view.animation.Animation +import android.view.animation.LinearInterpolator +import android.view.animation.RotateAnimation import android.widget.EditText +import android.widget.ImageView import android.widget.Toast import androidx.core.content.ContextCompat import com.otaliastudios.cameraview.CameraListener @@ -25,7 +29,7 @@ import java.io.ByteArrayInputStream import java.text.SimpleDateFormat import java.util.* -class CameraActivity : BaseActivity() { +class CameraActivity : BaseActivity(), SensorOrientationListener.Listener { companion object { private val flashModes = listOf(Flash.AUTO, Flash.ON, Flash.OFF) private val gridTitles = listOf(R.string.grid_none, R.string.grid_3x3, R.string.grid_4x4) @@ -45,6 +49,9 @@ class CameraActivity : BaseActivity() { image_timer.setImageResource(R.drawable.icon_timer_off) } } + private lateinit var sensorOrientationListener: SensorOrientationListener + private var previousOrientation: Float = 0f + private lateinit var orientedIcons: List private lateinit var gocryptfsVolume: GocryptfsVolume private lateinit var outputDirectory: String private lateinit var fileName: String @@ -72,6 +79,8 @@ class CameraActivity : BaseActivity() { } }) take_photo_button.onClick = ::onClickTakePhoto + orientedIcons = listOf(image_hdr, image_timer, image_grid, image_close, image_flash, image_camera_switch) + sensorOrientationListener = SensorOrientationListener(this) } private fun onClickTakePhoto() { @@ -192,13 +201,37 @@ class CameraActivity : BaseActivity() { override fun onPause() { super.onPause() + sensorOrientationListener.remove(this) if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED){ //if not asking for permission finish() } } + override fun onResume() { + super.onResume() + sensorOrientationListener.addListener(this) + } + override fun onBackPressed() { super.onBackPressed() isFinishingIntentionally = true } + + override fun onOrientationChange(newOrientation: Int) { + val reversedOrientation = when (newOrientation){ + 90 -> 270 + 270 -> 90 + else -> newOrientation + }.toFloat() + val rotateAnimation = RotateAnimation(previousOrientation, when { + reversedOrientation - previousOrientation > 180 -> reversedOrientation - 360 + reversedOrientation - previousOrientation < -180 -> reversedOrientation + 360 + else -> reversedOrientation + }, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f) + rotateAnimation.duration = 300 + rotateAnimation.interpolator = LinearInterpolator() + rotateAnimation.fillAfter = true + orientedIcons.map { it.startAnimation(rotateAnimation) } + previousOrientation = reversedOrientation + } } \ No newline at end of file diff --git a/app/src/main/java/sushi/hardcore/droidfs/SensorOrientationListener.kt b/app/src/main/java/sushi/hardcore/droidfs/SensorOrientationListener.kt new file mode 100644 index 0000000..16b3cc6 --- /dev/null +++ b/app/src/main/java/sushi/hardcore/droidfs/SensorOrientationListener.kt @@ -0,0 +1,95 @@ +package sushi.hardcore.droidfs + +import android.content.Context +import android.hardware.Sensor +import android.hardware.SensorEvent +import android.hardware.SensorEventListener +import android.hardware.SensorManager +import java.lang.ref.WeakReference +import java.util.* + +class SensorOrientationListener(context: Context) { + private val mSensorEventListener: SensorEventListener + private val mSensorManager: SensorManager + init { + mSensorEventListener = NotifierSensorEventListener() + mSensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager + } + private val mListeners = ArrayList>(3) + private var orientation = 0 + + private fun onResume() { + mSensorManager.registerListener( + mSensorEventListener, + mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), + SensorManager.SENSOR_DELAY_NORMAL + ) + } + + private fun onPause() { + mSensorManager.unregisterListener(mSensorEventListener) + } + + private inner class NotifierSensorEventListener : SensorEventListener { + override fun onSensorChanged(event: SensorEvent) { + val x = event.values[0] + val y = event.values[1] + var newOrientation: Int = orientation + if (x < 5 && x > -5 && y > 5) newOrientation = 0 + else if (x < -5 && y < 5 && y > -5) newOrientation = 90 + else if (x < 5 && x > -5 && y < -5) newOrientation = 180 + else if (x > 5 && y < 5 && y > -5) newOrientation = 270 + + if (orientation != newOrientation) { + orientation = newOrientation + notifyListeners() + } + } + + override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {} + } + + interface Listener { + fun onOrientationChange(newOrientation: Int) + } + + fun addListener(listener: Listener) { + if (get(listener) == null) // prevent duplications + mListeners.add(WeakReference(listener)) + if (mListeners.size == 1) { + onResume() // this is the first client + } + } + + fun remove(listener: Listener) { + val listenerWR = get(listener) + remove(listenerWR) + } + + private fun remove(listenerWR: WeakReference?) { + if (listenerWR != null) mListeners.remove(listenerWR) + if (mListeners.size == 0) { + onPause() + } + } + + private operator fun get(listener: Listener): WeakReference? { + for (existingListener in mListeners) if (existingListener.get() === listener) return existingListener + return null + } + + private fun notifyListeners() { + val deadListeners = ArrayList>() + for (wr in mListeners) { + if (wr.get() == null) + deadListeners.add(wr) + else + wr.get()!!.onOrientationChange(orientation) + } + + // remove dead references + for (wr in deadListeners) { + mListeners.remove(wr) + } + } +} \ No newline at end of file