blob: a3e529d3284bbea8f432a47a5bda8cfb6568e1ce [file] [log] [blame]
The Android Open Source Projectd097a182008-12-17 18:05:58 -08001/*
2 * Copyright (C) 2008 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.launcher;
18
19import android.content.ContentProvider;
20import android.content.Context;
21import android.content.ContentValues;
22import android.content.Intent;
23import android.content.ComponentName;
24import android.content.ContentUris;
25import android.content.ContentResolver;
26import android.content.pm.PackageManager;
27import android.content.pm.ActivityInfo;
28import android.database.sqlite.SQLiteOpenHelper;
29import android.database.sqlite.SQLiteDatabase;
30import android.database.sqlite.SQLiteQueryBuilder;
31import android.database.Cursor;
32import android.util.Log;
33import android.util.Xml;
34import android.net.Uri;
35import android.text.TextUtils;
36import android.os.*;
37import android.provider.Settings;
38
39import java.io.FileReader;
40import java.io.File;
41import java.io.FileNotFoundException;
42import java.io.IOException;
43
44import org.xmlpull.v1.XmlPullParser;
45import org.xmlpull.v1.XmlPullParserException;
46import com.android.internal.util.XmlUtils;
47
48public class LauncherProvider extends ContentProvider {
49 private static final String LOG_TAG = "LauncherSettingsProvider";
50
51 private static final String DATABASE_NAME = "launcher.db";
52 private static final int DATABASE_VERSION = 1;
53
54 static final String AUTHORITY = "com.android.launcher.settings";
55
56 static final String TABLE_FAVORITES = "favorites";
57 static final String PARAMETER_NOTIFY = "notify";
58
59 private SQLiteOpenHelper mOpenHelper;
60
61 @Override
62 public boolean onCreate() {
63 mOpenHelper = new DatabaseHelper(getContext());
64 return true;
65 }
66
67 @Override
68 public String getType(Uri uri) {
69 SqlArguments args = new SqlArguments(uri, null, null);
70 if (TextUtils.isEmpty(args.where)) {
71 return "vnd.android.cursor.dir/" + args.table;
72 } else {
73 return "vnd.android.cursor.item/" + args.table;
74 }
75 }
76
77 @Override
78 public Cursor query(Uri uri, String[] projection, String selection,
79 String[] selectionArgs, String sortOrder) {
80
81 SqlArguments args = new SqlArguments(uri, selection, selectionArgs);
82 SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
83 qb.setTables(args.table);
84
85 SQLiteDatabase db = mOpenHelper.getReadableDatabase();
86 Cursor result = qb.query(db, projection, args.where, args.args, null, null, sortOrder);
87 result.setNotificationUri(getContext().getContentResolver(), uri);
88
89 return result;
90 }
91
92 @Override
93 public Uri insert(Uri uri, ContentValues initialValues) {
94 SqlArguments args = new SqlArguments(uri);
95
96 SQLiteDatabase db = mOpenHelper.getWritableDatabase();
97 final long rowId = db.insert(args.table, null, initialValues);
98 if (rowId <= 0) return null;
99
100 uri = ContentUris.withAppendedId(uri, rowId);
101 sendNotify(uri);
102
103 return uri;
104 }
105
106 @Override
107 public int bulkInsert(Uri uri, ContentValues[] values) {
108 SqlArguments args = new SqlArguments(uri);
109
110 SQLiteDatabase db = mOpenHelper.getWritableDatabase();
111 db.beginTransaction();
112 try {
113 int numValues = values.length;
114 for (int i = 0; i < numValues; i++) {
115 if (db.insert(args.table, null, values[i]) < 0) return 0;
116 }
117 db.setTransactionSuccessful();
118 } finally {
119 db.endTransaction();
120 }
121
122 sendNotify(uri);
123 return values.length;
124 }
125
126 @Override
127 public int delete(Uri uri, String selection, String[] selectionArgs) {
128 SqlArguments args = new SqlArguments(uri, selection, selectionArgs);
129
130 SQLiteDatabase db = mOpenHelper.getWritableDatabase();
131 int count = db.delete(args.table, args.where, args.args);
132 if (count > 0) sendNotify(uri);
133
134 return count;
135 }
136
137 @Override
138 public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
139 SqlArguments args = new SqlArguments(uri, selection, selectionArgs);
140
141 SQLiteDatabase db = mOpenHelper.getWritableDatabase();
142 int count = db.update(args.table, values, args.where, args.args);
143 if (count > 0) sendNotify(uri);
144
145 return count;
146 }
147
148 private void sendNotify(Uri uri) {
149 String notify = uri.getQueryParameter(PARAMETER_NOTIFY);
150 if (notify == null || "true".equals(notify)) {
151 getContext().getContentResolver().notifyChange(uri, null);
152 }
153 }
154
155 private static class DatabaseHelper extends SQLiteOpenHelper {
156 /**
157 * Path to file containing default favorite packages, relative to ANDROID_ROOT.
158 */
159 private static final String DEFAULT_FAVORITES_PATH = "etc/favorites.xml";
160
161 private static final String TAG_FAVORITES = "favorites";
162 private static final String TAG_FAVORITE = "favorite";
163 private static final String TAG_PACKAGE = "package";
164 private static final String TAG_CLASS = "class";
165
166 private static final String ATTRIBUTE_SCREEN = "screen";
167 private static final String ATTRIBUTE_X = "x";
168 private static final String ATTRIBUTE_Y = "y";
169
170 private final Context mContext;
171
172 DatabaseHelper(Context context) {
173 super(context, DATABASE_NAME, null, DATABASE_VERSION);
174 mContext = context;
175 }
176
177 @Override
178 public void onCreate(SQLiteDatabase db) {
179 db.execSQL("CREATE TABLE favorites (" +
180 "_id INTEGER PRIMARY KEY," +
181 "title TEXT," +
182 "intent TEXT," +
183 "container INTEGER," +
184 "screen INTEGER," +
185 "cellX INTEGER," +
186 "cellY INTEGER," +
187 "spanX INTEGER," +
188 "spanY INTEGER," +
189 "itemType INTEGER," +
190 "isShortcut INTEGER," +
191 "iconType INTEGER," +
192 "iconPackage TEXT," +
193 "iconResource TEXT," +
194 "icon BLOB," +
195 "uri TEXT," +
196 "displayMode INTEGER" +
197 ");");
198
199 if (!convertDatabase(db)) {
200 // Populate favorites table with initial favorites
201 loadFavorites(db, DEFAULT_FAVORITES_PATH);
202 }
203 }
204
205 private boolean convertDatabase(SQLiteDatabase db) {
206 boolean converted = false;
207
208 final Uri uri = Uri.parse("content://" + Settings.AUTHORITY +
209 "/favorites?notify=true");
210 final ContentResolver resolver = mContext.getContentResolver();
211 Cursor cursor = null;
212
213 try {
214 cursor = resolver.query(uri, null, null, null, null);
215 } catch (Exception e) {
216 // Ignore
217 }
218
219 // We already have a favorites database in the old provider
220 if (cursor != null && cursor.getCount() > 0) {
221 try {
222 converted = copyFromCursor(db, cursor) > 0;
223 } finally {
224 cursor.close();
225 }
226
227 if (converted) {
228 resolver.delete(uri, null, null);
229 }
230 }
231
232 return converted;
233 }
234
235 private int copyFromCursor(SQLiteDatabase db, Cursor c) {
236 final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ID);
237 final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);
238 final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);
239 final int iconTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_TYPE);
240 final int iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);
241 final int iconPackageIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_PACKAGE);
242 final int iconResourceIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_RESOURCE);
243 final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
244 final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
245 final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);
246 final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
247 final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
248 final int uriIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI);
249 final int displayModeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.DISPLAY_MODE);
250
251 ContentValues[] rows = new ContentValues[c.getCount()];
252 int i = 0;
253 while (c.moveToNext()) {
254 ContentValues values = new ContentValues(c.getColumnCount());
255 values.put(LauncherSettings.Favorites.ID, c.getLong(idIndex));
256 values.put(LauncherSettings.Favorites.INTENT, c.getString(intentIndex));
257 values.put(LauncherSettings.Favorites.TITLE, c.getString(titleIndex));
258 values.put(LauncherSettings.Favorites.ICON_TYPE, c.getInt(iconTypeIndex));
259 values.put(LauncherSettings.Favorites.ICON, c.getBlob(iconIndex));
260 values.put(LauncherSettings.Favorites.ICON_PACKAGE, c.getString(iconPackageIndex));
261 values.put(LauncherSettings.Favorites.ICON_RESOURCE, c.getString(iconResourceIndex));
262 values.put(LauncherSettings.Favorites.CONTAINER, c.getInt(containerIndex));
263 values.put(LauncherSettings.Favorites.ITEM_TYPE, c.getInt(itemTypeIndex));
264 values.put(LauncherSettings.Favorites.SCREEN, c.getInt(screenIndex));
265 values.put(LauncherSettings.Favorites.CELLX, c.getInt(cellXIndex));
266 values.put(LauncherSettings.Favorites.CELLY, c.getInt(cellYIndex));
267 values.put(LauncherSettings.Favorites.URI, c.getString(uriIndex));
268 values.put(LauncherSettings.Favorites.DISPLAY_MODE, c.getInt(displayModeIndex));
269 rows[i++] = values;
270 }
271
272 db.beginTransaction();
273 int total = 0;
274 try {
275 int numValues = rows.length;
276 for (i = 0; i < numValues; i++) {
277 if (db.insert(TABLE_FAVORITES, null, rows[i]) < 0) {
278 return 0;
279 } else {
280 total++;
281 }
282 }
283 db.setTransactionSuccessful();
284 } finally {
285 db.endTransaction();
286 }
287
288 return total;
289 }
290
291 @Override
292 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
293 Log.w(LOG_TAG, "Upgrading database from version " + oldVersion + " to " +
294 newVersion + ", which will destroy all old data");
295
296 db.execSQL("DROP TABLE IF EXISTS " + TABLE_FAVORITES);
297 onCreate(db);
298 }
299
300
301 /**
302 * Loads the default set of favorite packages from an xml file.
303 *
304 * @param db The database to write the values into
305 * @param subPath The relative path from ANDROID_ROOT to the file to read
306 */
307 private int loadFavorites(SQLiteDatabase db, String subPath) {
308 FileReader favReader;
309
310 // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
311 final File favFile = new File(Environment.getRootDirectory(), subPath);
312 try {
313 favReader = new FileReader(favFile);
314 } catch (FileNotFoundException e) {
315 Log.e(LOG_TAG, "Couldn't find or open favorites file " + favFile);
316 return 0;
317 }
318
319 Intent intent = new Intent(Intent.ACTION_MAIN, null);
320 intent.addCategory(Intent.CATEGORY_LAUNCHER);
321 ContentValues values = new ContentValues();
322
323 PackageManager packageManager = mContext.getPackageManager();
324 ActivityInfo info;
325 int i = 0;
326 try {
327 XmlPullParser parser = Xml.newPullParser();
328 parser.setInput(favReader);
329
330 XmlUtils.beginDocument(parser, TAG_FAVORITES);
331
332 while (true) {
333 XmlUtils.nextElement(parser);
334
335 String name = parser.getName();
336 if (!TAG_FAVORITE.equals(name)) {
337 break;
338 }
339
340 String pkg = parser.getAttributeValue(null, TAG_PACKAGE);
341 String cls = parser.getAttributeValue(null, TAG_CLASS);
342 try {
343 ComponentName cn = new ComponentName(pkg, cls);
344 info = packageManager.getActivityInfo(cn, 0);
345 intent.setComponent(cn);
346 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
347 values.put(LauncherSettings.Favorites.INTENT, intent.toURI());
348 values.put(LauncherSettings.Favorites.TITLE,
349 info.loadLabel(packageManager).toString());
350 values.put(LauncherSettings.Favorites.CONTAINER,
351 LauncherSettings.Favorites.CONTAINER_DESKTOP);
352 values.put(LauncherSettings.Favorites.ITEM_TYPE,
353 LauncherSettings.Favorites.ITEM_TYPE_APPLICATION);
354 values.put(LauncherSettings.Favorites.SCREEN,
355 parser.getAttributeValue(null, ATTRIBUTE_SCREEN));
356 values.put(LauncherSettings.Favorites.CELLX,
357 parser.getAttributeValue(null, ATTRIBUTE_X));
358 values.put(LauncherSettings.Favorites.CELLY,
359 parser.getAttributeValue(null, ATTRIBUTE_Y));
360 values.put(LauncherSettings.Favorites.SPANX, 1);
361 values.put(LauncherSettings.Favorites.SPANY, 1);
362 db.insert(TABLE_FAVORITES, null, values);
363 i++;
364 } catch (PackageManager.NameNotFoundException e) {
365 Log.w(LOG_TAG, "Unable to add favorite: " + pkg + "/" + cls, e);
366 }
367 }
368 } catch (XmlPullParserException e) {
369 Log.w(LOG_TAG, "Got exception parsing favorites.", e);
370 } catch (IOException e) {
371 Log.w(LOG_TAG, "Got exception parsing favorites.", e);
372 }
373
374 // Add a clock
375 values.clear();
376 values.put(LauncherSettings.Favorites.CONTAINER,
377 LauncherSettings.Favorites.CONTAINER_DESKTOP);
378 values.put(LauncherSettings.Favorites.ITEM_TYPE,
379 LauncherSettings.Favorites.ITEM_TYPE_WIDGET_CLOCK);
380 values.put(LauncherSettings.Favorites.SCREEN, 1);
381 values.put(LauncherSettings.Favorites.CELLX, 1);
382 values.put(LauncherSettings.Favorites.CELLY, 0);
383 values.put(LauncherSettings.Favorites.SPANX, 2);
384 values.put(LauncherSettings.Favorites.SPANY, 2);
385 db.insert(TABLE_FAVORITES, null, values);
386
387 // Add a search box
388 values.clear();
389 values.put(LauncherSettings.Favorites.CONTAINER,
390 LauncherSettings.Favorites.CONTAINER_DESKTOP);
391 values.put(LauncherSettings.Favorites.ITEM_TYPE,
392 LauncherSettings.Favorites.ITEM_TYPE_WIDGET_SEARCH);
393 values.put(LauncherSettings.Favorites.SCREEN, 2);
394 values.put(LauncherSettings.Favorites.CELLX, 0);
395 values.put(LauncherSettings.Favorites.CELLY, 0);
396 values.put(LauncherSettings.Favorites.SPANX, 4);
397 values.put(LauncherSettings.Favorites.SPANY, 1);
398 db.insert(TABLE_FAVORITES, null, values);
399
400 return i;
401 }
402 }
403
404 static class SqlArguments {
405 public final String table;
406 public final String where;
407 public final String[] args;
408
409 SqlArguments(Uri url, String where, String[] args) {
410 if (url.getPathSegments().size() == 1) {
411 this.table = url.getPathSegments().get(0);
412 this.where = where;
413 this.args = args;
414 } else if (url.getPathSegments().size() != 2) {
415 throw new IllegalArgumentException("Invalid URI: " + url);
416 } else if (!TextUtils.isEmpty(where)) {
417 throw new UnsupportedOperationException("WHERE clause not supported: " + url);
418 } else {
419 this.table = url.getPathSegments().get(0);
420 this.where = "_id=" + ContentUris.parseId(url);
421 this.args = null;
422 }
423 }
424
425 SqlArguments(Uri url) {
426 if (url.getPathSegments().size() == 1) {
427 table = url.getPathSegments().get(0);
428 where = null;
429 args = null;
430 } else {
431 throw new IllegalArgumentException("Invalid URI: " + url);
432 }
433 }
434 }
435}