+ * If the user is running Android 6.0 (API level 23) or later, + * the user has to grant your app its permissions while they are running the app. + *
** Requests the WRITE_EXTERNAL_STORAGE permission. * If the permission has been denied previously, a SnackBar will prompt the user to grant the * permission, otherwise it is requested directly. + *
*/ private void requestReadExternalStoragePermission() { if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { // Should we show an explanation? - if (ActivityCompat.shouldShowRequestPermissionRationale(this, - Manifest.permission.WRITE_EXTERNAL_STORAGE)) { + if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { Snackbar.make(mLayout, R.string.permission_read_exteral_storage_rationale, @@ -603,6 +636,7 @@ public void onClick(View view) { } } + /** * Callback received when a permissions request has been completed. */ @@ -1648,8 +1682,7 @@ public void downloadFile(String dir, String fileName) { filePath); if (!txService.hasDownloadNotifProvider()) { - DownloadNotificationProvider provider = new DownloadNotificationProvider(txService.getDownloadTaskManager(), - txService); + DownloadNotificationProvider provider = new DownloadNotificationProvider(txService.getDownloadTaskManager(), txService); txService.saveDownloadNotifProvider(provider); } diff --git a/app/src/main/java/com/seafile/seadroid2/ui/adapter/GalleryAdapter.java b/app/src/main/java/com/seafile/seadroid2/ui/adapter/GalleryAdapter.java index fe66540bf..722e8935f 100644 --- a/app/src/main/java/com/seafile/seadroid2/ui/adapter/GalleryAdapter.java +++ b/app/src/main/java/com/seafile/seadroid2/ui/adapter/GalleryAdapter.java @@ -1,8 +1,6 @@ package com.seafile.seadroid2.ui.adapter; import android.graphics.Bitmap; -import androidx.annotation.Nullable; -import androidx.viewpager.widget.PagerAdapter; import android.util.DisplayMetrics; import android.view.LayoutInflater; import android.view.View; @@ -10,6 +8,9 @@ import android.widget.ImageView; import android.widget.ProgressBar; +import androidx.annotation.Nullable; +import androidx.viewpager.widget.PagerAdapter; + import com.bumptech.glide.load.DataSource; import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.load.engine.GlideException; diff --git a/app/src/main/java/com/seafile/seadroid2/ui/fragment/ReposFragment.java b/app/src/main/java/com/seafile/seadroid2/ui/fragment/ReposFragment.java index dfe0dad26..f2768e770 100644 --- a/app/src/main/java/com/seafile/seadroid2/ui/fragment/ReposFragment.java +++ b/app/src/main/java/com/seafile/seadroid2/ui/fragment/ReposFragment.java @@ -444,7 +444,6 @@ public void navToDirectory(boolean forceRefresh, boolean restorePosition) { if (nav.getDirPath().equals(BrowserActivity.ACTIONBAR_PARENT_PATH)) { mActivity.setUpButtonTitle(nav.getRepoName()); } else - mActivity.setUpButtonTitle(nav.getDirPath().substring( nav.getDirPath().lastIndexOf(BrowserActivity.ACTIONBAR_PARENT_PATH) + 1)); } @@ -477,7 +476,6 @@ public void startTimer() { isTimerStarted = true; Log.d(DEBUG_TAG, "timer started"); mTimer.postDelayed(new Runnable() { - @Override public void run() { if (mActivity == null) return; diff --git a/app/src/main/java/com/seafile/seadroid2/ui/fragment/SettingsFragment.java b/app/src/main/java/com/seafile/seadroid2/ui/fragment/SettingsFragment.java index 1a54d9b4b..02836c1f3 100644 --- a/app/src/main/java/com/seafile/seadroid2/ui/fragment/SettingsFragment.java +++ b/app/src/main/java/com/seafile/seadroid2/ui/fragment/SettingsFragment.java @@ -1,17 +1,22 @@ package com.seafile.seadroid2.ui.fragment; +import android.Manifest; import android.app.Activity; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.os.AsyncTask; +import android.os.Build; import android.os.Bundle; +import android.os.Environment; import android.preference.CheckBoxPreference; import android.preference.Preference; import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceCategory; import android.preference.PreferenceScreen; + import androidx.appcompat.app.AlertDialog; + import android.text.Html; import android.text.TextUtils; import android.util.Log; @@ -319,8 +324,7 @@ public boolean onPreferenceChange(Preference preference, Object newValue) { cFolderBackupCategory.removePreference(cBackupFolderState); SettingsManager.instance().saveFolderAutomaticBackup(false); } else { - - XXPermissions.with(getActivity()).permission(Permission.MANAGE_EXTERNAL_STORAGE).request(new OnPermissionCallback() { + XXPermissions.with(requireContext()).permission(Permission.MANAGE_EXTERNAL_STORAGE).request(new OnPermissionCallback() { @Override public void onGranted(List+ * " * < ? / : > convert to _ + *
+ * + * for example: + *+ * /a'"'a/b'*'b/c'<'c/d'>'d/e'?'e/f':'f/g'/'g/ + *
+ * convert to -> + *+ * /a_a/b_b/c_c/d_d/e_e/f_f/g_g/ + *
+ * + * and so on. + */ + public static String buildValidFilePathName(String fileName) { + + fileName = buildValidFatFilename(fileName); + fileName = buildValidExtFilename(fileName); + return fileName; + } + + + /** + * Check if given filename is valid for an ext4 filesystem. + */ + public static boolean isValidExtFilename(String name) { + return (name != null) && name.equals(buildValidExtFilename(name)); + } + + /** + * Mutate the given filename to make it valid for an ext4 filesystem, + * replacing any invalid characters with "_". + */ + public static String buildValidExtFilename(String name) { + if (TextUtils.isEmpty(name) || ".".equals(name) || "..".equals(name)) { + return "(invalid)"; + } + final StringBuilder res = new StringBuilder(name.length()); + for (int i = 0; i < name.length(); i++) { + final char c = name.charAt(i); + if (isValidExtFilenameChar(c)) { + res.append(c); + } else { + res.append('_'); + } + } + trimFilename(res, 255); + return res.toString(); + } + + private static boolean isValidExtFilenameChar(char c) { + switch (c) { + case '\0': + //case '/': + return false; + default: + return true; + } + } + + /** + * Check if given filename is valid for a FAT filesystem. + */ + public static boolean isValidFatFilename(String name) { + return (name != null) && name.equals(buildValidFatFilename(name)); + } + + /** + * Mutate the given filename to make it valid for a FAT filesystem, + * replacing any invalid characters with "_". + */ + public static String buildValidFatFilename(String name) { + if (TextUtils.isEmpty(name) || ".".equals(name) || "..".equals(name)) { + return "(invalid)"; + } + final StringBuilder res = new StringBuilder(name.length()); + for (int i = 0; i < name.length(); i++) { + final char c = name.charAt(i); + if (isValidFatFilenameChar(c)) { + res.append(c); + } else { + res.append('_'); + } + } + // Even though vfat allows 255 UCS-2 chars, we might eventually write to + // ext4 through a FUSE layer, so use that limit. + trimFilename(res, 255); + return res.toString(); + } + + private static boolean isValidFatFilenameChar(char c) { + if ((0x00 <= c && c <= 0x1f)) { + return false; + } + switch (c) { + case '"': + case '*': + //case '/': + case ':': + case '<': + case '>': + case '?': + case '\\': + case '|': + case 0x7F: + return false; + default: + return true; + } + } + + public static String trimFilename(String str, int maxBytes) { + final StringBuilder res = new StringBuilder(str); + trimFilename(res, maxBytes); + return res.toString(); + } + + private static void trimFilename(StringBuilder res, int maxBytes) { + byte[] raw = res.toString().getBytes(StandardCharsets.UTF_8); + if (raw.length > maxBytes) { + maxBytes -= 3; + while (raw.length > maxBytes) { + res.deleteCharAt(res.length() / 2); + raw = res.toString().getBytes(StandardCharsets.UTF_8); + } + res.insert(res.length() / 2, "..."); + } + } +} diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index fb7038663..b34a574f7 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -182,6 +182,7 @@%s
@@ -391,8 +392,8 @@ E-mail : support@seafile.com
https://github.com/haiwen/seadroid.git
%s
-
- Twitter: Seafile
- Email: support@seafile.com
-
https://github.com/haiwen/seadroid.git
-%s
+
+Twitter: Seafile
+Email: support@seafile.com
+
https://github.com/haiwen/seadroid.git
+京ICP备12015883号-10A
+