1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5package org.chromium.base;
6
7import android.content.ContentResolver;
8import android.content.Context;
9import android.database.Cursor;
10import android.net.Uri;
11import android.os.ParcelFileDescriptor;
12import android.util.Log;
13
14import java.io.File;
15
16/**
17 * This class provides methods to access content URI schemes.
18 */
19public abstract class ContentUriUtils {
20    private static final String TAG = "ContentUriUtils";
21    private static FileProviderUtil sFileProviderUtil;
22
23    /**
24     * Provides functionality to translate a file into a content URI for use
25     * with a content provider.
26     */
27    public interface FileProviderUtil {
28        /**
29         * Generate a content uri from the given file.
30         * @param context Application context.
31         * @param file The file to be translated.
32         */
33        public Uri getContentUriFromFile(Context context, File file);
34    }
35
36    // Prevent instantiation.
37    private ContentUriUtils() {}
38
39    public static void setFileProviderUtil(FileProviderUtil util) {
40        sFileProviderUtil = util;
41    }
42
43    public static Uri getContentUriFromFile(Context context, File file) {
44        ThreadUtils.assertOnUiThread();
45        if (sFileProviderUtil != null) {
46            return sFileProviderUtil.getContentUriFromFile(context, file);
47        }
48        return null;
49    }
50
51    /**
52     * Opens the content URI for reading, and returns the file descriptor to
53     * the caller. The caller is responsible for closing the file desciptor.
54     *
55     * @param context {@link Context} in interest
56     * @param uriString the content URI to open
57     * @returns file desciptor upon sucess, or -1 otherwise.
58     */
59    @CalledByNative
60    public static int openContentUriForRead(Context context, String uriString) {
61        ParcelFileDescriptor pfd = getParcelFileDescriptor(context, uriString);
62        if (pfd != null) {
63            return pfd.detachFd();
64        }
65        return -1;
66    }
67
68    /**
69     * Check whether a content URI exists.
70     *
71     * @param context {@link Context} in interest.
72     * @param uriString the content URI to query.
73     * @returns true if the uri exists, or false otherwise.
74     */
75    @CalledByNative
76    public static boolean contentUriExists(Context context, String uriString) {
77        ParcelFileDescriptor pfd = getParcelFileDescriptor(context, uriString);
78        if (pfd == null) {
79            return false;
80        }
81        return true;
82    }
83
84    /**
85     * Helper method to open a content URI and return the ParcelFileDescriptor.
86     *
87     * @param context {@link Context} in interest.
88     * @param uriString the content URI to open.
89     * @returns ParcelFileDescriptor of the content URI, or NULL if the file does not exist.
90     */
91    private static ParcelFileDescriptor getParcelFileDescriptor(Context context, String uriString) {
92        ContentResolver resolver = context.getContentResolver();
93        Uri uri = Uri.parse(uriString);
94
95        ParcelFileDescriptor pfd = null;
96        try {
97            pfd = resolver.openFileDescriptor(uri, "r");
98        } catch (java.io.FileNotFoundException e) {
99            Log.w(TAG, "Cannot find content uri: " + uriString, e);
100        }
101        return pfd;
102    }
103
104    /**
105     * Method to resolve the display name of a content URI.
106     *
107     * @param uri the content URI to be resolved.
108     * @param contentResolver the content resolver to query.
109     * @param columnField the column field to query.
110     * @returns the display name of the @code uri if present in the database
111     *  or an empty string otherwise.
112     */
113    public static String getDisplayName(
114            Uri uri, ContentResolver contentResolver, String columnField) {
115        if (contentResolver == null || uri == null) return "";
116        Cursor cursor = null;
117        try {
118            cursor = contentResolver.query(uri, null, null, null, null);
119
120            if (cursor != null && cursor.getCount() >= 1) {
121                cursor.moveToFirst();
122                int index = cursor.getColumnIndex(columnField);
123                if (index > -1) return cursor.getString(index);
124            }
125        } catch (NullPointerException e) {
126            // Some android models don't handle the provider call correctly.
127            // see crbug.com/345393
128            return "";
129        } finally {
130            if (cursor != null) cursor.close();
131        }
132        return "";
133    }
134}
135