фон
Начиная с Lollipop, приложения могут получить доступ к реальным SD-картам (после того, как они были недоступны в Kitkat и официально не поддерживались в предыдущих версиях), как я спросил о .
Проблема
Поскольку стало довольно редко видеть устройство Lollipop, поддерживающее SD-карту, и потому что эмулятор действительно не обладает способностью (или не так ли?), чтобы эмулировать поддержку SD-карты, мне потребовалось довольно много времени чтобы проверить его.
В любом случае кажется, что вместо обычного класса File для доступа к SD-карте (после получения разрешения для него) вам нужно использовать Uris для него, используя DocumentFile.
Это ограничивает доступ к обычным путям, поскольку я не могу найти способ конвертировать Uris в пути и наоборот (плюс это довольно раздражает). Это также означает, что я не знаю, как проверить, доступны ли текущие SD-карты, поэтому я не знаю, когда спросить у пользователя разрешение на чтение/запись на него (или на них).
Что я пробовал
В настоящее время я получаю пути ко всем SD-картам:
/**
* returns a list of all available sd cards paths, or null if not found.
*
* @param includePrimaryExternalStorage set to true if you wish to also include the path of the primary external storage
*/
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static List<String> getExternalStoragePaths(final Context context,final boolean includePrimaryExternalStorage)
{
final File primaryExternalStorageDirectory=Environment.getExternalStorageDirectory();
final List<String> result=new ArrayList<>();
final File[] externalCacheDirs=ContextCompat.getExternalCacheDirs(context);
if(externalCacheDirs==null||externalCacheDirs.length==0)
return result;
if(externalCacheDirs.length==1)
{
if(externalCacheDirs[0]==null)
return result;
final String storageState=EnvironmentCompat.getStorageState(externalCacheDirs[0]);
if(!Environment.MEDIA_MOUNTED.equals(storageState))
return result;
if(!includePrimaryExternalStorage&&VERSION.SDK_INT>=VERSION_CODES.HONEYCOMB&&Environment.isExternalStorageEmulated())
return result;
}
if(includePrimaryExternalStorage||externalCacheDirs.length==1)
{
if(primaryExternalStorageDirectory!=null)
result.add(primaryExternalStorageDirectory.getAbsolutePath());
else
result.add(getRootOfInnerSdCardFolder(externalCacheDirs[0]));
}
for(int i=1;i<externalCacheDirs.length;++i)
{
final File file=externalCacheDirs[i];
if(file==null)
continue;
final String storageState=EnvironmentCompat.getStorageState(file);
if(Environment.MEDIA_MOUNTED.equals(storageState))
result.add(getRootOfInnerSdCardFolder(externalCacheDirs[i]));
}
return result;
}
private static String getRootOfInnerSdCardFolder(File file)
{
if(file==null)
return null;
final long totalSpace=file.getTotalSpace();
while(true)
{
final File parentFile=file.getParentFile();
if(parentFile==null||parentFile.getTotalSpace()!=totalSpace)
return file.getAbsolutePath();
file=parentFile;
}
}
Вот как я проверяю, что может сделать Uris:
final List<UriPermission> persistedUriPermissions=getContentResolver().getPersistedUriPermissions();
Вот как получить доступ к SD-картам:
startActivityForResult(new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE),42);
public void onActivityResult(int requestCode,int resultCode,Intent resultData)
{
if(resultCode!=RESULT_OK)
return;
Uri treeUri=resultData.getData();
DocumentFile pickedDir=DocumentFile.fromTreeUri(this,treeUri);
grantUriPermission(getPackageName(),treeUri,Intent.FLAG_GRANT_READ_URI_PERMISSION|Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
getContentResolver().takePersistableUriPermission(treeUri,Intent.FLAG_GRANT_READ_URI_PERMISSION|Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
}
Вопросы
-
Можно ли проверить, доступны ли текущие SD-карты, а какие нет, и каким-то образом попросить пользователя получить разрешение на них?
-
Есть ли официальный способ конвертировать между DocumentFile uris и реальными путями? Я нашел этот ответ, но он разбился в моем случае, плюс он выглядит hack-y.
-
Можно ли запросить разрешение у пользователя о конкретном пути? Может быть, даже показать только диалог "вы принимаете" да/нет? "?
-
Можно ли использовать обычный API файлов вместо API DocumentFile после предоставления разрешения?
-
Учитывая путь к файлу/файлу, можно ли просто запросить разрешение на доступ к нему (и проверить, было ли оно задано раньше) или его корневой путь?
-
Можно ли сделать эмулятор SD-картой? В настоящее время упоминается "SD-карта", но она работает как основное внешнее хранилище, и я бы хотел протестировать ее с использованием вторичного внешнего хранилища, чтобы попробовать и использовать новый API.
Я думаю, что для некоторых из этих вопросов один помогает многому ответить другому.