diff --git a/BUILD.md b/BUILD.md index 3915eb5..451d8f1 100644 --- a/BUILD.md +++ b/BUILD.md @@ -45,16 +45,16 @@ $ git clone --depth=1 https://git.ffmpeg.org/ffmpeg.git If you want Gocryptfs support, you need to download OpenSSL: ``` $ cd ../libgocryptfs -$ wget https://www.openssl.org/source/openssl-1.1.1p.tar.gz +$ wget https://www.openssl.org/source/openssl-1.1.1q.tar.gz ``` Verify OpenSSL signature: ``` -$ wget https://www.openssl.org/source/openssl-1.1.1p.tar.gz.asc -$ gpg --verify openssl-1.1.1p.tar.gz.asc openssl-1.1.1p.tar.gz +$ wget https://www.openssl.org/source/openssl-1.1.1q.tar.gz.asc +$ gpg --verify openssl-1.1.1q.tar.gz.asc openssl-1.1.1q.tar.gz ``` Continue **ONLY** if the signature is **VALID**. ``` -$ tar -xzf openssl-1.1.1p.tar.gz +$ tar -xzf openssl-1.1.1q.tar.gz ``` If you want CryFS support, initialize libcryfs: ``` @@ -76,7 +76,7 @@ $ ./build.sh ffmpeg This step is only required if you want Gocryptfs support. ``` $ cd app/libgocryptfs -$ OPENSSL_PATH="./openssl-1.1.1p" ./build.sh +$ OPENSSL_PATH="./openssl-1.1.1q" ./build.sh ``` ## Compile APKs Gradle build libgocryptfs and libcryfs by default. diff --git a/app/build.gradle b/app/build.gradle index 084badc..f4eee07 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -14,9 +14,10 @@ if (hasProperty("disableGocryptfs")) { } android { - compileSdkVersion 31 - buildToolsVersion "31" - ndkVersion "23.1.7779620" + compileSdkVersion 33 + buildToolsVersion "33.0.0" + ndkVersion "25.1.8937393" + namespace "sushi.hardcore.droidfs" compileOptions { targetCompatibility JavaVersion.VERSION_1_8 @@ -86,24 +87,25 @@ dependencies { implementation project(":libpdfviewer:app") implementation fileTree(dir: "libs", include: ["*.jar"]) implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - implementation 'androidx.core:core-ktx:1.7.0' - implementation "androidx.appcompat:appcompat:1.4.1" - implementation "androidx.constraintlayout:constraintlayout:2.1.3" + implementation 'androidx.core:core-ktx:1.9.0' + implementation "androidx.appcompat:appcompat:1.5.1" + implementation "androidx.constraintlayout:constraintlayout:2.1.4" + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1" implementation "androidx.sqlite:sqlite-ktx:2.2.0" implementation "androidx.preference:preference-ktx:1.2.0" implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0" - implementation 'com.google.android.material:material:1.5.0' - implementation "com.github.bumptech.glide:glide:4.12.0" - implementation "androidx.biometric:biometric-ktx:1.2.0-alpha04" + implementation 'com.google.android.material:material:1.6.1' + implementation "com.github.bumptech.glide:glide:4.13.2" + implementation "androidx.biometric:biometric-ktx:1.2.0-alpha05" - def exoplayer_version = "2.17.1" + def exoplayer_version = "2.18.1" implementation "com.google.android.exoplayer:exoplayer-core:$exoplayer_version" implementation "com.google.android.exoplayer:exoplayer-ui:$exoplayer_version" implementation "androidx.concurrent:concurrent-futures:1.1.0" - def camerax_version = "1.1.0-beta03" + def camerax_version = "1.2.0-beta02" implementation "androidx.camera:camera-camera2:$camerax_version" implementation "androidx.camera:camera-lifecycle:$camerax_version" implementation "androidx.camera:camera-view:$camerax_version" diff --git a/app/libcryfs b/app/libcryfs index c5be03a..c0600c2 160000 --- a/app/libcryfs +++ b/app/libcryfs @@ -1 +1 @@ -Subproject commit c5be03ad3abea3aef5b0fcc5aa3af8cba2befdd1 +Subproject commit c0600c262480f6fb3d31e2b500ba04714f1ff342 diff --git a/app/libgocryptfs b/app/libgocryptfs index e6e4c20..27232cb 160000 --- a/app/libgocryptfs +++ b/app/libgocryptfs @@ -1 +1 @@ -Subproject commit e6e4c201dbf3834de1a49a8b67b4b54239d24249 +Subproject commit 27232cbdb7257be13a12545b71fa32ee193cb11b diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 134fe49..60e02a4 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,7 +1,6 @@ - + diff --git a/app/src/main/java/sushi/hardcore/droidfs/BaseActivity.kt b/app/src/main/java/sushi/hardcore/droidfs/BaseActivity.kt index b5c2fed..39bd0ad 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/BaseActivity.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/BaseActivity.kt @@ -1,19 +1,23 @@ package sushi.hardcore.droidfs +import android.content.Intent import android.content.SharedPreferences +import android.os.Build import android.os.Bundle +import android.os.Parcelable import android.view.WindowManager import androidx.appcompat.app.AppCompatActivity import androidx.preference.PreferenceManager open class BaseActivity: AppCompatActivity() { protected lateinit var sharedPrefs: SharedPreferences + protected var applyCustomTheme: Boolean = true lateinit var themeValue: String private var shouldCheckTheme = true override fun onCreate(savedInstanceState: Bundle?) { sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this) - if (shouldCheckTheme) { + if (shouldCheckTheme && applyCustomTheme) { themeValue = sharedPrefs.getString("theme", ConstValues.DEFAULT_THEME_VALUE)!! when (themeValue) { "black_green" -> setTheme(R.style.BlackGreen) @@ -28,8 +32,6 @@ open class BaseActivity: AppCompatActivity() { "dark_purple" -> setTheme(R.style.DarkPurple) "black_purple" -> setTheme(R.style.BlackPurple) } - } else { - shouldCheckTheme = true } super.onCreate(savedInstanceState) if (!sharedPrefs.getBoolean("usf_screenshot", false)){ @@ -37,12 +39,7 @@ open class BaseActivity: AppCompatActivity() { } } - override fun onStart() { - super.onStart() - val newThemeValue = sharedPrefs.getString("theme", "dark_green")!! - onThemeChanged(newThemeValue) - } - + // must not be called if applyCustomTheme is false fun onThemeChanged(newThemeValue: String) { if (newThemeValue != themeValue) { themeValue = newThemeValue @@ -50,4 +47,13 @@ open class BaseActivity: AppCompatActivity() { recreate() } } + + inline fun getParcelableExtra(intent: Intent, name: String): T? { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + intent.getParcelableExtra(name, T::class.java) + } else { + @Suppress("Deprecation") + intent.getParcelableExtra(name) + } + } } \ No newline at end of file diff --git a/app/src/main/java/sushi/hardcore/droidfs/CameraActivity.kt b/app/src/main/java/sushi/hardcore/droidfs/CameraActivity.kt index 5352fe7..ec6bee8 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/CameraActivity.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/CameraActivity.kt @@ -17,6 +17,7 @@ import android.view.animation.RotateAnimation import android.widget.ImageView import android.widget.RelativeLayout import android.widget.Toast +import androidx.activity.addCallback import androidx.annotation.RequiresApi import androidx.camera.camera2.interop.Camera2CameraInfo import androidx.camera.core.* @@ -94,7 +95,7 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener { binding = ActivityCameraBinding.inflate(layoutInflater) setContentView(binding.root) supportActionBar?.hide() - encryptedVolume = intent.getParcelableExtra("volume")!! + encryptedVolume = getParcelableExtra(intent, "volume")!! outputDirectory = intent.getStringExtra("path")!! if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { @@ -278,6 +279,11 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener { else -> false } } + onBackPressedDispatcher.addCallback(this) { + isFinishingIntentionally = true + isEnabled = false + onBackPressedDispatcher.onBackPressed() + } } @RequiresApi(Build.VERSION_CODES.M) @@ -506,11 +512,6 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener { sensorOrientationListener.addListener(this) } - override fun onBackPressed() { - super.onBackPressed() - isFinishingIntentionally = true - } - override fun onOrientationChange(newOrientation: Int) { val realOrientation = when (newOrientation) { Surface.ROTATION_0 -> 0f diff --git a/app/src/main/java/sushi/hardcore/droidfs/ChangePasswordActivity.kt b/app/src/main/java/sushi/hardcore/droidfs/ChangePasswordActivity.kt index aef4bec..6f261b3 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/ChangePasswordActivity.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/ChangePasswordActivity.kt @@ -27,7 +27,7 @@ class ChangePasswordActivity: BaseActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - volume = intent.getParcelableExtra("volume")!! + volume = getParcelableExtra(intent, "volume")!! binding = ActivityChangePasswordBinding.inflate(layoutInflater) setContentView(binding.root) title = getString(R.string.change_password) diff --git a/app/src/main/java/sushi/hardcore/droidfs/MainActivity.kt b/app/src/main/java/sushi/hardcore/droidfs/MainActivity.kt index bd23fd3..24e6de8 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/MainActivity.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/MainActivity.kt @@ -15,6 +15,7 @@ import android.view.MenuItem import android.view.View import android.view.WindowManager import android.widget.Toast +import androidx.activity.addCallback import androidx.activity.result.contract.ActivityResultContracts import androidx.documentfile.provider.DocumentFile import androidx.lifecycle.lifecycleScope @@ -134,6 +135,16 @@ class MainActivity : BaseActivity(), VolumeAdapter.Listener { unsetDefaultVolume() } } + onBackPressedDispatcher.addCallback(this) { + if (volumeAdapter.selectedItems.isNotEmpty()) { + unselectAll() + } else { + if (pickMode) + shouldCloseVolume = false + isEnabled = false + onBackPressedDispatcher.onBackPressed() + } + } Intent(this, FileOperationService::class.java).also { bindService(it, object : ServiceConnection { override fun onServiceConnected(className: ComponentName, service: IBinder) { @@ -146,6 +157,9 @@ class MainActivity : BaseActivity(), VolumeAdapter.Listener { override fun onStart() { super.onStart() + // refresh theme if changed in SettingsActivity + val newThemeValue = sharedPrefs.getString("theme", ConstValues.DEFAULT_THEME_VALUE)!! + onThemeChanged(newThemeValue) // refresh this in case another instance of MainActivity changes its value defaultVolumeName = sharedPrefs.getString(DEFAULT_VOLUME_KEY, null) } @@ -619,7 +633,7 @@ class MainActivity : BaseActivity(), VolumeAdapter.Listener { explorerIntent.putExtras(intent.extras!!) //forward extras } else if (pickMode) { explorerIntent = Intent(this, ExplorerActivityPick::class.java) - explorerIntent.putExtra("destinationVolume", intent.getParcelableExtra("volume")!!) + explorerIntent.putExtra("destinationVolume", getParcelableExtra(intent, "volume")!!) explorerIntent.flags = Intent.FLAG_ACTIVITY_FORWARD_RESULT } if (explorerIntent == null) { @@ -634,22 +648,12 @@ class MainActivity : BaseActivity(), VolumeAdapter.Listener { finish() } - override fun onBackPressed() { - if (volumeAdapter.selectedItems.isNotEmpty()) { - unselectAll() - } else { - if (pickMode) - shouldCloseVolume = false - super.onBackPressed() - } - } - override fun onStop() { super.onStop() if (pickMode && !usfKeepOpen) { finish() if (shouldCloseVolume) { - intent.getParcelableExtra("volume")?.close() + getParcelableExtra(intent, "volume")?.close() RestrictedFileProvider.wipeAll(this) } } diff --git a/app/src/main/java/sushi/hardcore/droidfs/SettingsActivity.kt b/app/src/main/java/sushi/hardcore/droidfs/SettingsActivity.kt index 9f45624..1892cbf 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/SettingsActivity.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/SettingsActivity.kt @@ -34,7 +34,7 @@ class SettingsActivity : BaseActivity() { override fun onOptionsItemSelected(item: MenuItem): Boolean { return when (item.itemId){ android.R.id.home -> { - onBackPressed() //return to the previous fragment rather than the activity + onBackPressedDispatcher.onBackPressed() //return to the previous fragment rather than the activity true } else -> super.onOptionsItemSelected(item) diff --git a/app/src/main/java/sushi/hardcore/droidfs/adapters/ExplorerElementAdapter.kt b/app/src/main/java/sushi/hardcore/droidfs/adapters/ExplorerElementAdapter.kt index 6a3505b..79d4ac0 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/adapters/ExplorerElementAdapter.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/adapters/ExplorerElementAdapter.kt @@ -41,6 +41,7 @@ class ExplorerElementAdapter( } var isUsingListLayout = true private var thumbnailsCache: LruCache? = null + var loadThumbnails = true init { if (encryptedVolume != null) { @@ -159,7 +160,7 @@ class ExplorerElementAdapter( if (thumbnail != null) { icon.setImageBitmap(thumbnail) setDefaultIcon = false - } else { + } else if (adapter.loadThumbnails) { loadThumbnail(fullPath, adapter) } } diff --git a/app/src/main/java/sushi/hardcore/droidfs/explorers/BaseExplorerActivity.kt b/app/src/main/java/sushi/hardcore/droidfs/explorers/BaseExplorerActivity.kt index 71c52ac..a0b021f 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/explorers/BaseExplorerActivity.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/explorers/BaseExplorerActivity.kt @@ -82,7 +82,7 @@ open class BaseExplorerActivity : BaseActivity(), ExplorerElementAdapter.Listene usf_open = sharedPrefs.getBoolean("usf_open", false) usf_keep_open = sharedPrefs.getBoolean("usf_keep_open", false) volumeName = intent.getStringExtra("volume_name") ?: "" - encryptedVolume = intent.getParcelableExtra("volume")!! + encryptedVolume = getParcelableExtra(intent, "volume")!! sortOrderEntries = resources.getStringArray(R.array.sort_orders_entries) sortOrderValues = resources.getStringArray(R.array.sort_orders_values) foldersFirst = sharedPrefs.getBoolean("folders_first", true) diff --git a/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerActivity.kt b/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerActivity.kt index b303e48..db23a22 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerActivity.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerActivity.kt @@ -35,7 +35,7 @@ class ExplorerActivity : BaseExplorerActivity() { private val pickFromOtherVolumes = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> if (result.resultCode == Activity.RESULT_OK) { result.data?.let { resultIntent -> - val remoteEncryptedVolume = resultIntent.getParcelableExtra("volume")!! + val remoteEncryptedVolume = getParcelableExtra(resultIntent, "volume")!! val path = resultIntent.getStringExtra("path") val operationFiles = ArrayList() if (path == null){ //multiples elements @@ -63,6 +63,8 @@ class ExplorerActivity : BaseExplorerActivity() { if (items == null) { remoteEncryptedVolume.close() } else { + // stop loading thumbnails while writing files + explorerAdapter.loadThumbnails = false taskScope.launch { val failedItem = fileOperationService.copyElements(items, remoteEncryptedVolume) if (failedItem == null) { @@ -74,6 +76,7 @@ class ExplorerActivity : BaseExplorerActivity() { .setPositiveButton(R.string.ok, null) .show() } + explorerAdapter.loadThumbnails = true setCurrentPath(currentDirectoryPath) remoteEncryptedVolume.close() } diff --git a/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerActivityDrop.kt b/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerActivityDrop.kt index ef38b2d..fedb66e 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerActivityDrop.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerActivityDrop.kt @@ -2,6 +2,7 @@ package sushi.hardcore.droidfs.explorers import android.content.Intent import android.net.Uri +import android.os.Build import android.view.Menu import android.view.MenuItem import sushi.hardcore.droidfs.R @@ -33,7 +34,7 @@ class ExplorerActivityDrop : BaseExplorerActivity() { val errorMsg: String? = if (extras != null && extras.containsKey(Intent.EXTRA_STREAM)) { when (intent.action) { Intent.ACTION_SEND -> { - val uri = intent.getParcelableExtra(Intent.EXTRA_STREAM) + val uri = getParcelableExtra(intent, Intent.EXTRA_STREAM) if (uri == null) { getString(R.string.share_intent_parsing_failed) } else { @@ -42,7 +43,12 @@ class ExplorerActivityDrop : BaseExplorerActivity() { } } Intent.ACTION_SEND_MULTIPLE -> { - val uris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM) + val uris: List? = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM, Uri::class.java) + } else { + @Suppress("Deprecation") + intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM) + } if (uris != null) { importFilesFromUris(uris, ::onImported) null diff --git a/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerActivityPick.kt b/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerActivityPick.kt index 3e14300..1838c61 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerActivityPick.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerActivityPick.kt @@ -83,7 +83,7 @@ class ExplorerActivityPick : BaseExplorerActivity() { override fun closeVolumeOnDestroy() { if (!isFinishingIntentionally && !usf_keep_open){ - intent.getParcelableExtra("destinationVolume")?.close() + getParcelableExtra(intent, "destinationVolume")?.close() super.closeVolumeOnDestroy() } } diff --git a/app/src/main/java/sushi/hardcore/droidfs/file_viewers/FileViewerActivity.kt b/app/src/main/java/sushi/hardcore/droidfs/file_viewers/FileViewerActivity.kt index 96c798f..9e80533 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/file_viewers/FileViewerActivity.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/file_viewers/FileViewerActivity.kt @@ -2,6 +2,7 @@ package sushi.hardcore.droidfs.file_viewers import android.os.Bundle import android.view.View +import androidx.activity.addCallback import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsControllerCompat import sushi.hardcore.droidfs.BaseActivity @@ -33,13 +34,18 @@ abstract class FileViewerActivity: BaseActivity() { super.onCreate(savedInstanceState) filePath = intent.getStringExtra("path")!! originalParentPath = PathUtils.getParentPath(filePath) - encryptedVolume = intent.getParcelableExtra("volume")!! + encryptedVolume = getParcelableExtra(intent, "volume")!! usf_keep_open = sharedPrefs.getBoolean("usf_keep_open", false) foldersFirst = sharedPrefs.getBoolean("folders_first", true) windowInsetsController = WindowInsetsControllerCompat(window, window.decorView) windowInsetsController.addOnControllableInsetsChangedListener { _, typeMask -> windowTypeMask = typeMask } + onBackPressedDispatcher.addCallback(this) { + isFinishingIntentionally = true + isEnabled = false + onBackPressedDispatcher.onBackPressed() + } hideSystemUi() viewFile() } @@ -75,7 +81,8 @@ abstract class FileViewerActivity: BaseActivity() { when (result.second) { 1 -> dialog.setMessage(R.string.get_size_failed) 2 -> dialog.setMessage(R.string.outofmemoryerror_msg) - else -> dialog.setMessage(R.string.read_file_failed) + 3 -> dialog.setMessage(R.string.read_file_failed) + 4 -> dialog.setMessage(R.string.io_error) } dialog.show() } @@ -145,9 +152,4 @@ abstract class FileViewerActivity: BaseActivity() { finish() } } - - override fun onBackPressed() { - super.onBackPressed() - isFinishingIntentionally = true - } } diff --git a/app/src/main/java/sushi/hardcore/droidfs/file_viewers/ImageViewer.kt b/app/src/main/java/sushi/hardcore/droidfs/file_viewers/ImageViewer.kt index b71c18c..d97558f 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/file_viewers/ImageViewer.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/file_viewers/ImageViewer.kt @@ -1,9 +1,7 @@ package sushi.hardcore.droidfs.file_viewers import android.content.res.Configuration -import android.content.res.Resources import android.graphics.Bitmap -import android.graphics.BitmapFactory import android.graphics.Matrix import android.graphics.drawable.Drawable import android.os.Handler @@ -11,7 +9,7 @@ import android.view.MotionEvent import android.view.View import android.view.WindowManager import android.widget.Toast -import androidx.exifinterface.media.ExifInterface +import androidx.activity.addCallback import com.bumptech.glide.Glide import com.bumptech.glide.RequestBuilder import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool @@ -35,7 +33,6 @@ class ImageViewer: FileViewerActivity() { private lateinit var fileName: String private lateinit var handler: Handler - private var bitmap: Bitmap? = null private var requestBuilder: RequestBuilder? = null private var x1 = 0F private var x2 = 0F @@ -151,53 +148,26 @@ class ImageViewer: FileViewerActivity() { rotationAngle -= 90 rotateImage() } + onBackPressedDispatcher.addCallback(this) { + if (slideshowActive) { + stopSlideshow() + } else { + askSaveRotation { + isEnabled = false + onBackPressedDispatcher.onBackPressed() + } + } + } loadImage() handler.postDelayed(hideUI, hideDelay) } private fun loadImage(){ - bitmap = null requestBuilder = null loadWholeFile(filePath)?.let { - val displayWithGlide = if (it.size < 5_000_000) { - true - } else { - bitmap = BitmapFactory.decodeByteArray(it, 0, it.size) - if (bitmap == null) { - true - } else { - val orientation = ExifInterface(ByteArrayInputStream(it)).getAttributeInt( - ExifInterface.TAG_ORIENTATION, - ExifInterface.ORIENTATION_NORMAL - ) - originalOrientation = when (orientation) { - ExifInterface.ORIENTATION_ROTATE_90 -> 90f - ExifInterface.ORIENTATION_ROTATE_180 -> 180f - ExifInterface.ORIENTATION_ROTATE_270 -> 270f - else -> 0f - } - val displayMetrics = Resources.getSystem().displayMetrics - if (displayMetrics.widthPixels < bitmap!!.width || displayMetrics.heightPixels < bitmap!!.height) { - val newWidth: Int - val newHeight: Int - if (displayMetrics.widthPixels > displayMetrics.heightPixels) { - newWidth = displayMetrics.widthPixels - newHeight = bitmap!!.height*displayMetrics.widthPixels/bitmap!!.width - } else { - newHeight = displayMetrics.heightPixels - newWidth = bitmap!!.width*displayMetrics.heightPixels/bitmap!!.height - } - bitmap = Bitmap.createScaledBitmap(bitmap!!, newWidth, newHeight, false) - } - Glide.with(this).load(bitmap).transform(OrientationTransformation(originalOrientation)).into(binding.imageViewer) - false - } - } - if (displayWithGlide) { - originalOrientation = 0f - requestBuilder = Glide.with(this).load(it) - requestBuilder?.into(binding.imageViewer) - } + originalOrientation = 0f + requestBuilder = Glide.with(this).load(it) + requestBuilder?.into(binding.imageViewer) fileName = File(filePath).name binding.textFilename.text = fileName rotationAngle = originalOrientation @@ -227,14 +197,6 @@ class ImageViewer: FileViewerActivity() { Toast.makeText(this, R.string.slideshow_stopped, Toast.LENGTH_SHORT).show() } - override fun onBackPressed() { - if (slideshowActive){ - stopSlideshow() - } else { - askSaveRotation { super.onBackPressed() } - } - } - class OrientationTransformation(private val orientation: Float): BitmapTransformation() { lateinit var bitmap: Bitmap @@ -255,7 +217,7 @@ class ImageViewer: FileViewerActivity() { private fun rotateImage(){ binding.imageViewer.restoreZoomNormal() orientationTransformation = OrientationTransformation(rotationAngle) - (requestBuilder ?: Glide.with(this).load(bitmap)).transform(orientationTransformation).into(binding.imageViewer) + requestBuilder?.transform(orientationTransformation)?.into(binding.imageViewer) } private fun askSaveRotation(callback: () -> Unit){ diff --git a/app/src/main/java/sushi/hardcore/droidfs/file_viewers/MediaPlayer.kt b/app/src/main/java/sushi/hardcore/droidfs/file_viewers/MediaPlayer.kt index 352929c..7dc3989 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/file_viewers/MediaPlayer.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/file_viewers/MediaPlayer.kt @@ -59,11 +59,10 @@ abstract class MediaPlayer: FileViewerActivity() { window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) } } - override fun onPositionDiscontinuity(reason: Int) { - if (player.currentMediaItemIndex != currentPlaylistIndex) { - playlistNext(player.currentMediaItemIndex == (currentPlaylistIndex+1) % mappedPlaylist.size) - refreshFileName() - } + + override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) { + playlistNext(player.currentMediaItemIndex == (currentPlaylistIndex+1) % mappedPlaylist.size) + refreshFileName() } }) player.prepare() diff --git a/app/src/main/java/sushi/hardcore/droidfs/file_viewers/PdfViewer.kt b/app/src/main/java/sushi/hardcore/droidfs/file_viewers/PdfViewer.kt index 8dd4b62..98378de 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/file_viewers/PdfViewer.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/file_viewers/PdfViewer.kt @@ -7,6 +7,9 @@ import java.io.ByteArrayInputStream import java.io.File class PdfViewer: FileViewerActivity() { + init { + applyCustomTheme = false + } private lateinit var pdfViewer: PdfViewer override fun hideSystemUi() { @@ -37,6 +40,11 @@ class PdfViewer: FileViewerActivity() { pdfViewer.onResume() } + override fun onDestroy() { + super.onDestroy() + pdfViewer.onDestroy() + } + override fun onPrepareOptionsMenu(menu: Menu?): Boolean { return pdfViewer.onPrepareOptionsMenu(menu) } diff --git a/app/src/main/java/sushi/hardcore/droidfs/file_viewers/VideoPlayer.kt b/app/src/main/java/sushi/hardcore/droidfs/file_viewers/VideoPlayer.kt index 3d93acd..caaf306 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/file_viewers/VideoPlayer.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/file_viewers/VideoPlayer.kt @@ -3,6 +3,7 @@ package sushi.hardcore.droidfs.file_viewers import android.content.pm.ActivityInfo import android.content.res.Configuration import com.google.android.exoplayer2.ExoPlayer +import com.google.android.exoplayer2.ui.StyledPlayerView import sushi.hardcore.droidfs.databinding.ActivityVideoPlayerBinding class VideoPlayer: MediaPlayer() { @@ -16,9 +17,9 @@ class VideoPlayer: MediaPlayer() { binding = ActivityVideoPlayerBinding.inflate(layoutInflater) setContentView(binding.root) binding.videoPlayer.doubleTapOverlay = binding.doubleTapOverlay - binding.videoPlayer.setControllerVisibilityListener { visibility -> + binding.videoPlayer.setControllerVisibilityListener(StyledPlayerView.ControllerVisibilityListener { visibility -> binding.topBar.visibility = visibility - } + }) binding.rotateButton.setOnClickListener { requestedOrientation = if (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) { diff --git a/app/src/main/java/sushi/hardcore/droidfs/util/PathUtils.kt b/app/src/main/java/sushi/hardcore/droidfs/util/PathUtils.kt index b3d82a0..6b54ad9 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/util/PathUtils.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/util/PathUtils.kt @@ -185,7 +185,7 @@ object PathUtils { return rootDirectory.delete() } - fun safePickDirectory(directoryPicker: ActivityResultLauncher, context: Context, themeValue: String) { + fun safePickDirectory(directoryPicker: ActivityResultLauncher, context: Context, themeValue: String) { try { directoryPicker.launch(null) } catch (e: ActivityNotFoundException) { diff --git a/app/src/main/java/sushi/hardcore/droidfs/video_recording/VideoCapture.java b/app/src/main/java/sushi/hardcore/droidfs/video_recording/VideoCapture.java index 0361455..94c44ec 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/video_recording/VideoCapture.java +++ b/app/src/main/java/sushi/hardcore/droidfs/video_recording/VideoCapture.java @@ -28,6 +28,7 @@ import static androidx.camera.core.impl.UseCaseConfig.OPTION_DEFAULT_CAPTURE_CON import static androidx.camera.core.impl.UseCaseConfig.OPTION_DEFAULT_SESSION_CONFIG; import static androidx.camera.core.impl.UseCaseConfig.OPTION_SESSION_CONFIG_UNPACKER; import static androidx.camera.core.impl.UseCaseConfig.OPTION_SURFACE_OCCUPANCY_PRIORITY; +import static androidx.camera.core.impl.UseCaseConfig.OPTION_ZSL_DISABLED; import static androidx.camera.core.impl.VideoCaptureConfig.OPTION_AUDIO_BIT_RATE; import static androidx.camera.core.impl.VideoCaptureConfig.OPTION_AUDIO_CHANNEL_COUNT; import static androidx.camera.core.impl.VideoCaptureConfig.OPTION_AUDIO_MIN_BUFFER_SIZE; @@ -121,6 +122,7 @@ import java.util.concurrent.atomic.AtomicReference; * @hide */ @RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java +@RestrictTo(Scope.LIBRARY_GROUP) public final class VideoCapture extends UseCase { //////////////////////////////////////////////////////////////////////////////////////////// @@ -1123,6 +1125,7 @@ public final class VideoCapture extends UseCase { } /** Set audio record parameters by CamcorderProfile */ + @SuppressWarnings("deprecation") private void setAudioParametersByCamcorderProfile(Size currentResolution, String cameraId) { CamcorderProfile profile; boolean isCamcorderProfileFound = false; @@ -1732,6 +1735,14 @@ public final class VideoCapture extends UseCase { return this; } + /** @hide */ + @RestrictTo(Scope.LIBRARY_GROUP) + @NonNull + @Override + public Builder setZslDisabled(boolean disabled) { + getMutableConfig().insertOption(OPTION_ZSL_DISABLED, disabled); + return this; + } } /** diff --git a/app/src/main/java/sushi/hardcore/droidfs/video_recording/VideoCaptureConfig.java b/app/src/main/java/sushi/hardcore/droidfs/video_recording/VideoCaptureConfig.java index 83dd74a..d00eb1d 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/video_recording/VideoCaptureConfig.java +++ b/app/src/main/java/sushi/hardcore/droidfs/video_recording/VideoCaptureConfig.java @@ -1,8 +1,23 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package sushi.hardcore.droidfs.video_recording; -import android.annotation.SuppressLint; - import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; import androidx.camera.core.impl.Config; import androidx.camera.core.impl.ImageFormatConstants; import androidx.camera.core.impl.ImageOutputConfig; @@ -15,7 +30,7 @@ import androidx.camera.core.internal.ThreadConfig; * *

