Update dependencies & Fix some bugs

This commit is contained in:
Matéo Duparc 2022-09-23 12:09:22 +02:00
parent 11cc15536f
commit 8f5afca823
Signed by untrusted user: hardcoresushi
GPG Key ID: AFE384344A45E13A
31 changed files with 161 additions and 142 deletions

View File

@ -45,16 +45,16 @@ $ git clone --depth=1 https://git.ffmpeg.org/ffmpeg.git
If you want Gocryptfs support, you need to download OpenSSL: If you want Gocryptfs support, you need to download OpenSSL:
``` ```
$ cd ../libgocryptfs $ 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: Verify OpenSSL signature:
``` ```
$ wget https://www.openssl.org/source/openssl-1.1.1p.tar.gz.asc $ wget https://www.openssl.org/source/openssl-1.1.1q.tar.gz.asc
$ gpg --verify openssl-1.1.1p.tar.gz.asc openssl-1.1.1p.tar.gz $ gpg --verify openssl-1.1.1q.tar.gz.asc openssl-1.1.1q.tar.gz
``` ```
Continue **ONLY** if the signature is **VALID**. 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: If you want CryFS support, initialize libcryfs:
``` ```
@ -76,7 +76,7 @@ $ ./build.sh ffmpeg
This step is only required if you want Gocryptfs support. This step is only required if you want Gocryptfs support.
``` ```
$ cd app/libgocryptfs $ cd app/libgocryptfs
$ OPENSSL_PATH="./openssl-1.1.1p" ./build.sh $ OPENSSL_PATH="./openssl-1.1.1q" ./build.sh
``` ```
## Compile APKs ## Compile APKs
Gradle build libgocryptfs and libcryfs by default. Gradle build libgocryptfs and libcryfs by default.

View File

