mirror of
				https://github.com/TeamNewPipe/NewPipe
				synced 2025-10-31 07:13:00 +00:00 
			
		
		
		
	Fix free storage space check for all APIs
See https://stackoverflow.com/q/31171838 See https://pubs.opengroup.org/onlinepubs/9699919799/functions/fstatvfs.html
This commit is contained in:
		| @@ -859,20 +859,19 @@ public class DownloadDialog extends DialogFragment | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         // Check for free memory space (for api 24 and up) | ||||
|         if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { | ||||
|             final long freeSpace = mainStorage.getFreeMemory(); | ||||
|             if (freeSpace <= size) { | ||||
|                 Toast.makeText(context, getString(R. | ||||
|                         string.error_insufficient_storage), Toast.LENGTH_LONG).show(); | ||||
|                 // move the user to storage setting tab | ||||
|                 final Intent storageSettingsIntent = new Intent(Settings. | ||||
|                         ACTION_INTERNAL_STORAGE_SETTINGS); | ||||
|                 if (storageSettingsIntent.resolveActivity(context.getPackageManager()) != null) { | ||||
|                     startActivity(storageSettingsIntent); | ||||
|                 } | ||||
|                 return; | ||||
|         // Check for free storage space | ||||
|         final long freeSpace = mainStorage.getFreeStorageSpace(); | ||||
|         if (freeSpace <= size) { | ||||
|             Toast.makeText(context, getString(R. | ||||
|                     string.error_insufficient_storage), Toast.LENGTH_LONG).show(); | ||||
|             // move the user to storage setting tab | ||||
|             final Intent storageSettingsIntent = new Intent(Settings. | ||||
|                     ACTION_INTERNAL_STORAGE_SETTINGS); | ||||
|             if (storageSettingsIntent.resolveActivity(context.getPackageManager()) | ||||
|                     != null) { | ||||
|                 startActivity(storageSettingsIntent); | ||||
|             } | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         // check for existing file with the same name | ||||
|   | ||||
| @@ -1,24 +1,29 @@ | ||||
| package org.schabi.newpipe.streams.io; | ||||
|  | ||||
| import static android.provider.DocumentsContract.Document.COLUMN_DISPLAY_NAME; | ||||
| import static android.provider.DocumentsContract.Root.COLUMN_DOCUMENT_ID; | ||||
| import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty; | ||||
|  | ||||
| import android.content.ContentResolver; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.database.Cursor; | ||||
| import android.net.Uri; | ||||
| import android.os.Build; | ||||
| import android.os.storage.StorageManager; | ||||
| import android.os.storage.StorageVolume; | ||||
| import android.os.ParcelFileDescriptor; | ||||
| import android.provider.DocumentsContract; | ||||
| import android.system.ErrnoException; | ||||
| import android.system.Os; | ||||
| import android.system.StructStatVfs; | ||||
| import android.util.Log; | ||||
|  | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.annotation.Nullable; | ||||
| import androidx.annotation.RequiresApi; | ||||
| import androidx.documentfile.provider.DocumentFile; | ||||
|  | ||||
| import org.schabi.newpipe.settings.NewPipeSettings; | ||||
| import org.schabi.newpipe.util.FilePickerActivityHelper; | ||||
|  | ||||
| import java.io.FileDescriptor; | ||||
| import java.io.IOException; | ||||
| import java.net.URI; | ||||
| import java.nio.file.Files; | ||||
| @@ -27,16 +32,9 @@ import java.nio.file.Paths; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collections; | ||||
| import java.util.List; | ||||
| import java.util.UUID; | ||||
| import java.util.stream.Collectors; | ||||
| import java.util.stream.Stream; | ||||
|  | ||||
| import static android.provider.DocumentsContract.Document.COLUMN_DISPLAY_NAME; | ||||
| import static android.provider.DocumentsContract.Root.COLUMN_DOCUMENT_ID; | ||||
| import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty; | ||||
|  | ||||
| import us.shandian.giga.util.Utility; | ||||
|  | ||||
| public class StoredDirectoryHelper { | ||||
|     private static final String TAG = StoredDirectoryHelper.class.getSimpleName(); | ||||
|     public static final int PERMISSION_FLAGS = Intent.FLAG_GRANT_READ_URI_PERMISSION | ||||
| @@ -45,6 +43,7 @@ public class StoredDirectoryHelper { | ||||
|     private Path ioTree; | ||||
|     private DocumentFile docTree; | ||||
|  | ||||
|     // will be `null` for non-SAF files, i.e. files that use `ioTree` | ||||
|     private Context context; | ||||
|  | ||||
|     private final String tag; | ||||
| @@ -176,41 +175,41 @@ public class StoredDirectoryHelper { | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Get free memory of the storage partition (root of the directory). | ||||
|      * @return amount of free memory in the volume of current directory (bytes) | ||||
|      * Get free memory of the storage partition this file belongs to (root of the directory). | ||||
|      * See <a href="https://stackoverflow.com/q/31171838">StackOverflow</a> and | ||||
|      * <a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/fstatvfs.html"> | ||||
|      *     {@code statvfs()} and {@code fstatvfs()} docs</a> | ||||
|      * | ||||
|      * @return amount of free memory in the volume of current directory (bytes), or {@link | ||||
|      * Long#MAX_VALUE} if an error occurred | ||||
|      */ | ||||
|     @RequiresApi(api = Build.VERSION_CODES.N)  // Necessary for `getStorageVolume()` | ||||
|     public long getFreeMemory() { | ||||
|         final Uri uri = getUri(); | ||||
|         final StorageManager storageManager = (StorageManager) context. | ||||
|                 getSystemService(Context.STORAGE_SERVICE); | ||||
|         final List<StorageVolume> volumes = storageManager.getStorageVolumes(); | ||||
|     public long getFreeStorageSpace() { | ||||
|         try { | ||||
|             final StructStatVfs stat; | ||||
|  | ||||
|         final String docId = DocumentsContract.getDocumentId(uri); | ||||
|         final String[] split = docId.split(":"); | ||||
|         if (split.length > 0) { | ||||
|             final String volumeId = split[0]; | ||||
|             if (ioTree != null) { | ||||
|                 // non-SAF file, use statvfs with the path directly (also, `context` would be null | ||||
|                 // for non-SAF files, so we wouldn't be able to call `getContentResolver` anyway) | ||||
|                 stat = Os.statvfs(ioTree.toString()); | ||||
|  | ||||
|             for (final StorageVolume volume : volumes) { | ||||
|                 // if the volume is an internal system volume | ||||
|                 if (volume.isPrimary() && volumeId.equalsIgnoreCase("primary")) { | ||||
|                     return Utility.getSystemFreeMemory(); | ||||
|                 } | ||||
|  | ||||
|                 // if the volume is a removable volume (normally an SD card) | ||||
|                 if (volume.isRemovable() && !volume.isPrimary()) { | ||||
|                     if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { | ||||
|                         try { | ||||
|                             final String sdCardUUID = volume.getUuid(); | ||||
|                             return storageManager.getAllocatableBytes(UUID.fromString(sdCardUUID)); | ||||
|                         } catch (final Exception e) { | ||||
|                             // do nothing | ||||
|                         } | ||||
|             } else { | ||||
|                 // SAF file, we can't get a path directly, so obtain a file descriptor first | ||||
|                 // and then use fstatvfs with the file descriptor | ||||
|                 try (ParcelFileDescriptor parcelFileDescriptor = | ||||
|                              context.getContentResolver().openFileDescriptor(getUri(), "r")) { | ||||
|                     if (parcelFileDescriptor == null) { | ||||
|                         return Long.MAX_VALUE; | ||||
|                     } | ||||
|                     final FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor(); | ||||
|                     stat = Os.fstatvfs(fileDescriptor); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             // this is the same formula used inside the FsStat class | ||||
|             return stat.f_bavail * stat.f_frsize; | ||||
|         } catch (final IOException | ErrnoException e) { | ||||
|             return Long.MAX_VALUE; | ||||
|         } | ||||
|         return Long.MAX_VALUE; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|   | ||||
| @@ -40,20 +40,6 @@ public class Utility { | ||||
|         UNKNOWN | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Get amount of free system's memory. | ||||
|      * @return free memory (bytes) | ||||
|      */ | ||||
|     public static long getSystemFreeMemory() { | ||||
|         try { | ||||
|             final StatFs statFs = new StatFs(Environment.getExternalStorageDirectory().getPath()); | ||||
|             return statFs.getAvailableBlocksLong() * statFs.getBlockSizeLong(); | ||||
|         } catch (final Exception e) { | ||||
|             // do nothing | ||||
|         } | ||||
|         return -1; | ||||
|     } | ||||
|  | ||||
|     public static String formatBytes(long bytes) { | ||||
|         Locale locale = Locale.getDefault(); | ||||
|         if (bytes < 1024) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Stypox
					Stypox