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