Android SAF的uri解析
2019-11-21 本文已影响0人
yunhen
import android.app.Activity;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.provider.OpenableColumns;
import android.support.v4.provider.DocumentFile;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.List;
public class MySafUtil {
private static final String TAG = MySafUtil.class.getSimpleName();
/**
* @param activity
* @param miniType 类型
* @param category 可打开:Intent.CATEGORY_OPENABLE
* @param isMultiple 是否可多选
* @param OPEN_DOCUMENT_CODE
*/
public static void openDocument(Activity activity,String miniType,String category
,boolean isMultiple,int OPEN_DOCUMENT_CODE) {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
//文档需要是可以打开的 Intent.CATEGORY_OPENABLE
intent.addCategory(category);
//指定文档的minitype为text类型
intent.setType(miniType);
//是否支持多选,默认不支持
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE,isMultiple);
activity.startActivityForResult(intent,OPEN_DOCUMENT_CODE);
}
public interface OnDocumentActionCallback {
void onResult(String path);
}
public static void handleOpenDocumentAction(Context context,Intent data
,OnDocumentActionCallback callback) {
if (data == null) {
return;
}
//获取文档指向的uri,注意这里是指单个文件。
Uri uri = data.getData();
//根据该Uri可以获取该Document的信息,其数据列的名称和解释可以在DocumentsContact类的内部类Document中找到
//我们在此查询的信息仅仅只是演示作用
Cursor cursor = context.getContentResolver().query(uri,null,
null,null,null,null);
StringBuilder sb = new StringBuilder(" open document Uri =>");
sb.append(uri.toString());
if (cursor != null && cursor.moveToFirst()) {
String documentId = cursor.getString(cursor.getColumnIndex(
DocumentsContract.Document.COLUMN_DOCUMENT_ID));
String name = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
// String path = cursor.getString(cursor.getColumnIndex(OpenableColumns.));
int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE);
String size = null;
if (!cursor.isNull(sizeIndex)) {
// Technically the column stores an int, but cursor.getString()
// will do the conversion automatically.
size = cursor.getString(sizeIndex);
} else {
size = "Unknown";
}
sb.append(" name ").append(name).append(" size ").append(size);
}
DocumentFile documentFile = DocumentFile.fromSingleUri(context,uri);
if (callback != null)
callback.onResult(uriDoc2FilePath(context,documentFile));
//以下为直接从该uri中获取InputSteam,并读取出文本的内容的操作,这个是纯粹的java流操作,大家应该已经很熟悉了
//我就不多解释了。另外这里也可以直接使用OutputSteam,向文档中写入数据。
// BufferedReader br = null;
// try {
// InputStream is = context.getContentResolver().openInputStream(uri);
// br = new BufferedReader(new InputStreamReader(is));
// String line;
// sb.append("\r\n content : ");
// while((line = br.readLine())!=null){
// sb.append(line);
// }
//// showToast(sb.toString());
// } catch (IOException e) {
// e.printStackTrace();
// }finally {
// closeSafe(br);
// }
}
public static void closeSafe(BufferedReader bufferedReader) {
if (bufferedReader != null)
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 打开目录,打开文档树
*
* @param activity
* @param OPEN_TREE_CODE
*/
public static void openDocTree(Activity activity,int OPEN_TREE_CODE) {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
activity.startActivityForResult(intent,OPEN_TREE_CODE);
}
public static void handleDocTreeAction(Context context,Intent data
,OnDocumentActionCallback callback) throws NumberFormatException {
if (data==null)
return;
Uri treeUri = data.getData();
//授予打开的文档树永久性的读写权限
final int takeFlags = data.getFlags()
& (Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
context.getContentResolver().takePersistableUriPermission(treeUri,takeFlags);
//使用DocumentFile构建一个根文档,之后的操作可以在该文档上进行
DocumentFile mDocFile = DocumentFile.fromTreeUri(context,treeUri);
// Uri uriDocFile = mDocFile.getUri();
// //显示结果toast
// L.d(TAG," open tree uriDocFile =>" + uriDocFile);
// final List<String> pathDocF = uriDocFile.getPathSegments();
// L.d(TAG," open tree PathSegmentsDocFile =>" + pathDocF.toString());
//
// L.d(TAG," open tree uri =>" + treeUri);
// final List<String> paths = treeUri.getPathSegments();
// L.d(TAG," open tree PathSegments =>" + paths.toString());
String path = uriDoc2FilePath(context,mDocFile);
if (callback!=null)
callback.onResult(path);
L.d(TAG," open tree path =>" + path);
L.d(TAG," open tree path --------------------------------" );
}
/**
*
* @param context
* @param mDocumentFile 如果是SAF文档的uri,要先 DocumentFile.fromTreeUri(context,treeUri)
* 后得到的DocumentFile.getUri();
* @return
*/
public static String uri2FilePath(Context context,Uri mDocumentFile
) {
Uri selectedUri = mDocumentFile;
if (selectedUri == null) {
return null;
}
if ( Build.VERSION.SDK_INT >= 19
&& DocumentsContract.isDocumentUri(context,selectedUri)) {
// 如果是Android 4.4之後的版本,而且屬於文件URI
final String authority = selectedUri.getAuthority();
L.d(TAG,"uri2FilePath authority ="+authority);
// 判斷Authority是否為本地端檔案所使用的
if ("com.android.externalstorage.documents".equals(authority)) {
// 外部儲存空間
final String docId = DocumentsContract.getDocumentId(selectedUri);
final String[] divide = docId.split(":");
final String type = divide[0];
if ("primary".equals(type)) {
String path = Environment.getExternalStorageDirectory().getAbsolutePath().concat("/").concat(divide[1]);
return path;
} else {
String path = "/storage/".concat(type).concat("/").concat(divide[1]);
return path;
}
} else if ("com.android.providers.downloads.documents".equals(authority)) {
// 下載目錄
// 下載目錄
final String docId = DocumentsContract.getDocumentId(selectedUri);
String path = null;
/**
* 用SAF 选啦 '下载内容' 后,id = "downloads",
* 看了一下,其实就是 Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
*/
final String DOC_ID_DOWNLOADS = "downloads";
if (docId.equals(DOC_ID_DOWNLOADS)) {
path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath();
}else {
if (docId.startsWith("raw:")) {
L.d(TAG,"uriDoc2FilePath -> providers.downloads.documents 2");
path = docId.replaceFirst("raw:","");
}else {
final Uri downloadUri;
downloadUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"),Long.parseLong(docId));
path = queryMediaAbsolutePath(context,downloadUri);
}
}
L.d(TAG,"uriDoc2FilePath -> com.android.providers.downloads.documents path ="+path);
return path;
} else if ("com.android.providers.media.documents".equals(authority)) {
// 圖片、影音檔案
final String docId = DocumentsContract.getDocumentId(selectedUri);
final String[] divide = docId.split(":");
final String type = divide[0];
Uri mediaUri = null;
if ("image".equals(type)) {
mediaUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
mediaUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
mediaUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
} else {
return null;
}
mediaUri = ContentUris.withAppendedId(mediaUri,Long.parseLong(divide[1]));
String path = queryMediaAbsolutePath(context,mediaUri);
return path;
}
} else {
L.d(TAG,"uri2FilePath 一般的URI ");
// 如果是一般的URI
final String scheme = selectedUri.getScheme();
String path = null;
if ("content".equals(scheme)) {
// 內容URI
path = queryMediaAbsolutePath(context,selectedUri);
} else if ("file".equals(scheme)) {
// 檔案URI
path = selectedUri.getPath();
}
return path;
}
return null;
}
/**
*
* @param context
* @param mDocumentFile
* @return
*/
public static String uriDoc2FilePath(Context context,DocumentFile mDocumentFile
) throws NumberFormatException{
if (mDocumentFile == null) {
return null;
}
Uri selectedUri = mDocumentFile.getUri();
if (selectedUri == null) {
return null;
}
if ( Build.VERSION.SDK_INT >= 19
&& DocumentsContract.isDocumentUri(context,selectedUri)) {
// 如果是Android 4.4之後的版本,而且屬於文件URI
final String authority = selectedUri.getAuthority();
L.d(TAG,"uriDoc2FilePath authority ="+authority);
// 判斷Authority是否為本地端檔案所使用的
if ("com.android.externalstorage.documents".equals(authority)) {
// 外部儲存空間
final String docId = DocumentsContract.getDocumentId(selectedUri);
final String[] divide = docId.split(":");
final String type = divide[0];
if ("primary".equals(type)) {
String path = Environment.getExternalStorageDirectory().getAbsolutePath().concat("/").concat(divide[1]);
return path;
} else {
String path = "/storage/".concat(type).concat("/").concat(divide[1]);
return path;
}
} else if ("com.android.providers.downloads.documents".equals(authority)) {
L.d(TAG,"uriDoc2FilePath -> providers.downloads.documents 1");
// 下載目錄
final String docId = DocumentsContract.getDocumentId(selectedUri);
String path = null;
/**
* 用SAF 选啦 '下载内容' 后,id = "downloads",
* 看了一下,其实就是 Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
*/
final String DOC_ID_DOWNLOADS = "downloads";
if (docId.equals(DOC_ID_DOWNLOADS)) {
L.d(TAG,"uriDoc2FilePath -> providers.downloads.documents 2 uri.path="+selectedUri.getPath());
path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath();
}else {
if (docId.startsWith("raw:")) {
L.d(TAG,"uriDoc2FilePath -> providers.downloads.documents 3");
path = docId.replaceFirst("raw:","");
}else {
L.d(TAG,"uriDoc2FilePath -> providers.downloads.documents 4");
final Uri downloadUri;
downloadUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"),Long.parseLong(docId));
path = queryMediaAbsolutePath(context,downloadUri);
}
}
L.d(TAG,"uriDoc2FilePath -> com.android.providers.downloads.documents path ="+path);
return path;
} else if ("com.android.providers.media.documents".equals(authority)) {
// 圖片、影音檔案
final String docId = DocumentsContract.getDocumentId(selectedUri);
final String[] divide = docId.split(":");
final String type = divide[0];
Uri mediaUri = null;
if ("image".equals(type)) {
mediaUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
mediaUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
mediaUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
} else {
return null;
}
mediaUri = ContentUris.withAppendedId(mediaUri,Long.parseLong(divide[1]));
String path = queryMediaAbsolutePath(context,mediaUri);
return path;
}
} else {
L.d(TAG,"uri2FilePath 一般的URI ");
// 如果是一般的URI
final String scheme = selectedUri.getScheme();
String path = null;
if ("content".equals(scheme)) {
// 內容URI
path = queryMediaAbsolutePath(context,selectedUri);
} else if ("file".equals(scheme)) {
// 檔案URI
path = selectedUri.getPath();
}
return path;
}
return null;
}
public static String queryMediaAbsolutePath(final Context context,final Uri uri) {
final String[] projection = {MediaStore.MediaColumns.DATA};
Cursor cursor = null;
try {
cursor = context.getContentResolver().query(uri,projection,null,null,null);
if (cursor != null && cursor.moveToFirst()) {
final int index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
return cursor.getString(index);
}
} catch (final Exception ex) {
ex.printStackTrace();
if (cursor != null) {
cursor.close();
}
}
return null;
}
}