In the earlier stage, the VideoCapture is deprioritized. */ -@SuppressLint("RestrictedApi") +@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java public final class VideoCaptureConfig implements UseCaseConfig, ImageOutputConfig, diff --git a/app/src/main/java/sushi/hardcore/droidfs/widgets/CircleClipTapView.kt b/app/src/main/java/sushi/hardcore/droidfs/widgets/CircleClipTapView.kt index 2475831..295ab4c 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/widgets/CircleClipTapView.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/widgets/CircleClipTapView.kt @@ -146,16 +146,16 @@ internal class CircleClipTapView(context: Context, attrs: AttributeSet): View(co } addListener(object : Animator.AnimatorListener { - override fun onAnimationStart(animation: Animator?) { + override fun onAnimationStart(animation: Animator) { visibility = VISIBLE } - override fun onAnimationEnd(animation: Animator?) { + override fun onAnimationEnd(animation: Animator) { if (!forceReset) performAtEnd() } - override fun onAnimationRepeat(animation: Animator?) {} - override fun onAnimationCancel(animation: Animator?) {} + override fun onAnimationRepeat(animation: Animator) {} + override fun onAnimationCancel(animation: Animator) {} }) } } diff --git a/app/src/main/java/sushi/hardcore/droidfs/widgets/DoubleTapPlayerView.kt b/app/src/main/java/sushi/hardcore/droidfs/widgets/DoubleTapPlayerView.kt index cf66aa2..e3e37da 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/widgets/DoubleTapPlayerView.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/widgets/DoubleTapPlayerView.kt @@ -46,7 +46,7 @@ class DoubleTapPlayerView @JvmOverloads constructor( return true } - override fun onSingleTapConfirmed(e: MotionEvent?): Boolean { + override fun onSingleTapConfirmed(e: MotionEvent): Boolean { if (!isDoubleTapping) performClick() return true diff --git a/app/src/main/native/libmux.c b/app/src/main/native/libmux.c index f83653f..f2b6d0c 100644 --- a/app/src/main/native/libmux.c +++ b/app/src/main/native/libmux.c @@ -18,7 +18,7 @@ int write_packet(void* opaque, uint8_t* buff, int buff_size) { JNIEnv *env; (*muxer->jvm)->GetEnv(muxer->jvm, (void **) &env, JNI_VERSION_1_6); jbyteArray jarray = (*env)->NewByteArray(env, buff_size); - (*env)->SetByteArrayRegion(env, jarray, 0, buff_size, buff); + (*env)->SetByteArrayRegion(env, jarray, 0, buff_size, (const signed char*)buff); (*env)->CallVoidMethod(env, muxer->thiz, muxer->write_packet_method_id, jarray, buff_size); return buff_size; } @@ -52,8 +52,7 @@ Java_sushi_hardcore_droidfs_video_1recording_MediaMuxer_addAudioTrack(JNIEnv *en const AVCodec* encoder = avcodec_find_encoder(AV_CODEC_ID_AAC); AVStream* stream = avformat_new_stream((AVFormatContext *) format_context, NULL); AVCodecContext* codec_context = avcodec_alloc_context3(encoder); - codec_context->channels = channel_count; - codec_context->channel_layout = av_get_default_channel_layout(channel_count); + av_channel_layout_default(&codec_context->ch_layout, channel_count); codec_context->sample_rate = sample_rate; codec_context->sample_fmt = encoder->sample_fmts[0]; codec_context->bit_rate = bitrate; @@ -105,8 +104,8 @@ Java_sushi_hardcore_droidfs_video_1recording_MediaMuxer_writePacket(JNIEnv *env, r.den = 1000000; av_packet_rescale_ts(packet, r, ((AVFormatContext *)format_context)->streams[stream_index]->time_base); } - unsigned char* buff = malloc(size); - (*env)->GetByteArrayRegion(env, buffer, 0, size, buff); + uint8_t* buff = malloc(size); + (*env)->GetByteArrayRegion(env, buffer, 0, size, (signed char*)buff); packet->data = buff; if (is_key_frame) { packet->flags = AV_PKT_FLAG_KEY; diff --git a/app/src/main/res/layout/activity_camera.xml b/app/src/main/res/layout/activity_camera.xml index a70ba60..731469c 100644 --- a/app/src/main/res/layout/activity_camera.xml +++ b/app/src/main/res/layout/activity_camera.xml @@ -5,7 +5,7 @@ android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto" tools:context=".CameraActivity" - android:background="#000000"> + android:background="@color/fullScreenBackgroundColor"> Deleting files… (%s) (%s, read-only) + I/O Error. diff --git a/build.gradle b/build.gradle index e119c0c..53b347b 100644 --- a/build.gradle +++ b/build.gradle @@ -1,12 +1,11 @@ -// Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = "1.6.10" + ext.kotlin_version = "1.7.10" repositories { google() mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:7.2.1' + classpath 'com.android.tools.build:gradle:7.3.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 1e3ef59..562920e 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Wed Sep 01 11:25:55 UTC 2021 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/libpdfviewer b/libpdfviewer index 8fe8b2f..06e54db 160000 --- a/libpdfviewer +++ b/libpdfviewer @@ -1 +1 @@ -Subproject commit 8fe8b2f4b3aecd3ad210478fd99df9f260503db8 +Subproject commit 06e54dbb03098c0d0d113ed7b3fc93d74050f590