1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.messaging.datamodel;
18
19import android.content.ContentProvider;
20import android.content.ContentResolver;
21import android.content.ContentValues;
22import android.database.Cursor;
23import android.net.Uri;
24import android.os.ParcelFileDescriptor;
25import android.text.TextUtils;
26
27import java.io.File;
28import java.io.FileNotFoundException;
29import java.io.IOException;
30import java.util.Random;
31
32/**
33 * A very simple content provider that can serve files.
34 */
35public abstract class FileProvider extends ContentProvider {
36    // Object to generate random id for temp images.
37    private static final Random RANDOM_ID = new Random();
38
39    abstract File getFile(final String path, final String extension);
40
41    private static final String FILE_EXTENSION_PARAM_KEY = "ext";
42
43    /**
44     * Check if filename conforms to requirement for our provider
45     * @param fileId filename (optionally starting with path character
46     * @return true if filename consists only of digits
47     */
48    protected static boolean isValidFileId(final String fileId) {
49        // Ignore initial "/"
50        for (int index = (fileId.startsWith("/") ? 1 : 0); index < fileId.length(); index++) {
51            final Character c = fileId.charAt(index);
52            if (!Character.isDigit(c)) {
53                return false;
54            }
55        }
56        return true;
57    }
58
59    /**
60     * Create a temp file (to allow writing to that one particular file)
61     * @param file the file to create
62     * @return true if file successfully created
63     */
64    protected static boolean ensureFileExists(final File file) {
65        try {
66            final File parentDir = file.getParentFile();
67            if (parentDir.exists() || parentDir.mkdirs()) {
68                return file.createNewFile();
69            }
70        } catch (final IOException e) {
71            // fail on exceptions creating the file
72        }
73        return false;
74    }
75
76    /**
77     * Build uri for a new temporary file (creating file)
78     * @param authority authority with which to populate uri
79     * @param extension optional file extension
80     * @return unique uri that can be used to write temporary files
81     */
82    protected static Uri buildFileUri(final String authority, final String extension) {
83        final long fileId = Math.abs(RANDOM_ID.nextLong());
84        final Uri.Builder builder = (new Uri.Builder()).authority(authority).scheme(
85                ContentResolver.SCHEME_CONTENT);
86        builder.appendPath(String.valueOf(fileId));
87        if (!TextUtils.isEmpty(extension)) {
88            builder.appendQueryParameter(FILE_EXTENSION_PARAM_KEY, extension);
89        }
90        return builder.build();
91    }
92
93    @Override
94    public boolean onCreate() {
95        return true;
96    }
97
98    @Override
99    public int delete(final Uri uri, final String selection, final String[] selectionArgs) {
100        final String fileId = uri.getPath();
101        if (isValidFileId(fileId)) {
102            final File file = getFile(fileId, getExtensionFromUri(uri));
103            return file.delete() ? 1 : 0;
104        }
105        return 0;
106    }
107
108    @Override
109    public ParcelFileDescriptor openFile(final Uri uri, final String fileMode)
110            throws FileNotFoundException {
111        final String fileId = uri.getPath();
112        if (isValidFileId(fileId)) {
113            final File file = getFile(fileId, getExtensionFromUri(uri));
114            final int mode =
115                    (TextUtils.equals(fileMode, "r") ? ParcelFileDescriptor.MODE_READ_ONLY :
116                        ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_TRUNCATE);
117            return ParcelFileDescriptor.open(file, mode);
118        }
119        return null;
120    }
121
122    protected static String getExtensionFromUri(final Uri uri) {
123        return uri.getQueryParameter(FILE_EXTENSION_PARAM_KEY);
124    }
125
126    @Override
127    public Cursor query(final Uri uri, final String[] projection, final String selection,
128            final String[] selectionArgs, final String sortOrder) {
129        // Don't support queries.
130        return null;
131    }
132
133    @Override
134    public Uri insert(final Uri uri, final ContentValues values) {
135        // Don't support inserts.
136        return null;
137    }
138
139    @Override
140    public int update(final Uri uri, final ContentValues values, final String selection,
141            final String[] selectionArgs) {
142        // Don't support updates.
143        return 0;
144    }
145
146    @Override
147    public String getType(final Uri uri) {
148        // No need for mime types.
149        return null;
150    }
151}
152