1d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd/*
2d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Copyright (C) 2015 The Android Open Source Project
3d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
4d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Licensed under the Apache License, Version 2.0 (the "License");
5d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * you may not use this file except in compliance with the License.
6d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * You may obtain a copy of the License at
7d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
8d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *      http://www.apache.org/licenses/LICENSE-2.0
9d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
10d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Unless required by applicable law or agreed to in writing, software
11d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * distributed under the License is distributed on an "AS IS" BASIS,
12d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * See the License for the specific language governing permissions and
14d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * limitations under the License.
15d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */
16d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
17d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpackage com.android.messaging.datamodel;
18d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
19d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.ContentResolver;
20d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.Context;
21d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.database.Cursor;
22d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.database.MatrixCursor;
23d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.database.MatrixCursor.RowBuilder;
24d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.net.Uri;
25d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.provider.OpenableColumns;
26d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.support.v4.util.SimpleArrayMap;
27d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.text.TextUtils;
28d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
29d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.Factory;
30d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.Assert;
31d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.LogUtil;
32d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.google.common.annotations.VisibleForTesting;
33d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
34d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.io.File;
35a2aa53f83afbd13b04cbdcca494fd3cf659c155dTom Taylorimport java.io.IOException;
36d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.List;
37d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
38d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd/**
39d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * A very simple content provider that can serve media files from our cache directory.
40d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */
41d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpublic class MediaScratchFileProvider extends FileProvider {
42d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final String TAG = LogUtil.BUGLE_TAG;
43d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
44d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final SimpleArrayMap<Uri, String> sUriToDisplayNameMap =
45d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            new SimpleArrayMap<Uri, String>();
46d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
47d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    @VisibleForTesting
48d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final String AUTHORITY =
49d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            "com.android.messaging.datamodel.MediaScratchFileProvider";
50d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final String MEDIA_SCRATCH_SPACE_DIR = "mediascratchspace";
51d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
52d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static boolean isMediaScratchSpaceUri(final Uri uri) {
53d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (uri == null) {
54d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return false;
55d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
56d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
57d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final List<String> segments = uri.getPathSegments();
58d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return (TextUtils.equals(uri.getScheme(), ContentResolver.SCHEME_CONTENT) &&
59d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                TextUtils.equals(uri.getAuthority(), AUTHORITY) &&
60d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                segments.size() == 1 && FileProvider.isValidFileId(segments.get(0)));
61d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
62d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
63d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
64d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Returns a uri that can be used to access a raw mms file.
65d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
66d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return the URI for an raw mms file
67d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
68d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static Uri buildMediaScratchSpaceUri(final String extension) {
69d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final Uri uri = FileProvider.buildFileUri(AUTHORITY, extension);
70d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final File file = getFileWithExtension(uri.getPath(), extension);
71d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (!ensureFileExists(file)) {
72d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            LogUtil.e(TAG, "Failed to create temp file " + file.getAbsolutePath());
73d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
74d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return uri;
75d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
76d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
77d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static File getFileFromUri(final Uri uri) {
78d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        Assert.equals(AUTHORITY, uri.getAuthority());
79d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return getFileWithExtension(uri.getPath(), getExtensionFromUri(uri));
80d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
81d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
82d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static Uri.Builder getUriBuilder() {
83d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return (new Uri.Builder()).authority(AUTHORITY).scheme(ContentResolver.SCHEME_CONTENT);
84d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
85d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
86d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    @Override
87d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    File getFile(final String path, final String extension) {
88d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return getFileWithExtension(path, extension);
89d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
90d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
91d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static File getFileWithExtension(final String path, final String extension) {
92d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final Context context = Factory.get().getApplicationContext();
93a2aa53f83afbd13b04cbdcca494fd3cf659c155dTom Taylor        final File filePath = new File(getDirectory(context),
94d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                TextUtils.isEmpty(extension) ? path : path + "." + extension);
95a2aa53f83afbd13b04cbdcca494fd3cf659c155dTom Taylor
96a2aa53f83afbd13b04cbdcca494fd3cf659c155dTom Taylor        try {
97a2aa53f83afbd13b04cbdcca494fd3cf659c155dTom Taylor            if (!filePath.getCanonicalPath()
98a2aa53f83afbd13b04cbdcca494fd3cf659c155dTom Taylor                    .startsWith(getDirectory(context).getCanonicalPath())) {
99a2aa53f83afbd13b04cbdcca494fd3cf659c155dTom Taylor                LogUtil.e(TAG, "getFileWithExtension: path "
100a2aa53f83afbd13b04cbdcca494fd3cf659c155dTom Taylor                        + filePath.getCanonicalPath()
101a2aa53f83afbd13b04cbdcca494fd3cf659c155dTom Taylor                        + " does not start with "
102a2aa53f83afbd13b04cbdcca494fd3cf659c155dTom Taylor                        + getDirectory(context).getCanonicalPath());
103a2aa53f83afbd13b04cbdcca494fd3cf659c155dTom Taylor                return null;
104a2aa53f83afbd13b04cbdcca494fd3cf659c155dTom Taylor            }
105a2aa53f83afbd13b04cbdcca494fd3cf659c155dTom Taylor        } catch (IOException e) {
106a2aa53f83afbd13b04cbdcca494fd3cf659c155dTom Taylor            LogUtil.e(TAG, "getFileWithExtension: getCanonicalPath failed ", e);
107a2aa53f83afbd13b04cbdcca494fd3cf659c155dTom Taylor            return null;
108a2aa53f83afbd13b04cbdcca494fd3cf659c155dTom Taylor        }
109a2aa53f83afbd13b04cbdcca494fd3cf659c155dTom Taylor        return filePath;
110d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
111d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
112d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static File getDirectory(final Context context) {
113d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return new File(context.getCacheDir(), MEDIA_SCRATCH_SPACE_DIR);
114d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
115d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
116d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    @Override
117d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public Cursor query(final Uri uri, final String[] projection, final String selection,
118d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final String[] selectionArgs, final String sortOrder) {
119d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (projection != null && projection.length > 0 &&
120d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                TextUtils.equals(projection[0], OpenableColumns.DISPLAY_NAME) &&
121d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                isMediaScratchSpaceUri(uri)) {
122d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Retrieve the display name associated with a temp file. This is used by the Contacts
123d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // ImportVCardActivity to retrieve the name of the contact(s) being imported.
124d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            String displayName;
125d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            synchronized (sUriToDisplayNameMap) {
126d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                displayName = sUriToDisplayNameMap.get(uri);
127d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
128d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (!TextUtils.isEmpty(displayName)) {
129d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                MatrixCursor cursor =
130d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        new MatrixCursor(new String[] { OpenableColumns.DISPLAY_NAME });
131d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                RowBuilder row = cursor.newRow();
132d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                row.add(displayName);
133d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                return cursor;
134d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
135d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
136d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return null;
137d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
138d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
139d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static void addUriToDisplayNameEntry(final Uri scratchFileUri,
140d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final String displayName) {
141d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (TextUtils.isEmpty(displayName)) {
142d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return;
143d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
144d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        synchronized (sUriToDisplayNameMap) {
145d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            sUriToDisplayNameMap.put(scratchFileUri, displayName);
146d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
147d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
148d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd}
149