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