1 /* 2 * Copyright (C) 2010 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 com.android.gallery3d.gadget; 18 19 import android.content.ContentValues; 20 import android.content.Context; 21 import android.database.Cursor; 22 import android.database.sqlite.SQLiteDatabase; 23 import android.database.sqlite.SQLiteException; 24 import android.database.sqlite.SQLiteOpenHelper; 25 import android.graphics.Bitmap; 26 import android.net.Uri; 27 import android.util.Log; 28 29 import com.android.gallery3d.common.Utils; 30 31 import java.io.ByteArrayOutputStream; 32 import java.util.ArrayList; 33 import java.util.List; 34 35 public class WidgetDatabaseHelper extends SQLiteOpenHelper { 36 private static final String TAG = "PhotoDatabaseHelper"; 37 private static final String DATABASE_NAME = "launcher.db"; 38 39 // Increment the database version to 5. In version 5, we 40 // add a column in widgets table to record relative paths. 41 private static final int DATABASE_VERSION = 5; 42 43 private static final String TABLE_WIDGETS = "widgets"; 44 45 private static final String FIELD_APPWIDGET_ID = "appWidgetId"; 46 private static final String FIELD_IMAGE_URI = "imageUri"; 47 private static final String FIELD_PHOTO_BLOB = "photoBlob"; 48 private static final String FIELD_WIDGET_TYPE = "widgetType"; 49 private static final String FIELD_ALBUM_PATH = "albumPath"; 50 private static final String FIELD_RELATIVE_PATH = "relativePath"; 51 52 public static final int TYPE_SINGLE_PHOTO = 0; 53 public static final int TYPE_SHUFFLE = 1; 54 public static final int TYPE_ALBUM = 2; 55 56 private static final String[] PROJECTION = { 57 FIELD_WIDGET_TYPE, FIELD_IMAGE_URI, FIELD_PHOTO_BLOB, FIELD_ALBUM_PATH, 58 FIELD_APPWIDGET_ID, FIELD_RELATIVE_PATH}; 59 private static final int INDEX_WIDGET_TYPE = 0; 60 private static final int INDEX_IMAGE_URI = 1; 61 private static final int INDEX_PHOTO_BLOB = 2; 62 private static final int INDEX_ALBUM_PATH = 3; 63 private static final int INDEX_APPWIDGET_ID = 4; 64 private static final int INDEX_RELATIVE_PATH = 5; 65 private static final String WHERE_APPWIDGET_ID = FIELD_APPWIDGET_ID + " = ?"; 66 private static final String WHERE_WIDGET_TYPE = FIELD_WIDGET_TYPE + " = ?"; 67 68 public static class Entry { 69 public int widgetId; 70 public int type; 71 public String imageUri; 72 public byte imageData[]; 73 public String albumPath; 74 public String relativePath; 75 76 private Entry() {} 77 78 private Entry(int id, Cursor cursor) { 79 widgetId = id; 80 type = cursor.getInt(INDEX_WIDGET_TYPE); 81 if (type == TYPE_SINGLE_PHOTO) { 82 imageUri = cursor.getString(INDEX_IMAGE_URI); 83 imageData = cursor.getBlob(INDEX_PHOTO_BLOB); 84 } else if (type == TYPE_ALBUM) { 85 albumPath = cursor.getString(INDEX_ALBUM_PATH); 86 relativePath = cursor.getString(INDEX_RELATIVE_PATH); 87 } 88 } 89 90 private Entry(Cursor cursor) { 91 this(cursor.getInt(INDEX_APPWIDGET_ID), cursor); 92 } 93 } 94 95 public WidgetDatabaseHelper(Context context) { 96 super(context, DATABASE_NAME, null, DATABASE_VERSION); 97 } 98 99 @Override 100 public void onCreate(SQLiteDatabase db) { 101 db.execSQL("CREATE TABLE " + TABLE_WIDGETS + " (" 102 + FIELD_APPWIDGET_ID + " INTEGER PRIMARY KEY, " 103 + FIELD_WIDGET_TYPE + " INTEGER DEFAULT 0, " 104 + FIELD_IMAGE_URI + " TEXT, " 105 + FIELD_ALBUM_PATH + " TEXT, " 106 + FIELD_PHOTO_BLOB + " BLOB, " 107 + FIELD_RELATIVE_PATH + " TEXT)"); 108 } 109 110 private void saveData(SQLiteDatabase db, int oldVersion, ArrayList<Entry> data) { 111 if (oldVersion <= 2) { 112 Cursor cursor = db.query("photos", 113 new String[] {FIELD_APPWIDGET_ID, FIELD_PHOTO_BLOB}, 114 null, null, null, null, null); 115 if (cursor == null) return; 116 try { 117 while (cursor.moveToNext()) { 118 Entry entry = new Entry(); 119 entry.type = TYPE_SINGLE_PHOTO; 120 entry.widgetId = cursor.getInt(0); 121 entry.imageData = cursor.getBlob(1); 122 data.add(entry); 123 } 124 } finally { 125 cursor.close(); 126 } 127 } else if (oldVersion == 3) { 128 Cursor cursor = db.query("photos", 129 new String[] {FIELD_APPWIDGET_ID, FIELD_PHOTO_BLOB, FIELD_IMAGE_URI}, 130 null, null, null, null, null); 131 if (cursor == null) return; 132 try { 133 while (cursor.moveToNext()) { 134 Entry entry = new Entry(); 135 entry.type = TYPE_SINGLE_PHOTO; 136 entry.widgetId = cursor.getInt(0); 137 entry.imageData = cursor.getBlob(1); 138 entry.imageUri = cursor.getString(2); 139 data.add(entry); 140 } 141 } finally { 142 cursor.close(); 143 } 144 } 145 } 146 147 private void restoreData(SQLiteDatabase db, ArrayList<Entry> data) { 148 db.beginTransaction(); 149 try { 150 for (Entry entry : data) { 151 ContentValues values = new ContentValues(); 152 values.put(FIELD_APPWIDGET_ID, entry.widgetId); 153 values.put(FIELD_WIDGET_TYPE, entry.type); 154 values.put(FIELD_IMAGE_URI, entry.imageUri); 155 values.put(FIELD_PHOTO_BLOB, entry.imageData); 156 values.put(FIELD_ALBUM_PATH, entry.albumPath); 157 db.insert(TABLE_WIDGETS, null, values); 158 } 159 db.setTransactionSuccessful(); 160 } finally { 161 db.endTransaction(); 162 } 163 } 164 165 @Override 166 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 167 if (oldVersion < 4) { 168 // Table "photos" is renamed to "widget" in version 4 169 ArrayList<Entry> data = new ArrayList<Entry>(); 170 saveData(db, oldVersion, data); 171 172 Log.w(TAG, "destroying all old data."); 173 db.execSQL("DROP TABLE IF EXISTS photos"); 174 db.execSQL("DROP TABLE IF EXISTS " + TABLE_WIDGETS); 175 onCreate(db); 176 177 restoreData(db, data); 178 } 179 // Add a column for relative path 180 if (oldVersion < DATABASE_VERSION) { 181 try { 182 db.execSQL("ALTER TABLE widgets ADD COLUMN relativePath TEXT"); 183 } catch (Throwable t) { 184 Log.e(TAG, "Failed to add the column for relative path."); 185 return; 186 } 187 } 188 } 189 190 /** 191 * Store the given bitmap in this database for the given appWidgetId. 192 */ 193 public boolean setPhoto(int appWidgetId, Uri imageUri, Bitmap bitmap) { 194 try { 195 // Try go guesstimate how much space the icon will take when 196 // serialized to avoid unnecessary allocations/copies during 197 // the write. 198 int size = bitmap.getWidth() * bitmap.getHeight() * 4; 199 ByteArrayOutputStream out = new ByteArrayOutputStream(size); 200 bitmap.compress(Bitmap.CompressFormat.PNG, 100, out); 201 out.close(); 202 203 ContentValues values = new ContentValues(); 204 values.put(FIELD_APPWIDGET_ID, appWidgetId); 205 values.put(FIELD_WIDGET_TYPE, TYPE_SINGLE_PHOTO); 206 values.put(FIELD_IMAGE_URI, imageUri.toString()); 207 values.put(FIELD_PHOTO_BLOB, out.toByteArray()); 208 209 SQLiteDatabase db = getWritableDatabase(); 210 db.replaceOrThrow(TABLE_WIDGETS, null, values); 211 return true; 212 } catch (Throwable e) { 213 Log.e(TAG, "set widget photo fail", e); 214 return false; 215 } 216 } 217 218 public boolean setWidget(int id, int type, String albumPath, String relativePath) { 219 try { 220 ContentValues values = new ContentValues(); 221 values.put(FIELD_APPWIDGET_ID, id); 222 values.put(FIELD_WIDGET_TYPE, type); 223 values.put(FIELD_ALBUM_PATH, Utils.ensureNotNull(albumPath)); 224 values.put(FIELD_RELATIVE_PATH, relativePath); 225 getWritableDatabase().replaceOrThrow(TABLE_WIDGETS, null, values); 226 return true; 227 } catch (Throwable e) { 228 Log.e(TAG, "set widget fail", e); 229 return false; 230 } 231 } 232 233 public Entry getEntry(int appWidgetId) { 234 Cursor cursor = null; 235 try { 236 SQLiteDatabase db = getReadableDatabase(); 237 cursor = db.query(TABLE_WIDGETS, PROJECTION, 238 WHERE_APPWIDGET_ID, new String[] {String.valueOf(appWidgetId)}, 239 null, null, null); 240 if (cursor == null || !cursor.moveToNext()) { 241 Log.e(TAG, "query fail: empty cursor: " + cursor + " appWidgetId: " 242 + appWidgetId); 243 return null; 244 } 245 return new Entry(appWidgetId, cursor); 246 } catch (Throwable e) { 247 Log.e(TAG, "Could not load photo from database", e); 248 return null; 249 } finally { 250 Utils.closeSilently(cursor); 251 } 252 } 253 254 public List<Entry> getEntries(int type) { 255 Cursor cursor = null; 256 try { 257 SQLiteDatabase db = getReadableDatabase(); 258 cursor = db.query(TABLE_WIDGETS, PROJECTION, 259 WHERE_WIDGET_TYPE, new String[] {String.valueOf(type)}, 260 null, null, null); 261 if (cursor == null) { 262 Log.e(TAG, "query fail: null cursor: " + cursor); 263 return null; 264 } 265 ArrayList<Entry> result = new ArrayList<Entry>(cursor.getCount()); 266 while (cursor.moveToNext()) { 267 result.add(new Entry(cursor)); 268 } 269 return result; 270 } catch (Throwable e) { 271 Log.e(TAG, "Could not load widget from database", e); 272 return null; 273 } finally { 274 Utils.closeSilently(cursor); 275 } 276 } 277 278 /** 279 * Updates the entry in the widget database. 280 */ 281 public void updateEntry(Entry entry) { 282 deleteEntry(entry.widgetId); 283 try { 284 ContentValues values = new ContentValues(); 285 values.put(FIELD_APPWIDGET_ID, entry.widgetId); 286 values.put(FIELD_WIDGET_TYPE, entry.type); 287 values.put(FIELD_ALBUM_PATH, entry.albumPath); 288 values.put(FIELD_IMAGE_URI, entry.imageUri); 289 values.put(FIELD_PHOTO_BLOB, entry.imageData); 290 values.put(FIELD_RELATIVE_PATH, entry.relativePath); 291 getWritableDatabase().insert(TABLE_WIDGETS, null, values); 292 } catch (Throwable e) { 293 Log.e(TAG, "set widget fail", e); 294 } 295 } 296 297 /** 298 * Remove any bitmap associated with the given appWidgetId. 299 */ 300 public void deleteEntry(int appWidgetId) { 301 try { 302 SQLiteDatabase db = getWritableDatabase(); 303 db.delete(TABLE_WIDGETS, WHERE_APPWIDGET_ID, 304 new String[] {String.valueOf(appWidgetId)}); 305 } catch (SQLiteException e) { 306 Log.e(TAG, "Could not delete photo from database", e); 307 } 308 } 309 } 310