@ -14,9 +14,10 @@ if (hasProperty("disableGocryptfs")) {
} }
android { android {
compileSdkVersion 31 compileSdkVersion 33
buildToolsVersion "31" buildToolsVersion "33.0.0"
ndkVersion "23.1.7779620" ndkVersion "25.1.8937393"
namespace "sushi.hardcore.droidfs"
compileOptions { compileOptions {
targetCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8
@ -86,24 +87,25 @@ dependencies {
implementation project(":libpdfviewer:app") implementation project(":libpdfviewer:app")
implementation fileTree(dir: "libs", include: ["*.jar"]) implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation 'androidx.core:core-ktx:1.7.0' implementation 'androidx.core:core-ktx:1.9.0'
implementation "androidx.appcompat:appcompat:1.4.1" implementation "androidx.appcompat:appcompat:1.5.1"
implementation "androidx.constraintlayout:constraintlayout:2.1.3" 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.sqlite:sqlite-ktx:2.2.0"
implementation "androidx.preference:preference-ktx:1.2.0" implementation "androidx.preference:preference-ktx:1.2.0"
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0" implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
implementation 'com.google.android.material:material:1.5.0' implementation 'com.google.android.material:material:1.6.1'
implementation "com.github.bumptech.glide:glide:4.12.0" implementation "com.github.bumptech.glide:glide:4.13.2"
implementation "androidx.biometric:biometric-ktx:1.2.0-alpha04" 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-core:$exoplayer_version"
implementation "com.google.android.exoplayer:exoplayer-ui:$exoplayer_version" implementation "com.google.android.exoplayer:exoplayer-ui:$exoplayer_version"
implementation "androidx.concurrent:concurrent-futures:1.1.0" 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-camera2:$camerax_version"
implementation "androidx.camera:camera-lifecycle:$camerax_version" implementation "androidx.camera:camera-lifecycle:$camerax_version"
implementation "androidx.camera:camera-view:$camerax_version" implementation "androidx.camera:camera-view:$camerax_version"

@ -1 +1 @@
Subproject commit c5be03ad3abea3aef5b0fcc5aa3af8cba2befdd1 Subproject commit c0600c262480f6fb3d31e2b500ba04714f1ff342

@ -1 +1 @@
Subproject commit e6e4c201dbf3834de1a49a8b67b4b54239d24249 Subproject commit 27232cbdb7257be13a12545b71fa32ee193cb11b

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
package="sushi.hardcore.droidfs"
android:installLocation="auto"> android:installLocation="auto">
<permission <permission
@ -51,7 +50,7 @@
<activity android:name=".explorers.ExplorerActivityDrop"/> <activity android:name=".explorers.ExplorerActivityDrop"/>
<activity android:name=".file_viewers.ImageViewer" android:configChanges="screenSize|orientation" /> <!-- don't reload content on configuration change --> <activity android:name=".file_viewers.ImageViewer" android:configChanges="screenSize|orientation" /> <!-- don't reload content on configuration change -->
<activity android:name=".file_viewers.VideoPlayer" android:configChanges="screenSize|orientation" /> <activity android:name=".file_viewers.VideoPlayer" android:configChanges="screenSize|orientation" />
<activity android:name=".file_viewers.PdfViewer" android:configChanges="screenSize|orientation" /> <activity android:name=".file_viewers.PdfViewer" android:configChanges="screenSize|orientation" android:theme="@style/AppTheme" />
<activity android:name=".file_viewers.AudioPlayer" android:configChanges="screenSize|orientation" /> <activity android:name=".file_viewers.AudioPlayer" android:configChanges="screenSize|orientation" />
<activity android:name=".file_viewers.TextEditor" android:configChanges="screenSize|orientation" /> <activity android:name=".file_viewers.TextEditor" android:configChanges="screenSize|orientation" />
<activity android:name=".CameraActivity" android:screenOrientation="nosensor" /> <activity android:name=".CameraActivity" android:screenOrientation="nosensor" />

View File

@ -1,19 +1,23 @@
package sushi.hardcore.droidfs package sushi.hardcore.droidfs
import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.Parcelable
import android.view.WindowManager import android.view.WindowManager
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
open class BaseActivity: AppCompatActivity() { open class BaseActivity: AppCompatActivity() {
protected lateinit var sharedPrefs: SharedPreferences protected lateinit var sharedPrefs: SharedPreferences
protected var applyCustomTheme: Boolean = true
lateinit var themeValue: String lateinit var themeValue: String
private var shouldCheckTheme = true private var shouldCheckTheme = true
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this) sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this)
if (shouldCheckTheme) { if (shouldCheckTheme && applyCustomTheme) {
themeValue = sharedPrefs.getString("theme", ConstValues.DEFAULT_THEME_VALUE)!! themeValue = sharedPrefs.getString("theme", ConstValues.DEFAULT_THEME_VALUE)!!
when (themeValue) { when (themeValue) {
"black_green" -> setTheme(R.style.BlackGreen) "black_green" -> setTheme(R.style.BlackGreen)
@ -28,8 +32,6 @@ open class BaseActivity: AppCompatActivity() {
"dark_purple" -> setTheme(R.style.DarkPurple) "dark_purple" -> setTheme(R.style.DarkPurple)
"black_purple" -> setTheme(R.style.BlackPurple) "black_purple" -> setTheme(R.style.BlackPurple)
} }
} else {
shouldCheckTheme = true
} }
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
if (!sharedPrefs.getBoolean("usf_screenshot", false)){ if (!sharedPrefs.getBoolean("usf_screenshot", false)){
@ -37,12 +39,7 @@ open class BaseActivity: AppCompatActivity() {
} }
} }
override fun onStart() { // must not be called if applyCustomTheme is false
super.onStart()
val newThemeValue = sharedPrefs.getString("theme", "dark_green")!!
onThemeChanged(newThemeValue)
}
fun onThemeChanged(newThemeValue: String) { fun onThemeChanged(newThemeValue: String) {
if (newThemeValue != themeValue) { if (newThemeValue != themeValue) {
themeValue = newThemeValue themeValue = newThemeValue
@ -50,4 +47,13 @@ open class BaseActivity: AppCompatActivity() {
recreate() recreate()
} }
} }
inline fun <reified T: Parcelable> 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)
}
}
} }

View File

@ -17,6 +17,7 @@ import android.view.animation.RotateAnimation
import android.widget.ImageView import android.widget.ImageView
import android.widget.RelativeLayout import android.widget.RelativeLayout
import android.widget.Toast import android.widget.Toast
import androidx.activity.addCallback
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.camera.camera2.interop.Camera2CameraInfo import androidx.camera.camera2.interop.Camera2CameraInfo
import androidx.camera.core.* import androidx.camera.core.*
@ -94,7 +95,7 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener {
binding = ActivityCameraBinding.inflate(layoutInflater) binding = ActivityCameraBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
supportActionBar?.hide() supportActionBar?.hide()
encryptedVolume = intent.getParcelableExtra("volume")!! encryptedVolume = getParcelableExtra(intent, "volume")!!
outputDirectory = intent.getStringExtra("path")!! outputDirectory = intent.getStringExtra("path")!!
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
@ -278,6 +279,11 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener {
else -> false else -> false
} }
} }
onBackPressedDispatcher.addCallback(this) {
isFinishingIntentionally = true
isEnabled = false
onBackPressedDispatcher.onBackPressed()
}
} }
@RequiresApi(Build.VERSION_CODES.M) @RequiresApi(Build.VERSION_CODES.M)
@ -506,11 +512,6 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener {
sensorOrientationListener.addListener(this) sensorOrientationListener.addListener(this)
} }
override fun onBackPressed() {
super.onBackPressed()
isFinishingIntentionally = true
}
override fun onOrientationChange(newOrientation: Int) { override fun onOrientationChange(newOrientation: Int) {
val realOrientation = when (newOrientation) { val realOrientation = when (newOrientation) {
Surface.ROTATION_0 -> 0f Surface.ROTATION_0 -> 0f

View File

@ -27,7 +27,7 @@ class ChangePasswordActivity: BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
volume = intent.getParcelableExtra("volume")!! volume = getParcelableExtra(intent, "volume")!!
binding = ActivityChangePasswordBinding.inflate(layoutInflater) binding = ActivityChangePasswordBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
title = getString(R.string.change_password) title = getString(R.string.change_password)

View File

@ -15,6 +15,7 @@ import android.view.MenuItem
import android.view.View import android.view.View
import android.view.WindowManager import android.view.WindowManager
import android.widget.Toast import android.widget.Toast
import androidx.activity.addCallback
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.documentfile.provider.DocumentFile import androidx.documentfile.provider.DocumentFile
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
@ -134,6 +135,16 @@ class MainActivity : BaseActivity(), VolumeAdapter.Listener {
unsetDefaultVolume() unsetDefaultVolume()
} }
} }
onBackPressedDispatcher.addCallback(this) {
if (volumeAdapter.selectedItems.isNotEmpty()) {
unselectAll()
} else {
if (pickMode)
shouldCloseVolume = false
isEnabled = false
onBackPressedDispatcher.onBackPressed()
}
}
Intent(this, FileOperationService::class.java).also { Intent(this, FileOperationService::class.java).also {
bindService(it, object : ServiceConnection { bindService(it, object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, service: IBinder) { override fun onServiceConnected(className: ComponentName, service: IBinder) {
@ -146,6 +157,9 @@ class MainActivity : BaseActivity(), VolumeAdapter.Listener {
override fun onStart() { override fun onStart() {
super.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 // refresh this in case another instance of MainActivity changes its value
defaultVolumeName = sharedPrefs.getString(DEFAULT_VOLUME_KEY, null) defaultVolumeName = sharedPrefs.getString(DEFAULT_VOLUME_KEY, null)
} }
@ -619,7 +633,7 @@ class MainActivity : BaseActivity(), VolumeAdapter.Listener {
explorerIntent.putExtras(intent.extras!!) //forward extras explorerIntent.putExtras(intent.extras!!) //forward extras
} else if (pickMode) { } else if (pickMode) {
explorerIntent = Intent(this, ExplorerActivityPick::class.java) explorerIntent = Intent(this, ExplorerActivityPick::class.java)
explorerIntent.putExtra("destinationVolume", intent.getParcelableExtra<EncryptedVolume>("volume")!!) explorerIntent.putExtra("destinationVolume", getParcelableExtra<EncryptedVolume>(intent, "volume")!!)
explorerIntent.flags = Intent.FLAG_ACTIVITY_FORWARD_RESULT explorerIntent.flags = Intent.FLAG_ACTIVITY_FORWARD_RESULT
} }
if (explorerIntent == null) { if (explorerIntent == null) {
@ -634,22 +648,12 @@ class MainActivity : BaseActivity(), VolumeAdapter.Listener {
finish() finish()
} }
override fun onBackPressed() {
if (volumeAdapter.selectedItems.isNotEmpty()) {
unselectAll()
} else {
if (pickMode)
shouldCloseVolume = false
super.onBackPressed()
}
}
override fun onStop() { override fun onStop() {
super.onStop() super.onStop()
if (pickMode && !usfKeepOpen) { if (pickMode && !usfKeepOpen) {
finish() finish()
if (shouldCloseVolume) { if (shouldCloseVolume) {
intent.getParcelableExtra<EncryptedVolume>("volume")?.close() getParcelableExtra<EncryptedVolume>(intent, "volume")?.close()
RestrictedFileProvider.wipeAll(this) RestrictedFileProvider.wipeAll(this)
} }
} }

View File

@ -34,7 +34,7 @@ class SettingsActivity : BaseActivity() {
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId){ return when (item.itemId){
android.R.id.home -> { 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 true
} }
else -> super.onOptionsItemSelected(item) else -> super.onOptionsItemSelected(item)

View File

@ -41,6 +41,7 @@ class ExplorerElementAdapter(
} }
var isUsingListLayout = true var isUsingListLayout = true
private var thumbnailsCache: LruCache<String, Bitmap>? = null private var thumbnailsCache: LruCache<String, Bitmap>? = null
var loadThumbnails = true
init { init {
if (encryptedVolume != null) { if (encryptedVolume != null) {
@ -159,7 +160,7 @@ class ExplorerElementAdapter(
if (thumbnail != null) { if (thumbnail != null) {
icon.setImageBitmap(thumbnail) icon.setImageBitmap(thumbnail)
setDefaultIcon = false setDefaultIcon = false
} else { } else if (adapter.loadThumbnails) {
loadThumbnail(fullPath, adapter) loadThumbnail(fullPath, adapter)
} }
} }

View File

@ -82,7 +82,7 @@ open class BaseExplorerActivity : BaseActivity(), ExplorerElementAdapter.Listene
usf_open = sharedPrefs.getBoolean("usf_open", false) usf_open = sharedPrefs.getBoolean("usf_open", false)
usf_keep_open = sharedPrefs.getBoolean("usf_keep_open", false) usf_keep_open = sharedPrefs.getBoolean("usf_keep_open", false)
volumeName = intent.getStringExtra("volume_name") ?: "" volumeName = intent.getStringExtra("volume_name") ?: ""
encryptedVolume = intent.getParcelableExtra("volume")!! encryptedVolume = getParcelableExtra(intent, "volume")!!
sortOrderEntries = resources.getStringArray(R.array.sort_orders_entries) sortOrderEntries = resources.getStringArray(R.array.sort_orders_entries)
sortOrderValues = resources.getStringArray(R.array.sort_orders_values) sortOrderValues = resources.getStringArray(R.array.sort_orders_values)
foldersFirst = sharedPrefs.getBoolean("folders_first", true) foldersFirst = sharedPrefs.getBoolean("folders_first", true)

View File

@ -35,7 +35,7 @@ class ExplorerActivity : BaseExplorerActivity() {
private val pickFromOtherVolumes = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> private val pickFromOtherVolumes = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) { if (result.resultCode == Activity.RESULT_OK) {
result.data?.let { resultIntent -> result.data?.let { resultIntent ->
val remoteEncryptedVolume = resultIntent.getParcelableExtra<EncryptedVolume>("volume")!! val remoteEncryptedVolume = getParcelableExtra<EncryptedVolume>(resultIntent, "volume")!!
val path = resultIntent.getStringExtra("path") val path = resultIntent.getStringExtra("path")
val operationFiles = ArrayList<OperationFile>() val operationFiles = ArrayList<OperationFile>()
if (path == null){ //multiples elements if (path == null){ //multiples elements
@ -63,6 +63,8 @@ class ExplorerActivity : BaseExplorerActivity() {
if (items == null) { if (items == null) {
remoteEncryptedVolume.close() remoteEncryptedVolume.close()
} else { } else {
// stop loading thumbnails while writing files
explorerAdapter.loadThumbnails = false
taskScope.launch { taskScope.launch {
val failedItem = fileOperationService.copyElements(items, remoteEncryptedVolume) val failedItem = fileOperationService.copyElements(items, remoteEncryptedVolume)
if (failedItem == null) { if (failedItem == null) {
@ -74,6 +76,7 @@ class ExplorerActivity : BaseExplorerActivity() {
.setPositiveButton(R.string.ok, null) .setPositiveButton(R.string.ok, null)
.show() .show()
} }
explorerAdapter.loadThumbnails = true
setCurrentPath(currentDirectoryPath) setCurrentPath(currentDirectoryPath)
remoteEncryptedVolume.close() remoteEncryptedVolume.close()
} }

View File

@ -2,6 +2,7 @@ package sushi.hardcore.droidfs.explorers
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Build
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import sushi.hardcore.droidfs.R import sushi.hardcore.droidfs.R
@ -33,7 +34,7 @@ class ExplorerActivityDrop : BaseExplorerActivity() {
val errorMsg: String? = if (extras != null && extras.containsKey(Intent.EXTRA_STREAM)) { val errorMsg: String? = if (extras != null && extras.containsKey(Intent.EXTRA_STREAM)) {
when (intent.action) { when (intent.action) {
Intent.ACTION_SEND -> { Intent.ACTION_SEND -> {
val uri = intent.getParcelableExtra<Uri>(Intent.EXTRA_STREAM) val uri = getParcelableExtra<Uri>(intent, Intent.EXTRA_STREAM)
if (uri == null) { if (uri == null) {
getString(R.string.share_intent_parsing_failed) getString(R.string.share_intent_parsing_failed)
} else { } else {
@ -42,7 +43,12 @@ class ExplorerActivityDrop : BaseExplorerActivity() {
} }
} }
Intent.ACTION_SEND_MULTIPLE -> { Intent.ACTION_SEND_MULTIPLE -> {
val uris = intent.getParcelableArrayListExtra<Uri>(Intent.EXTRA_STREAM) val uris: List<Uri>? = 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) { if (uris != null) {
importFilesFromUris(uris, ::onImported) importFilesFromUris(uris, ::onImported)
null null

View File

@ -83,7 +83,7 @@ class ExplorerActivityPick : BaseExplorerActivity() {
override fun closeVolumeOnDestroy() { override fun closeVolumeOnDestroy() {
if (!isFinishingIntentionally && !usf_keep_open){ if (!isFinishingIntentionally && !usf_keep_open){
intent.getParcelableExtra<EncryptedVolume>("destinationVolume")?.close() getParcelableExtra<EncryptedVolume>(intent, "destinationVolume")?.close()
super.closeVolumeOnDestroy() super.closeVolumeOnDestroy()
} }
} }

View File

@ -2,6 +2,7 @@ package sushi.hardcore.droidfs.file_viewers
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import androidx.activity.addCallback
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat import androidx.core.view.WindowInsetsControllerCompat
import sushi.hardcore.droidfs.BaseActivity import sushi.hardcore.droidfs.BaseActivity
@ -33,13 +34,18 @@ abstract class FileViewerActivity: BaseActivity() {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
filePath = intent.getStringExtra("path")!! filePath = intent.getStringExtra("path")!!
originalParentPath = PathUtils.getParentPath(filePath) originalParentPath = PathUtils.getParentPath(filePath)
encryptedVolume = intent.getParcelableExtra("volume")!! encryptedVolume = getParcelableExtra(intent, "volume")!!
usf_keep_open = sharedPrefs.getBoolean("usf_keep_open", false) usf_keep_open = sharedPrefs.getBoolean("usf_keep_open", false)
foldersFirst = sharedPrefs.getBoolean("folders_first", true) foldersFirst = sharedPrefs.getBoolean("folders_first", true)
windowInsetsController = WindowInsetsControllerCompat(window, window.decorView) windowInsetsController = WindowInsetsControllerCompat(window, window.decorView)
windowInsetsController.addOnControllableInsetsChangedListener { _, typeMask -> windowInsetsController.addOnControllableInsetsChangedListener { _, typeMask ->
windowTypeMask = typeMask windowTypeMask = typeMask
} }
onBackPressedDispatcher.addCallback(this) {
isFinishingIntentionally = true
isEnabled = false
onBackPressedDispatcher.onBackPressed()
}
hideSystemUi() hideSystemUi()
viewFile() viewFile()
} }
@ -75,7 +81,8 @@ abstract class FileViewerActivity: BaseActivity() {
when (result.second) { when (result.second) {
1 -> dialog.setMessage(R.string.get_size_failed) 1 -> dialog.setMessage(R.string.get_size_failed)
2 -> dialog.setMessage(R.string.outofmemoryerror_msg) 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() dialog.show()
} }
@ -145,9 +152,4 @@ abstract class FileViewerActivity: BaseActivity() {
finish() finish()
} }
} }
override fun onBackPressed() {
super.onBackPressed()
isFinishingIntentionally = true
}
} }

View File

@ -1,9 +1,7 @@
package sushi.hardcore.droidfs.file_viewers package sushi.hardcore.droidfs.file_viewers
import android.content.res.Configuration import android.content.res.Configuration
import android.content.res.Resources
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Matrix import android.graphics.Matrix
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.os.Handler import android.os.Handler
@ -11,7 +9,7 @@ import android.view.MotionEvent
import android.view.View import android.view.View
import android.view.WindowManager import android.view.WindowManager
import android.widget.Toast import android.widget.Toast
import androidx.exifinterface.media.ExifInterface import androidx.activity.addCallback
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.RequestBuilder import com.bumptech.glide.RequestBuilder
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool
@ -35,7 +33,6 @@ class ImageViewer: FileViewerActivity() {
private lateinit var fileName: String private lateinit var fileName: String
private lateinit var handler: Handler private lateinit var handler: Handler
private var bitmap: Bitmap? = null
private var requestBuilder: RequestBuilder<Drawable>? = null private var requestBuilder: RequestBuilder<Drawable>? = null
private var x1 = 0F private var x1 = 0F
private var x2 = 0F private var x2 = 0F
@ -151,53 +148,26 @@ class ImageViewer: FileViewerActivity() {
rotationAngle -= 90 rotationAngle -= 90
rotateImage() rotateImage()
} }
onBackPressedDispatcher.addCallback(this) {
if (slideshowActive) {
stopSlideshow()
} else {
askSaveRotation {
isEnabled = false
onBackPressedDispatcher.onBackPressed()
}
}
}
loadImage() loadImage()
handler.postDelayed(hideUI, hideDelay) handler.postDelayed(hideUI, hideDelay)
} }
private fun loadImage(){ private fun loadImage(){
bitmap = null
requestBuilder = null requestBuilder = null
loadWholeFile(filePath)?.let { 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 originalOrientation = 0f
requestBuilder = Glide.with(this).load(it) requestBuilder = Glide.with(this).load(it)
requestBuilder?.into(binding.imageViewer) requestBuilder?.into(binding.imageViewer)
}
fileName = File(filePath).name fileName = File(filePath).name
binding.textFilename.text = fileName binding.textFilename.text = fileName
rotationAngle = originalOrientation rotationAngle = originalOrientation
@ -227,14 +197,6 @@ class ImageViewer: FileViewerActivity() {
Toast.makeText(this, R.string.slideshow_stopped, Toast.LENGTH_SHORT).show() 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() { class OrientationTransformation(private val orientation: Float): BitmapTransformation() {
lateinit var bitmap: Bitmap lateinit var bitmap: Bitmap
@ -255,7 +217,7 @@ class ImageViewer: FileViewerActivity() {
private fun rotateImage(){ private fun rotateImage(){
binding.imageViewer.restoreZoomNormal() binding.imageViewer.restoreZoomNormal()
orientationTransformation = OrientationTransformation(rotationAngle) 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){ private fun askSaveRotation(callback: () -> Unit){

View File

@ -59,12 +59,11 @@ abstract class MediaPlayer: FileViewerActivity() {
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
} }
} }
override fun onPositionDiscontinuity(reason: Int) {
if (player.currentMediaItemIndex != currentPlaylistIndex) { override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {
playlistNext(player.currentMediaItemIndex == (currentPlaylistIndex+1) % mappedPlaylist.size) playlistNext(player.currentMediaItemIndex == (currentPlaylistIndex+1) % mappedPlaylist.size)
refreshFileName() refreshFileName()
} }
}
}) })
player.prepare() player.prepare()
} }

View File

@ -7,6 +7,9 @@ import java.io.ByteArrayInputStream
import java.io.File import java.io.File
class PdfViewer: FileViewerActivity() { class PdfViewer: FileViewerActivity() {
init {
applyCustomTheme = false
}
private lateinit var pdfViewer: PdfViewer private lateinit var pdfViewer: PdfViewer
override fun hideSystemUi() { override fun hideSystemUi() {
@ -37,6 +40,11 @@ class PdfViewer: FileViewerActivity() {
pdfViewer.onResume() pdfViewer.onResume()
} }
override fun onDestroy() {
super.onDestroy()
pdfViewer.onDestroy()
}
override fun onPrepareOptionsMenu(menu: Menu?): Boolean { override fun onPrepareOptionsMenu(menu: Menu?): Boolean {
return pdfViewer.onPrepareOptionsMenu(menu) return pdfViewer.onPrepareOptionsMenu(menu)
} }

View File

@ -3,6 +3,7 @@ package sushi.hardcore.droidfs.file_viewers
import android.content.pm.ActivityInfo import android.content.pm.ActivityInfo
import android.content.res.Configuration import android.content.res.Configuration
import com.google.android.exoplayer2.ExoPlayer import com.google.android.exoplayer2.ExoPlayer
import com.google.android.exoplayer2.ui.StyledPlayerView
import sushi.hardcore.droidfs.databinding.ActivityVideoPlayerBinding import sushi.hardcore.droidfs.databinding.ActivityVideoPlayerBinding
class VideoPlayer: MediaPlayer() { class VideoPlayer: MediaPlayer() {
@ -16,9 +17,9 @@ class VideoPlayer: MediaPlayer() {
binding = ActivityVideoPlayerBinding.inflate(layoutInflater) binding = ActivityVideoPlayerBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
binding.videoPlayer.doubleTapOverlay = binding.doubleTapOverlay binding.videoPlayer.doubleTapOverlay = binding.doubleTapOverlay
binding.videoPlayer.setControllerVisibilityListener { visibility -> binding.videoPlayer.setControllerVisibilityListener(StyledPlayerView.ControllerVisibilityListener { visibility ->
binding.topBar.visibility = visibility binding.topBar.visibility = visibility
} })
binding.rotateButton.setOnClickListener { binding.rotateButton.setOnClickListener {
requestedOrientation = requestedOrientation =
if (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) { if (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {

View File

@ -185,7 +185,7 @@ object PathUtils {
return rootDirectory.delete() return rootDirectory.delete()
} }
fun safePickDirectory(directoryPicker: ActivityResultLauncher<Uri>, context: Context, themeValue: String) { fun safePickDirectory(directoryPicker: ActivityResultLauncher<Uri?>, context: Context, themeValue: String) {
try { try {
directoryPicker.launch(null) directoryPicker.launch(null)
} catch (e: ActivityNotFoundException) { } catch (e: ActivityNotFoundException) {

View File

@ -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_DEFAULT_SESSION_CONFIG;
import static androidx.camera.core.impl.UseCaseConfig.OPTION_SESSION_CONFIG_UNPACKER; 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_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_BIT_RATE;
import static androidx.camera.core.impl.VideoCaptureConfig.OPTION_AUDIO_CHANNEL_COUNT; import static androidx.camera.core.impl.VideoCaptureConfig.OPTION_AUDIO_CHANNEL_COUNT;
import static androidx.camera.core.impl.VideoCaptureConfig.OPTION_AUDIO_MIN_BUFFER_SIZE; import static androidx.camera.core.impl.VideoCaptureConfig.OPTION_AUDIO_MIN_BUFFER_SIZE;
@ -121,6 +122,7 @@ import java.util.concurrent.atomic.AtomicReference;
* @hide * @hide
*/ */
@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java @RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
@RestrictTo(Scope.LIBRARY_GROUP)
public final class VideoCapture extends UseCase { public final class VideoCapture extends UseCase {
//////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////
@ -1123,6 +1125,7 @@ public final class VideoCapture extends UseCase {
} }
/** Set audio record parameters by CamcorderProfile */ /** Set audio record parameters by CamcorderProfile */
@SuppressWarnings("deprecation")
private void setAudioParametersByCamcorderProfile(Size currentResolution, String cameraId) { private void setAudioParametersByCamcorderProfile(Size currentResolution, String cameraId) {
CamcorderProfile profile; CamcorderProfile profile;
boolean isCamcorderProfileFound = false; boolean isCamcorderProfileFound = false;
@ -1732,6 +1735,14 @@ public final class VideoCapture extends UseCase {
return this; return this;
} }
/** @hide */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
@Override
public Builder setZslDisabled(boolean disabled) {
getMutableConfig().insertOption(OPTION_ZSL_DISABLED, disabled);
return this;
}
} }
/** /**

View File

@ -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; package sushi.hardcore.droidfs.video_recording;
import android.annotation.SuppressLint;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.camera.core.impl.Config; import androidx.camera.core.impl.Config;
import androidx.camera.core.impl.ImageFormatConstants; import androidx.camera.core.impl.ImageFormatConstants;
import androidx.camera.core.impl.ImageOutputConfig; import androidx.camera.core.impl.ImageOutputConfig;
@ -15,7 +30,7 @@ import androidx.camera.core.internal.ThreadConfig;
* *
* <p>In the earlier stage, the VideoCapture is deprioritized. * <p>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 public final class VideoCaptureConfig
implements UseCaseConfig<VideoCapture>, implements UseCaseConfig<VideoCapture>,
ImageOutputConfig, ImageOutputConfig,

View File

@ -146,16 +146,16 @@ internal class CircleClipTapView(context: Context, attrs: AttributeSet): View(co
} }
addListener(object : Animator.AnimatorListener { addListener(object : Animator.AnimatorListener {
override fun onAnimationStart(animation: Animator?) { override fun onAnimationStart(animation: Animator) {
visibility = VISIBLE visibility = VISIBLE
} }
override fun onAnimationEnd(animation: Animator?) { override fun onAnimationEnd(animation: Animator) {
if (!forceReset) performAtEnd() if (!forceReset) performAtEnd()
} }
override fun onAnimationRepeat(animation: Animator?) {} override fun onAnimationRepeat(animation: Animator) {}
override fun onAnimationCancel(animation: Animator?) {} override fun onAnimationCancel(animation: Animator) {}
}) })
} }
} }

View File

@ -46,7 +46,7 @@ class DoubleTapPlayerView @JvmOverloads constructor(
return true return true
} }
override fun onSingleTapConfirmed(e: MotionEvent?): Boolean { override fun onSingleTapConfirmed(e: MotionEvent): Boolean {
if (!isDoubleTapping) if (!isDoubleTapping)
performClick() performClick()
return true return true

View File

@ -18,7 +18,7 @@ int write_packet(void* opaque, uint8_t* buff, int buff_size) {
JNIEnv *env; JNIEnv *env;
(*muxer->jvm)->GetEnv(muxer->jvm, (void **) &env, JNI_VERSION_1_6); (*muxer->jvm)->GetEnv(muxer->jvm, (void **) &env, JNI_VERSION_1_6);
jbyteArray jarray = (*env)->NewByteArray(env, buff_size); 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); (*env)->CallVoidMethod(env, muxer->thiz, muxer->write_packet_method_id, jarray, buff_size);
return 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); const AVCodec* encoder = avcodec_find_encoder(AV_CODEC_ID_AAC);
AVStream* stream = avformat_new_stream((AVFormatContext *) format_context, NULL); AVStream* stream = avformat_new_stream((AVFormatContext *) format_context, NULL);
AVCodecContext* codec_context = avcodec_alloc_context3(encoder); AVCodecContext* codec_context = avcodec_alloc_context3(encoder);
codec_context->channels = channel_count; av_channel_layout_default(&codec_context->ch_layout, channel_count);
codec_context->channel_layout = av_get_default_channel_layout(channel_count);
codec_context->sample_rate = sample_rate; codec_context->sample_rate = sample_rate;
codec_context->sample_fmt = encoder->sample_fmts[0]; codec_context->sample_fmt = encoder->sample_fmts[0];
codec_context->bit_rate = bitrate; codec_context->bit_rate = bitrate;
@ -105,8 +104,8 @@ Java_sushi_hardcore_droidfs_video_1recording_MediaMuxer_writePacket(JNIEnv *env,
r.den = 1000000; r.den = 1000000;
av_packet_rescale_ts(packet, r, ((AVFormatContext *)format_context)->streams[stream_index]->time_base); av_packet_rescale_ts(packet, r, ((AVFormatContext *)format_context)->streams[stream_index]->time_base);
} }
unsigned char* buff = malloc(size); uint8_t* buff = malloc(size);
(*env)->GetByteArrayRegion(env, buffer, 0, size, buff); (*env)->GetByteArrayRegion(env, buffer, 0, size, (signed char*)buff);
packet->data = buff; packet->data = buff;
if (is_key_frame) { if (is_key_frame) {
packet->flags = AV_PKT_FLAG_KEY; packet->flags = AV_PKT_FLAG_KEY;

View File

@ -5,7 +5,7 @@
android:layout_height="match_parent" android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".CameraActivity" tools:context=".CameraActivity"
android:background="#000000"> android:background="@color/fullScreenBackgroundColor">
<androidx.camera.view.PreviewView <androidx.camera.view.PreviewView
android:id="@+id/camera_preview" android:id="@+id/camera_preview"

View File

@ -248,4 +248,5 @@
<string name="file_op_delete_msg">Deleting files…</string> <string name="file_op_delete_msg">Deleting files…</string>
<string name="volume_type">(%s)</string> <string name="volume_type">(%s)</string>
<string name="volume_type_read_only">(%s, read-only)</string> <string name="volume_type_read_only">(%s, read-only)</string>
<string name="io_error">I/O Error.</string>
</resources> </resources>

View File

@ -1,12 +1,11 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript { buildscript {
ext.kotlin_version = "1.6.10" ext.kotlin_version = "1.7.10"
repositories { repositories {
google() google()
mavenCentral() mavenCentral()
} }
dependencies { 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" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
} }
} }

View File

@ -1,6 +1,6 @@
#Wed Sep 01 11:25:55 UTC 2021 #Wed Sep 01 11:25:55 UTC 2021
distributionBase=GRADLE_USER_HOME 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 distributionPath=wrapper/dists
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME

@ -1 +1 @@
Subproject commit 8fe8b2f4b3aecd3ad210478fd99df9f260503db8 Subproject commit 06e54dbb03098c0d0d113ed7b3fc93d74050f590