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.ContentProvider;
20d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.ContentResolver;
21d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.ContentValues;
22d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.database.Cursor;
23d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.net.Uri;
24d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.os.ParcelFileDescriptor;
25d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.text.TextUtils;
26d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
27d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.io.File;
28d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.io.FileNotFoundException;
29d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.io.IOException;
30d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.Random;
31d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
32d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd/**
33d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * A very simple content provider that can serve files.
34d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */
35d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpublic abstract class FileProvider extends ContentProvider {
36d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    // Object to generate random id for temp images.
37d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final Random RANDOM_ID = new Random();
38d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
39d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    abstract File getFile(final String path, final String extension);
40d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
41d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final String FILE_EXTENSION_PARAM_KEY = "ext";
42d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
43d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
44d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Check if filename conforms to requirement for our provider
45d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param fileId filename (optionally starting with path character
46d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return true if filename consists only of digits
47d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
48d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    protected static boolean isValidFileId(final String fileId) {
49d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Ignore initial "/"
50d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        for (int index = (fileId.startsWith("/") ? 1 : 0); index < fileId.length(); index++) {
51d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final Character c = fileId.charAt(index);
52d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (!Character.isDigit(c)) {
53d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                return false;
54d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
55d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
56d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return true;
57d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
58d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
59d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
60d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Create a temp file (to allow writing to that one particular file)
61d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param file the file to create
62d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return true if file successfully created
63d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
64d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    protected static boolean ensureFileExists(final File file) {
65d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        try {
66d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final File parentDir = file.getParentFile();
67d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (parentDir.exists() || parentDir.mkdirs()) {
68d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                return file.createNewFile();
69d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
70d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } catch (final IOException e) {
71d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // fail on exceptions creating the file
72d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
73d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return false;
74d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
75d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
76d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
77d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Build uri for a new temporary file (creating file)
78d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param authority authority with which to populate uri
79d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param extension optional file extension
80d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return unique uri that can be used to write temporary files
81d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
82d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    protected static Uri buildFileUri(final String authority, final String extension) {
83d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final long fileId = Math.abs(RANDOM_ID.nextLong());
84d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final Uri.Builder builder = (new Uri.Builder()).authority(authority).scheme(
85d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                ContentResolver.SCHEME_CONTENT);
86d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        builder.appendPath(String.valueOf(fileId));
87d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (!TextUtils.isEmpty(extension)) {
88d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            builder.appendQueryParameter(FILE_EXTENSION_PARAM_KEY, extension);
89d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
90d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return builder.build();
91d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
92d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
93d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    @Override
94d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public boolean onCreate() {
95d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return true;
96d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
97d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
98d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    @Override
99d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public int delete(final Uri uri, final String selection, final String[] selectionArgs) {
100d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final String fileId = uri.getPath();
101d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (isValidFileId(fileId)) {
102d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final File file = getFile(fileId, getExtensionFromUri(uri));
103d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return file.delete() ? 1 : 0;
104d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
105d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return 0;
106d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
107d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
108d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    @Override
109d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public ParcelFileDescriptor openFile(final Uri uri, final String fileMode)
110d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            throws FileNotFoundException {
111d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final String fileId = uri.getPath();
112d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (isValidFileId(fileId)) {
113d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final File file = getFile(fileId, getExtensionFromUri(uri));
114d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final int mode =
115d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    (TextUtils.equals(fileMode, "r") ? ParcelFileDescriptor.MODE_READ_ONLY :
116d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_TRUNCATE);
117d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return ParcelFileDescriptor.open(file, mode);
118d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
119d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return null;
120d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
121d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
122d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    protected static String getExtensionFromUri(final Uri uri) {
123d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return uri.getQueryParameter(FILE_EXTENSION_PARAM_KEY);
124d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
125d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
126d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    @Override
127d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public Cursor query(final Uri uri, final String[] projection, final String selection,
128d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final String[] selectionArgs, final String sortOrder) {
129d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Don't support queries.
130d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return null;
131d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
132d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
133d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    @Override
134d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public Uri insert(final Uri uri, final ContentValues values) {
135d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Don't support inserts.
136d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return null;
137d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
138d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
139d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    @Override
140d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public int update(final Uri uri, final ContentValues values, final String selection,
141d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final String[] selectionArgs) {
142d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Don't support updates.
143d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return 0;
144d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
145d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
146d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    @Override
147d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public String getType(final Uri uri) {
148d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // No need for mime types.
149d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return null;
150d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
151d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd}
152