blob: e63ef3084f8054d9332c3fc5612cddfe4fa3d816 [file] [log] [blame]
The Android Open Source Project31dd5032009-03-03 19:32:27 -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
The Android Open Source Project7376fae2009-03-11 12:11:58 -070019import android.appwidget.AppWidgetHost;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080020import android.content.ContentProvider;
21import android.content.Context;
22import android.content.ContentValues;
23import android.content.Intent;
24import android.content.ComponentName;
25import android.content.ContentUris;
26import android.content.ContentResolver;
The Android Open Source Projectf96811c2009-03-18 17:39:48 -070027import android.content.res.XmlResourceParser;
28import android.content.res.TypedArray;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080029import android.content.pm.PackageManager;
30import android.content.pm.ActivityInfo;
31import android.database.sqlite.SQLiteOpenHelper;
32import android.database.sqlite.SQLiteDatabase;
33import android.database.sqlite.SQLiteQueryBuilder;
34import android.database.Cursor;
35import android.database.SQLException;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080036import android.util.Log;
37import android.util.Xml;
The Android Open Source Projectf96811c2009-03-18 17:39:48 -070038import android.util.AttributeSet;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080039import android.net.Uri;
40import android.text.TextUtils;
41import android.os.*;
42import android.provider.Settings;
43
The Android Open Source Project31dd5032009-03-03 19:32:27 -080044import java.io.IOException;
45import java.util.ArrayList;
46
The Android Open Source Project31dd5032009-03-03 19:32:27 -080047import org.xmlpull.v1.XmlPullParserException;
The Android Open Source Projectf96811c2009-03-18 17:39:48 -070048import org.xmlpull.v1.XmlPullParser;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080049import com.android.internal.util.XmlUtils;
50import com.android.launcher.LauncherSettings.Favorites;
51
52public class LauncherProvider extends ContentProvider {
53 private static final String LOG_TAG = "LauncherProvider";
54 private static final boolean LOGD = true;
55
56 private static final String DATABASE_NAME = "launcher.db";
57
The Android Open Source Projectca9475f2009-03-13 13:04:24 -070058 private static final int DATABASE_VERSION = 3;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080059
60 static final String AUTHORITY = "com.android.launcher.settings";
61
62 static final String EXTRA_BIND_SOURCES = "com.android.launcher.settings.bindsources";
63 static final String EXTRA_BIND_TARGETS = "com.android.launcher.settings.bindtargets";
64
65 static final String TABLE_FAVORITES = "favorites";
66 static final String PARAMETER_NOTIFY = "notify";
67
68 private SQLiteOpenHelper mOpenHelper;
69
70 @Override
71 public boolean onCreate() {
72 mOpenHelper = new DatabaseHelper(getContext());
73 return true;
74 }
75
76 @Override
77 public String getType(Uri uri) {
78 SqlArguments args = new SqlArguments(uri, null, null);
79 if (TextUtils.isEmpty(args.where)) {
80 return "vnd.android.cursor.dir/" + args.table;
81 } else {
82 return "vnd.android.cursor.item/" + args.table;
83 }
84 }
85
86 @Override
87 public Cursor query(Uri uri, String[] projection, String selection,
88 String[] selectionArgs, String sortOrder) {
89
90 SqlArguments args = new SqlArguments(uri, selection, selectionArgs);
91 SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
92 qb.setTables(args.table);
93
94 SQLiteDatabase db = mOpenHelper.getReadableDatabase();
95 Cursor result = qb.query(db, projection, args.where, args.args, null, null, sortOrder);
96 result.setNotificationUri(getContext().getContentResolver(), uri);
97
98 return result;
99 }
100
101 @Override
102 public Uri insert(Uri uri, ContentValues initialValues) {
103 SqlArguments args = new SqlArguments(uri);
104
105 SQLiteDatabase db = mOpenHelper.getWritableDatabase();
106 final long rowId = db.insert(args.table, null, initialValues);
107 if (rowId <= 0) return null;
108
109 uri = ContentUris.withAppendedId(uri, rowId);
110 sendNotify(uri);
111
112 return uri;
113 }
114
115 @Override
116 public int bulkInsert(Uri uri, ContentValues[] values) {
117 SqlArguments args = new SqlArguments(uri);
118
119 SQLiteDatabase db = mOpenHelper.getWritableDatabase();
120 db.beginTransaction();
121 try {
122 int numValues = values.length;
123 for (int i = 0; i < numValues; i++) {
124 if (db.insert(args.table, null, values[i]) < 0) return 0;
125 }
126 db.setTransactionSuccessful();
127 } finally {
128 db.endTransaction();
129 }
130
131 sendNotify(uri);
132 return values.length;
133 }
134
135 @Override
136 public int delete(Uri uri, String selection, String[] selectionArgs) {
137 SqlArguments args = new SqlArguments(uri, selection, selectionArgs);
138
139 SQLiteDatabase db = mOpenHelper.getWritableDatabase();
140 int count = db.delete(args.table, args.where, args.args);
141 if (count > 0) sendNotify(uri);
142
143 return count;
144 }
145
146 @Override
147 public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
148 SqlArguments args = new SqlArguments(uri, selection, selectionArgs);
149
150 SQLiteDatabase db = mOpenHelper.getWritableDatabase();
151 int count = db.update(args.table, values, args.where, args.args);
152 if (count > 0) sendNotify(uri);
153
154 return count;
155 }
156
157 private void sendNotify(Uri uri) {
158 String notify = uri.getQueryParameter(PARAMETER_NOTIFY);
159 if (notify == null || "true".equals(notify)) {
160 getContext().getContentResolver().notifyChange(uri, null);
161 }
162 }
163
164 private static class DatabaseHelper extends SQLiteOpenHelper {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800165 private static final String TAG_FAVORITES = "favorites";
166 private static final String TAG_FAVORITE = "favorite";
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700167 private static final String TAG_CLOCK = "clock";
168 private static final String TAG_SEARCH = "search";
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800169
170 private final Context mContext;
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700171 private final AppWidgetHost mAppWidgetHost;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800172
173 DatabaseHelper(Context context) {
174 super(context, DATABASE_NAME, null, DATABASE_VERSION);
175 mContext = context;
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700176 mAppWidgetHost = new AppWidgetHost(context, Launcher.APPWIDGET_HOST_ID);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800177 }
178
179 @Override
180 public void onCreate(SQLiteDatabase db) {
181 if (LOGD) Log.d(LOG_TAG, "creating new launcher database");
182
183 db.execSQL("CREATE TABLE favorites (" +
184 "_id INTEGER PRIMARY KEY," +
185 "title TEXT," +
186 "intent TEXT," +
187 "container INTEGER," +
188 "screen INTEGER," +
189 "cellX INTEGER," +
190 "cellY INTEGER," +
191 "spanX INTEGER," +
192 "spanY INTEGER," +
193 "itemType INTEGER," +
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700194 "appWidgetId INTEGER NOT NULL DEFAULT -1," +
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800195 "isShortcut INTEGER," +
196 "iconType INTEGER," +
197 "iconPackage TEXT," +
198 "iconResource TEXT," +
199 "icon BLOB," +
200 "uri TEXT," +
201 "displayMode INTEGER" +
202 ");");
203
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700204 // Database was just created, so wipe any previous widgets
205 if (mAppWidgetHost != null) {
206 mAppWidgetHost.deleteHost();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800207 }
208
209 if (!convertDatabase(db)) {
210 // Populate favorites table with initial favorites
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700211 loadFavorites(db);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800212 }
213 }
214
215 private boolean convertDatabase(SQLiteDatabase db) {
216 if (LOGD) Log.d(LOG_TAG, "converting database from an older format, but not onUpgrade");
217 boolean converted = false;
218
219 final Uri uri = Uri.parse("content://" + Settings.AUTHORITY +
220 "/old_favorites?notify=true");
221 final ContentResolver resolver = mContext.getContentResolver();
222 Cursor cursor = null;
223
224 try {
225 cursor = resolver.query(uri, null, null, null, null);
226 } catch (Exception e) {
227 // Ignore
228 }
229
230 // We already have a favorites database in the old provider
231 if (cursor != null && cursor.getCount() > 0) {
232 try {
233 converted = copyFromCursor(db, cursor) > 0;
234 } finally {
235 cursor.close();
236 }
237
238 if (converted) {
239 resolver.delete(uri, null, null);
240 }
241 }
242
243 if (converted) {
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700244 // Convert widgets from this import into widgets
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800245 if (LOGD) Log.d(LOG_TAG, "converted and now triggering widget upgrade");
246 convertWidgets(db);
247 }
248
249 return converted;
250 }
251
252 private int copyFromCursor(SQLiteDatabase db, Cursor c) {
253 final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ID);
254 final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);
255 final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);
256 final int iconTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_TYPE);
257 final int iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);
258 final int iconPackageIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_PACKAGE);
259 final int iconResourceIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_RESOURCE);
260 final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
261 final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
262 final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);
263 final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
264 final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
265 final int uriIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI);
266 final int displayModeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.DISPLAY_MODE);
267
268 ContentValues[] rows = new ContentValues[c.getCount()];
269 int i = 0;
270 while (c.moveToNext()) {
271 ContentValues values = new ContentValues(c.getColumnCount());
272 values.put(LauncherSettings.Favorites.ID, c.getLong(idIndex));
273 values.put(LauncherSettings.Favorites.INTENT, c.getString(intentIndex));
274 values.put(LauncherSettings.Favorites.TITLE, c.getString(titleIndex));
275 values.put(LauncherSettings.Favorites.ICON_TYPE, c.getInt(iconTypeIndex));
276 values.put(LauncherSettings.Favorites.ICON, c.getBlob(iconIndex));
277 values.put(LauncherSettings.Favorites.ICON_PACKAGE, c.getString(iconPackageIndex));
278 values.put(LauncherSettings.Favorites.ICON_RESOURCE, c.getString(iconResourceIndex));
279 values.put(LauncherSettings.Favorites.CONTAINER, c.getInt(containerIndex));
280 values.put(LauncherSettings.Favorites.ITEM_TYPE, c.getInt(itemTypeIndex));
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700281 values.put(LauncherSettings.Favorites.APPWIDGET_ID, -1);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800282 values.put(LauncherSettings.Favorites.SCREEN, c.getInt(screenIndex));
283 values.put(LauncherSettings.Favorites.CELLX, c.getInt(cellXIndex));
284 values.put(LauncherSettings.Favorites.CELLY, c.getInt(cellYIndex));
285 values.put(LauncherSettings.Favorites.URI, c.getString(uriIndex));
286 values.put(LauncherSettings.Favorites.DISPLAY_MODE, c.getInt(displayModeIndex));
287 rows[i++] = values;
288 }
289
290 db.beginTransaction();
291 int total = 0;
292 try {
293 int numValues = rows.length;
294 for (i = 0; i < numValues; i++) {
295 if (db.insert(TABLE_FAVORITES, null, rows[i]) < 0) {
296 return 0;
297 } else {
298 total++;
299 }
300 }
301 db.setTransactionSuccessful();
302 } finally {
303 db.endTransaction();
304 }
305
306 return total;
307 }
308
309 @Override
310 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
311 if (LOGD) Log.d(LOG_TAG, "onUpgrade triggered");
312
313 int version = oldVersion;
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700314 if (version < 3) {
315 // upgrade 1,2 -> 3 added appWidgetId column
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800316 db.beginTransaction();
317 try {
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700318 // Insert new column for holding appWidgetIds
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800319 db.execSQL("ALTER TABLE favorites " +
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700320 "ADD COLUMN appWidgetId INTEGER NOT NULL DEFAULT -1;");
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800321 db.setTransactionSuccessful();
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700322 version = 3;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800323 } catch (SQLException ex) {
324 // Old version remains, which means we wipe old data
325 Log.e(LOG_TAG, ex.getMessage(), ex);
326 } finally {
327 db.endTransaction();
328 }
329
330 // Convert existing widgets only if table upgrade was successful
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700331 if (version == 3) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800332 convertWidgets(db);
333 }
334 }
335
336 if (version != DATABASE_VERSION) {
337 Log.w(LOG_TAG, "Destroying all old data.");
338 db.execSQL("DROP TABLE IF EXISTS " + TABLE_FAVORITES);
339 onCreate(db);
340 }
341 }
342
343 /**
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700344 * Upgrade existing clock and photo frame widgets into their new widget
345 * equivalents. This method allocates appWidgetIds, and then hands off to
346 * LauncherAppWidgetBinder to finish the actual binding.
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800347 */
348 private void convertWidgets(SQLiteDatabase db) {
349 final int[] bindSources = new int[] {
350 Favorites.ITEM_TYPE_WIDGET_CLOCK,
351 Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME,
352 };
353
354 final ArrayList<ComponentName> bindTargets = new ArrayList<ComponentName>();
355 bindTargets.add(new ComponentName("com.android.alarmclock",
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700356 "com.android.alarmclock.AnalogAppWidgetProvider"));
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800357 bindTargets.add(new ComponentName("com.android.camera",
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700358 "com.android.camera.PhotoAppWidgetProvider"));
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800359
360 final String selectWhere = buildOrWhereString(Favorites.ITEM_TYPE, bindSources);
361
362 Cursor c = null;
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700363 boolean allocatedAppWidgets = false;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800364
365 db.beginTransaction();
366 try {
367 // Select and iterate through each matching widget
368 c = db.query(TABLE_FAVORITES, new String[] { Favorites._ID },
369 selectWhere, null, null, null, null);
370
371 if (LOGD) Log.d(LOG_TAG, "found upgrade cursor count="+c.getCount());
372
373 final ContentValues values = new ContentValues();
374 while (c != null && c.moveToNext()) {
375 long favoriteId = c.getLong(0);
376
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700377 // Allocate and update database with new appWidgetId
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800378 try {
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700379 int appWidgetId = mAppWidgetHost.allocateAppWidgetId();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800380
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700381 if (LOGD) Log.d(LOG_TAG, "allocated appWidgetId="+appWidgetId+" for favoriteId="+favoriteId);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800382
383 values.clear();
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700384 values.put(LauncherSettings.Favorites.APPWIDGET_ID, appWidgetId);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800385
386 // Original widgets might not have valid spans when upgrading
387 values.put(LauncherSettings.Favorites.SPANX, 2);
388 values.put(LauncherSettings.Favorites.SPANY, 2);
389
390 String updateWhere = Favorites._ID + "=" + favoriteId;
391 db.update(TABLE_FAVORITES, values, updateWhere, null);
392
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700393 allocatedAppWidgets = true;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800394 } catch (RuntimeException ex) {
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700395 Log.e(LOG_TAG, "Problem allocating appWidgetId", ex);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800396 }
397 }
398
399 db.setTransactionSuccessful();
400 } catch (SQLException ex) {
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700401 Log.w(LOG_TAG, "Problem while allocating appWidgetIds for existing widgets", ex);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800402 } finally {
403 db.endTransaction();
404 if (c != null) {
405 c.close();
406 }
407 }
408
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700409 // If any appWidgetIds allocated, then launch over to binder
410 if (allocatedAppWidgets) {
411 launchAppWidgetBinder(bindSources, bindTargets);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800412 }
413 }
414
415 /**
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700416 * Launch the widget binder that walks through the Launcher database,
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800417 * binding any matching widgets to the corresponding targets. We can't
418 * bind ourselves because our parent process can't obtain the
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700419 * BIND_APPWIDGET permission.
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800420 */
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700421 private void launchAppWidgetBinder(int[] bindSources, ArrayList<ComponentName> bindTargets) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800422 final Intent intent = new Intent();
423 intent.setComponent(new ComponentName("com.android.settings",
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700424 "com.android.settings.LauncherAppWidgetBinder"));
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800425 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
426
427 final Bundle extras = new Bundle();
428 extras.putIntArray(EXTRA_BIND_SOURCES, bindSources);
429 extras.putParcelableArrayList(EXTRA_BIND_TARGETS, bindTargets);
430 intent.putExtras(extras);
431
432 mContext.startActivity(intent);
433 }
434
435 /**
436 * Loads the default set of favorite packages from an xml file.
437 *
438 * @param db The database to write the values into
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800439 */
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700440 private int loadFavorites(SQLiteDatabase db) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800441 Intent intent = new Intent(Intent.ACTION_MAIN, null);
442 intent.addCategory(Intent.CATEGORY_LAUNCHER);
443 ContentValues values = new ContentValues();
444
445 PackageManager packageManager = mContext.getPackageManager();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800446 int i = 0;
447 try {
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700448 XmlResourceParser parser = mContext.getResources().getXml(R.xml.default_workspace);
449 AttributeSet attrs = Xml.asAttributeSet(parser);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800450 XmlUtils.beginDocument(parser, TAG_FAVORITES);
451
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700452 final int depth = parser.getDepth();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800453
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700454 int type;
455 while (((type = parser.next()) != XmlPullParser.END_TAG ||
456 parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
457
458 if (type != XmlPullParser.START_TAG) {
459 continue;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800460 }
461
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700462 boolean added = false;
463 final String name = parser.getName();
464
465 TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.Favorite);
466
467 values.clear();
468 values.put(LauncherSettings.Favorites.CONTAINER,
469 LauncherSettings.Favorites.CONTAINER_DESKTOP);
470 values.put(LauncherSettings.Favorites.SCREEN,
471 a.getString(R.styleable.Favorite_screen));
472 values.put(LauncherSettings.Favorites.CELLX,
473 a.getString(R.styleable.Favorite_x));
474 values.put(LauncherSettings.Favorites.CELLY,
475 a.getString(R.styleable.Favorite_y));
476
477 if (TAG_FAVORITE.equals(name)) {
478 added = addShortcut(db, values, a, packageManager, intent);
479 } else if (TAG_SEARCH.equals(name)) {
480 added = addSearchWidget(db, values);
481 } else if (TAG_CLOCK.equals(name)) {
482 added = addClockWidget(db, values);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800483 }
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700484
485 if (added) i++;
486
487 a.recycle();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800488 }
489 } catch (XmlPullParserException e) {
490 Log.w(LOG_TAG, "Got exception parsing favorites.", e);
491 } catch (IOException e) {
492 Log.w(LOG_TAG, "Got exception parsing favorites.", e);
493 }
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700494
495 return i;
496 }
497
498 private boolean addShortcut(SQLiteDatabase db, ContentValues values, TypedArray a,
499 PackageManager packageManager, Intent intent) {
500
501 ActivityInfo info;
502 String packageName = a.getString(R.styleable.Favorite_packageName);
503 String className = a.getString(R.styleable.Favorite_className);
504 try {
505 ComponentName cn = new ComponentName(packageName, className);
506 info = packageManager.getActivityInfo(cn, 0);
507 intent.setComponent(cn);
Dianne Hackbornbd2e54d2009-03-24 21:00:33 -0700508 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
509 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700510 values.put(Favorites.INTENT, intent.toURI());
511 values.put(Favorites.TITLE, info.loadLabel(packageManager).toString());
512 values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_APPLICATION);
513 values.put(Favorites.SPANX, 1);
514 values.put(Favorites.SPANY, 1);
515 db.insert(TABLE_FAVORITES, null, values);
516 } catch (PackageManager.NameNotFoundException e) {
517 Log.w(LOG_TAG, "Unable to add favorite: " + packageName +
518 "/" + className, e);
519 return false;
520 }
521 return true;
522 }
523
524 private boolean addSearchWidget(SQLiteDatabase db, ContentValues values) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800525 // Add a search box
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700526 values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_WIDGET_SEARCH);
527 values.put(Favorites.SPANX, 4);
528 values.put(Favorites.SPANY, 1);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800529 db.insert(TABLE_FAVORITES, null, values);
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700530
531 return true;
532 }
533
534 private boolean addClockWidget(SQLiteDatabase db, ContentValues values) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800535 final int[] bindSources = new int[] {
536 Favorites.ITEM_TYPE_WIDGET_CLOCK,
537 };
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700538
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800539 final ArrayList<ComponentName> bindTargets = new ArrayList<ComponentName>();
540 bindTargets.add(new ComponentName("com.android.alarmclock",
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700541 "com.android.alarmclock.AnalogAppWidgetProvider"));
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700542
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700543 boolean allocatedAppWidgets = false;
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700544
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700545 // Try binding to an analog clock widget
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800546 try {
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700547 int appWidgetId = mAppWidgetHost.allocateAppWidgetId();
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700548
549 values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_WIDGET_CLOCK);
550 values.put(Favorites.SPANX, 2);
551 values.put(Favorites.SPANY, 2);
552 values.put(Favorites.APPWIDGET_ID, appWidgetId);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800553 db.insert(TABLE_FAVORITES, null, values);
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700554
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700555 allocatedAppWidgets = true;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800556 } catch (RuntimeException ex) {
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700557 Log.e(LOG_TAG, "Problem allocating appWidgetId", ex);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800558 }
559
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700560 // If any appWidgetIds allocated, then launch over to binder
561 if (allocatedAppWidgets) {
562 launchAppWidgetBinder(bindSources, bindTargets);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800563 }
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700564
565 return allocatedAppWidgets;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800566 }
567 }
568
569 /**
570 * Build a query string that will match any row where the column matches
571 * anything in the values list.
572 */
573 static String buildOrWhereString(String column, int[] values) {
574 StringBuilder selectWhere = new StringBuilder();
575 for (int i = values.length - 1; i >= 0; i--) {
576 selectWhere.append(column).append("=").append(values[i]);
577 if (i > 0) {
578 selectWhere.append(" OR ");
579 }
580 }
581 return selectWhere.toString();
582 }
583
584 static class SqlArguments {
585 public final String table;
586 public final String where;
587 public final String[] args;
588
589 SqlArguments(Uri url, String where, String[] args) {
590 if (url.getPathSegments().size() == 1) {
591 this.table = url.getPathSegments().get(0);
592 this.where = where;
593 this.args = args;
594 } else if (url.getPathSegments().size() != 2) {
595 throw new IllegalArgumentException("Invalid URI: " + url);
596 } else if (!TextUtils.isEmpty(where)) {
597 throw new UnsupportedOperationException("WHERE clause not supported: " + url);
598 } else {
599 this.table = url.getPathSegments().get(0);
600 this.where = "_id=" + ContentUris.parseId(url);
601 this.args = null;
602 }
603 }
604
605 SqlArguments(Uri url) {
606 if (url.getPathSegments().size() == 1) {
607 table = url.getPathSegments().get(0);
608 where = null;
609 args = null;
610 } else {
611 throw new IllegalArgumentException("Invalid URI: " + url);
612 }
613 }
614 }
615}