Android适配

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;
    }

}
上一篇 下一篇

猜你喜欢

热点阅读