blob: f971a3743c46f66d84c66304e89aa1b304bdec7d [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
Daniel Sandler325dc232013-06-05 22:57:57 -040017package com.android.launcher3;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080018
Bjorn Bringertcd8fec02010-01-14 13:26:43 +000019import android.app.SearchManager;
The Android Open Source Project7376fae2009-03-11 12:11:58 -070020import android.appwidget.AppWidgetHost;
Mike Cleronb87bd162009-10-30 16:36:56 -070021import android.appwidget.AppWidgetManager;
Bjorn Bringertcd8fec02010-01-14 13:26:43 +000022import android.appwidget.AppWidgetProviderInfo;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080023import android.content.ComponentName;
Adam Cohen228da5a2011-07-27 22:23:47 -070024import android.content.ContentProvider;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080025import android.content.ContentResolver;
Adam Cohen228da5a2011-07-27 22:23:47 -070026import android.content.ContentUris;
27import android.content.ContentValues;
28import android.content.Context;
29import android.content.Intent;
Michael Jurkab85f8a42012-04-25 15:48:32 -070030import android.content.SharedPreferences;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080031import android.content.pm.ActivityInfo;
Adam Cohen228da5a2011-07-27 22:23:47 -070032import android.content.pm.PackageManager;
33import android.content.res.Resources;
34import android.content.res.TypedArray;
35import android.content.res.XmlResourceParser;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080036import android.database.Cursor;
37import android.database.SQLException;
Adam Cohen228da5a2011-07-27 22:23:47 -070038import android.database.sqlite.SQLiteDatabase;
39import android.database.sqlite.SQLiteOpenHelper;
40import android.database.sqlite.SQLiteQueryBuilder;
41import android.database.sqlite.SQLiteStatement;
Joe Onorato0589f0f2010-02-08 13:44:00 -080042import android.graphics.Bitmap;
43import android.graphics.BitmapFactory;
Adam Cohen228da5a2011-07-27 22:23:47 -070044import android.net.Uri;
Winson Chungb3302ae2012-05-01 10:19:14 -070045import android.os.Bundle;
Adam Cohen228da5a2011-07-27 22:23:47 -070046import android.provider.Settings;
47import android.text.TextUtils;
48import android.util.AttributeSet;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080049import android.util.Log;
50import android.util.Xml;
Adam Cohen228da5a2011-07-27 22:23:47 -070051
Daniel Sandler325dc232013-06-05 22:57:57 -040052import com.android.launcher3.R;
53import com.android.launcher3.LauncherSettings.Favorites;
Michael Jurka8b805b12012-04-18 14:23:14 -070054
55import org.xmlpull.v1.XmlPullParser;
56import org.xmlpull.v1.XmlPullParserException;
57
The Android Open Source Project31dd5032009-03-03 19:32:27 -080058import java.io.IOException;
Mike Cleronb87bd162009-10-30 16:36:56 -070059import java.net.URISyntaxException;
Adam Cohen228da5a2011-07-27 22:23:47 -070060import java.util.ArrayList;
Bjorn Bringertcd8fec02010-01-14 13:26:43 +000061import java.util.List;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080062
The Android Open Source Project31dd5032009-03-03 19:32:27 -080063public class LauncherProvider extends ContentProvider {
Joe Onoratoa30ce8e2009-11-11 08:16:49 -080064 private static final String TAG = "Launcher.LauncherProvider";
65 private static final boolean LOGD = false;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080066
67 private static final String DATABASE_NAME = "launcher.db";
Winson Chung3d503fb2011-07-13 17:25:49 -070068
Daniel Lehmannd02402c2012-05-14 18:30:53 -070069 private static final int DATABASE_VERSION = 12;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080070
Adam Cohene25af792013-06-06 23:08:25 -070071 static final String OLD_AUTHORITY = "com.android.launcher2.settings";
Daniel Sandler325dc232013-06-05 22:57:57 -040072 static final String AUTHORITY = "com.android.launcher3.settings";
Winson Chung3d503fb2011-07-13 17:25:49 -070073
The Android Open Source Project31dd5032009-03-03 19:32:27 -080074 static final String TABLE_FAVORITES = "favorites";
75 static final String PARAMETER_NOTIFY = "notify";
Michael Jurkab85f8a42012-04-25 15:48:32 -070076 static final String DB_CREATED_BUT_DEFAULT_WORKSPACE_NOT_LOADED =
77 "DB_CREATED_BUT_DEFAULT_WORKSPACE_NOT_LOADED";
Michael Jurka45355c42012-10-08 13:21:35 +020078 static final String DEFAULT_WORKSPACE_RESOURCE_ID =
79 "DEFAULT_WORKSPACE_RESOURCE_ID";
The Android Open Source Project31dd5032009-03-03 19:32:27 -080080
Winson Chungb3302ae2012-05-01 10:19:14 -070081 private static final String ACTION_APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE =
Adam Cohene25af792013-06-06 23:08:25 -070082 "com.android.launcher.action.APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE";
Winson Chungb3302ae2012-05-01 10:19:14 -070083
Jeffrey Sharkey2bbcae12009-03-31 14:37:57 -070084 /**
Romain Guy73b979d2009-06-09 12:57:21 -070085 * {@link Uri} triggered at any registered {@link android.database.ContentObserver} when
Jeffrey Sharkey2bbcae12009-03-31 14:37:57 -070086 * {@link AppWidgetHost#deleteHost()} is called during database creation.
87 * Use this to recall {@link AppWidgetHost#startListening()} if needed.
88 */
89 static final Uri CONTENT_APPWIDGET_RESET_URI =
90 Uri.parse("content://" + AUTHORITY + "/appWidgetReset");
Daniel Lehmannc3a80402012-04-23 21:35:11 -070091
Michael Jurkaa8c760d2011-04-28 14:59:33 -070092 private DatabaseHelper mOpenHelper;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080093
94 @Override
95 public boolean onCreate() {
96 mOpenHelper = new DatabaseHelper(getContext());
Daniel Sandlercc8befa2013-06-11 14:45:48 -040097 LauncherAppState.getInstance().setLauncherProvider(this);
The Android Open Source Project31dd5032009-03-03 19:32:27 -080098 return true;
99 }
100
101 @Override
102 public String getType(Uri uri) {
103 SqlArguments args = new SqlArguments(uri, null, null);
104 if (TextUtils.isEmpty(args.where)) {
105 return "vnd.android.cursor.dir/" + args.table;
106 } else {
107 return "vnd.android.cursor.item/" + args.table;
108 }
109 }
110
111 @Override
112 public Cursor query(Uri uri, String[] projection, String selection,
113 String[] selectionArgs, String sortOrder) {
114
115 SqlArguments args = new SqlArguments(uri, selection, selectionArgs);
116 SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
117 qb.setTables(args.table);
118
Romain Guy73b979d2009-06-09 12:57:21 -0700119 SQLiteDatabase db = mOpenHelper.getWritableDatabase();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800120 Cursor result = qb.query(db, projection, args.where, args.args, null, null, sortOrder);
121 result.setNotificationUri(getContext().getContentResolver(), uri);
122
123 return result;
124 }
125
Michael Jurkaa8c760d2011-04-28 14:59:33 -0700126 private static long dbInsertAndCheck(DatabaseHelper helper,
127 SQLiteDatabase db, String table, String nullColumnHack, ContentValues values) {
128 if (!values.containsKey(LauncherSettings.Favorites._ID)) {
129 throw new RuntimeException("Error: attempting to add item without specifying an id");
130 }
131 return db.insert(table, nullColumnHack, values);
132 }
133
Adam Cohen228da5a2011-07-27 22:23:47 -0700134 private static void deleteId(SQLiteDatabase db, long id) {
135 Uri uri = LauncherSettings.Favorites.getContentUri(id, false);
136 SqlArguments args = new SqlArguments(uri, null, null);
137 db.delete(args.table, args.where, args.args);
138 }
139
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800140 @Override
141 public Uri insert(Uri uri, ContentValues initialValues) {
142 SqlArguments args = new SqlArguments(uri);
143
144 SQLiteDatabase db = mOpenHelper.getWritableDatabase();
Michael Jurkaa8c760d2011-04-28 14:59:33 -0700145 final long rowId = dbInsertAndCheck(mOpenHelper, db, args.table, null, initialValues);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800146 if (rowId <= 0) return null;
147
148 uri = ContentUris.withAppendedId(uri, rowId);
149 sendNotify(uri);
150
151 return uri;
152 }
153
154 @Override
155 public int bulkInsert(Uri uri, ContentValues[] values) {
156 SqlArguments args = new SqlArguments(uri);
157
158 SQLiteDatabase db = mOpenHelper.getWritableDatabase();
159 db.beginTransaction();
160 try {
161 int numValues = values.length;
162 for (int i = 0; i < numValues; i++) {
Michael Jurkaa8c760d2011-04-28 14:59:33 -0700163 if (dbInsertAndCheck(mOpenHelper, db, args.table, null, values[i]) < 0) {
164 return 0;
165 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800166 }
167 db.setTransactionSuccessful();
168 } finally {
169 db.endTransaction();
170 }
171
172 sendNotify(uri);
173 return values.length;
174 }
175
176 @Override
177 public int delete(Uri uri, String selection, String[] selectionArgs) {
178 SqlArguments args = new SqlArguments(uri, selection, selectionArgs);
179
180 SQLiteDatabase db = mOpenHelper.getWritableDatabase();
181 int count = db.delete(args.table, args.where, args.args);
182 if (count > 0) sendNotify(uri);
183
184 return count;
185 }
186
187 @Override
188 public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
189 SqlArguments args = new SqlArguments(uri, selection, selectionArgs);
190
191 SQLiteDatabase db = mOpenHelper.getWritableDatabase();
192 int count = db.update(args.table, values, args.where, args.args);
193 if (count > 0) sendNotify(uri);
194
195 return count;
196 }
197
198 private void sendNotify(Uri uri) {
199 String notify = uri.getQueryParameter(PARAMETER_NOTIFY);
200 if (notify == null || "true".equals(notify)) {
201 getContext().getContentResolver().notifyChange(uri, null);
202 }
203 }
204
Michael Jurkaa8c760d2011-04-28 14:59:33 -0700205 public long generateNewId() {
206 return mOpenHelper.generateNewId();
207 }
208
Brian Muramatsu5524b492012-10-02 16:55:54 -0700209 /**
Adam Cohene25af792013-06-06 23:08:25 -0700210 * @param Should we load the old db for upgrade? first run only.
211 */
212 synchronized public boolean shouldLoadOldDb() {
Daniel Sandlercc8befa2013-06-11 14:45:48 -0400213 String spKey = LauncherAppState.getSharedPreferencesKey();
Adam Cohene25af792013-06-06 23:08:25 -0700214 SharedPreferences sp = getContext().getSharedPreferences(spKey, Context.MODE_PRIVATE);
215
216 boolean loadOldDb = false;
217 if (sp.getBoolean(DB_CREATED_BUT_DEFAULT_WORKSPACE_NOT_LOADED, false)) {
218
219 SharedPreferences.Editor editor = sp.edit();
220 editor.remove(DB_CREATED_BUT_DEFAULT_WORKSPACE_NOT_LOADED);
221 editor.commit();
222 loadOldDb = true;
223 }
224 return loadOldDb;
225 }
226
227 /**
Brian Muramatsu5524b492012-10-02 16:55:54 -0700228 * @param workspaceResId that can be 0 to use default or non-zero for specific resource
229 */
Michael Jurka45355c42012-10-08 13:21:35 +0200230 synchronized public void loadDefaultFavoritesIfNecessary(int origWorkspaceResId) {
Daniel Sandlercc8befa2013-06-11 14:45:48 -0400231 String spKey = LauncherAppState.getSharedPreferencesKey();
Michael Jurkab85f8a42012-04-25 15:48:32 -0700232 SharedPreferences sp = getContext().getSharedPreferences(spKey, Context.MODE_PRIVATE);
Adam Cohene25af792013-06-06 23:08:25 -0700233
Michael Jurkab85f8a42012-04-25 15:48:32 -0700234 if (sp.getBoolean(DB_CREATED_BUT_DEFAULT_WORKSPACE_NOT_LOADED, false)) {
Michael Jurka45355c42012-10-08 13:21:35 +0200235 int workspaceResId = origWorkspaceResId;
236
Brian Muramatsu5524b492012-10-02 16:55:54 -0700237 // Use default workspace resource if none provided
238 if (workspaceResId == 0) {
Michael Jurka45355c42012-10-08 13:21:35 +0200239 workspaceResId = sp.getInt(DEFAULT_WORKSPACE_RESOURCE_ID, R.xml.default_workspace);
Brian Muramatsu5524b492012-10-02 16:55:54 -0700240 }
241
Michael Jurkab85f8a42012-04-25 15:48:32 -0700242 // Populate favorites table with initial favorites
243 SharedPreferences.Editor editor = sp.edit();
244 editor.remove(DB_CREATED_BUT_DEFAULT_WORKSPACE_NOT_LOADED);
Michael Jurka45355c42012-10-08 13:21:35 +0200245 if (origWorkspaceResId != 0) {
246 editor.putInt(DEFAULT_WORKSPACE_RESOURCE_ID, origWorkspaceResId);
247 }
Adam Cohene25af792013-06-06 23:08:25 -0700248
Brian Muramatsu5524b492012-10-02 16:55:54 -0700249 mOpenHelper.loadFavorites(mOpenHelper.getWritableDatabase(), workspaceResId);
Michael Jurkab85f8a42012-04-25 15:48:32 -0700250 editor.commit();
251 }
252 }
253
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800254 private static class DatabaseHelper extends SQLiteOpenHelper {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800255 private static final String TAG_FAVORITES = "favorites";
256 private static final String TAG_FAVORITE = "favorite";
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700257 private static final String TAG_CLOCK = "clock";
258 private static final String TAG_SEARCH = "search";
Mike Cleronb87bd162009-10-30 16:36:56 -0700259 private static final String TAG_APPWIDGET = "appwidget";
260 private static final String TAG_SHORTCUT = "shortcut";
Adam Cohen228da5a2011-07-27 22:23:47 -0700261 private static final String TAG_FOLDER = "folder";
Winson Chungb3302ae2012-05-01 10:19:14 -0700262 private static final String TAG_EXTRA = "extra";
Winson Chung3d503fb2011-07-13 17:25:49 -0700263
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800264 private final Context mContext;
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700265 private final AppWidgetHost mAppWidgetHost;
Michael Jurkaa8c760d2011-04-28 14:59:33 -0700266 private long mMaxId = -1;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800267
268 DatabaseHelper(Context context) {
269 super(context, DATABASE_NAME, null, DATABASE_VERSION);
270 mContext = context;
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700271 mAppWidgetHost = new AppWidgetHost(context, Launcher.APPWIDGET_HOST_ID);
Winson Chung3d503fb2011-07-13 17:25:49 -0700272
273 // In the case where neither onCreate nor onUpgrade gets called, we read the maxId from
274 // the DB here
275 if (mMaxId == -1) {
276 mMaxId = initializeMaxId(getWritableDatabase());
277 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800278 }
279
Jeffrey Sharkey2bbcae12009-03-31 14:37:57 -0700280 /**
281 * Send notification that we've deleted the {@link AppWidgetHost},
282 * probably as part of the initial database creation. The receiver may
283 * want to re-call {@link AppWidgetHost#startListening()} to ensure
284 * callbacks are correctly set.
285 */
286 private void sendAppWidgetResetNotify() {
287 final ContentResolver resolver = mContext.getContentResolver();
288 resolver.notifyChange(CONTENT_APPWIDGET_RESET_URI, null);
289 }
290
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800291 @Override
292 public void onCreate(SQLiteDatabase db) {
Joe Onoratoa30ce8e2009-11-11 08:16:49 -0800293 if (LOGD) Log.d(TAG, "creating new launcher database");
Michael Jurkaa8c760d2011-04-28 14:59:33 -0700294
295 mMaxId = 1;
296
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800297 db.execSQL("CREATE TABLE favorites (" +
298 "_id INTEGER PRIMARY KEY," +
299 "title TEXT," +
300 "intent TEXT," +
301 "container INTEGER," +
302 "screen INTEGER," +
303 "cellX INTEGER," +
304 "cellY INTEGER," +
305 "spanX INTEGER," +
306 "spanY INTEGER," +
307 "itemType INTEGER," +
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700308 "appWidgetId INTEGER NOT NULL DEFAULT -1," +
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800309 "isShortcut INTEGER," +
310 "iconType INTEGER," +
311 "iconPackage TEXT," +
312 "iconResource TEXT," +
313 "icon BLOB," +
314 "uri TEXT," +
315 "displayMode INTEGER" +
316 ");");
317
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700318 // Database was just created, so wipe any previous widgets
319 if (mAppWidgetHost != null) {
320 mAppWidgetHost.deleteHost();
Jeffrey Sharkey2bbcae12009-03-31 14:37:57 -0700321 sendAppWidgetResetNotify();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800322 }
Winson Chung3d503fb2011-07-13 17:25:49 -0700323
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800324 if (!convertDatabase(db)) {
Michael Jurkab85f8a42012-04-25 15:48:32 -0700325 // Set a shared pref so that we know we need to load the default workspace later
326 setFlagToLoadDefaultWorkspaceLater();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800327 }
328 }
329
Michael Jurkab85f8a42012-04-25 15:48:32 -0700330 private void setFlagToLoadDefaultWorkspaceLater() {
Daniel Sandlercc8befa2013-06-11 14:45:48 -0400331 String spKey = LauncherAppState.getSharedPreferencesKey();
Michael Jurkab85f8a42012-04-25 15:48:32 -0700332 SharedPreferences sp = mContext.getSharedPreferences(spKey, Context.MODE_PRIVATE);
333 SharedPreferences.Editor editor = sp.edit();
334 editor.putBoolean(DB_CREATED_BUT_DEFAULT_WORKSPACE_NOT_LOADED, true);
335 editor.commit();
336 }
337
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800338 private boolean convertDatabase(SQLiteDatabase db) {
Joe Onoratoa30ce8e2009-11-11 08:16:49 -0800339 if (LOGD) Log.d(TAG, "converting database from an older format, but not onUpgrade");
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800340 boolean converted = false;
341
342 final Uri uri = Uri.parse("content://" + Settings.AUTHORITY +
343 "/old_favorites?notify=true");
344 final ContentResolver resolver = mContext.getContentResolver();
345 Cursor cursor = null;
346
347 try {
348 cursor = resolver.query(uri, null, null, null, null);
349 } catch (Exception e) {
Michael Jurkaa8c760d2011-04-28 14:59:33 -0700350 // Ignore
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800351 }
352
353 // We already have a favorites database in the old provider
354 if (cursor != null && cursor.getCount() > 0) {
355 try {
356 converted = copyFromCursor(db, cursor) > 0;
357 } finally {
358 cursor.close();
359 }
360
361 if (converted) {
362 resolver.delete(uri, null, null);
363 }
364 }
Daniel Lehmannc3a80402012-04-23 21:35:11 -0700365
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800366 if (converted) {
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700367 // Convert widgets from this import into widgets
Joe Onoratoa30ce8e2009-11-11 08:16:49 -0800368 if (LOGD) Log.d(TAG, "converted and now triggering widget upgrade");
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800369 convertWidgets(db);
370 }
371
372 return converted;
373 }
374
375 private int copyFromCursor(SQLiteDatabase db, Cursor c) {
Romain Guy73b979d2009-06-09 12:57:21 -0700376 final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800377 final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);
378 final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);
379 final int iconTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_TYPE);
380 final int iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);
381 final int iconPackageIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_PACKAGE);
382 final int iconResourceIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_RESOURCE);
383 final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
384 final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
385 final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);
386 final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
387 final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
388 final int uriIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI);
389 final int displayModeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.DISPLAY_MODE);
390
391 ContentValues[] rows = new ContentValues[c.getCount()];
392 int i = 0;
393 while (c.moveToNext()) {
394 ContentValues values = new ContentValues(c.getColumnCount());
Romain Guy73b979d2009-06-09 12:57:21 -0700395 values.put(LauncherSettings.Favorites._ID, c.getLong(idIndex));
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800396 values.put(LauncherSettings.Favorites.INTENT, c.getString(intentIndex));
397 values.put(LauncherSettings.Favorites.TITLE, c.getString(titleIndex));
398 values.put(LauncherSettings.Favorites.ICON_TYPE, c.getInt(iconTypeIndex));
399 values.put(LauncherSettings.Favorites.ICON, c.getBlob(iconIndex));
400 values.put(LauncherSettings.Favorites.ICON_PACKAGE, c.getString(iconPackageIndex));
401 values.put(LauncherSettings.Favorites.ICON_RESOURCE, c.getString(iconResourceIndex));
402 values.put(LauncherSettings.Favorites.CONTAINER, c.getInt(containerIndex));
403 values.put(LauncherSettings.Favorites.ITEM_TYPE, c.getInt(itemTypeIndex));
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700404 values.put(LauncherSettings.Favorites.APPWIDGET_ID, -1);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800405 values.put(LauncherSettings.Favorites.SCREEN, c.getInt(screenIndex));
406 values.put(LauncherSettings.Favorites.CELLX, c.getInt(cellXIndex));
407 values.put(LauncherSettings.Favorites.CELLY, c.getInt(cellYIndex));
408 values.put(LauncherSettings.Favorites.URI, c.getString(uriIndex));
409 values.put(LauncherSettings.Favorites.DISPLAY_MODE, c.getInt(displayModeIndex));
410 rows[i++] = values;
411 }
412
413 db.beginTransaction();
414 int total = 0;
415 try {
416 int numValues = rows.length;
417 for (i = 0; i < numValues; i++) {
Michael Jurkaa8c760d2011-04-28 14:59:33 -0700418 if (dbInsertAndCheck(this, db, TABLE_FAVORITES, null, rows[i]) < 0) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800419 return 0;
420 } else {
421 total++;
422 }
423 }
424 db.setTransactionSuccessful();
425 } finally {
426 db.endTransaction();
427 }
428
429 return total;
430 }
431
432 @Override
433 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Joe Onoratoa30ce8e2009-11-11 08:16:49 -0800434 if (LOGD) Log.d(TAG, "onUpgrade triggered");
Daniel Lehmannc3a80402012-04-23 21:35:11 -0700435
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800436 int version = oldVersion;
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700437 if (version < 3) {
438 // upgrade 1,2 -> 3 added appWidgetId column
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800439 db.beginTransaction();
440 try {
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700441 // Insert new column for holding appWidgetIds
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800442 db.execSQL("ALTER TABLE favorites " +
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700443 "ADD COLUMN appWidgetId INTEGER NOT NULL DEFAULT -1;");
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800444 db.setTransactionSuccessful();
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700445 version = 3;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800446 } catch (SQLException ex) {
447 // Old version remains, which means we wipe old data
Joe Onoratoa30ce8e2009-11-11 08:16:49 -0800448 Log.e(TAG, ex.getMessage(), ex);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800449 } finally {
450 db.endTransaction();
451 }
Daniel Lehmannc3a80402012-04-23 21:35:11 -0700452
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800453 // Convert existing widgets only if table upgrade was successful
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700454 if (version == 3) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800455 convertWidgets(db);
456 }
457 }
Romain Guy73b979d2009-06-09 12:57:21 -0700458
459 if (version < 4) {
Romain Guy7eb9e5e2009-12-02 20:10:07 -0800460 version = 4;
Romain Guy73b979d2009-06-09 12:57:21 -0700461 }
Daniel Lehmannc3a80402012-04-23 21:35:11 -0700462
Romain Guy509cd6a2010-03-23 15:10:56 -0700463 // Where's version 5?
464 // - Donut and sholes on 2.0 shipped with version 4 of launcher1.
Daniel Sandler325dc232013-06-05 22:57:57 -0400465 // - Passion shipped on 2.1 with version 6 of launcher3
Romain Guy509cd6a2010-03-23 15:10:56 -0700466 // - Sholes shipped on 2.1r1 (aka Mr. 3) with version 5 of launcher 1
467 // but version 5 on there was the updateContactsShortcuts change
468 // which was version 6 in launcher 2 (first shipped on passion 2.1r1).
469 // The updateContactsShortcuts change is idempotent, so running it twice
470 // is okay so we'll do that when upgrading the devices that shipped with it.
471 if (version < 6) {
Mike Cleron3a2b3f22009-11-05 17:17:42 -0800472 // We went from 3 to 5 screens. Move everything 1 to the right
473 db.beginTransaction();
474 try {
475 db.execSQL("UPDATE favorites SET screen=(screen + 1);");
476 db.setTransactionSuccessful();
Mike Cleron3a2b3f22009-11-05 17:17:42 -0800477 } catch (SQLException ex) {
478 // Old version remains, which means we wipe old data
Joe Onoratoa30ce8e2009-11-11 08:16:49 -0800479 Log.e(TAG, ex.getMessage(), ex);
Mike Cleron3a2b3f22009-11-05 17:17:42 -0800480 } finally {
481 db.endTransaction();
482 }
Daniel Lehmannc3a80402012-04-23 21:35:11 -0700483
Romain Guy509cd6a2010-03-23 15:10:56 -0700484 // We added the fast track.
Romain Guy7eb9e5e2009-12-02 20:10:07 -0800485 if (updateContactsShortcuts(db)) {
486 version = 6;
487 }
488 }
Bjorn Bringert7984c942009-12-09 15:38:25 +0000489
490 if (version < 7) {
491 // Version 7 gets rid of the special search widget.
492 convertWidgets(db);
493 version = 7;
494 }
495
Joe Onorato0589f0f2010-02-08 13:44:00 -0800496 if (version < 8) {
497 // Version 8 (froyo) has the icons all normalized. This should
498 // already be the case in practice, but we now rely on it and don't
499 // resample the images each time.
500 normalizeIcons(db);
501 version = 8;
502 }
503
Winson Chung3d503fb2011-07-13 17:25:49 -0700504 if (version < 9) {
505 // The max id is not yet set at this point (onUpgrade is triggered in the ctor
506 // before it gets a change to get set, so we need to read it here when we use it)
507 if (mMaxId == -1) {
508 mMaxId = initializeMaxId(db);
509 }
510
511 // Add default hotseat icons
Winson Chung6d092682011-11-16 18:43:26 -0800512 loadFavorites(db, R.xml.update_workspace);
Winson Chung3d503fb2011-07-13 17:25:49 -0700513 version = 9;
514 }
515
Daniel Lehmannd02402c2012-05-14 18:30:53 -0700516 // We bumped the version three time during JB, once to update the launch flags, once to
517 // update the override for the default launch animation and once to set the mimetype
518 // to improve startup performance
519 if (version < 12) {
Daniel Lehmannc3a80402012-04-23 21:35:11 -0700520 // Contact shortcuts need a different set of flags to be launched now
521 // The updateContactsShortcuts change is idempotent, so we can keep using it like
522 // back in the Donut days
523 updateContactsShortcuts(db);
Daniel Lehmannd02402c2012-05-14 18:30:53 -0700524 version = 12;
Daniel Lehmannc3a80402012-04-23 21:35:11 -0700525 }
526
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800527 if (version != DATABASE_VERSION) {
Joe Onoratoa30ce8e2009-11-11 08:16:49 -0800528 Log.w(TAG, "Destroying all old data.");
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800529 db.execSQL("DROP TABLE IF EXISTS " + TABLE_FAVORITES);
530 onCreate(db);
531 }
532 }
Romain Guy7eb9e5e2009-12-02 20:10:07 -0800533
534 private boolean updateContactsShortcuts(SQLiteDatabase db) {
Romain Guy7eb9e5e2009-12-02 20:10:07 -0800535 final String selectWhere = buildOrWhereString(Favorites.ITEM_TYPE,
536 new int[] { Favorites.ITEM_TYPE_SHORTCUT });
537
Daniel Lehmannc3a80402012-04-23 21:35:11 -0700538 Cursor c = null;
539 final String actionQuickContact = "com.android.contacts.action.QUICK_CONTACT";
Romain Guy7eb9e5e2009-12-02 20:10:07 -0800540 db.beginTransaction();
541 try {
542 // Select and iterate through each matching widget
Daniel Lehmannc3a80402012-04-23 21:35:11 -0700543 c = db.query(TABLE_FAVORITES,
544 new String[] { Favorites._ID, Favorites.INTENT },
Romain Guy7eb9e5e2009-12-02 20:10:07 -0800545 selectWhere, null, null, null, null);
Daniel Lehmannc3a80402012-04-23 21:35:11 -0700546 if (c == null) return false;
547
Romain Guy7eb9e5e2009-12-02 20:10:07 -0800548 if (LOGD) Log.d(TAG, "found upgrade cursor count=" + c.getCount());
Daniel Lehmannc3a80402012-04-23 21:35:11 -0700549
Romain Guy7eb9e5e2009-12-02 20:10:07 -0800550 final int idIndex = c.getColumnIndex(Favorites._ID);
551 final int intentIndex = c.getColumnIndex(Favorites.INTENT);
Daniel Lehmannc3a80402012-04-23 21:35:11 -0700552
553 while (c.moveToNext()) {
Romain Guy7eb9e5e2009-12-02 20:10:07 -0800554 long favoriteId = c.getLong(idIndex);
555 final String intentUri = c.getString(intentIndex);
556 if (intentUri != null) {
557 try {
Daniel Lehmannc3a80402012-04-23 21:35:11 -0700558 final Intent intent = Intent.parseUri(intentUri, 0);
Romain Guy7eb9e5e2009-12-02 20:10:07 -0800559 android.util.Log.d("Home", intent.toString());
560 final Uri uri = intent.getData();
Daniel Lehmannc3a80402012-04-23 21:35:11 -0700561 if (uri != null) {
562 final String data = uri.toString();
563 if ((Intent.ACTION_VIEW.equals(intent.getAction()) ||
564 actionQuickContact.equals(intent.getAction())) &&
565 (data.startsWith("content://contacts/people/") ||
566 data.startsWith("content://com.android.contacts/" +
567 "contacts/lookup/"))) {
Romain Guy7eb9e5e2009-12-02 20:10:07 -0800568
Daniel Lehmannc3a80402012-04-23 21:35:11 -0700569 final Intent newIntent = new Intent(actionQuickContact);
570 // When starting from the launcher, start in a new, cleared task
571 // CLEAR_WHEN_TASK_RESET cannot reset the root of a task, so we
572 // clear the whole thing preemptively here since
573 // QuickContactActivity will finish itself when launching other
574 // detail activities.
575 newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
576 Intent.FLAG_ACTIVITY_CLEAR_TASK);
Winson Chung2672ff92012-05-04 16:22:30 -0700577 newIntent.putExtra(
578 Launcher.INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION, true);
Daniel Lehmannc3a80402012-04-23 21:35:11 -0700579 newIntent.setData(uri);
Daniel Lehmannd02402c2012-05-14 18:30:53 -0700580 // Determine the type and also put that in the shortcut
581 // (that can speed up launch a bit)
582 newIntent.setDataAndType(uri, newIntent.resolveType(mContext));
Romain Guy7eb9e5e2009-12-02 20:10:07 -0800583
Daniel Lehmannc3a80402012-04-23 21:35:11 -0700584 final ContentValues values = new ContentValues();
585 values.put(LauncherSettings.Favorites.INTENT,
586 newIntent.toUri(0));
587
588 String updateWhere = Favorites._ID + "=" + favoriteId;
589 db.update(TABLE_FAVORITES, values, updateWhere, null);
590 }
Romain Guy7eb9e5e2009-12-02 20:10:07 -0800591 }
592 } catch (RuntimeException ex) {
593 Log.e(TAG, "Problem upgrading shortcut", ex);
594 } catch (URISyntaxException e) {
Daniel Lehmannc3a80402012-04-23 21:35:11 -0700595 Log.e(TAG, "Problem upgrading shortcut", e);
Romain Guy7eb9e5e2009-12-02 20:10:07 -0800596 }
597 }
598 }
Daniel Lehmannc3a80402012-04-23 21:35:11 -0700599
Romain Guy7eb9e5e2009-12-02 20:10:07 -0800600 db.setTransactionSuccessful();
601 } catch (SQLException ex) {
602 Log.w(TAG, "Problem while upgrading contacts", ex);
603 return false;
604 } finally {
605 db.endTransaction();
606 if (c != null) {
607 c.close();
608 }
609 }
610
611 return true;
612 }
613
Joe Onorato0589f0f2010-02-08 13:44:00 -0800614 private void normalizeIcons(SQLiteDatabase db) {
615 Log.d(TAG, "normalizing icons");
616
Joe Onorato346e1292010-02-18 10:34:24 -0500617 db.beginTransaction();
Joe Onorato0589f0f2010-02-08 13:44:00 -0800618 Cursor c = null;
Joe Onorato9690b392010-03-23 17:34:37 -0400619 SQLiteStatement update = null;
Joe Onorato0589f0f2010-02-08 13:44:00 -0800620 try {
621 boolean logged = false;
Joe Onorato9690b392010-03-23 17:34:37 -0400622 update = db.compileStatement("UPDATE favorites "
Jeff Hamiltoneaf77d62010-02-13 00:08:17 -0600623 + "SET icon=? WHERE _id=?");
Joe Onorato0589f0f2010-02-08 13:44:00 -0800624
625 c = db.rawQuery("SELECT _id, icon FROM favorites WHERE iconType=" +
626 Favorites.ICON_TYPE_BITMAP, null);
627
628 final int idIndex = c.getColumnIndexOrThrow(Favorites._ID);
629 final int iconIndex = c.getColumnIndexOrThrow(Favorites.ICON);
630
631 while (c.moveToNext()) {
632 long id = c.getLong(idIndex);
633 byte[] data = c.getBlob(iconIndex);
634 try {
635 Bitmap bitmap = Utilities.resampleIconBitmap(
636 BitmapFactory.decodeByteArray(data, 0, data.length),
637 mContext);
638 if (bitmap != null) {
639 update.bindLong(1, id);
640 data = ItemInfo.flattenBitmap(bitmap);
641 if (data != null) {
642 update.bindBlob(2, data);
643 update.execute();
644 }
645 bitmap.recycle();
Joe Onorato0589f0f2010-02-08 13:44:00 -0800646 }
647 } catch (Exception e) {
648 if (!logged) {
649 Log.e(TAG, "Failed normalizing icon " + id, e);
650 } else {
651 Log.e(TAG, "Also failed normalizing icon " + id);
652 }
653 logged = true;
654 }
655 }
Bjorn Bringert3a928e42010-02-19 11:15:40 +0000656 db.setTransactionSuccessful();
Joe Onorato0589f0f2010-02-08 13:44:00 -0800657 } catch (SQLException ex) {
658 Log.w(TAG, "Problem while allocating appWidgetIds for existing widgets", ex);
659 } finally {
660 db.endTransaction();
Joe Onorato9690b392010-03-23 17:34:37 -0400661 if (update != null) {
662 update.close();
663 }
Joe Onorato0589f0f2010-02-08 13:44:00 -0800664 if (c != null) {
665 c.close();
666 }
667 }
Michael Jurkaa8c760d2011-04-28 14:59:33 -0700668 }
669
670 // Generates a new ID to use for an object in your database. This method should be only
671 // called from the main UI thread. As an exception, we do call it when we call the
672 // constructor from the worker thread; however, this doesn't extend until after the
673 // constructor is called, and we only pass a reference to LauncherProvider to LauncherApp
674 // after that point
675 public long generateNewId() {
676 if (mMaxId < 0) {
677 throw new RuntimeException("Error: max id was not initialized");
678 }
679 mMaxId += 1;
680 return mMaxId;
681 }
682
683 private long initializeMaxId(SQLiteDatabase db) {
684 Cursor c = db.rawQuery("SELECT MAX(_id) FROM favorites", null);
685
686 // get the result
687 final int maxIdIndex = 0;
688 long id = -1;
689 if (c != null && c.moveToNext()) {
690 id = c.getLong(maxIdIndex);
691 }
Michael Jurka5130e402011-10-13 04:55:35 -0700692 if (c != null) {
693 c.close();
694 }
Michael Jurkaa8c760d2011-04-28 14:59:33 -0700695
696 if (id == -1) {
697 throw new RuntimeException("Error: could not query max id");
698 }
699
700 return id;
Joe Onorato0589f0f2010-02-08 13:44:00 -0800701 }
702
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800703 /**
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700704 * Upgrade existing clock and photo frame widgets into their new widget
Bjorn Bringert93c45762009-12-16 13:19:47 +0000705 * equivalents.
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800706 */
707 private void convertWidgets(SQLiteDatabase db) {
Bjorn Bringert34251342009-12-15 13:33:11 +0000708 final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800709 final int[] bindSources = new int[] {
710 Favorites.ITEM_TYPE_WIDGET_CLOCK,
711 Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME,
Bjorn Bringert7984c942009-12-09 15:38:25 +0000712 Favorites.ITEM_TYPE_WIDGET_SEARCH,
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800713 };
Bjorn Bringert7984c942009-12-09 15:38:25 +0000714
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800715 final String selectWhere = buildOrWhereString(Favorites.ITEM_TYPE, bindSources);
Daniel Lehmannc3a80402012-04-23 21:35:11 -0700716
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800717 Cursor c = null;
Daniel Lehmannc3a80402012-04-23 21:35:11 -0700718
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800719 db.beginTransaction();
720 try {
721 // Select and iterate through each matching widget
Bjorn Bringert7984c942009-12-09 15:38:25 +0000722 c = db.query(TABLE_FAVORITES, new String[] { Favorites._ID, Favorites.ITEM_TYPE },
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800723 selectWhere, null, null, null, null);
Daniel Lehmannc3a80402012-04-23 21:35:11 -0700724
Joe Onoratoa30ce8e2009-11-11 08:16:49 -0800725 if (LOGD) Log.d(TAG, "found upgrade cursor count=" + c.getCount());
Daniel Lehmannc3a80402012-04-23 21:35:11 -0700726
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800727 final ContentValues values = new ContentValues();
728 while (c != null && c.moveToNext()) {
729 long favoriteId = c.getLong(0);
Bjorn Bringert7984c942009-12-09 15:38:25 +0000730 int favoriteType = c.getInt(1);
731
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700732 // Allocate and update database with new appWidgetId
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800733 try {
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700734 int appWidgetId = mAppWidgetHost.allocateAppWidgetId();
Daniel Lehmannc3a80402012-04-23 21:35:11 -0700735
Joe Onoratoa30ce8e2009-11-11 08:16:49 -0800736 if (LOGD) {
737 Log.d(TAG, "allocated appWidgetId=" + appWidgetId
738 + " for favoriteId=" + favoriteId);
739 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800740 values.clear();
Bjorn Bringert7984c942009-12-09 15:38:25 +0000741 values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_APPWIDGET);
742 values.put(Favorites.APPWIDGET_ID, appWidgetId);
743
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800744 // Original widgets might not have valid spans when upgrading
Bjorn Bringert7984c942009-12-09 15:38:25 +0000745 if (favoriteType == Favorites.ITEM_TYPE_WIDGET_SEARCH) {
746 values.put(LauncherSettings.Favorites.SPANX, 4);
747 values.put(LauncherSettings.Favorites.SPANY, 1);
748 } else {
749 values.put(LauncherSettings.Favorites.SPANX, 2);
750 values.put(LauncherSettings.Favorites.SPANY, 2);
751 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800752
753 String updateWhere = Favorites._ID + "=" + favoriteId;
754 db.update(TABLE_FAVORITES, values, updateWhere, null);
Bjorn Bringert34251342009-12-15 13:33:11 +0000755
Bjorn Bringert34251342009-12-15 13:33:11 +0000756 if (favoriteType == Favorites.ITEM_TYPE_WIDGET_CLOCK) {
Michael Jurka8b805b12012-04-18 14:23:14 -0700757 // TODO: check return value
758 appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId,
Bjorn Bringert34251342009-12-15 13:33:11 +0000759 new ComponentName("com.android.alarmclock",
760 "com.android.alarmclock.AnalogAppWidgetProvider"));
761 } else if (favoriteType == Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME) {
Michael Jurka8b805b12012-04-18 14:23:14 -0700762 // TODO: check return value
763 appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId,
Bjorn Bringert34251342009-12-15 13:33:11 +0000764 new ComponentName("com.android.camera",
765 "com.android.camera.PhotoAppWidgetProvider"));
766 } else if (favoriteType == Favorites.ITEM_TYPE_WIDGET_SEARCH) {
Michael Jurka8b805b12012-04-18 14:23:14 -0700767 // TODO: check return value
768 appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId,
Bjorn Bringertcd8fec02010-01-14 13:26:43 +0000769 getSearchWidgetProvider());
Bjorn Bringert34251342009-12-15 13:33:11 +0000770 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800771 } catch (RuntimeException ex) {
Joe Onoratoa30ce8e2009-11-11 08:16:49 -0800772 Log.e(TAG, "Problem allocating appWidgetId", ex);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800773 }
774 }
Daniel Lehmannc3a80402012-04-23 21:35:11 -0700775
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800776 db.setTransactionSuccessful();
777 } catch (SQLException ex) {
Joe Onoratoa30ce8e2009-11-11 08:16:49 -0800778 Log.w(TAG, "Problem while allocating appWidgetIds for existing widgets", ex);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800779 } finally {
780 db.endTransaction();
781 if (c != null) {
782 c.close();
783 }
784 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800785 }
786
Michael Jurka8b805b12012-04-18 14:23:14 -0700787 private static final void beginDocument(XmlPullParser parser, String firstElementName)
788 throws XmlPullParserException, IOException {
789 int type;
Michael Jurka9bc8eba2012-05-21 20:36:44 -0700790 while ((type = parser.next()) != XmlPullParser.START_TAG
791 && type != XmlPullParser.END_DOCUMENT) {
Michael Jurka8b805b12012-04-18 14:23:14 -0700792 ;
793 }
794
Michael Jurka9bc8eba2012-05-21 20:36:44 -0700795 if (type != XmlPullParser.START_TAG) {
Michael Jurka8b805b12012-04-18 14:23:14 -0700796 throw new XmlPullParserException("No start tag found");
797 }
798
799 if (!parser.getName().equals(firstElementName)) {
800 throw new XmlPullParserException("Unexpected start tag: found " + parser.getName() +
801 ", expected " + firstElementName);
802 }
803 }
804
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800805 /**
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800806 * Loads the default set of favorite packages from an xml file.
807 *
808 * @param db The database to write the values into
Winson Chung3d503fb2011-07-13 17:25:49 -0700809 * @param filterContainerId The specific container id of items to load
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800810 */
Winson Chung6d092682011-11-16 18:43:26 -0800811 private int loadFavorites(SQLiteDatabase db, int workspaceResourceId) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800812 Intent intent = new Intent(Intent.ACTION_MAIN, null);
813 intent.addCategory(Intent.CATEGORY_LAUNCHER);
814 ContentValues values = new ContentValues();
815
816 PackageManager packageManager = mContext.getPackageManager();
Andrew Flynn0dca1ec2012-02-29 13:33:22 -0800817 int allAppsButtonRank =
818 mContext.getResources().getInteger(R.integer.hotseat_all_apps_index);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800819 int i = 0;
820 try {
Winson Chung6d092682011-11-16 18:43:26 -0800821 XmlResourceParser parser = mContext.getResources().getXml(workspaceResourceId);
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700822 AttributeSet attrs = Xml.asAttributeSet(parser);
Michael Jurka8b805b12012-04-18 14:23:14 -0700823 beginDocument(parser, TAG_FAVORITES);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800824
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700825 final int depth = parser.getDepth();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800826
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700827 int type;
828 while (((type = parser.next()) != XmlPullParser.END_TAG ||
829 parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
830
831 if (type != XmlPullParser.START_TAG) {
832 continue;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800833 }
834
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700835 boolean added = false;
836 final String name = parser.getName();
837
838 TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.Favorite);
839
Winson Chung3d503fb2011-07-13 17:25:49 -0700840 long container = LauncherSettings.Favorites.CONTAINER_DESKTOP;
841 if (a.hasValue(R.styleable.Favorite_container)) {
842 container = Long.valueOf(a.getString(R.styleable.Favorite_container));
843 }
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700844
Winson Chung6d092682011-11-16 18:43:26 -0800845 String screen = a.getString(R.styleable.Favorite_screen);
846 String x = a.getString(R.styleable.Favorite_x);
847 String y = a.getString(R.styleable.Favorite_y);
848
849 // If we are adding to the hotseat, the screen is used as the position in the
850 // hotseat. This screen can't be at position 0 because AllApps is in the
851 // zeroth position.
Andrew Flynn0dca1ec2012-02-29 13:33:22 -0800852 if (container == LauncherSettings.Favorites.CONTAINER_HOTSEAT
853 && Integer.valueOf(screen) == allAppsButtonRank) {
Winson Chung6d092682011-11-16 18:43:26 -0800854 throw new RuntimeException("Invalid screen position for hotseat item");
855 }
856
857 values.clear();
858 values.put(LauncherSettings.Favorites.CONTAINER, container);
859 values.put(LauncherSettings.Favorites.SCREEN, screen);
860 values.put(LauncherSettings.Favorites.CELLX, x);
861 values.put(LauncherSettings.Favorites.CELLY, y);
862
863 if (TAG_FAVORITE.equals(name)) {
864 long id = addAppShortcut(db, values, a, packageManager, intent);
865 added = id >= 0;
866 } else if (TAG_SEARCH.equals(name)) {
867 added = addSearchWidget(db, values);
868 } else if (TAG_CLOCK.equals(name)) {
869 added = addClockWidget(db, values);
870 } else if (TAG_APPWIDGET.equals(name)) {
Winson Chungb3302ae2012-05-01 10:19:14 -0700871 added = addAppWidget(parser, attrs, type, db, values, a, packageManager);
Winson Chung6d092682011-11-16 18:43:26 -0800872 } else if (TAG_SHORTCUT.equals(name)) {
873 long id = addUriShortcut(db, values, a);
874 added = id >= 0;
875 } else if (TAG_FOLDER.equals(name)) {
876 String title;
877 int titleResId = a.getResourceId(R.styleable.Favorite_title, -1);
878 if (titleResId != -1) {
879 title = mContext.getResources().getString(titleResId);
880 } else {
881 title = mContext.getResources().getString(R.string.folder_name);
Winson Chung3d503fb2011-07-13 17:25:49 -0700882 }
Winson Chung6d092682011-11-16 18:43:26 -0800883 values.put(LauncherSettings.Favorites.TITLE, title);
884 long folderId = addFolder(db, values);
885 added = folderId >= 0;
Winson Chung3d503fb2011-07-13 17:25:49 -0700886
Winson Chung6d092682011-11-16 18:43:26 -0800887 ArrayList<Long> folderItems = new ArrayList<Long>();
Winson Chung3d503fb2011-07-13 17:25:49 -0700888
Winson Chung6d092682011-11-16 18:43:26 -0800889 int folderDepth = parser.getDepth();
890 while ((type = parser.next()) != XmlPullParser.END_TAG ||
891 parser.getDepth() > folderDepth) {
892 if (type != XmlPullParser.START_TAG) {
893 continue;
894 }
895 final String folder_item_name = parser.getName();
896
897 TypedArray ar = mContext.obtainStyledAttributes(attrs,
898 R.styleable.Favorite);
899 values.clear();
900 values.put(LauncherSettings.Favorites.CONTAINER, folderId);
901
902 if (TAG_FAVORITE.equals(folder_item_name) && folderId >= 0) {
903 long id =
904 addAppShortcut(db, values, ar, packageManager, intent);
905 if (id >= 0) {
906 folderItems.add(id);
907 }
908 } else if (TAG_SHORTCUT.equals(folder_item_name) && folderId >= 0) {
909 long id = addUriShortcut(db, values, ar);
910 if (id >= 0) {
911 folderItems.add(id);
912 }
Adam Cohen228da5a2011-07-27 22:23:47 -0700913 } else {
Winson Chung6d092682011-11-16 18:43:26 -0800914 throw new RuntimeException("Folders can " +
915 "contain only shortcuts");
Adam Cohen228da5a2011-07-27 22:23:47 -0700916 }
Winson Chung6d092682011-11-16 18:43:26 -0800917 ar.recycle();
918 }
919 // We can only have folders with >= 2 items, so we need to remove the
920 // folder and clean up if less than 2 items were included, or some
921 // failed to add, and less than 2 were actually added
922 if (folderItems.size() < 2 && folderId >= 0) {
923 // We just delete the folder and any items that made it
924 deleteId(db, folderId);
925 if (folderItems.size() > 0) {
926 deleteId(db, folderItems.get(0));
Adam Cohen228da5a2011-07-27 22:23:47 -0700927 }
Winson Chung6d092682011-11-16 18:43:26 -0800928 added = false;
Winson Chung3d503fb2011-07-13 17:25:49 -0700929 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800930 }
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700931 if (added) i++;
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700932 a.recycle();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800933 }
934 } catch (XmlPullParserException e) {
Joe Onoratoa30ce8e2009-11-11 08:16:49 -0800935 Log.w(TAG, "Got exception parsing favorites.", e);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800936 } catch (IOException e) {
Joe Onoratoa30ce8e2009-11-11 08:16:49 -0800937 Log.w(TAG, "Got exception parsing favorites.", e);
Winson Chung3d503fb2011-07-13 17:25:49 -0700938 } catch (RuntimeException e) {
939 Log.w(TAG, "Got exception parsing favorites.", e);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800940 }
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700941
942 return i;
943 }
944
Adam Cohen228da5a2011-07-27 22:23:47 -0700945 private long addAppShortcut(SQLiteDatabase db, ContentValues values, TypedArray a,
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700946 PackageManager packageManager, Intent intent) {
Adam Cohen228da5a2011-07-27 22:23:47 -0700947 long id = -1;
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700948 ActivityInfo info;
949 String packageName = a.getString(R.styleable.Favorite_packageName);
950 String className = a.getString(R.styleable.Favorite_className);
951 try {
Romain Guy693599f2010-03-23 10:58:18 -0700952 ComponentName cn;
953 try {
954 cn = new ComponentName(packageName, className);
955 info = packageManager.getActivityInfo(cn, 0);
956 } catch (PackageManager.NameNotFoundException nnfe) {
957 String[] packages = packageManager.currentToCanonicalPackageNames(
958 new String[] { packageName });
959 cn = new ComponentName(packages[0], className);
960 info = packageManager.getActivityInfo(cn, 0);
961 }
Adam Cohen228da5a2011-07-27 22:23:47 -0700962 id = generateNewId();
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700963 intent.setComponent(cn);
Romain Guy693599f2010-03-23 10:58:18 -0700964 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
965 Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
Romain Guy1ce1a242009-06-23 17:34:54 -0700966 values.put(Favorites.INTENT, intent.toUri(0));
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700967 values.put(Favorites.TITLE, info.loadLabel(packageManager).toString());
968 values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_APPLICATION);
969 values.put(Favorites.SPANX, 1);
970 values.put(Favorites.SPANY, 1);
Michael Jurkaa8c760d2011-04-28 14:59:33 -0700971 values.put(Favorites._ID, generateNewId());
Adam Cohen228da5a2011-07-27 22:23:47 -0700972 if (dbInsertAndCheck(this, db, TABLE_FAVORITES, null, values) < 0) {
973 return -1;
974 }
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700975 } catch (PackageManager.NameNotFoundException e) {
Joe Onoratoa30ce8e2009-11-11 08:16:49 -0800976 Log.w(TAG, "Unable to add favorite: " + packageName +
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700977 "/" + className, e);
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700978 }
Adam Cohen228da5a2011-07-27 22:23:47 -0700979 return id;
980 }
981
982 private long addFolder(SQLiteDatabase db, ContentValues values) {
983 values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_FOLDER);
984 values.put(Favorites.SPANX, 1);
985 values.put(Favorites.SPANY, 1);
986 long id = generateNewId();
987 values.put(Favorites._ID, id);
988 if (dbInsertAndCheck(this, db, TABLE_FAVORITES, null, values) <= 0) {
989 return -1;
990 } else {
991 return id;
992 }
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700993 }
994
Bjorn Bringertcd8fec02010-01-14 13:26:43 +0000995 private ComponentName getSearchWidgetProvider() {
996 SearchManager searchManager =
997 (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
998 ComponentName searchComponent = searchManager.getGlobalSearchActivity();
999 if (searchComponent == null) return null;
1000 return getProviderInPackage(searchComponent.getPackageName());
1001 }
1002
1003 /**
1004 * Gets an appwidget provider from the given package. If the package contains more than
1005 * one appwidget provider, an arbitrary one is returned.
1006 */
1007 private ComponentName getProviderInPackage(String packageName) {
1008 AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext);
1009 List<AppWidgetProviderInfo> providers = appWidgetManager.getInstalledProviders();
1010 if (providers == null) return null;
1011 final int providerCount = providers.size();
1012 for (int i = 0; i < providerCount; i++) {
1013 ComponentName provider = providers.get(i).provider;
1014 if (provider != null && provider.getPackageName().equals(packageName)) {
1015 return provider;
1016 }
1017 }
1018 return null;
1019 }
1020
The Android Open Source Projectf96811c2009-03-18 17:39:48 -07001021 private boolean addSearchWidget(SQLiteDatabase db, ContentValues values) {
Bjorn Bringertcd8fec02010-01-14 13:26:43 +00001022 ComponentName cn = getSearchWidgetProvider();
Winson Chungb3302ae2012-05-01 10:19:14 -07001023 return addAppWidget(db, values, cn, 4, 1, null);
The Android Open Source Projectf96811c2009-03-18 17:39:48 -07001024 }
1025
1026 private boolean addClockWidget(SQLiteDatabase db, ContentValues values) {
Bjorn Bringert34251342009-12-15 13:33:11 +00001027 ComponentName cn = new ComponentName("com.android.alarmclock",
1028 "com.android.alarmclock.AnalogAppWidgetProvider");
Winson Chungb3302ae2012-05-01 10:19:14 -07001029 return addAppWidget(db, values, cn, 2, 2, null);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001030 }
Adam Cohen228da5a2011-07-27 22:23:47 -07001031
Winson Chungb3302ae2012-05-01 10:19:14 -07001032 private boolean addAppWidget(XmlResourceParser parser, AttributeSet attrs, int type,
1033 SQLiteDatabase db, ContentValues values, TypedArray a,
1034 PackageManager packageManager) throws XmlPullParserException, IOException {
Romain Guy693599f2010-03-23 10:58:18 -07001035
Mike Cleronb87bd162009-10-30 16:36:56 -07001036 String packageName = a.getString(R.styleable.Favorite_packageName);
1037 String className = a.getString(R.styleable.Favorite_className);
1038
1039 if (packageName == null || className == null) {
1040 return false;
1041 }
Romain Guy693599f2010-03-23 10:58:18 -07001042
1043 boolean hasPackage = true;
Mike Cleronb87bd162009-10-30 16:36:56 -07001044 ComponentName cn = new ComponentName(packageName, className);
Romain Guy693599f2010-03-23 10:58:18 -07001045 try {
1046 packageManager.getReceiverInfo(cn, 0);
1047 } catch (Exception e) {
1048 String[] packages = packageManager.currentToCanonicalPackageNames(
1049 new String[] { packageName });
1050 cn = new ComponentName(packages[0], className);
1051 try {
1052 packageManager.getReceiverInfo(cn, 0);
1053 } catch (Exception e1) {
1054 hasPackage = false;
1055 }
1056 }
1057
1058 if (hasPackage) {
1059 int spanX = a.getInt(R.styleable.Favorite_spanX, 0);
1060 int spanY = a.getInt(R.styleable.Favorite_spanY, 0);
Winson Chungb3302ae2012-05-01 10:19:14 -07001061
1062 // Read the extras
1063 Bundle extras = new Bundle();
1064 int widgetDepth = parser.getDepth();
1065 while ((type = parser.next()) != XmlPullParser.END_TAG ||
1066 parser.getDepth() > widgetDepth) {
1067 if (type != XmlPullParser.START_TAG) {
1068 continue;
1069 }
1070
1071 TypedArray ar = mContext.obtainStyledAttributes(attrs, R.styleable.Extra);
1072 if (TAG_EXTRA.equals(parser.getName())) {
1073 String key = ar.getString(R.styleable.Extra_key);
1074 String value = ar.getString(R.styleable.Extra_value);
1075 if (key != null && value != null) {
1076 extras.putString(key, value);
1077 } else {
1078 throw new RuntimeException("Widget extras must have a key and value");
1079 }
1080 } else {
1081 throw new RuntimeException("Widgets can contain only extras");
1082 }
1083 ar.recycle();
1084 }
1085
1086 return addAppWidget(db, values, cn, spanX, spanY, extras);
Romain Guy693599f2010-03-23 10:58:18 -07001087 }
Daniel Lehmannc3a80402012-04-23 21:35:11 -07001088
Romain Guy693599f2010-03-23 10:58:18 -07001089 return false;
Bjorn Bringert7984c942009-12-09 15:38:25 +00001090 }
1091
1092 private boolean addAppWidget(SQLiteDatabase db, ContentValues values, ComponentName cn,
Winson Chungb3302ae2012-05-01 10:19:14 -07001093 int spanX, int spanY, Bundle extras) {
Mike Cleronb87bd162009-10-30 16:36:56 -07001094 boolean allocatedAppWidgets = false;
1095 final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext);
1096
1097 try {
1098 int appWidgetId = mAppWidgetHost.allocateAppWidgetId();
Daniel Lehmannc3a80402012-04-23 21:35:11 -07001099
Mike Cleronb87bd162009-10-30 16:36:56 -07001100 values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_APPWIDGET);
Bjorn Bringert7984c942009-12-09 15:38:25 +00001101 values.put(Favorites.SPANX, spanX);
1102 values.put(Favorites.SPANY, spanY);
Mike Cleronb87bd162009-10-30 16:36:56 -07001103 values.put(Favorites.APPWIDGET_ID, appWidgetId);
Michael Jurkaa8c760d2011-04-28 14:59:33 -07001104 values.put(Favorites._ID, generateNewId());
1105 dbInsertAndCheck(this, db, TABLE_FAVORITES, null, values);
Mike Cleronb87bd162009-10-30 16:36:56 -07001106
1107 allocatedAppWidgets = true;
Daniel Lehmannc3a80402012-04-23 21:35:11 -07001108
Michael Jurka8b805b12012-04-18 14:23:14 -07001109 // TODO: need to check return value
1110 appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId, cn);
Winson Chungb3302ae2012-05-01 10:19:14 -07001111
1112 // Send a broadcast to configure the widget
1113 if (extras != null && !extras.isEmpty()) {
1114 Intent intent = new Intent(ACTION_APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE);
1115 intent.setComponent(cn);
1116 intent.putExtras(extras);
1117 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
1118 mContext.sendBroadcast(intent);
1119 }
Mike Cleronb87bd162009-10-30 16:36:56 -07001120 } catch (RuntimeException ex) {
Joe Onoratoa30ce8e2009-11-11 08:16:49 -08001121 Log.e(TAG, "Problem allocating appWidgetId", ex);
Mike Cleronb87bd162009-10-30 16:36:56 -07001122 }
Daniel Lehmannc3a80402012-04-23 21:35:11 -07001123
Mike Cleronb87bd162009-10-30 16:36:56 -07001124 return allocatedAppWidgets;
1125 }
Adam Cohen228da5a2011-07-27 22:23:47 -07001126
1127 private long addUriShortcut(SQLiteDatabase db, ContentValues values,
Mike Cleronb87bd162009-10-30 16:36:56 -07001128 TypedArray a) {
1129 Resources r = mContext.getResources();
1130
1131 final int iconResId = a.getResourceId(R.styleable.Favorite_icon, 0);
1132 final int titleResId = a.getResourceId(R.styleable.Favorite_title, 0);
1133
Romain Guy7eb9e5e2009-12-02 20:10:07 -08001134 Intent intent;
Mike Cleronb87bd162009-10-30 16:36:56 -07001135 String uri = null;
1136 try {
1137 uri = a.getString(R.styleable.Favorite_uri);
1138 intent = Intent.parseUri(uri, 0);
1139 } catch (URISyntaxException e) {
Joe Onoratoa30ce8e2009-11-11 08:16:49 -08001140 Log.w(TAG, "Shortcut has malformed uri: " + uri);
Adam Cohen228da5a2011-07-27 22:23:47 -07001141 return -1; // Oh well
Mike Cleronb87bd162009-10-30 16:36:56 -07001142 }
1143
1144 if (iconResId == 0 || titleResId == 0) {
Joe Onoratoa30ce8e2009-11-11 08:16:49 -08001145 Log.w(TAG, "Shortcut is missing title or icon resource ID");
Adam Cohen228da5a2011-07-27 22:23:47 -07001146 return -1;
Mike Cleronb87bd162009-10-30 16:36:56 -07001147 }
1148
Adam Cohen228da5a2011-07-27 22:23:47 -07001149 long id = generateNewId();
Mike Cleronb87bd162009-10-30 16:36:56 -07001150 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1151 values.put(Favorites.INTENT, intent.toUri(0));
1152 values.put(Favorites.TITLE, r.getString(titleResId));
1153 values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_SHORTCUT);
1154 values.put(Favorites.SPANX, 1);
1155 values.put(Favorites.SPANY, 1);
1156 values.put(Favorites.ICON_TYPE, Favorites.ICON_TYPE_RESOURCE);
1157 values.put(Favorites.ICON_PACKAGE, mContext.getPackageName());
1158 values.put(Favorites.ICON_RESOURCE, r.getResourceName(iconResId));
Adam Cohen228da5a2011-07-27 22:23:47 -07001159 values.put(Favorites._ID, id);
Mike Cleronb87bd162009-10-30 16:36:56 -07001160
Adam Cohen228da5a2011-07-27 22:23:47 -07001161 if (dbInsertAndCheck(this, db, TABLE_FAVORITES, null, values) < 0) {
1162 return -1;
1163 }
1164 return id;
Mike Cleronb87bd162009-10-30 16:36:56 -07001165 }
1166 }
Daniel Lehmannc3a80402012-04-23 21:35:11 -07001167
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001168 /**
1169 * Build a query string that will match any row where the column matches
1170 * anything in the values list.
1171 */
1172 static String buildOrWhereString(String column, int[] values) {
1173 StringBuilder selectWhere = new StringBuilder();
1174 for (int i = values.length - 1; i >= 0; i--) {
1175 selectWhere.append(column).append("=").append(values[i]);
1176 if (i > 0) {
1177 selectWhere.append(" OR ");
1178 }
1179 }
1180 return selectWhere.toString();
1181 }
1182
1183 static class SqlArguments {
1184 public final String table;
1185 public final String where;
1186 public final String[] args;
1187
1188 SqlArguments(Uri url, String where, String[] args) {
1189 if (url.getPathSegments().size() == 1) {
1190 this.table = url.getPathSegments().get(0);
1191 this.where = where;
1192 this.args = args;
1193 } else if (url.getPathSegments().size() != 2) {
1194 throw new IllegalArgumentException("Invalid URI: " + url);
1195 } else if (!TextUtils.isEmpty(where)) {
1196 throw new UnsupportedOperationException("WHERE clause not supported: " + url);
1197 } else {
1198 this.table = url.getPathSegments().get(0);
Daniel Lehmannc3a80402012-04-23 21:35:11 -07001199 this.where = "_id=" + ContentUris.parseId(url);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001200 this.args = null;
1201 }
1202 }
1203
1204 SqlArguments(Uri url) {
1205 if (url.getPathSegments().size() == 1) {
1206 table = url.getPathSegments().get(0);
1207 where = null;
1208 args = null;
1209 } else {
1210 throw new IllegalArgumentException("Invalid URI: " + url);
1211 }
1212 }
1213 }
1214}