1 /* 2 * Copyright (C) 2009 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 17 package android.content; 18 19 import android.content.ContentProvider; 20 import android.content.ContentValues; 21 import android.content.Context; 22 import android.content.UriMatcher; 23 import android.content.res.AssetFileDescriptor; 24 import android.database.Cursor; 25 import android.database.sqlite.SQLiteDatabase; 26 import android.database.sqlite.SQLiteOpenHelper; 27 import android.net.Uri; 28 import android.os.MemoryFile; 29 import android.os.ParcelFileDescriptor; 30 import android.util.Log; 31 32 import java.io.File; 33 import java.io.FileNotFoundException; 34 import java.io.IOException; 35 import java.io.OutputStream; 36 37 /** Simple test provider that runs in the local process. */ 38 public class MemoryFileProvider extends ContentProvider { 39 private static final String TAG = "MemoryFileProvider"; 40 41 private static final String DATA_FILE = "data.bin"; 42 43 // some random data 44 public static final byte[] TEST_BLOB = new byte[] { 45 -12, 127, 0, 3, 1, 2, 3, 4, 5, 6, 1, -128, -1, -54, -65, 35, 46 -53, -96, -74, -74, -55, -43, -69, 3, 52, -58, 47 -121, 127, 87, -73, 16, -13, -103, -65, -128, -36, 48 107, 24, 118, -17, 97, 97, -88, 19, -94, -54, 49 53, 43, 44, -27, -124, 28, -74, 26, 35, -36, 50 16, -124, -31, -31, -128, -79, 108, 116, 43, -17 }; 51 52 private SQLiteOpenHelper mOpenHelper; 53 54 private static final int DATA_ID_BLOB = 1; 55 private static final int HUGE = 2; 56 private static final int FILE = 3; 57 58 private static final UriMatcher sURLMatcher = new UriMatcher( 59 UriMatcher.NO_MATCH); 60 61 static { 62 sURLMatcher.addURI("*", "data/#/blob", DATA_ID_BLOB); 63 sURLMatcher.addURI("*", "huge", HUGE); 64 sURLMatcher.addURI("*", "file", FILE); 65 } 66 67 private static class DatabaseHelper extends SQLiteOpenHelper { 68 private static final String DATABASE_NAME = "local.db"; 69 private static final int DATABASE_VERSION = 1; 70 DatabaseHelper(Context context)71 public DatabaseHelper(Context context) { 72 super(context, DATABASE_NAME, null, DATABASE_VERSION); 73 } 74 75 @Override onCreate(SQLiteDatabase db)76 public void onCreate(SQLiteDatabase db) { 77 db.execSQL("CREATE TABLE data (" + 78 "_id INTEGER PRIMARY KEY," + 79 "_blob TEXT, " + 80 "integer INTEGER);"); 81 82 // insert alarms 83 ContentValues values = new ContentValues(); 84 values.put("_id", 1); 85 values.put("_blob", TEST_BLOB); 86 values.put("integer", 100); 87 db.insert("data", null, values); 88 } 89 90 @Override onUpgrade(SQLiteDatabase db, int oldVersion, int currentVersion)91 public void onUpgrade(SQLiteDatabase db, int oldVersion, int currentVersion) { 92 Log.w(TAG, "Upgrading test database from version " + 93 oldVersion + " to " + currentVersion + 94 ", which will destroy all old data"); 95 db.execSQL("DROP TABLE IF EXISTS data"); 96 onCreate(db); 97 } 98 } 99 100 MemoryFileProvider()101 public MemoryFileProvider() { 102 } 103 104 @Override onCreate()105 public boolean onCreate() { 106 mOpenHelper = new DatabaseHelper(getContext()); 107 try { 108 OutputStream out = getContext().openFileOutput(DATA_FILE, Context.MODE_PRIVATE); 109 out.write(TEST_BLOB); 110 out.close(); 111 } catch (IOException ex) { 112 ex.printStackTrace(); 113 } 114 return true; 115 } 116 117 @Override query(Uri url, String[] projectionIn, String selection, String[] selectionArgs, String sort)118 public Cursor query(Uri url, String[] projectionIn, String selection, 119 String[] selectionArgs, String sort) { 120 throw new UnsupportedOperationException("query not supported"); 121 } 122 123 @Override getType(Uri url)124 public String getType(Uri url) { 125 int match = sURLMatcher.match(url); 126 switch (match) { 127 case DATA_ID_BLOB: 128 return "application/octet-stream"; 129 case FILE: 130 return "application/octet-stream"; 131 default: 132 throw new IllegalArgumentException("Unknown URL"); 133 } 134 } 135 136 @Override openAssetFile(Uri url, String mode)137 public AssetFileDescriptor openAssetFile(Uri url, String mode) throws FileNotFoundException { 138 int match = sURLMatcher.match(url); 139 switch (match) { 140 case DATA_ID_BLOB: 141 String sql = "SELECT _blob FROM data WHERE _id=" + url.getPathSegments().get(1); 142 return getBlobColumnAsAssetFile(url, mode, sql); 143 case HUGE: 144 try { 145 MemoryFile memoryFile = new MemoryFile(null, 5000000); 146 memoryFile.writeBytes(TEST_BLOB, 0, 1000000, TEST_BLOB.length); 147 memoryFile.deactivate(); 148 return AssetFileDescriptor.fromMemoryFile(memoryFile); 149 } catch (IOException ex) { 150 throw new FileNotFoundException("Error reading " + url + ":" + ex.toString()); 151 } 152 case FILE: 153 File file = getContext().getFileStreamPath(DATA_FILE); 154 ParcelFileDescriptor fd = 155 ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY); 156 return new AssetFileDescriptor(fd, 0, AssetFileDescriptor.UNKNOWN_LENGTH); 157 default: 158 throw new FileNotFoundException("No files supported by provider at " + url); 159 } 160 } 161 getBlobColumnAsAssetFile(Uri url, String mode, String sql)162 private AssetFileDescriptor getBlobColumnAsAssetFile(Uri url, String mode, String sql) 163 throws FileNotFoundException { 164 if (!"r".equals(mode)) { 165 throw new FileNotFoundException("Mode " + mode + " not supported for " + url); 166 } 167 try { 168 SQLiteDatabase db = mOpenHelper.getReadableDatabase(); 169 MemoryFile file = simpleQueryForBlobMemoryFile(db, sql); 170 if (file == null) throw new FileNotFoundException("No such entry: " + url); 171 AssetFileDescriptor afd = AssetFileDescriptor.fromMemoryFile(file); 172 file.deactivate(); 173 // need to dup and then close? openFileHelper() doesn't do that though 174 return afd; 175 } catch (IOException ex) { 176 throw new FileNotFoundException("Error reading " + url + ":" + ex.toString()); 177 } 178 } 179 simpleQueryForBlobMemoryFile(SQLiteDatabase db, String sql)180 private MemoryFile simpleQueryForBlobMemoryFile(SQLiteDatabase db, String sql) throws IOException { 181 Cursor cursor = db.rawQuery(sql, null); 182 try { 183 if (!cursor.moveToFirst()) { 184 return null; 185 } 186 byte[] bytes = cursor.getBlob(0); 187 MemoryFile file = new MemoryFile(null, bytes.length); 188 file.writeBytes(bytes, 0, 0, bytes.length); 189 return file; 190 } finally { 191 if (cursor != null) { 192 cursor.close(); 193 } 194 } 195 } 196 197 @Override update(Uri url, ContentValues values, String where, String[] whereArgs)198 public int update(Uri url, ContentValues values, String where, String[] whereArgs) { 199 throw new UnsupportedOperationException("update not supported"); 200 } 201 202 @Override insert(Uri url, ContentValues initialValues)203 public Uri insert(Uri url, ContentValues initialValues) { 204 throw new UnsupportedOperationException("insert not supported"); 205 } 206 207 @Override delete(Uri url, String where, String[] whereArgs)208 public int delete(Uri url, String where, String[] whereArgs) { 209 throw new UnsupportedOperationException("delete not supported"); 210 } 211 } 212