Adapt to write access at Android/data/sushi.hardcore.droidfs on SD cards

This commit is contained in:
Matéo Duparc 2021-10-19 15:54:38 +02:00
parent 6158b36c9f
commit e96d4724d3
Signed by untrusted user: hardcoresushi
GPG Key ID: 007F84120107191E
9 changed files with 98 additions and 121 deletions

View File

@ -1,6 +1,5 @@
package sushi.hardcore.droidfs package sushi.hardcore.droidfs
import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.text.Editable import android.text.Editable
@ -84,27 +83,6 @@ class ChangePasswordActivity : VolumeActionActivity() {
} }
} }
override fun onDirectoryPicked(uri: Uri) {
if (PathUtils.isTreeUriOnPrimaryStorage(uri)){
val path = PathUtils.getFullPathFromTreeUri(uri, this)
if (path != null){
editVolumePath.setText(path)
} else {
ColoredAlertDialogBuilder(this)
.setTitle(R.string.error)
.setMessage(R.string.path_from_uri_null_error_msg)
.setPositiveButton(R.string.ok, null)
.show()
}
} else {
ColoredAlertDialogBuilder(this)
.setTitle(R.string.warning)
.setMessage(R.string.change_pwd_on_sdcard_error_msg)
.setPositiveButton(R.string.ok, null)
.show()
}
}
fun checkVolumePathThenChangePassword() { fun checkVolumePathThenChangePassword() {
loadVolumePath { loadVolumePath {
val volumeFile = File(currentVolumePath) val volumeFile = File(currentVolumePath)
@ -115,11 +93,7 @@ class ChangePasswordActivity : VolumeActionActivity() {
.setPositiveButton(R.string.ok, null) .setPositiveButton(R.string.ok, null)
.show() .show()
} else if (!volumeFile.canWrite()){ } else if (!volumeFile.canWrite()){
ColoredAlertDialogBuilder(this) errorDirectoryNotWritable(R.string.change_pwd_cant_write_error_msg)
.setTitle(R.string.warning)
.setMessage(R.string.change_pwd_cant_write_error_msg)
.setPositiveButton(R.string.ok, null)
.show()
} else { } else {
changePassword() changePassword()
} }

View File

@ -1,7 +1,6 @@
package sushi.hardcore.droidfs package sushi.hardcore.droidfs
import android.content.Intent import android.content.Intent
import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
@ -9,7 +8,6 @@ import android.widget.*
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import sushi.hardcore.droidfs.databinding.ActivityCreateBinding import sushi.hardcore.droidfs.databinding.ActivityCreateBinding
import sushi.hardcore.droidfs.explorers.ExplorerActivity import sushi.hardcore.droidfs.explorers.ExplorerActivity
import sushi.hardcore.droidfs.util.PathUtils
import sushi.hardcore.droidfs.util.Wiper import sushi.hardcore.droidfs.util.Wiper
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
import java.io.File import java.io.File
@ -65,27 +63,6 @@ class CreateActivity : VolumeActionActivity() {
} }
} }
override fun onDirectoryPicked(uri: Uri) {
if (PathUtils.isTreeUriOnPrimaryStorage(uri)){
val path = PathUtils.getFullPathFromTreeUri(uri, this)
if (path != null){
editVolumePath.setText(path)
} else {
ColoredAlertDialogBuilder(this)
.setTitle(R.string.error)
.setMessage(R.string.path_from_uri_null_error_msg)
.setPositiveButton(R.string.ok, null)
.show()
}
} else {
ColoredAlertDialogBuilder(this)
.setTitle(R.string.warning)
.setMessage(R.string.create_on_sdcard_error_msg)
.setPositiveButton(R.string.ok, null)
.show()
}
}
fun createVolume() { fun createVolume() {
loadVolumePath { loadVolumePath {
val password = binding.editPassword.text.toString().toCharArray() val password = binding.editPassword.text.toString().toCharArray()
@ -93,21 +70,13 @@ class CreateActivity : VolumeActionActivity() {
if (!password.contentEquals(passwordConfirm)) { if (!password.contentEquals(passwordConfirm)) {
Toast.makeText(this, R.string.passwords_mismatch, Toast.LENGTH_SHORT).show() Toast.makeText(this, R.string.passwords_mismatch, Toast.LENGTH_SHORT).show()
} else { } else {
object: LoadingTask(this, R.string.loading_msg_create){
override fun doTask(activity: AppCompatActivity) {
val volumeFile = File(currentVolumePath) val volumeFile = File(currentVolumePath)
var goodDirectory = false var goodDirectory = false
if (!volumeFile.isDirectory) { if (!volumeFile.isDirectory) {
if (volumeFile.mkdirs()) { if (volumeFile.mkdirs()) {
goodDirectory = true goodDirectory = true
} else { } else {
stopTask { errorDirectoryNotWritable(R.string.create_cant_write_error_msg)
ColoredAlertDialogBuilder(activity)
.setTitle(R.string.warning)
.setMessage(R.string.create_cant_write_error_msg)
.setPositiveButton(R.string.ok, null)
.show()
}
} }
} else { } else {
val dirContent = volumeFile.list() val dirContent = volumeFile.list()
@ -116,22 +85,18 @@ class CreateActivity : VolumeActionActivity() {
if (volumeFile.canWrite()) { if (volumeFile.canWrite()) {
goodDirectory = true goodDirectory = true
} else { } else {
stopTask { errorDirectoryNotWritable(R.string.create_cant_write_error_msg)
ColoredAlertDialogBuilder(activity)
.setTitle(R.string.warning)
.setMessage(R.string.create_cant_write_error_msg)
.setPositiveButton(R.string.ok, null)
.show()
}
} }
} else { } else {
stopTaskWithToast(R.string.dir_not_empty) Toast.makeText(this, R.string.dir_not_empty, Toast.LENGTH_SHORT).show()
} }
} else { } else {
stopTaskWithToast(R.string.listdir_null_error_msg) Toast.makeText(this, R.string.listdir_null_error_msg, Toast.LENGTH_SHORT).show()
} }
} }
if (goodDirectory) { if (goodDirectory) {
object: LoadingTask(this, R.string.loading_msg_create){
override fun doTask(activity: AppCompatActivity) {
val xchacha = when (binding.spinnerXchacha.selectedItemPosition) { val xchacha = when (binding.spinnerXchacha.selectedItemPosition) {
0 -> 0 0 -> 0
1 -> 1 1 -> 1
@ -172,7 +137,6 @@ class CreateActivity : VolumeActionActivity() {
} }
} }
} }
}
override fun doFinally(activity: AppCompatActivity) { override fun doFinally(activity: AppCompatActivity) {
Arrays.fill(password, 0.toChar()) Arrays.fill(password, 0.toChar())
Arrays.fill(passwordConfirm, 0.toChar()) Arrays.fill(passwordConfirm, 0.toChar())
@ -181,6 +145,7 @@ class CreateActivity : VolumeActionActivity() {
} }
} }
} }
}
private fun startExplorer(){ private fun startExplorer(){
ColoredAlertDialogBuilder(this) ColoredAlertDialogBuilder(this)

View File

@ -1,13 +1,13 @@
package sushi.hardcore.droidfs package sushi.hardcore.droidfs
import android.content.Intent import android.content.Intent
import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.text.Editable import android.text.Editable
import android.text.TextWatcher import android.text.TextWatcher
import android.view.MenuItem import android.view.MenuItem
import android.widget.AdapterView.OnItemClickListener import android.widget.AdapterView.OnItemClickListener
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import sushi.hardcore.droidfs.adapters.SavedVolumesAdapter import sushi.hardcore.droidfs.adapters.SavedVolumesAdapter
import sushi.hardcore.droidfs.content_providers.RestrictedFileProvider import sushi.hardcore.droidfs.content_providers.RestrictedFileProvider
@ -112,19 +112,6 @@ class OpenActivity : VolumeActionActivity() {
isStartingActivity = true isStartingActivity = true
} }
override fun onDirectoryPicked(uri: Uri) {
val path = PathUtils.getFullPathFromTreeUri(uri, this)
if (path != null){
editVolumePath.setText(path)
} else {
ColoredAlertDialogBuilder(this)
.setTitle(R.string.error)
.setMessage(R.string.path_from_uri_null_error_msg)
.setPositiveButton(R.string.ok, null)
.show()
}
}
fun checkVolumePathThenOpen() { fun checkVolumePathThenOpen() {
loadVolumePath { loadVolumePath {
val volumeFile = File(currentVolumePath) val volumeFile = File(currentVolumePath)
@ -147,7 +134,12 @@ class OpenActivity : VolumeActionActivity() {
.setCancelable(false) .setCancelable(false)
.setPositiveButton(R.string.ok) { _, _ -> openVolume() } .setPositiveButton(R.string.ok) { _, _ -> openVolume() }
if (PathUtils.isPathOnExternalStorage(currentVolumeName, this)){ if (PathUtils.isPathOnExternalStorage(currentVolumeName, this)){
dialog.setMessage(R.string.open_on_sdcard_warning) dialog.setView(
layoutInflater.inflate(R.layout.dialog_sdcard_error, null).apply {
findViewById<TextView>(R.id.path).text = PathUtils.getPackageDataFolder(this@OpenActivity)
findViewById<TextView>(R.id.footer).text = getString(R.string.open_read_only)
}
)
} else { } else {
dialog.setMessage(R.string.open_cant_write_warning) dialog.setMessage(R.string.open_cant_write_warning)
} }

View File

@ -118,7 +118,18 @@ abstract class VolumeActionActivity : BaseActivity() {
} }
protected open fun onPickingDirectory() {} protected open fun onPickingDirectory() {}
protected abstract fun onDirectoryPicked(uri: Uri) protected fun onDirectoryPicked(uri: Uri) {
val path = PathUtils.getFullPathFromTreeUri(uri, this)
if (path != null) {
editVolumePath.setText(path)
} else {
ColoredAlertDialogBuilder(this)
.setTitle(R.string.error)
.setMessage(R.string.path_from_uri_null_error_msg)
.setPositiveButton(R.string.ok, null)
.show()
}
}
private fun safePickDirectory() { private fun safePickDirectory() {
try { try {
@ -368,4 +379,20 @@ abstract class VolumeActionActivity : BaseActivity() {
callback() callback()
} }
} }
fun errorDirectoryNotWritable(errorMsg: Int) {
val dialog = ColoredAlertDialogBuilder(this)
.setTitle(R.string.error)
.setPositiveButton(R.string.ok, null)
if (PathUtils.isPathOnExternalStorage(currentVolumePath, this)) {
dialog.setView(
layoutInflater.inflate(R.layout.dialog_sdcard_error, null).apply {
findViewById<TextView>(R.id.path).text = PathUtils.getPackageDataFolder(this@VolumeActionActivity)
}
)
} else {
dialog.setMessage(errorMsg)
}
dialog.show()
}
} }

View File

@ -94,19 +94,14 @@ object PathUtils {
) + " " + units[digitGroups] ) + " " + units[digitGroups]
} }
fun isTreeUriOnPrimaryStorage(treeUri: Uri): Boolean { fun getPackageDataFolder(context: Context): String {
val volumeId = getVolumeIdFromTreeUri(treeUri) return "Android/data/${context.packageName}/"
return if (volumeId != null) {
volumeId == PRIMARY_VOLUME_NAME || volumeId == "home" || volumeId == "downloads"
} else {
false
}
} }
private fun getExternalStoragePath(context: Context): List<String> { private fun getExternalStoragePath(context: Context): List<String> {
val externalPaths: MutableList<String> = ArrayList() val externalPaths: MutableList<String> = ArrayList()
ContextCompat.getExternalFilesDirs(context, null).forEach { ContextCompat.getExternalFilesDirs(context, null).forEach {
val rootPath = it.path.substring(0, it.path.indexOf(pathJoin("Android/data/", context.packageName, "files"))) val rootPath = it.path.substring(0, it.path.indexOf(getPackageDataFolder(context)+"files"))
if (!rootPath.endsWith("/0/")){ //not primary storage if (!rootPath.endsWith("/0/")){ //not primary storage
externalPaths.add(rootPath) externalPaths.add(rootPath)
} }

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingHorizontal="25dp"
android:paddingTop="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/sdcard_error_header"
android:textSize="16sp"/>
<TextView
android:id="@+id/path"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"
android:textStyle="bold"
android:layout_marginVertical="10dp"/>
<TextView
android:id="@+id/footer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/sdcard_error_footer"
android:textSize="16sp"/>
</LinearLayout>

View File

@ -159,12 +159,9 @@
<string name="timer_empty_error_msg">Por favor, digite um valor numérico</string> <string name="timer_empty_error_msg">Por favor, digite um valor numérico</string>
<string name="path_from_uri_null_error_msg">Falha ao carregar o local selecionado.</string> <string name="path_from_uri_null_error_msg">Falha ao carregar o local selecionado.</string>
<string name="create_cant_write_error_msg">DroidFS não pode salvar neste local. Por favor, tente algum outro.</string> <string name="create_cant_write_error_msg">DroidFS não pode salvar neste local. Por favor, tente algum outro.</string>
<string name="create_on_sdcard_error_msg">DroidFS não pode salvar em cartões SD externos, por favor selecione um local no armazenamento interno.</string>
<string name="open_on_sdcard_warning">DroidFS não pode salvar em cartões SD exteros. Abrindo o volume apenas com acesso de leitura.</string>
<string name="open_cant_write_warning">DroidFS não tem permissão para salvar neste local. Abrindo o volume apenas com acesso de leitura.</string> <string name="open_cant_write_warning">DroidFS não tem permissão para salvar neste local. Abrindo o volume apenas com acesso de leitura.</string>
<string name="open_cant_write_error_msg">DroidFS não tem permissão para salvar neste local. Por favor, tente outro volume.</string> <string name="open_cant_write_error_msg">DroidFS não tem permissão para salvar neste local. Por favor, tente outro volume.</string>
<string name="change_pwd_cant_write_error_msg">DroidFS não tem permissão para salvar neste local. Pode tentar mover o volume para um local com permissão de escrita.</string> <string name="change_pwd_cant_write_error_msg">DroidFS não tem permissão para salvar neste local. Pode tentar mover o volume para um local com permissão de escrita.</string>
<string name="change_pwd_on_sdcard_error_msg">DroidFS não pode salvar em cartões SD externos, por favor transfira o volume ao armazenamento interno.</string>
<string name="slideshow_stopped">Apresentação parou</string> <string name="slideshow_stopped">Apresentação parou</string>
<string name="slideshow_started">Apresentação começou</string> <string name="slideshow_started">Apresentação começou</string>
<string name="ask_save_img_rotated">A imagem foi alternada. Você deseja salvar estas mudanças e substituir a imagem original?</string> <string name="ask_save_img_rotated">A imagem foi alternada. Você deseja salvar estas mudanças e substituir a imagem original?</string>

View File

@ -156,12 +156,9 @@
<string name="timer_empty_error_msg">Введите числовое значение.</string> <string name="timer_empty_error_msg">Введите числовое значение.</string>
<string name="path_from_uri_null_error_msg">Невозможно получить выбранный путь.</string> <string name="path_from_uri_null_error_msg">Невозможно получить выбранный путь.</string>
<string name="create_cant_write_error_msg">DroidFS не имеет доступа на запись по этому пути. Попробуйте найти другое место.</string> <string name="create_cant_write_error_msg">DroidFS не имеет доступа на запись по этому пути. Попробуйте найти другое место.</string>
<string name="create_on_sdcard_error_msg">DroidFS не может записывать на съёмные SD-карты, выберите путь во внутренней памяти.</string>
<string name="open_on_sdcard_warning">DroidFS не может писать на съёмные SD-карты. Том открывается только для чтения.</string>
<string name="open_cant_write_warning">DroidFS не имеет доступа на запись по этому пути. Том открывается только для чтения.</string> <string name="open_cant_write_warning">DroidFS не имеет доступа на запись по этому пути. Том открывается только для чтения.</string>
<string name="open_cant_write_error_msg">DroidFS не имеет доступа на запись по этому пути. Попробуйте другой том.</string> <string name="open_cant_write_error_msg">DroidFS не имеет доступа на запись по этому пути. Попробуйте другой том.</string>
<string name="change_pwd_cant_write_error_msg">DroidFS не имеет доступа на запись по этому пути. Попробуйте переместить том в место, доступное для записи.</string> <string name="change_pwd_cant_write_error_msg">DroidFS не имеет доступа на запись по этому пути. Попробуйте переместить том в место, доступное для записи.</string>
<string name="change_pwd_on_sdcard_error_msg">DroidFS не может писать на съёмные SD-карты, переместите том во внутреннюю память.</string>
<string name="slideshow_stopped">Слайдшоу остановлено</string> <string name="slideshow_stopped">Слайдшоу остановлено</string>
<string name="slideshow_started">Слайдшоу началось</string> <string name="slideshow_started">Слайдшоу началось</string>
<string name="ask_save_img_rotated">Изображение было повёрнуто. Сохранить изменения и перезаписать исходное изображение?</string> <string name="ask_save_img_rotated">Изображение было повёрнуто. Сохранить изменения и перезаписать исходное изображение?</string>

View File

@ -162,12 +162,12 @@
<string name="timer_empty_error_msg">Please enter a numeric value</string> <string name="timer_empty_error_msg">Please enter a numeric value</string>
<string name="path_from_uri_null_error_msg">Failed to retrieve the selected path.</string> <string name="path_from_uri_null_error_msg">Failed to retrieve the selected path.</string>
<string name="create_cant_write_error_msg">DroidFS doesn\'t have write access to this path. Please try another location.</string> <string name="create_cant_write_error_msg">DroidFS doesn\'t have write access to this path. Please try another location.</string>
<string name="create_on_sdcard_error_msg">DroidFS can\'t write on removable SD cards, please select a path on internal storage.</string> <string name="open_read_only">Opening volume with read-only access.</string>
<string name="open_on_sdcard_warning">DroidFS can\'t write on removable SD cards. Opening volume with read-only access.</string>
<string name="open_cant_write_warning">DroidFS doesn\'t have write access to this path. Opening volume with read-only access.</string> <string name="open_cant_write_warning">DroidFS doesn\'t have write access to this path. Opening volume with read-only access.</string>
<string name="open_cant_write_error_msg">DroidFS doesn\'t have write access to this path. Please try another volume.</string> <string name="open_cant_write_error_msg">DroidFS doesn\'t have write access to this path. Please try another volume.</string>
<string name="sdcard_error_header">DroidFS can only write to removable SD cards under:</string>
<string name="sdcard_error_footer">Please use a subdirectory of this path or internal storage.</string>
<string name="change_pwd_cant_write_error_msg">DroidFS doesn\'t have write access to this path. You can try to move the volume to a writable location.</string> <string name="change_pwd_cant_write_error_msg">DroidFS doesn\'t have write access to this path. You can try to move the volume to a writable location.</string>
<string name="change_pwd_on_sdcard_error_msg">DroidFS can\'t write on removable SD cards, please move the volume to internal storage.</string>
<string name="slideshow_stopped">Slideshow stopped</string> <string name="slideshow_stopped">Slideshow stopped</string>
<string name="slideshow_started">Slideshow started</string> <string name="slideshow_started">Slideshow started</string>
<string name="ask_save_img_rotated">The image has been rotated. Do you want to save these changes and overwrite the original image ?</string> <string name="ask_save_img_rotated">The image has been rotated. Do you want to save these changes and overwrite the original image ?</string>