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}