mirror of
https://github.com/WinampDesktop/winamp.git
synced 2025-05-12 02:45:41 -04:00
Android: Fall back to native paths on <9
Apparently some of these devices have broken scoped storage?
This commit is contained in:
parent
2fe1f3c2f7
commit
6f38e171b2
@ -1,15 +1,21 @@
|
|||||||
package com.github.stenzek.duckstation;
|
package com.github.stenzek.duckstation;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.annotation.TargetApi;
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.ImageDecoder;
|
import android.graphics.ImageDecoder;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
|
import android.os.storage.StorageManager;
|
||||||
import android.provider.DocumentsContract;
|
import android.provider.DocumentsContract;
|
||||||
import android.provider.MediaStore;
|
import android.provider.MediaStore;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
@ -17,6 +23,8 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.lang.reflect.Array;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -463,6 +471,127 @@ public class FileHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final String PRIMARY_VOLUME_NAME = "primary";
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static String getFullPathFromTreeUri(@Nullable final Uri treeUri, Context con) {
|
||||||
|
if (treeUri == null) return null;
|
||||||
|
String volumePath = getVolumePath(getVolumeIdFromTreeUri(treeUri), con);
|
||||||
|
if (volumePath == null) return File.separator;
|
||||||
|
if (volumePath.endsWith(File.separator))
|
||||||
|
volumePath = volumePath.substring(0, volumePath.length() - 1);
|
||||||
|
|
||||||
|
String documentPath = getDocumentPathFromTreeUri(treeUri);
|
||||||
|
if (documentPath.endsWith(File.separator))
|
||||||
|
documentPath = documentPath.substring(0, documentPath.length() - 1);
|
||||||
|
|
||||||
|
if (documentPath.length() > 0) {
|
||||||
|
if (documentPath.startsWith(File.separator))
|
||||||
|
return volumePath + documentPath;
|
||||||
|
else
|
||||||
|
return volumePath + File.separator + documentPath;
|
||||||
|
} else return volumePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("ObsoleteSdkInt")
|
||||||
|
private static String getVolumePath(final String volumeId, Context context) {
|
||||||
|
if (volumeId == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return null;
|
||||||
|
try {
|
||||||
|
StorageManager mStorageManager =
|
||||||
|
(StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
|
||||||
|
Class<?> storageVolumeClazz = Class.forName("android.os.storage.StorageVolume");
|
||||||
|
Method getVolumeList = mStorageManager.getClass().getMethod("getVolumeList");
|
||||||
|
Method getUuid = storageVolumeClazz.getMethod("getUuid");
|
||||||
|
Method getPath = storageVolumeClazz.getMethod("getPath");
|
||||||
|
Method isPrimary = storageVolumeClazz.getMethod("isPrimary");
|
||||||
|
Object result = getVolumeList.invoke(mStorageManager);
|
||||||
|
|
||||||
|
final int length = Array.getLength(result);
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
Object storageVolumeElement = Array.get(result, i);
|
||||||
|
String uuid = (String) getUuid.invoke(storageVolumeElement);
|
||||||
|
Boolean primary = (Boolean) isPrimary.invoke(storageVolumeElement);
|
||||||
|
|
||||||
|
// primary volume?
|
||||||
|
if (primary && PRIMARY_VOLUME_NAME.equals(volumeId))
|
||||||
|
return (String) getPath.invoke(storageVolumeElement);
|
||||||
|
|
||||||
|
// other volumes?
|
||||||
|
if (uuid != null && uuid.equals(volumeId))
|
||||||
|
return (String) getPath.invoke(storageVolumeElement);
|
||||||
|
}
|
||||||
|
// not found.
|
||||||
|
return null;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||||
|
private static String getVolumeIdFromTreeUri(final Uri treeUri) {
|
||||||
|
final String docId = DocumentsContract.getTreeDocumentId(treeUri);
|
||||||
|
final String[] split = docId.split(":");
|
||||||
|
if (split.length > 0) return split[0];
|
||||||
|
else return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||||
|
private static String getDocumentPathFromTreeUri(final Uri treeUri) {
|
||||||
|
final String docId = DocumentsContract.getTreeDocumentId(treeUri);
|
||||||
|
final String[] split = docId.split(":");
|
||||||
|
if ((split.length >= 2) && (split[1] != null)) return split[1];
|
||||||
|
else return File.separator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static String getFullPathFromUri(@Nullable final Uri treeUri, Context con) {
|
||||||
|
if (treeUri == null) return null;
|
||||||
|
String volumePath = getVolumePath(getVolumeIdFromUri(treeUri), con);
|
||||||
|
if (volumePath == null) return File.separator;
|
||||||
|
if (volumePath.endsWith(File.separator))
|
||||||
|
volumePath = volumePath.substring(0, volumePath.length() - 1);
|
||||||
|
|
||||||
|
String documentPath = getDocumentPathFromUri(treeUri);
|
||||||
|
if (documentPath.endsWith(File.separator))
|
||||||
|
documentPath = documentPath.substring(0, documentPath.length() - 1);
|
||||||
|
|
||||||
|
if (documentPath.length() > 0) {
|
||||||
|
if (documentPath.startsWith(File.separator))
|
||||||
|
return volumePath + documentPath;
|
||||||
|
else
|
||||||
|
return volumePath + File.separator + documentPath;
|
||||||
|
} else return volumePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||||
|
private static String getVolumeIdFromUri(final Uri treeUri) {
|
||||||
|
try {
|
||||||
|
final String docId = DocumentsContract.getDocumentId(treeUri);
|
||||||
|
final String[] split = docId.split(":");
|
||||||
|
if (split.length > 0) return split[0];
|
||||||
|
else return null;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||||
|
private static String getDocumentPathFromUri(final Uri treeUri) {
|
||||||
|
try {
|
||||||
|
final String docId = DocumentsContract.getDocumentId(treeUri);
|
||||||
|
final String[] split = docId.split(":");
|
||||||
|
if ((split.length >= 2) && (split[1] != null)) return split[1];
|
||||||
|
else return File.separator;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Java class containing the data for a file in a find operation.
|
* Java class containing the data for a file in a find operation.
|
||||||
*/
|
*/
|
||||||
|
@ -7,6 +7,7 @@ import android.content.Intent;
|
|||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.FileUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Property;
|
import android.util.Property;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
@ -291,6 +292,17 @@ public class GameDirectoriesActivity extends AppCompatActivity {
|
|||||||
if (resultCode != RESULT_OK || data.getData() == null)
|
if (resultCode != RESULT_OK || data.getData() == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Use legacy storage on devices older than Android 9... apparently some of them
|
||||||
|
// have broken storage access framework....
|
||||||
|
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.P) {
|
||||||
|
final String path = FileHelper.getFullPathFromTreeUri(data.getData(), this);
|
||||||
|
if (path != null) {
|
||||||
|
addSearchDirectory(this, path, true);
|
||||||
|
mDirectoryListAdapter.reload();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
getContentResolver().takePersistableUriPermission(data.getData(),
|
getContentResolver().takePersistableUriPermission(data.getData(),
|
||||||
Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||||
|
@ -272,6 +272,17 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
if (resultCode != RESULT_OK || data.getData() == null)
|
if (resultCode != RESULT_OK || data.getData() == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Use legacy storage on devices older than Android 9... apparently some of them
|
||||||
|
// have broken storage access framework....
|
||||||
|
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.P) {
|
||||||
|
final String path = FileHelper.getFullPathFromTreeUri(data.getData(), this);
|
||||||
|
if (path != null) {
|
||||||
|
GameDirectoriesActivity.addSearchDirectory(this, path, true);
|
||||||
|
mGameList.refresh(false, false, this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
getContentResolver().takePersistableUriPermission(data.getData(),
|
getContentResolver().takePersistableUriPermission(data.getData(),
|
||||||
Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user