Auto gocryptfs cipher by default & Fix FileOperationsService notification permission request

This commit is contained in:
Matéo Duparc 2024-07-18 22:10:47 +02:00
parent bb49501403
commit 15f288be11
Signed by: hardcoresushi
GPG Key ID: AFE384344A45E13A
8 changed files with 47 additions and 72 deletions

View File

@ -116,7 +116,6 @@ dependencies {
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version" implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version" implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version"
implementation "androidx.sqlite:sqlite-ktx:2.4.0"
implementation "androidx.preference:preference-ktx:1.2.1" implementation "androidx.preference:preference-ktx:1.2.1"
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0" implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
implementation 'com.google.android.material:material:1.12.0' implementation 'com.google.android.material:material:1.12.0'
@ -128,14 +127,14 @@ dependencies {
implementation "androidx.media3:media3-ui:$media3_version" implementation "androidx.media3:media3-ui:$media3_version"
implementation "androidx.media3:media3-datasource:$media3_version" implementation "androidx.media3:media3-datasource:$media3_version"
implementation "androidx.concurrent:concurrent-futures:1.1.0"
def camerax_version = "1.3.3" def camerax_version = "1.3.3"
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"
implementation "androidx.camera:camera-extensions:$camerax_version" implementation "androidx.camera:camera-extensions:$camerax_version"
// dependencies needed by CameraX patch
implementation "androidx.concurrent:concurrent-futures:1.1.0"
def autoValueVersion = '1.10.4' def autoValueVersion = '1.10.4'
implementation "com.google.auto.value:auto-value-annotations:$autoValueVersion" implementation "com.google.auto.value:auto-value-annotations:$autoValueVersion"
annotationProcessor "com.google.auto.value:auto-value:$autoValueVersion" annotationProcessor "com.google.auto.value:auto-value:$autoValueVersion"

View File

@ -299,6 +299,7 @@ class MainActivity : BaseActivity(), VolumeAdapter.Listener {
selectedVolumePosition = volumeAdapter.selectedItems.elementAt(0) selectedVolumePosition = volumeAdapter.selectedItems.elementAt(0)
val volume = volumeAdapter.volumes[selectedVolumePosition!!] val volume = volumeAdapter.volumes[selectedVolumePosition!!]
if (volume.isHidden) { if (volume.isHidden) {
(application as VolumeManagerApp).isStartingExternalApp = true
PathUtils.safePickDirectory(pickDirectory, this, theme) PathUtils.safePickDirectory(pickDirectory, this, theme)
} else { } else {
val hiddenVolumeFile = File(VolumeData.getHiddenVolumeFullPath(filesDir.path, volume.shortName)) val hiddenVolumeFile = File(VolumeData.getHiddenVolumeFullPath(filesDir.path, volume.shortName))

View File

@ -175,9 +175,9 @@ class CreateVolumeFragment: Fragment() {
volumeFile.mkdirs() volumeFile.mkdirs()
val result = if (volumeTypes[binding.spinnerVolumeType.selectedItemPosition] == resources.getString(R.string.gocryptfs)) { val result = if (volumeTypes[binding.spinnerVolumeType.selectedItemPosition] == resources.getString(R.string.gocryptfs)) {
val xchacha = when (binding.spinnerCipher.selectedItemPosition) { val xchacha = when (binding.spinnerCipher.selectedItemPosition) {
0 -> 0 0 -> -1 // auto
1 -> 1 1 -> 0 // AES-GCM
else -> -1 else -> 1 // XChaCha20-Poly1305
} }
generateResult(GocryptfsVolume.createAndOpenVolume( generateResult(GocryptfsVolume.createAndOpenVolume(
volumePath, volumePath,

View File

@ -17,12 +17,13 @@ import android.os.Bundle
import android.os.IBinder import android.os.IBinder
import android.provider.Settings import android.provider.Settings
import android.util.Log import android.util.Log
import androidx.activity.result.ActivityResultLauncher
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import androidx.core.app.ServiceCompat import androidx.core.app.ServiceCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.documentfile.provider.DocumentFile import androidx.documentfile.provider.DocumentFile
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.Deferred import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -90,14 +91,27 @@ class FileOperationService : Service() {
*/ */
fun bind(activity: BaseActivity, onBound: (FileOperationService) -> Unit) { fun bind(activity: BaseActivity, onBound: (FileOperationService) -> Unit) {
val helper = AndroidUtils.NotificationPermissionHelper(activity) val helper = AndroidUtils.NotificationPermissionHelper(activity)
activity.bindService(Intent(activity, FileOperationService::class.java), object : ServiceConnection { lateinit var service: FileOperationService
val serviceConnection = object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, binder: IBinder) { override fun onServiceConnected(className: ComponentName, binder: IBinder) {
onBound((binder as FileOperationService.LocalBinder).getService().also { onBound((binder as FileOperationService.LocalBinder).getService().also {
it.notificationPermissionHelper = helper service = it
it.notificationPermissionHelpers.addLast(helper)
}) })
} }
override fun onServiceDisconnected(arg0: ComponentName) {} override fun onServiceDisconnected(arg0: ComponentName) {}
}, Context.BIND_AUTO_CREATE) }
activity.lifecycle.addObserver(object : DefaultLifecycleObserver {
override fun onDestroy(owner: LifecycleOwner) {
activity.unbindService(serviceConnection)
service.notificationPermissionHelpers.removeLast()
}
})
activity.bindService(
Intent(activity, FileOperationService::class.java),
serviceConnection,
Context.BIND_AUTO_CREATE
)
} }
} }
@ -105,7 +119,7 @@ class FileOperationService : Service() {
private val binder = LocalBinder() private val binder = LocalBinder()
private lateinit var volumeManger: VolumeManager private lateinit var volumeManger: VolumeManager
private var serviceScope = MainScope() private var serviceScope = MainScope()
private lateinit var notificationPermissionHelper: AndroidUtils.NotificationPermissionHelper<BaseActivity> private val notificationPermissionHelpers = ArrayDeque<AndroidUtils.NotificationPermissionHelper<BaseActivity>>(2)
private var askForNotificationPermission = true private var askForNotificationPermission = true
private lateinit var notificationManager: NotificationManagerCompat private lateinit var notificationManager: NotificationManagerCompat
private val notifications = HashMap<Int, NotificationCompat.Builder>() private val notifications = HashMap<Int, NotificationCompat.Builder>()
@ -293,25 +307,27 @@ class FileOperationService : Service() {
} }
pendingTask = task pendingTask = task
if (askForNotificationPermission) { if (askForNotificationPermission) {
notificationPermissionHelper.askAndRun { granted -> with (notificationPermissionHelpers.last()) {
if (granted) { askAndRun { granted ->
processPendingTask() if (granted) {
} else { processPendingTask()
CustomAlertDialogBuilder(notificationPermissionHelper.activity, notificationPermissionHelper.activity.theme) } else {
.setTitle(R.string.warning) CustomAlertDialogBuilder(activity, activity.theme)
.setMessage(R.string.notification_denied_msg) .setTitle(R.string.warning)
.setPositiveButton(R.string.settings) { _, _ -> .setMessage(R.string.notification_denied_msg)
(application as VolumeManagerApp).isStartingExternalApp = true .setPositiveButton(R.string.settings) { _, _ ->
notificationPermissionHelper.activity.startActivity( (application as VolumeManagerApp).isStartingExternalApp = true
Intent( activity.startActivity(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Intent(
Uri.fromParts("package", packageName, null) Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.fromParts("package", packageName, null)
)
) )
) }
} .setNegativeButton(R.string.later, null)
.setNegativeButton(R.string.later, null) .setOnDismissListener { processPendingTask() }
.setOnDismissListener { processPendingTask() } .show()
.show() }
} }
} }
askForNotificationPermission = false // only ask once per service instance askForNotificationPermission = false // only ask once per service instance

View File

@ -7,7 +7,6 @@ import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.os.Build import android.os.Build
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
@ -31,7 +30,7 @@ object AndroidUtils {
* *
* Must be initialized before [Activity.onCreate]. * Must be initialized before [Activity.onCreate].
*/ */
class NotificationPermissionHelper<A: AppCompatActivity>(val activity: A) { class NotificationPermissionHelper<out A: AppCompatActivity>(val activity: A) {
private var listener: ((Boolean) -> Unit)? = null private var listener: ((Boolean) -> Unit)? = null
private val launcher = activity.registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted -> private val launcher = activity.registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
listener?.invoke(granted) listener?.invoke(granted)

View File

@ -1,24 +1,4 @@
<resources> <resources>
<string-array name="gocryptfs_encryption_ciphers">
<item>AES-GCM</item>
<item>XChaCha20-Poly1305</item>
<item>@string/auto</item>
</string-array>
<string-array name="cryfs_encryption_ciphers">
<item>xchacha20-poly1305</item>
<item>aes-256-gcm</item>
<item>aes-128-gcm</item>
<item>twofish-256-gcm</item>
<item>twofish-128-gcm</item>
<item>serpent-256-gcm</item>
<item>serpent-128-gcm</item>
<item>cast-256-gcm</item>
<item>mars-448-gcm</item>
<item>mars-256-gcm</item>
<item>mars-128-gcm</item>
</string-array>
<string-array name="sort_orders_entries"> <string-array name="sort_orders_entries">
<item>اسم</item> <item>اسم</item>
<item>حجم</item> <item>حجم</item>

View File

@ -1,24 +1,4 @@
<resources> <resources>
<string-array name="gocryptfs_encryption_ciphers">
<item>AES-GCM</item>
<item>XChaCha20-Poly1305</item>
<item>@string/auto</item>
</string-array>
<string-array name="cryfs_encryption_ciphers">
<item>xchacha20-poly1305</item>
<item>aes-256-gcm</item>
<item>aes-128-gcm</item>
<item>twofish-256-gcm</item>
<item>twofish-128-gcm</item>
<item>serpent-256-gcm</item>
<item>serpent-128-gcm</item>
<item>cast-256-gcm</item>
<item>mars-448-gcm</item>
<item>mars-256-gcm</item>
<item>mars-128-gcm</item>
</string-array>
<string-array name="sort_orders_entries"> <string-array name="sort_orders_entries">
<item>Ad</item> <item>Ad</item>
<item>Boyut</item> <item>Boyut</item>

View File

@ -1,8 +1,8 @@
<resources> <resources>
<string-array name="gocryptfs_encryption_ciphers"> <string-array name="gocryptfs_encryption_ciphers">
<item>@string/auto</item>
<item>AES-GCM</item> <item>AES-GCM</item>
<item>XChaCha20-Poly1305</item> <item>XChaCha20-Poly1305</item>
<item>@string/auto</item>
</string-array> </string-array>
<string-array name="cryfs_encryption_ciphers"> <string-array name="cryfs_encryption_ciphers">