diff --git a/android/src/org/ppsspp/ppsspp/PpssppActivity.java b/android/src/org/ppsspp/ppsspp/PpssppActivity.java index fc68e78d9f26..b72bb1617838 100644 --- a/android/src/org/ppsspp/ppsspp/PpssppActivity.java +++ b/android/src/org/ppsspp/ppsspp/PpssppActivity.java @@ -16,10 +16,8 @@ import android.content.ContentResolver; import android.database.Cursor; import android.provider.DocumentsContract; -import android.os.Environment; import androidx.documentfile.provider.DocumentFile; -import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Locale; import java.util.UUID; @@ -44,7 +42,6 @@ public class PpssppActivity extends NativeActivity { private static final int STORAGE_ERROR_DISK_FULL = -3; private static final int STORAGE_ERROR_ALREADY_EXISTS = -4; - @SuppressWarnings("deprecation") public static void CheckABIAndLoadLibrary() { if (Build.CPU_ABI.equals("armeabi")) { m_hasUnsupportedABI = true; @@ -53,7 +50,7 @@ public static void CheckABIAndLoadLibrary() { System.loadLibrary("ppsspp_jni"); libraryLoaded = true; } catch (UnsatisfiedLinkError e) { - Log.e(TAG, "LoadLibrary failed, UnsatifiedLinkError: " + e.toString()); + Log.e(TAG, "LoadLibrary failed, UnsatifiedLinkError: " + e); m_hasNoNativeBinary = true; } } @@ -79,7 +76,6 @@ public PpssppActivity() { public void onCreate(Bundle savedInstanceState) { if (m_hasUnsupportedABI || m_hasNoNativeBinary) { new Thread() { - @SuppressWarnings("deprecation") @Override public void run() { Looper.prepare(); @@ -162,7 +158,7 @@ public int openContentUri(String uriString, String mode) { } return filePfd.detachFd(); // Take ownership of the fd. } catch (Exception e) { - Log.e(TAG, "openContentUri exception: " + e.toString()); + Log.e(TAG, "openContentUri exception: " + e); return -1; } } @@ -175,6 +171,7 @@ public int openContentUri(String uriString, String mode) { DocumentsContract.Document.COLUMN_LAST_MODIFIED }; + @TargetApi(Build.VERSION_CODES.KITKAT) private String cursorToString(Cursor c) { final int flags = c.getInt(2); // Filter out any virtual or partial nonsense. @@ -197,6 +194,7 @@ private String cursorToString(Cursor c) { return str + size + "|" + documentName + "|" + lastModified; } + @TargetApi(Build.VERSION_CODES.LOLLIPOP) private long directorySizeRecursion(Uri uri) { Cursor c = null; try { @@ -214,7 +212,7 @@ private long directorySizeRecursion(Uri uri) { // Buffer the URIs so we only have one cursor active at once. I don't trust the storage framework // to handle more than one... - ArrayList childDirs = new ArrayList(); + ArrayList childDirs = new ArrayList<>(); while (c.moveToNext()) { final String mimeType = c.getString(2); @@ -249,6 +247,7 @@ private long directorySizeRecursion(Uri uri) { } } + @TargetApi(Build.VERSION_CODES.LOLLIPOP) public long computeRecursiveDirectorySize(String uriString) { try { Uri uri = Uri.parse(uriString); @@ -256,14 +255,16 @@ public long computeRecursiveDirectorySize(String uriString) { return totalSize; } catch (Exception e) { - Log.e(TAG, "computeRecursiveSize exception: " + e.toString()); + Log.e(TAG, "computeRecursiveSize exception: " + e); return -1; } } // TODO: Maybe add a cheaper version that doesn't extract all the file information? // TODO: Replace with a proper query: - // * https://stackoverflow.com/questions/42186820/documentfile-is-very-slow + // * https://stackoverflow.com/q + // uestions/42186820/documentfile-is-very-slow + @TargetApi(Build.VERSION_CODES.LOLLIPOP) public String[] listContentUriDir(String uriString) { Cursor c = null; try { @@ -273,6 +274,9 @@ public String[] listContentUriDir(String uriString) { uri, DocumentsContract.getDocumentId(uri)); final ArrayList listing = new ArrayList<>(); c = resolver.query(childrenUri, columns, null, null, null); + if (c == null) { + return new String[]{ "X" }; + } while (c.moveToNext()) { String str = cursorToString(c); if (str != null) { @@ -287,7 +291,7 @@ public String[] listContentUriDir(String uriString) { // a FileNotFoundException if the directory doesn't exist. return new String[]{ "X" }; } catch (Exception e) { - Log.e(TAG, "listContentUriDir exception: " + e.toString()); + Log.e(TAG, "listContentUriDir exception: " + e); return new String[]{ "X" }; } finally { if (c != null) { @@ -308,7 +312,7 @@ public int contentUriCreateDirectory(String rootTreeUri, String dirName) { return STORAGE_ERROR_UNKNOWN; } } catch (Exception e) { - Log.e(TAG, "contentUriCreateDirectory exception: " + e.toString()); + Log.e(TAG, "contentUriCreateDirectory exception: " + e); return STORAGE_ERROR_UNKNOWN; } } @@ -322,11 +326,11 @@ public int contentUriCreateFile(String rootTreeUri, String fileName) { DocumentFile createdFile = documentFile.createFile("application/octet-stream", fileName); return createdFile != null ? STORAGE_ERROR_SUCCESS : STORAGE_ERROR_UNKNOWN; } else { - Log.e(TAG, "contentUriCreateFile: fromTreeUri returned null"); + Log.e(TAG, "contentUriCreateFile: fromTreeUrisv returned null"); return STORAGE_ERROR_UNKNOWN; } } catch (Exception e) { - Log.e(TAG, "contentUriCreateFile exception: " + e.toString()); + Log.e(TAG, "contentUriCreateFile exception: " + e); return STORAGE_ERROR_UNKNOWN; } } @@ -341,26 +345,28 @@ public int contentUriRemoveFile(String fileName) { return STORAGE_ERROR_UNKNOWN; } } catch (Exception e) { - Log.e(TAG, "contentUriRemoveFile exception: " + e.toString()); + Log.e(TAG, "contentUriRemoveFile exception: " + e); return STORAGE_ERROR_UNKNOWN; } } // NOTE: The destination is the parent directory! This means that contentUriCopyFile // cannot rename things as part of the operation. + @TargetApi(Build.VERSION_CODES.N) public int contentUriCopyFile(String srcFileUri, String dstParentDirUri) { try { Uri srcUri = Uri.parse(srcFileUri); Uri dstParentUri = Uri.parse(dstParentDirUri); return DocumentsContract.copyDocument(getContentResolver(), srcUri, dstParentUri) != null ? STORAGE_ERROR_SUCCESS : STORAGE_ERROR_UNKNOWN; } catch (Exception e) { - Log.e(TAG, "contentUriCopyFile exception: " + e.toString()); + Log.e(TAG, "contentUriCopyFile exception: " + e); return STORAGE_ERROR_UNKNOWN; } } // NOTE: The destination is the parent directory! This means that contentUriCopyFile // cannot rename things as part of the operation. + @TargetApi(Build.VERSION_CODES.N_MR1) public int contentUriMoveFile(String srcFileUri, String srcParentDirUri, String dstParentDirUri) { try { Uri srcUri = Uri.parse(srcFileUri); @@ -368,11 +374,12 @@ public int contentUriMoveFile(String srcFileUri, String srcParentDirUri, String Uri dstParentUri = Uri.parse(dstParentDirUri); return DocumentsContract.moveDocument(getContentResolver(), srcUri, srcParentUri, dstParentUri) != null ? STORAGE_ERROR_SUCCESS : STORAGE_ERROR_UNKNOWN; } catch (Exception e) { - Log.e(TAG, "contentUriMoveFile exception: " + e.toString()); + Log.e(TAG, "contentUriMoveFile exception: " + e); return STORAGE_ERROR_UNKNOWN; } } + @TargetApi(Build.VERSION_CODES.LOLLIPOP) public int contentUriRenameFileTo(String fileUri, String newName) { try { Uri uri = Uri.parse(fileUri); @@ -380,10 +387,11 @@ public int contentUriRenameFileTo(String fileUri, String newName) { // Instead we use the DocumentsContract API directly. // See https://stackoverflow.com/questions/37168200/android-5-0-new-sd-card-access-api-documentfile-renameto-unsupportedoperation. Uri newUri = DocumentsContract.renameDocument(getContentResolver(), uri, newName); + // NOTE: we don't use the returned newUri for anything right now. return STORAGE_ERROR_SUCCESS; } catch (Exception e) { // TODO: More detailed exception processing. - Log.e(TAG, "contentUriRenameFile exception: " + e.toString()); + Log.e(TAG, "contentUriRenameFile exception: " + e); return STORAGE_ERROR_UNKNOWN; } } @@ -391,7 +399,9 @@ public int contentUriRenameFileTo(String fileUri, String newName) { private static void closeQuietly(AutoCloseable closeable) { if (closeable != null) { try { - closeable.close(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + closeable.close(); + } } catch (RuntimeException rethrown) { throw rethrown; } catch (Exception ignored) { @@ -401,17 +411,26 @@ private static void closeQuietly(AutoCloseable closeable) { // Probably slightly faster than contentUriGetFileInfo. // Smaller difference now than before I changed that one to a query... + @TargetApi(Build.VERSION_CODES.KITKAT) public boolean contentUriFileExists(String fileUri) { Cursor c = null; try { Uri uri = Uri.parse(fileUri); c = getContentResolver().query(uri, new String[] { DocumentsContract.Document.COLUMN_DOCUMENT_ID }, null, null, null); - return c.getCount() > 0; + if (c != null) { + return c.getCount() > 0; + } else { + return false; + } } catch (Exception e) { // Log.w(TAG, "Failed query: " + e); return false; } finally { - closeQuietly(c); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + closeQuietly(c); + } else if (c != null) { + c.close(); + } } } @@ -421,14 +440,13 @@ public String contentUriGetFileInfo(String fileName) { Uri uri = Uri.parse(fileName); final ContentResolver resolver = getContentResolver(); c = resolver.query(uri, columns, null, null, null); - if (c.moveToNext()) { - String str = cursorToString(c); - return str; + if (c != null && c.moveToNext()) { + return cursorToString(c); } else { return null; } } catch (Exception e) { - Log.e(TAG, "contentUriGetFileInfo exception: " + e.toString()); + Log.e(TAG, "contentUriGetFileInfo exception: " + e); return null; } finally { if (c != null) { @@ -440,11 +458,11 @@ public String contentUriGetFileInfo(String fileName) { // The example in Android documentation uses this.getFilesDir for path. // There's also a way to beg the OS for more space, which might clear caches, but // let's just not bother with that for now. + @TargetApi(Build.VERSION_CODES.M) + public long contentUriGetFreeStorageSpace(String fileName) { try { Uri uri = Uri.parse(fileName); - StorageManager storageManager = getApplicationContext().getSystemService(StorageManager.class); - ParcelFileDescriptor pfd = getContentResolver().openFileDescriptor(uri, "r"); if (pfd == null) { Log.w(TAG, "Failed to get free storage space from URI: " + fileName); @@ -457,20 +475,19 @@ public long contentUriGetFreeStorageSpace(String fileName) { } catch (Exception e) { // FileNotFoundException | ErrnoException e // Log.getStackTraceString(e) - Log.e(TAG, "contentUriGetFreeStorageSpace exception: " + e.toString()); + Log.e(TAG, "contentUriGetFreeStorageSpace exception: " + e); return -1; } } - + @TargetApi(Build.VERSION_CODES.O) public long filePathGetFreeStorageSpace(String filePath) { try { StorageManager storageManager = getApplicationContext().getSystemService(StorageManager.class); File file = new File(filePath); UUID volumeUUID = storageManager.getUuidForPath(file); - long availableBytes = storageManager.getAllocatableBytes(volumeUUID); - return availableBytes; + return storageManager.getAllocatableBytes(volumeUUID); } catch (Exception e) { - Log.e(TAG, "filePathGetFreeStorageSpace exception: " + e.toString()); + Log.e(TAG, "filePathGetFreeStorageSpace exception: " + e); return -1; } }