Home | History | Annotate | Download | only in gadget
      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