diff --git a/app/src/main/java/deltazero/amarok/PrefMgr.java b/app/src/main/java/deltazero/amarok/PrefMgr.java index 3d7f39ab..0b8f1cbe 100644 --- a/app/src/main/java/deltazero/amarok/PrefMgr.java +++ b/app/src/main/java/deltazero/amarok/PrefMgr.java @@ -52,6 +52,7 @@ public static SharedPreferences getPrefs() { public static final String FILE_HIDER_MODE = "fileHiderMode"; public static final String IS_ENABLE_AUTO_UPDATE = "isEnableAutoUpdate"; public static final String ENABLE_OBFUSCATE_FILE_HEADER = "enableObfuscateFileHeader"; + public static final String ENABLE_TRUNCATE_FILE_NAMES = "enableTruncateFileName"; public static final String ENABLE_OBFUSCATE_TEXT_FILE = "enableObfuscateTextFile"; public static final String ENABLE_OBFUSCATE_TEXT_FILE_ENHANCED = "enableObfuscateTextFileEnhanced"; public static final String ENABLE_QUICK_HIDE_SERVICE = "enableQuickHideService"; @@ -139,6 +140,15 @@ public static BaseFileHider getFileHider(Context context) { }; } + public static void setTruncate(boolean shouldTruncate) { + mPrefEditor.putBoolean(ENABLE_TRUNCATE_FILE_NAMES, shouldTruncate); + mPrefEditor.apply(); + } + + public static boolean getTruncate() { + return mPrefs.getBoolean(ENABLE_TRUNCATE_FILE_NAMES, false); + } + public static void setFileHiderMode(Class mode) { int modeCode; if (mode == NoneFileHider.class) diff --git a/app/src/main/java/deltazero/amarok/filehider/ObfuscateFileHider.java b/app/src/main/java/deltazero/amarok/filehider/ObfuscateFileHider.java index 7c654574..a1b5859d 100644 --- a/app/src/main/java/deltazero/amarok/filehider/ObfuscateFileHider.java +++ b/app/src/main/java/deltazero/amarok/filehider/ObfuscateFileHider.java @@ -20,6 +20,7 @@ import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; import java.util.Set; +import java.nio.charset.StandardCharsets; import deltazero.amarok.PrefMgr; import deltazero.amarok.utils.FileHiderUtil; @@ -28,6 +29,7 @@ public class ObfuscateFileHider extends BaseFileHider { private final static String TAG = "FileHider"; + private static final int MAX_FILENAME_LENGTH = 255; private final static int MAX_PROCESS_WHOLE_FILE_SIZE_KB = 10 * 1024; // In KB. private final static int MAX_PROCESS_ENHANCED_WHOLE_FILE_SIZE_KB = 30 * 1024; private final static int BASE64_TAG = Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING; @@ -104,7 +106,6 @@ public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) { endingMark = FILENAME_FULL_PROCESS_MARK; // Process filename - // TODO: 2023/1/9 Handle long filename that invalid to android after Base64 encode Path newPath = processFilename(path, method, endingMark); // Process file content @@ -148,52 +149,26 @@ public FileVisitResult postVisitDirectory(Path dir, IOException e) { */ @Nullable private Path processFilename(Path path, ProcessMethod method, String extraEndingMark) { - String filename = path.getFileName().toString(); - String newFilename = null; - Path newPath; - - boolean hasEncoded = FileHiderUtil.checkIsMarkInFilename(filename); - - if (method == HIDE) { - if (hasEncoded) { - Log.d(TAG, "Found encoded name: " + filename + ", skip..."); - return null; + String originalFilename = path.getFileName().toString(); + String encodedFilename = Base64.encodeToString(originalFilename.getBytes(StandardCharsets.UTF_8), Base64.URL_SAFE | Base64.NO_WRAP); + if (encodedFilename.length() > MAX_FILENAME_LENGTH) { + String truncatedFilename = encodedFilename.substring(0, MAX_FILENAME_LENGTH - extraEndingMark.length()) + extraEndingMark; + String fileExtension = ""; + int extIndex = originalFilename.lastIndexOf('.'); + if (extIndex > 0) { + fileExtension = originalFilename.substring(extIndex); } - newFilename = "." + Base64.encodeToString(filename.getBytes(UTF_8), BASE64_TAG) + extraEndingMark; - Log.d(TAG, "Encode: " + path + " -> " + newFilename); + Path parentDir = path.getParent(); + Path newPath = parentDir.resolve(truncatedFilename + fileExtension); - } else if (method == UNHIDE) { - if (!hasEncoded) { - Log.w(TAG, "Found not coded name: " + filename + ", skip..."); - return null; - } - - try { - newFilename = new String( - Base64.decode(FileHiderUtil.stripFilenameExtras(filename), BASE64_TAG), UTF_8 - ); - } catch (IllegalArgumentException e) { - Log.w(TAG, "Unable to decode: " + filename); - return null; - } - - Log.d(TAG, "Decode: " + path + " -> " + newFilename); - } - - // Try to rename. - - assert newFilename != null; - newPath = Paths.get(path.getParent().toString(), newFilename); - - boolean is_succeeded = path.toFile().renameTo(newPath.toFile()); - - if (!is_succeeded) { - Log.w(TAG, "Error when renaming file: " + path + " -> " + newPath); - return null; - } else { + Log.i(TAG, "Filename exceeded limit, truncated to: " + newPath); return newPath; } + + Path parentDir = path.getParent(); + Path newPath = parentDir.resolve(encodedFilename + extraEndingMark); + return newPath; } private void processFileHeader(Path path) { diff --git a/app/src/main/java/deltazero/amarok/ui/settings/ObfuscateFileHiderSettingsActivity.java b/app/src/main/java/deltazero/amarok/ui/settings/ObfuscateFileHiderSettingsActivity.java index f0a613ec..653d10f3 100644 --- a/app/src/main/java/deltazero/amarok/ui/settings/ObfuscateFileHiderSettingsActivity.java +++ b/app/src/main/java/deltazero/amarok/ui/settings/ObfuscateFileHiderSettingsActivity.java @@ -11,7 +11,7 @@ public class ObfuscateFileHiderSettingsActivity extends AmarokActivity { - private MaterialSwitch swObfuscateFileHeader, swObfuscateTextFile, swObfuscateTextFileEnhanced; + private MaterialSwitch swObfuscateFileHeader, swObfuscateTextFile, swObfuscateTextFileEnhanced, swTruncateFileNames; private MaterialToolbar tbToolBar; @Override @@ -22,6 +22,7 @@ protected void onCreate(Bundle savedInstanceState) { swObfuscateFileHeader = findViewById(R.id.switch_filehider_sw_obfuscate_header); swObfuscateTextFile = findViewById(R.id.switch_filehider_sw_obfuscate_text); swObfuscateTextFileEnhanced = findViewById(R.id.switch_filehider_sw_obfuscate_text_enhanced); + swTruncateFileNames = findViewById(R.id.filehider_truncate_long_names); tbToolBar = findViewById(R.id.switch_filehider_tb_toolbar); // Init UI @@ -44,6 +45,11 @@ protected void onCreate(Bundle savedInstanceState) { PrefMgr.setEnableObfuscateTextFileEnhanced(isChecked); updateUI(); }); + swTruncateFileNames.setOnCheckedChangeListener((buttonView, isChecked) -> { + PrefMgr.setTruncate(isChecked); + updateUI(); + }); + // Enable back button tbToolBar.setNavigationOnClickListener(v -> finish()); @@ -62,8 +68,9 @@ private void updateUI() { swObfuscateFileHeader.setChecked(PrefMgr.getEnableObfuscateFileHeader()); swObfuscateTextFile.setChecked(PrefMgr.getEnableObfuscateTextFile()); swObfuscateTextFileEnhanced.setChecked(PrefMgr.getEnableObfuscateTextFileEnhanced()); + swTruncateFileNames.setChecked(PrefMgr.getTruncate()); swObfuscateTextFile.setEnabled(PrefMgr.getEnableObfuscateFileHeader()); swObfuscateTextFileEnhanced.setEnabled(PrefMgr.getEnableObfuscateFileHeader() && PrefMgr.getEnableObfuscateTextFile()); } -} \ No newline at end of file +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 37e25d04..78afecd4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -162,6 +162,7 @@ Change file permissions to make them unreadable. Root access required. The procedure is immediate. NoMedia Mode Simply adds .nomedia to folders. No root access required. + Truncates overly long file names for better filesystem compatibility. No root access required. Welcome Amarok is a free and freedom tool for hiding private files & applications.\n\nPlease note that Amarok is not an encryption software, but rather a tool for hiding things. We strongly advise against using Amarok to protect confidential files and applications.\n\nDisclaimers: Amarok is provided without any warranties or conditions. The user is fully responsible for any harm or consequences that may arise from using Amarok. WARNING