2009-03-03 19:32:27 -08:00
|
|
|
/*
|
|
|
|
|
* Copyright (C) 2008 The Android Open Source Project
|
|
|
|
|
*
|
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
|
*
|
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
*
|
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
|
* limitations under the License.
|
|
|
|
|
*/
|
|
|
|
|
|
2009-07-30 13:37:37 -07:00
|
|
|
package com.android.launcher2;
|
2009-03-03 19:32:27 -08:00
|
|
|
|
2010-01-14 13:26:43 +00:00
|
|
|
import android.app.SearchManager;
|
2009-03-11 12:11:58 -07:00
|
|
|
import android.appwidget.AppWidgetHost;
|
2009-10-30 16:36:56 -07:00
|
|
|
import android.appwidget.AppWidgetManager;
|
2010-01-14 13:26:43 +00:00
|
|
|
import android.appwidget.AppWidgetProviderInfo;
|
2009-03-03 19:32:27 -08:00
|
|
|
import android.content.ContentProvider;
|
|
|
|
|
import android.content.Context;
|
|
|
|
|
import android.content.ContentValues;
|
|
|
|
|
import android.content.Intent;
|
|
|
|
|
import android.content.ComponentName;
|
|
|
|
|
import android.content.ContentUris;
|
|
|
|
|
import android.content.ContentResolver;
|
2009-10-30 16:36:56 -07:00
|
|
|
import android.content.res.Resources;
|
2009-03-18 17:39:48 -07:00
|
|
|
import android.content.res.XmlResourceParser;
|
|
|
|
|
import android.content.res.TypedArray;
|
2009-03-03 19:32:27 -08:00
|
|
|
import android.content.pm.PackageManager;
|
|
|
|
|
import android.content.pm.ActivityInfo;
|
2011-04-28 14:59:33 -07:00
|
|
|
import android.content.SharedPreferences;
|
2009-03-03 19:32:27 -08:00
|
|
|
import android.database.sqlite.SQLiteOpenHelper;
|
|
|
|
|
import android.database.sqlite.SQLiteDatabase;
|
2010-02-08 13:44:00 -08:00
|
|
|
import android.database.sqlite.SQLiteStatement;
|
2009-03-03 19:32:27 -08:00
|
|
|
import android.database.sqlite.SQLiteQueryBuilder;
|
|
|
|
|
import android.database.Cursor;
|
|
|
|
|
import android.database.SQLException;
|
2010-02-08 13:44:00 -08:00
|
|
|
import android.graphics.Bitmap;
|
|
|
|
|
import android.graphics.BitmapFactory;
|
2009-03-03 19:32:27 -08:00
|
|
|
import android.util.Log;
|
|
|
|
|
import android.util.Xml;
|
2009-03-18 17:39:48 -07:00
|
|
|
import android.util.AttributeSet;
|
2009-03-03 19:32:27 -08:00
|
|
|
import android.net.Uri;
|
|
|
|
|
import android.text.TextUtils;
|
|
|
|
|
import android.provider.Settings;
|
|
|
|
|
|
|
|
|
|
import java.io.IOException;
|
2009-10-30 16:36:56 -07:00
|
|
|
import java.net.URISyntaxException;
|
2010-01-14 13:26:43 +00:00
|
|
|
import java.util.List;
|
2009-03-03 19:32:27 -08:00
|
|
|
|
|
|
|
|
import org.xmlpull.v1.XmlPullParserException;
|
2009-03-18 17:39:48 -07:00
|
|
|
import org.xmlpull.v1.XmlPullParser;
|
2010-02-24 20:01:46 -08:00
|
|
|
|
|
|
|
|
import com.android.internal.util.XmlUtils;
|
2009-07-30 13:37:37 -07:00
|
|
|
import com.android.launcher2.LauncherSettings.Favorites;
|
2009-03-03 19:32:27 -08:00
|
|
|
|
2010-03-04 13:03:17 -08:00
|
|
|
import com.android.launcher.R;
|
|
|
|
|
|
2009-03-03 19:32:27 -08:00
|
|
|
public class LauncherProvider extends ContentProvider {
|
2009-11-11 08:16:49 -08:00
|
|
|
private static final String TAG = "Launcher.LauncherProvider";
|
|
|
|
|
private static final boolean LOGD = false;
|
2009-03-03 19:32:27 -08:00
|
|
|
|
|
|
|
|
private static final String DATABASE_NAME = "launcher.db";
|
|
|
|
|
|
2010-02-08 13:44:00 -08:00
|
|
|
private static final int DATABASE_VERSION = 8;
|
2009-03-03 19:32:27 -08:00
|
|
|
|
2009-07-30 13:37:37 -07:00
|
|
|
static final String AUTHORITY = "com.android.launcher2.settings";
|
2009-03-03 19:32:27 -08:00
|
|
|
|
|
|
|
|
static final String TABLE_FAVORITES = "favorites";
|
|
|
|
|
static final String PARAMETER_NOTIFY = "notify";
|
|
|
|
|
|
AI 143776: am: CL 143622 Correctly startListening() for widget updates when first boot completes.
During the first boot upgrade, LauncherProvider will deleteHost() to clear out any old appWidgetId bindings. During the first boot, Launcher calls AppWidgetHost.startListening() to watch for widget updates. It also calls loadUserItems(), which loads data from LauncherProvider, triggering the database creation and deleteHost() call. Because deleteHost() removes any existing callbacks, any future widget updates are dropped on the floor. (This can currently be solved by rebooting, because there isn't an upgrade on subsequent boots.)
This bug was particularly evident on vfpioneer-userdebug builds, as there aren't any configuration changes that cause Launcher to be destroyed and recreated. (When destroyed and recreated, we startListening() again, and LauncherProvider doesn't call deleteHost().)
To handle this special case, Launcher creates a ContentObserver pointing at a specific URI, which the LauncherProvider notifies when the AppWidgetHost is reset through deleteHost(), allowing Launcher to correctly startListening() again.
Original author: jsharkey
Merged from: //branches/cupcake/...
Automated import of CL 143776
2009-03-31 14:37:57 -07:00
|
|
|
/**
|
2009-06-09 12:57:21 -07:00
|
|
|
* {@link Uri} triggered at any registered {@link android.database.ContentObserver} when
|
AI 143776: am: CL 143622 Correctly startListening() for widget updates when first boot completes.
During the first boot upgrade, LauncherProvider will deleteHost() to clear out any old appWidgetId bindings. During the first boot, Launcher calls AppWidgetHost.startListening() to watch for widget updates. It also calls loadUserItems(), which loads data from LauncherProvider, triggering the database creation and deleteHost() call. Because deleteHost() removes any existing callbacks, any future widget updates are dropped on the floor. (This can currently be solved by rebooting, because there isn't an upgrade on subsequent boots.)
This bug was particularly evident on vfpioneer-userdebug builds, as there aren't any configuration changes that cause Launcher to be destroyed and recreated. (When destroyed and recreated, we startListening() again, and LauncherProvider doesn't call deleteHost().)
To handle this special case, Launcher creates a ContentObserver pointing at a specific URI, which the LauncherProvider notifies when the AppWidgetHost is reset through deleteHost(), allowing Launcher to correctly startListening() again.
Original author: jsharkey
Merged from: //branches/cupcake/...
Automated import of CL 143776
2009-03-31 14:37:57 -07:00
|
|
|
* {@link AppWidgetHost#deleteHost()} is called during database creation.
|
|
|
|
|
* Use this to recall {@link AppWidgetHost#startListening()} if needed.
|
|
|
|
|
*/
|
|
|
|
|
static final Uri CONTENT_APPWIDGET_RESET_URI =
|
|
|
|
|
Uri.parse("content://" + AUTHORITY + "/appWidgetReset");
|
|
|
|
|
|
2011-04-28 14:59:33 -07:00
|
|
|
private DatabaseHelper mOpenHelper;
|
2009-03-03 19:32:27 -08:00
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean onCreate() {
|
|
|
|
|
mOpenHelper = new DatabaseHelper(getContext());
|
2011-04-28 14:59:33 -07:00
|
|
|
((LauncherApplication) getContext()).setLauncherProvider(this);
|
2009-03-03 19:32:27 -08:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public String getType(Uri uri) {
|
|
|
|
|
SqlArguments args = new SqlArguments(uri, null, null);
|
|
|
|
|
if (TextUtils.isEmpty(args.where)) {
|
|
|
|
|
return "vnd.android.cursor.dir/" + args.table;
|
|
|
|
|
} else {
|
|
|
|
|
return "vnd.android.cursor.item/" + args.table;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Cursor query(Uri uri, String[] projection, String selection,
|
|
|
|
|
String[] selectionArgs, String sortOrder) {
|
|
|
|
|
|
|
|
|
|
SqlArguments args = new SqlArguments(uri, selection, selectionArgs);
|
|
|
|
|
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
|
|
|
|
|
qb.setTables(args.table);
|
|
|
|
|
|
2009-06-09 12:57:21 -07:00
|
|
|
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
|
2009-03-03 19:32:27 -08:00
|
|
|
Cursor result = qb.query(db, projection, args.where, args.args, null, null, sortOrder);
|
|
|
|
|
result.setNotificationUri(getContext().getContentResolver(), uri);
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-28 14:59:33 -07:00
|
|
|
private static long dbInsertAndCheck(DatabaseHelper helper,
|
|
|
|
|
SQLiteDatabase db, String table, String nullColumnHack, ContentValues values) {
|
|
|
|
|
if (!values.containsKey(LauncherSettings.Favorites._ID)) {
|
|
|
|
|
throw new RuntimeException("Error: attempting to add item without specifying an id");
|
|
|
|
|
}
|
|
|
|
|
return db.insert(table, nullColumnHack, values);
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-03 19:32:27 -08:00
|
|
|
@Override
|
|
|
|
|
public Uri insert(Uri uri, ContentValues initialValues) {
|
|
|
|
|
SqlArguments args = new SqlArguments(uri);
|
|
|
|
|
|
|
|
|
|
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
|
2011-04-28 14:59:33 -07:00
|
|
|
final long rowId = dbInsertAndCheck(mOpenHelper, db, args.table, null, initialValues);
|
2009-03-03 19:32:27 -08:00
|
|
|
if (rowId <= 0) return null;
|
|
|
|
|
|
|
|
|
|
uri = ContentUris.withAppendedId(uri, rowId);
|
|
|
|
|
sendNotify(uri);
|
|
|
|
|
|
|
|
|
|
return uri;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public int bulkInsert(Uri uri, ContentValues[] values) {
|
|
|
|
|
SqlArguments args = new SqlArguments(uri);
|
|
|
|
|
|
|
|
|
|
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
|
|
|
|
|
db.beginTransaction();
|
|
|
|
|
try {
|
|
|
|
|
int numValues = values.length;
|
|
|
|
|
for (int i = 0; i < numValues; i++) {
|
2011-04-28 14:59:33 -07:00
|
|
|
if (dbInsertAndCheck(mOpenHelper, db, args.table, null, values[i]) < 0) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2009-03-03 19:32:27 -08:00
|
|
|
}
|
|
|
|
|
db.setTransactionSuccessful();
|
|
|
|
|
} finally {
|
|
|
|
|
db.endTransaction();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sendNotify(uri);
|
|
|
|
|
return values.length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public int delete(Uri uri, String selection, String[] selectionArgs) {
|
|
|
|
|
SqlArguments args = new SqlArguments(uri, selection, selectionArgs);
|
|
|
|
|
|
|
|
|
|
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
|
|
|
|
|
int count = db.delete(args.table, args.where, args.args);
|
|
|
|
|
if (count > 0) sendNotify(uri);
|
|
|
|
|
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
|
|
|
|
|
SqlArguments args = new SqlArguments(uri, selection, selectionArgs);
|
|
|
|
|
|
|
|
|
|
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
|
|
|
|
|
int count = db.update(args.table, values, args.where, args.args);
|
|
|
|
|
if (count > 0) sendNotify(uri);
|
|
|
|
|
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void sendNotify(Uri uri) {
|
|
|
|
|
String notify = uri.getQueryParameter(PARAMETER_NOTIFY);
|
|
|
|
|
if (notify == null || "true".equals(notify)) {
|
|
|
|
|
getContext().getContentResolver().notifyChange(uri, null);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-28 14:59:33 -07:00
|
|
|
public long generateNewId() {
|
|
|
|
|
return mOpenHelper.generateNewId();
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-03 19:32:27 -08:00
|
|
|
private static class DatabaseHelper extends SQLiteOpenHelper {
|
|
|
|
|
private static final String TAG_FAVORITES = "favorites";
|
|
|
|
|
private static final String TAG_FAVORITE = "favorite";
|
2009-03-18 17:39:48 -07:00
|
|
|
private static final String TAG_CLOCK = "clock";
|
|
|
|
|
private static final String TAG_SEARCH = "search";
|
2009-10-30 16:36:56 -07:00
|
|
|
private static final String TAG_APPWIDGET = "appwidget";
|
|
|
|
|
private static final String TAG_SHORTCUT = "shortcut";
|
|
|
|
|
|
2009-03-03 19:32:27 -08:00
|
|
|
private final Context mContext;
|
2009-03-11 12:11:58 -07:00
|
|
|
private final AppWidgetHost mAppWidgetHost;
|
2011-04-28 14:59:33 -07:00
|
|
|
private long mMaxId = -1;
|
2009-03-03 19:32:27 -08:00
|
|
|
|
|
|
|
|
DatabaseHelper(Context context) {
|
|
|
|
|
super(context, DATABASE_NAME, null, DATABASE_VERSION);
|
|
|
|
|
mContext = context;
|
2009-03-11 12:11:58 -07:00
|
|
|
mAppWidgetHost = new AppWidgetHost(context, Launcher.APPWIDGET_HOST_ID);
|
2011-04-28 14:59:33 -07:00
|
|
|
mMaxId = initializeMaxId(getWritableDatabase());
|
2009-03-03 19:32:27 -08:00
|
|
|
}
|
|
|
|
|
|
AI 143776: am: CL 143622 Correctly startListening() for widget updates when first boot completes.
During the first boot upgrade, LauncherProvider will deleteHost() to clear out any old appWidgetId bindings. During the first boot, Launcher calls AppWidgetHost.startListening() to watch for widget updates. It also calls loadUserItems(), which loads data from LauncherProvider, triggering the database creation and deleteHost() call. Because deleteHost() removes any existing callbacks, any future widget updates are dropped on the floor. (This can currently be solved by rebooting, because there isn't an upgrade on subsequent boots.)
This bug was particularly evident on vfpioneer-userdebug builds, as there aren't any configuration changes that cause Launcher to be destroyed and recreated. (When destroyed and recreated, we startListening() again, and LauncherProvider doesn't call deleteHost().)
To handle this special case, Launcher creates a ContentObserver pointing at a specific URI, which the LauncherProvider notifies when the AppWidgetHost is reset through deleteHost(), allowing Launcher to correctly startListening() again.
Original author: jsharkey
Merged from: //branches/cupcake/...
Automated import of CL 143776
2009-03-31 14:37:57 -07:00
|
|
|
/**
|
|
|
|
|
* Send notification that we've deleted the {@link AppWidgetHost},
|
|
|
|
|
* probably as part of the initial database creation. The receiver may
|
|
|
|
|
* want to re-call {@link AppWidgetHost#startListening()} to ensure
|
|
|
|
|
* callbacks are correctly set.
|
|
|
|
|
*/
|
|
|
|
|
private void sendAppWidgetResetNotify() {
|
|
|
|
|
final ContentResolver resolver = mContext.getContentResolver();
|
|
|
|
|
resolver.notifyChange(CONTENT_APPWIDGET_RESET_URI, null);
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-03 19:32:27 -08:00
|
|
|
@Override
|
|
|
|
|
public void onCreate(SQLiteDatabase db) {
|
2009-11-11 08:16:49 -08:00
|
|
|
if (LOGD) Log.d(TAG, "creating new launcher database");
|
2011-04-28 14:59:33 -07:00
|
|
|
|
|
|
|
|
mMaxId = 1;
|
|
|
|
|
|
2009-03-03 19:32:27 -08:00
|
|
|
db.execSQL("CREATE TABLE favorites (" +
|
|
|
|
|
"_id INTEGER PRIMARY KEY," +
|
|
|
|
|
"title TEXT," +
|
|
|
|
|
"intent TEXT," +
|
|
|
|
|
"container INTEGER," +
|
|
|
|
|
"screen INTEGER," +
|
|
|
|
|
"cellX INTEGER," +
|
|
|
|
|
"cellY INTEGER," +
|
|
|
|
|
"spanX INTEGER," +
|
|
|
|
|
"spanY INTEGER," +
|
|
|
|
|
"itemType INTEGER," +
|
2009-03-13 13:04:24 -07:00
|
|
|
"appWidgetId INTEGER NOT NULL DEFAULT -1," +
|
2009-03-03 19:32:27 -08:00
|
|
|
"isShortcut INTEGER," +
|
|
|
|
|
"iconType INTEGER," +
|
|
|
|
|
"iconPackage TEXT," +
|
|
|
|
|
"iconResource TEXT," +
|
|
|
|
|
"icon BLOB," +
|
|
|
|
|
"uri TEXT," +
|
|
|
|
|
"displayMode INTEGER" +
|
|
|
|
|
");");
|
|
|
|
|
|
2009-03-11 12:11:58 -07:00
|
|
|
// Database was just created, so wipe any previous widgets
|
|
|
|
|
if (mAppWidgetHost != null) {
|
|
|
|
|
mAppWidgetHost.deleteHost();
|
AI 143776: am: CL 143622 Correctly startListening() for widget updates when first boot completes.
During the first boot upgrade, LauncherProvider will deleteHost() to clear out any old appWidgetId bindings. During the first boot, Launcher calls AppWidgetHost.startListening() to watch for widget updates. It also calls loadUserItems(), which loads data from LauncherProvider, triggering the database creation and deleteHost() call. Because deleteHost() removes any existing callbacks, any future widget updates are dropped on the floor. (This can currently be solved by rebooting, because there isn't an upgrade on subsequent boots.)
This bug was particularly evident on vfpioneer-userdebug builds, as there aren't any configuration changes that cause Launcher to be destroyed and recreated. (When destroyed and recreated, we startListening() again, and LauncherProvider doesn't call deleteHost().)
To handle this special case, Launcher creates a ContentObserver pointing at a specific URI, which the LauncherProvider notifies when the AppWidgetHost is reset through deleteHost(), allowing Launcher to correctly startListening() again.
Original author: jsharkey
Merged from: //branches/cupcake/...
Automated import of CL 143776
2009-03-31 14:37:57 -07:00
|
|
|
sendAppWidgetResetNotify();
|
2009-03-03 19:32:27 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!convertDatabase(db)) {
|
|
|
|
|
// Populate favorites table with initial favorites
|
2009-03-18 17:39:48 -07:00
|
|
|
loadFavorites(db);
|
2009-03-03 19:32:27 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private boolean convertDatabase(SQLiteDatabase db) {
|
2009-11-11 08:16:49 -08:00
|
|
|
if (LOGD) Log.d(TAG, "converting database from an older format, but not onUpgrade");
|
2009-03-03 19:32:27 -08:00
|
|
|
boolean converted = false;
|
|
|
|
|
|
|
|
|
|
final Uri uri = Uri.parse("content://" + Settings.AUTHORITY +
|
|
|
|
|
"/old_favorites?notify=true");
|
|
|
|
|
final ContentResolver resolver = mContext.getContentResolver();
|
|
|
|
|
Cursor cursor = null;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
cursor = resolver.query(uri, null, null, null, null);
|
|
|
|
|
} catch (Exception e) {
|
2011-04-28 14:59:33 -07:00
|
|
|
// Ignore
|
2009-03-03 19:32:27 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We already have a favorites database in the old provider
|
|
|
|
|
if (cursor != null && cursor.getCount() > 0) {
|
|
|
|
|
try {
|
|
|
|
|
converted = copyFromCursor(db, cursor) > 0;
|
|
|
|
|
} finally {
|
|
|
|
|
cursor.close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (converted) {
|
|
|
|
|
resolver.delete(uri, null, null);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (converted) {
|
2009-03-11 12:11:58 -07:00
|
|
|
// Convert widgets from this import into widgets
|
2009-11-11 08:16:49 -08:00
|
|
|
if (LOGD) Log.d(TAG, "converted and now triggering widget upgrade");
|
2009-03-03 19:32:27 -08:00
|
|
|
convertWidgets(db);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return converted;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private int copyFromCursor(SQLiteDatabase db, Cursor c) {
|
2009-06-09 12:57:21 -07:00
|
|
|
final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
|
2009-03-03 19:32:27 -08:00
|
|
|
final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);
|
|
|
|
|
final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);
|
|
|
|
|
final int iconTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_TYPE);
|
|
|
|
|
final int iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);
|
|
|
|
|
final int iconPackageIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_PACKAGE);
|
|
|
|
|
final int iconResourceIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_RESOURCE);
|
|
|
|
|
final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
|
|
|
|
|
final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
|
|
|
|
|
final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);
|
|
|
|
|
final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
|
|
|
|
|
final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
|
|
|
|
|
final int uriIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI);
|
|
|
|
|
final int displayModeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.DISPLAY_MODE);
|
|
|
|
|
|
|
|
|
|
ContentValues[] rows = new ContentValues[c.getCount()];
|
|
|
|
|
int i = 0;
|
|
|
|
|
while (c.moveToNext()) {
|
|
|
|
|
ContentValues values = new ContentValues(c.getColumnCount());
|
2009-06-09 12:57:21 -07:00
|
|
|
values.put(LauncherSettings.Favorites._ID, c.getLong(idIndex));
|
2009-03-03 19:32:27 -08:00
|
|
|
values.put(LauncherSettings.Favorites.INTENT, c.getString(intentIndex));
|
|
|
|
|
values.put(LauncherSettings.Favorites.TITLE, c.getString(titleIndex));
|
|
|
|
|
values.put(LauncherSettings.Favorites.ICON_TYPE, c.getInt(iconTypeIndex));
|
|
|
|
|
values.put(LauncherSettings.Favorites.ICON, c.getBlob(iconIndex));
|
|
|
|
|
values.put(LauncherSettings.Favorites.ICON_PACKAGE, c.getString(iconPackageIndex));
|
|
|
|
|
values.put(LauncherSettings.Favorites.ICON_RESOURCE, c.getString(iconResourceIndex));
|
|
|
|
|
values.put(LauncherSettings.Favorites.CONTAINER, c.getInt(containerIndex));
|
|
|
|
|
values.put(LauncherSettings.Favorites.ITEM_TYPE, c.getInt(itemTypeIndex));
|
2009-03-11 12:11:58 -07:00
|
|
|
values.put(LauncherSettings.Favorites.APPWIDGET_ID, -1);
|
2009-03-03 19:32:27 -08:00
|
|
|
values.put(LauncherSettings.Favorites.SCREEN, c.getInt(screenIndex));
|
|
|
|
|
values.put(LauncherSettings.Favorites.CELLX, c.getInt(cellXIndex));
|
|
|
|
|
values.put(LauncherSettings.Favorites.CELLY, c.getInt(cellYIndex));
|
|
|
|
|
values.put(LauncherSettings.Favorites.URI, c.getString(uriIndex));
|
|
|
|
|
values.put(LauncherSettings.Favorites.DISPLAY_MODE, c.getInt(displayModeIndex));
|
|
|
|
|
rows[i++] = values;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
db.beginTransaction();
|
|
|
|
|
int total = 0;
|
|
|
|
|
try {
|
|
|
|
|
int numValues = rows.length;
|
|
|
|
|
for (i = 0; i < numValues; i++) {
|
2011-04-28 14:59:33 -07:00
|
|
|
if (dbInsertAndCheck(this, db, TABLE_FAVORITES, null, rows[i]) < 0) {
|
2009-03-03 19:32:27 -08:00
|
|
|
return 0;
|
|
|
|
|
} else {
|
|
|
|
|
total++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
db.setTransactionSuccessful();
|
|
|
|
|
} finally {
|
|
|
|
|
db.endTransaction();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return total;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
2009-11-11 08:16:49 -08:00
|
|
|
if (LOGD) Log.d(TAG, "onUpgrade triggered");
|
2009-03-03 19:32:27 -08:00
|
|
|
|
|
|
|
|
int version = oldVersion;
|
2009-03-13 13:04:24 -07:00
|
|
|
if (version < 3) {
|
|
|
|
|
// upgrade 1,2 -> 3 added appWidgetId column
|
2009-03-03 19:32:27 -08:00
|
|
|
db.beginTransaction();
|
|
|
|
|
try {
|
2009-03-11 12:11:58 -07:00
|
|
|
// Insert new column for holding appWidgetIds
|
2009-03-03 19:32:27 -08:00
|
|
|
db.execSQL("ALTER TABLE favorites " +
|
2009-03-13 13:04:24 -07:00
|
|
|
"ADD COLUMN appWidgetId INTEGER NOT NULL DEFAULT -1;");
|
2009-03-03 19:32:27 -08:00
|
|
|
db.setTransactionSuccessful();
|
2009-03-13 13:04:24 -07:00
|
|
|
version = 3;
|
2009-03-03 19:32:27 -08:00
|
|
|
} catch (SQLException ex) {
|
|
|
|
|
// Old version remains, which means we wipe old data
|
2009-11-11 08:16:49 -08:00
|
|
|
Log.e(TAG, ex.getMessage(), ex);
|
2009-03-03 19:32:27 -08:00
|
|
|
} finally {
|
|
|
|
|
db.endTransaction();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Convert existing widgets only if table upgrade was successful
|
2009-03-13 13:04:24 -07:00
|
|
|
if (version == 3) {
|
2009-03-03 19:32:27 -08:00
|
|
|
convertWidgets(db);
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-06-09 12:57:21 -07:00
|
|
|
|
|
|
|
|
if (version < 4) {
|
2009-12-02 20:10:07 -08:00
|
|
|
version = 4;
|
2009-06-09 12:57:21 -07:00
|
|
|
}
|
2009-03-03 19:32:27 -08:00
|
|
|
|
2010-03-23 15:10:56 -07:00
|
|
|
// Where's version 5?
|
|
|
|
|
// - Donut and sholes on 2.0 shipped with version 4 of launcher1.
|
|
|
|
|
// - Passion shipped on 2.1 with version 6 of launcher2
|
|
|
|
|
// - Sholes shipped on 2.1r1 (aka Mr. 3) with version 5 of launcher 1
|
|
|
|
|
// but version 5 on there was the updateContactsShortcuts change
|
|
|
|
|
// which was version 6 in launcher 2 (first shipped on passion 2.1r1).
|
|
|
|
|
// The updateContactsShortcuts change is idempotent, so running it twice
|
|
|
|
|
// is okay so we'll do that when upgrading the devices that shipped with it.
|
|
|
|
|
if (version < 6) {
|
2009-11-05 17:17:42 -08:00
|
|
|
// We went from 3 to 5 screens. Move everything 1 to the right
|
|
|
|
|
db.beginTransaction();
|
|
|
|
|
try {
|
|
|
|
|
db.execSQL("UPDATE favorites SET screen=(screen + 1);");
|
|
|
|
|
db.setTransactionSuccessful();
|
|
|
|
|
} catch (SQLException ex) {
|
|
|
|
|
// Old version remains, which means we wipe old data
|
2009-11-11 08:16:49 -08:00
|
|
|
Log.e(TAG, ex.getMessage(), ex);
|
2009-11-05 17:17:42 -08:00
|
|
|
} finally {
|
|
|
|
|
db.endTransaction();
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-23 15:10:56 -07:00
|
|
|
// We added the fast track.
|
2009-12-02 20:10:07 -08:00
|
|
|
if (updateContactsShortcuts(db)) {
|
|
|
|
|
version = 6;
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-12-09 15:38:25 +00:00
|
|
|
|
|
|
|
|
if (version < 7) {
|
|
|
|
|
// Version 7 gets rid of the special search widget.
|
|
|
|
|
convertWidgets(db);
|
|
|
|
|
version = 7;
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-08 13:44:00 -08:00
|
|
|
if (version < 8) {
|
|
|
|
|
// Version 8 (froyo) has the icons all normalized. This should
|
|
|
|
|
// already be the case in practice, but we now rely on it and don't
|
|
|
|
|
// resample the images each time.
|
|
|
|
|
normalizeIcons(db);
|
|
|
|
|
version = 8;
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-03 19:32:27 -08:00
|
|
|
if (version != DATABASE_VERSION) {
|
2009-11-11 08:16:49 -08:00
|
|
|
Log.w(TAG, "Destroying all old data.");
|
2009-03-03 19:32:27 -08:00
|
|
|
db.execSQL("DROP TABLE IF EXISTS " + TABLE_FAVORITES);
|
|
|
|
|
onCreate(db);
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-12-02 20:10:07 -08:00
|
|
|
|
|
|
|
|
private boolean updateContactsShortcuts(SQLiteDatabase db) {
|
|
|
|
|
Cursor c = null;
|
|
|
|
|
final String selectWhere = buildOrWhereString(Favorites.ITEM_TYPE,
|
|
|
|
|
new int[] { Favorites.ITEM_TYPE_SHORTCUT });
|
|
|
|
|
|
|
|
|
|
db.beginTransaction();
|
|
|
|
|
try {
|
|
|
|
|
// Select and iterate through each matching widget
|
|
|
|
|
c = db.query(TABLE_FAVORITES, new String[] { Favorites._ID, Favorites.INTENT },
|
|
|
|
|
selectWhere, null, null, null, null);
|
|
|
|
|
|
|
|
|
|
if (LOGD) Log.d(TAG, "found upgrade cursor count=" + c.getCount());
|
|
|
|
|
|
|
|
|
|
final ContentValues values = new ContentValues();
|
|
|
|
|
final int idIndex = c.getColumnIndex(Favorites._ID);
|
|
|
|
|
final int intentIndex = c.getColumnIndex(Favorites.INTENT);
|
|
|
|
|
|
|
|
|
|
while (c != null && c.moveToNext()) {
|
|
|
|
|
long favoriteId = c.getLong(idIndex);
|
|
|
|
|
final String intentUri = c.getString(intentIndex);
|
|
|
|
|
if (intentUri != null) {
|
|
|
|
|
try {
|
|
|
|
|
Intent intent = Intent.parseUri(intentUri, 0);
|
|
|
|
|
android.util.Log.d("Home", intent.toString());
|
|
|
|
|
final Uri uri = intent.getData();
|
|
|
|
|
final String data = uri.toString();
|
|
|
|
|
if (Intent.ACTION_VIEW.equals(intent.getAction()) &&
|
|
|
|
|
(data.startsWith("content://contacts/people/") ||
|
|
|
|
|
data.startsWith("content://com.android.contacts/contacts/lookup/"))) {
|
|
|
|
|
|
|
|
|
|
intent = new Intent("com.android.contacts.action.QUICK_CONTACT");
|
|
|
|
|
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
|
|
|
|
|
Intent.FLAG_ACTIVITY_CLEAR_TOP |
|
|
|
|
|
Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
|
|
|
|
|
|
|
|
|
|
intent.setData(uri);
|
|
|
|
|
intent.putExtra("mode", 3);
|
|
|
|
|
intent.putExtra("exclude_mimes", (String[]) null);
|
|
|
|
|
|
|
|
|
|
values.clear();
|
|
|
|
|
values.put(LauncherSettings.Favorites.INTENT, intent.toUri(0));
|
|
|
|
|
|
|
|
|
|
String updateWhere = Favorites._ID + "=" + favoriteId;
|
|
|
|
|
db.update(TABLE_FAVORITES, values, updateWhere, null);
|
|
|
|
|
}
|
|
|
|
|
} catch (RuntimeException ex) {
|
|
|
|
|
Log.e(TAG, "Problem upgrading shortcut", ex);
|
|
|
|
|
} catch (URISyntaxException e) {
|
|
|
|
|
Log.e(TAG, "Problem upgrading shortcut", e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
db.setTransactionSuccessful();
|
|
|
|
|
} catch (SQLException ex) {
|
|
|
|
|
Log.w(TAG, "Problem while upgrading contacts", ex);
|
|
|
|
|
return false;
|
|
|
|
|
} finally {
|
|
|
|
|
db.endTransaction();
|
|
|
|
|
if (c != null) {
|
|
|
|
|
c.close();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-08 13:44:00 -08:00
|
|
|
private void normalizeIcons(SQLiteDatabase db) {
|
|
|
|
|
Log.d(TAG, "normalizing icons");
|
|
|
|
|
|
2010-02-18 10:34:24 -05:00
|
|
|
db.beginTransaction();
|
2010-02-08 13:44:00 -08:00
|
|
|
Cursor c = null;
|
2010-03-23 17:34:37 -04:00
|
|
|
SQLiteStatement update = null;
|
2010-02-08 13:44:00 -08:00
|
|
|
try {
|
|
|
|
|
boolean logged = false;
|
2010-03-23 17:34:37 -04:00
|
|
|
update = db.compileStatement("UPDATE favorites "
|
2010-02-13 00:08:17 -06:00
|
|
|
+ "SET icon=? WHERE _id=?");
|
2010-02-08 13:44:00 -08:00
|
|
|
|
|
|
|
|
c = db.rawQuery("SELECT _id, icon FROM favorites WHERE iconType=" +
|
|
|
|
|
Favorites.ICON_TYPE_BITMAP, null);
|
|
|
|
|
|
|
|
|
|
final int idIndex = c.getColumnIndexOrThrow(Favorites._ID);
|
|
|
|
|
final int iconIndex = c.getColumnIndexOrThrow(Favorites.ICON);
|
|
|
|
|
|
|
|
|
|
while (c.moveToNext()) {
|
|
|
|
|
long id = c.getLong(idIndex);
|
|
|
|
|
byte[] data = c.getBlob(iconIndex);
|
|
|
|
|
try {
|
|
|
|
|
Bitmap bitmap = Utilities.resampleIconBitmap(
|
|
|
|
|
BitmapFactory.decodeByteArray(data, 0, data.length),
|
|
|
|
|
mContext);
|
|
|
|
|
if (bitmap != null) {
|
|
|
|
|
update.bindLong(1, id);
|
|
|
|
|
data = ItemInfo.flattenBitmap(bitmap);
|
|
|
|
|
if (data != null) {
|
|
|
|
|
update.bindBlob(2, data);
|
|
|
|
|
update.execute();
|
|
|
|
|
}
|
|
|
|
|
bitmap.recycle();
|
|
|
|
|
}
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
if (!logged) {
|
|
|
|
|
Log.e(TAG, "Failed normalizing icon " + id, e);
|
|
|
|
|
} else {
|
|
|
|
|
Log.e(TAG, "Also failed normalizing icon " + id);
|
|
|
|
|
}
|
|
|
|
|
logged = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-02-19 11:15:40 +00:00
|
|
|
db.setTransactionSuccessful();
|
2010-02-08 13:44:00 -08:00
|
|
|
} catch (SQLException ex) {
|
|
|
|
|
Log.w(TAG, "Problem while allocating appWidgetIds for existing widgets", ex);
|
|
|
|
|
} finally {
|
|
|
|
|
db.endTransaction();
|
2010-03-23 17:34:37 -04:00
|
|
|
if (update != null) {
|
|
|
|
|
update.close();
|
|
|
|
|
}
|
2010-02-08 13:44:00 -08:00
|
|
|
if (c != null) {
|
|
|
|
|
c.close();
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-04-28 14:59:33 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Generates a new ID to use for an object in your database. This method should be only
|
|
|
|
|
// called from the main UI thread. As an exception, we do call it when we call the
|
|
|
|
|
// constructor from the worker thread; however, this doesn't extend until after the
|
|
|
|
|
// constructor is called, and we only pass a reference to LauncherProvider to LauncherApp
|
|
|
|
|
// after that point
|
|
|
|
|
public long generateNewId() {
|
|
|
|
|
if (mMaxId < 0) {
|
|
|
|
|
throw new RuntimeException("Error: max id was not initialized");
|
|
|
|
|
}
|
|
|
|
|
mMaxId += 1;
|
|
|
|
|
return mMaxId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private long initializeMaxId(SQLiteDatabase db) {
|
|
|
|
|
Cursor c = db.rawQuery("SELECT MAX(_id) FROM favorites", null);
|
|
|
|
|
|
|
|
|
|
// get the result
|
|
|
|
|
final int maxIdIndex = 0;
|
|
|
|
|
long id = -1;
|
|
|
|
|
if (c != null && c.moveToNext()) {
|
|
|
|
|
id = c.getLong(maxIdIndex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (id == -1) {
|
|
|
|
|
throw new RuntimeException("Error: could not query max id");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return id;
|
2010-02-08 13:44:00 -08:00
|
|
|
}
|
|
|
|
|
|
2009-03-03 19:32:27 -08:00
|
|
|
/**
|
2009-03-11 12:11:58 -07:00
|
|
|
* Upgrade existing clock and photo frame widgets into their new widget
|
2009-12-16 13:19:47 +00:00
|
|
|
* equivalents.
|
2009-03-03 19:32:27 -08:00
|
|
|
*/
|
|
|
|
|
private void convertWidgets(SQLiteDatabase db) {
|
2009-12-15 13:33:11 +00:00
|
|
|
final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext);
|
2009-03-03 19:32:27 -08:00
|
|
|
final int[] bindSources = new int[] {
|
|
|
|
|
Favorites.ITEM_TYPE_WIDGET_CLOCK,
|
|
|
|
|
Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME,
|
2009-12-09 15:38:25 +00:00
|
|
|
Favorites.ITEM_TYPE_WIDGET_SEARCH,
|
2009-03-03 19:32:27 -08:00
|
|
|
};
|
2009-12-09 15:38:25 +00:00
|
|
|
|
2009-03-03 19:32:27 -08:00
|
|
|
final String selectWhere = buildOrWhereString(Favorites.ITEM_TYPE, bindSources);
|
|
|
|
|
|
|
|
|
|
Cursor c = null;
|
|
|
|
|
|
|
|
|
|
db.beginTransaction();
|
|
|
|
|
try {
|
|
|
|
|
// Select and iterate through each matching widget
|
2009-12-09 15:38:25 +00:00
|
|
|
c = db.query(TABLE_FAVORITES, new String[] { Favorites._ID, Favorites.ITEM_TYPE },
|
2009-03-03 19:32:27 -08:00
|
|
|
selectWhere, null, null, null, null);
|
|
|
|
|
|
2009-11-11 08:16:49 -08:00
|
|
|
if (LOGD) Log.d(TAG, "found upgrade cursor count=" + c.getCount());
|
2009-03-03 19:32:27 -08:00
|
|
|
|
|
|
|
|
final ContentValues values = new ContentValues();
|
|
|
|
|
while (c != null && c.moveToNext()) {
|
|
|
|
|
long favoriteId = c.getLong(0);
|
2009-12-09 15:38:25 +00:00
|
|
|
int favoriteType = c.getInt(1);
|
|
|
|
|
|
2009-03-11 12:11:58 -07:00
|
|
|
// Allocate and update database with new appWidgetId
|
2009-03-03 19:32:27 -08:00
|
|
|
try {
|
2009-03-11 12:11:58 -07:00
|
|
|
int appWidgetId = mAppWidgetHost.allocateAppWidgetId();
|
2009-03-03 19:32:27 -08:00
|
|
|
|
2009-11-11 08:16:49 -08:00
|
|
|
if (LOGD) {
|
|
|
|
|
Log.d(TAG, "allocated appWidgetId=" + appWidgetId
|
|
|
|
|
+ " for favoriteId=" + favoriteId);
|
|
|
|
|
}
|
2009-03-03 19:32:27 -08:00
|
|
|
values.clear();
|
2009-12-09 15:38:25 +00:00
|
|
|
values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_APPWIDGET);
|
|
|
|
|
values.put(Favorites.APPWIDGET_ID, appWidgetId);
|
|
|
|
|
|
2009-03-03 19:32:27 -08:00
|
|
|
// Original widgets might not have valid spans when upgrading
|
2009-12-09 15:38:25 +00:00
|
|
|
if (favoriteType == Favorites.ITEM_TYPE_WIDGET_SEARCH) {
|
|
|
|
|
values.put(LauncherSettings.Favorites.SPANX, 4);
|
|
|
|
|
values.put(LauncherSettings.Favorites.SPANY, 1);
|
|
|
|
|
} else {
|
|
|
|
|
values.put(LauncherSettings.Favorites.SPANX, 2);
|
|
|
|
|
values.put(LauncherSettings.Favorites.SPANY, 2);
|
|
|
|
|
}
|
2009-03-03 19:32:27 -08:00
|
|
|
|
|
|
|
|
String updateWhere = Favorites._ID + "=" + favoriteId;
|
|
|
|
|
db.update(TABLE_FAVORITES, values, updateWhere, null);
|
2009-12-15 13:33:11 +00:00
|
|
|
|
|
|
|
|
if (favoriteType == Favorites.ITEM_TYPE_WIDGET_CLOCK) {
|
|
|
|
|
appWidgetManager.bindAppWidgetId(appWidgetId,
|
|
|
|
|
new ComponentName("com.android.alarmclock",
|
|
|
|
|
"com.android.alarmclock.AnalogAppWidgetProvider"));
|
|
|
|
|
} else if (favoriteType == Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME) {
|
|
|
|
|
appWidgetManager.bindAppWidgetId(appWidgetId,
|
|
|
|
|
new ComponentName("com.android.camera",
|
|
|
|
|
"com.android.camera.PhotoAppWidgetProvider"));
|
|
|
|
|
} else if (favoriteType == Favorites.ITEM_TYPE_WIDGET_SEARCH) {
|
|
|
|
|
appWidgetManager.bindAppWidgetId(appWidgetId,
|
2010-01-14 13:26:43 +00:00
|
|
|
getSearchWidgetProvider());
|
2009-12-15 13:33:11 +00:00
|
|
|
}
|
2009-03-03 19:32:27 -08:00
|
|
|
} catch (RuntimeException ex) {
|
2009-11-11 08:16:49 -08:00
|
|
|
Log.e(TAG, "Problem allocating appWidgetId", ex);
|
2009-03-03 19:32:27 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
db.setTransactionSuccessful();
|
|
|
|
|
} catch (SQLException ex) {
|
2009-11-11 08:16:49 -08:00
|
|
|
Log.w(TAG, "Problem while allocating appWidgetIds for existing widgets", ex);
|
2009-03-03 19:32:27 -08:00
|
|
|
} finally {
|
|
|
|
|
db.endTransaction();
|
|
|
|
|
if (c != null) {
|
|
|
|
|
c.close();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Loads the default set of favorite packages from an xml file.
|
|
|
|
|
*
|
|
|
|
|
* @param db The database to write the values into
|
|
|
|
|
*/
|
2009-03-18 17:39:48 -07:00
|
|
|
private int loadFavorites(SQLiteDatabase db) {
|
2009-03-03 19:32:27 -08:00
|
|
|
Intent intent = new Intent(Intent.ACTION_MAIN, null);
|
|
|
|
|
intent.addCategory(Intent.CATEGORY_LAUNCHER);
|
|
|
|
|
ContentValues values = new ContentValues();
|
|
|
|
|
|
|
|
|
|
PackageManager packageManager = mContext.getPackageManager();
|
|
|
|
|
int i = 0;
|
|
|
|
|
try {
|
2009-03-18 17:39:48 -07:00
|
|
|
XmlResourceParser parser = mContext.getResources().getXml(R.xml.default_workspace);
|
|
|
|
|
AttributeSet attrs = Xml.asAttributeSet(parser);
|
2009-03-03 19:32:27 -08:00
|
|
|
XmlUtils.beginDocument(parser, TAG_FAVORITES);
|
|
|
|
|
|
2009-03-18 17:39:48 -07:00
|
|
|
final int depth = parser.getDepth();
|
2009-03-03 19:32:27 -08:00
|
|
|
|
2009-03-18 17:39:48 -07:00
|
|
|
int type;
|
|
|
|
|
while (((type = parser.next()) != XmlPullParser.END_TAG ||
|
|
|
|
|
parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
|
|
|
|
|
|
|
|
|
|
if (type != XmlPullParser.START_TAG) {
|
|
|
|
|
continue;
|
2009-03-03 19:32:27 -08:00
|
|
|
}
|
|
|
|
|
|
2009-03-18 17:39:48 -07:00
|
|
|
boolean added = false;
|
|
|
|
|
final String name = parser.getName();
|
|
|
|
|
|
|
|
|
|
TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.Favorite);
|
|
|
|
|
|
|
|
|
|
values.clear();
|
|
|
|
|
values.put(LauncherSettings.Favorites.CONTAINER,
|
|
|
|
|
LauncherSettings.Favorites.CONTAINER_DESKTOP);
|
|
|
|
|
values.put(LauncherSettings.Favorites.SCREEN,
|
|
|
|
|
a.getString(R.styleable.Favorite_screen));
|
|
|
|
|
values.put(LauncherSettings.Favorites.CELLX,
|
|
|
|
|
a.getString(R.styleable.Favorite_x));
|
|
|
|
|
values.put(LauncherSettings.Favorites.CELLY,
|
|
|
|
|
a.getString(R.styleable.Favorite_y));
|
|
|
|
|
|
|
|
|
|
if (TAG_FAVORITE.equals(name)) {
|
2009-10-30 16:36:56 -07:00
|
|
|
added = addAppShortcut(db, values, a, packageManager, intent);
|
2009-03-18 17:39:48 -07:00
|
|
|
} else if (TAG_SEARCH.equals(name)) {
|
|
|
|
|
added = addSearchWidget(db, values);
|
|
|
|
|
} else if (TAG_CLOCK.equals(name)) {
|
|
|
|
|
added = addClockWidget(db, values);
|
2009-10-30 16:36:56 -07:00
|
|
|
} else if (TAG_APPWIDGET.equals(name)) {
|
2010-03-23 10:58:18 -07:00
|
|
|
added = addAppWidget(db, values, a, packageManager);
|
2009-10-30 16:36:56 -07:00
|
|
|
} else if (TAG_SHORTCUT.equals(name)) {
|
|
|
|
|
added = addUriShortcut(db, values, a);
|
2009-03-03 19:32:27 -08:00
|
|
|
}
|
2009-03-18 17:39:48 -07:00
|
|
|
|
|
|
|
|
if (added) i++;
|
|
|
|
|
|
|
|
|
|
a.recycle();
|
2009-03-03 19:32:27 -08:00
|
|
|
}
|
|
|
|
|
} catch (XmlPullParserException e) {
|
2009-11-11 08:16:49 -08:00
|
|
|
Log.w(TAG, "Got exception parsing favorites.", e);
|
2009-03-03 19:32:27 -08:00
|
|
|
} catch (IOException e) {
|
2009-11-11 08:16:49 -08:00
|
|
|
Log.w(TAG, "Got exception parsing favorites.", e);
|
2009-03-03 19:32:27 -08:00
|
|
|
}
|
2009-03-18 17:39:48 -07:00
|
|
|
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
|
2009-10-30 16:36:56 -07:00
|
|
|
private boolean addAppShortcut(SQLiteDatabase db, ContentValues values, TypedArray a,
|
2009-03-18 17:39:48 -07:00
|
|
|
PackageManager packageManager, Intent intent) {
|
|
|
|
|
|
|
|
|
|
ActivityInfo info;
|
|
|
|
|
String packageName = a.getString(R.styleable.Favorite_packageName);
|
|
|
|
|
String className = a.getString(R.styleable.Favorite_className);
|
|
|
|
|
try {
|
2010-03-23 10:58:18 -07:00
|
|
|
ComponentName cn;
|
|
|
|
|
try {
|
|
|
|
|
cn = new ComponentName(packageName, className);
|
|
|
|
|
info = packageManager.getActivityInfo(cn, 0);
|
|
|
|
|
} catch (PackageManager.NameNotFoundException nnfe) {
|
|
|
|
|
String[] packages = packageManager.currentToCanonicalPackageNames(
|
|
|
|
|
new String[] { packageName });
|
|
|
|
|
cn = new ComponentName(packages[0], className);
|
|
|
|
|
info = packageManager.getActivityInfo(cn, 0);
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-18 17:39:48 -07:00
|
|
|
intent.setComponent(cn);
|
2010-03-23 10:58:18 -07:00
|
|
|
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
|
|
|
|
|
Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
|
2009-06-23 17:34:54 -07:00
|
|
|
values.put(Favorites.INTENT, intent.toUri(0));
|
2009-03-18 17:39:48 -07:00
|
|
|
values.put(Favorites.TITLE, info.loadLabel(packageManager).toString());
|
|
|
|
|
values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_APPLICATION);
|
|
|
|
|
values.put(Favorites.SPANX, 1);
|
|
|
|
|
values.put(Favorites.SPANY, 1);
|
2011-04-28 14:59:33 -07:00
|
|
|
values.put(Favorites._ID, generateNewId());
|
|
|
|
|
dbInsertAndCheck(this, db, TABLE_FAVORITES, null, values);
|
2009-03-18 17:39:48 -07:00
|
|
|
} catch (PackageManager.NameNotFoundException e) {
|
2009-11-11 08:16:49 -08:00
|
|
|
Log.w(TAG, "Unable to add favorite: " + packageName +
|
2009-03-18 17:39:48 -07:00
|
|
|
"/" + className, e);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-14 13:26:43 +00:00
|
|
|
private ComponentName getSearchWidgetProvider() {
|
|
|
|
|
SearchManager searchManager =
|
|
|
|
|
(SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
|
|
|
|
|
ComponentName searchComponent = searchManager.getGlobalSearchActivity();
|
|
|
|
|
if (searchComponent == null) return null;
|
|
|
|
|
return getProviderInPackage(searchComponent.getPackageName());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Gets an appwidget provider from the given package. If the package contains more than
|
|
|
|
|
* one appwidget provider, an arbitrary one is returned.
|
|
|
|
|
*/
|
|
|
|
|
private ComponentName getProviderInPackage(String packageName) {
|
|
|
|
|
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext);
|
|
|
|
|
List<AppWidgetProviderInfo> providers = appWidgetManager.getInstalledProviders();
|
|
|
|
|
if (providers == null) return null;
|
|
|
|
|
final int providerCount = providers.size();
|
|
|
|
|
for (int i = 0; i < providerCount; i++) {
|
|
|
|
|
ComponentName provider = providers.get(i).provider;
|
|
|
|
|
if (provider != null && provider.getPackageName().equals(packageName)) {
|
|
|
|
|
return provider;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-18 17:39:48 -07:00
|
|
|
private boolean addSearchWidget(SQLiteDatabase db, ContentValues values) {
|
2010-01-14 13:26:43 +00:00
|
|
|
ComponentName cn = getSearchWidgetProvider();
|
2009-12-09 15:38:25 +00:00
|
|
|
return addAppWidget(db, values, cn, 4, 1);
|
2009-03-18 17:39:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private boolean addClockWidget(SQLiteDatabase db, ContentValues values) {
|
2009-12-15 13:33:11 +00:00
|
|
|
ComponentName cn = new ComponentName("com.android.alarmclock",
|
|
|
|
|
"com.android.alarmclock.AnalogAppWidgetProvider");
|
|
|
|
|
return addAppWidget(db, values, cn, 2, 2);
|
2009-03-03 19:32:27 -08:00
|
|
|
}
|
2009-10-30 16:36:56 -07:00
|
|
|
|
2010-03-23 10:58:18 -07:00
|
|
|
private boolean addAppWidget(SQLiteDatabase db, ContentValues values, TypedArray a,
|
|
|
|
|
PackageManager packageManager) {
|
|
|
|
|
|
2009-10-30 16:36:56 -07:00
|
|
|
String packageName = a.getString(R.styleable.Favorite_packageName);
|
|
|
|
|
String className = a.getString(R.styleable.Favorite_className);
|
|
|
|
|
|
|
|
|
|
if (packageName == null || className == null) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2010-03-23 10:58:18 -07:00
|
|
|
|
|
|
|
|
boolean hasPackage = true;
|
2009-10-30 16:36:56 -07:00
|
|
|
ComponentName cn = new ComponentName(packageName, className);
|
2010-03-23 10:58:18 -07:00
|
|
|
try {
|
|
|
|
|
packageManager.getReceiverInfo(cn, 0);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
String[] packages = packageManager.currentToCanonicalPackageNames(
|
|
|
|
|
new String[] { packageName });
|
|
|
|
|
cn = new ComponentName(packages[0], className);
|
|
|
|
|
try {
|
|
|
|
|
packageManager.getReceiverInfo(cn, 0);
|
|
|
|
|
} catch (Exception e1) {
|
|
|
|
|
hasPackage = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (hasPackage) {
|
|
|
|
|
int spanX = a.getInt(R.styleable.Favorite_spanX, 0);
|
|
|
|
|
int spanY = a.getInt(R.styleable.Favorite_spanY, 0);
|
|
|
|
|
return addAppWidget(db, values, cn, spanX, spanY);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
2009-12-09 15:38:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private boolean addAppWidget(SQLiteDatabase db, ContentValues values, ComponentName cn,
|
|
|
|
|
int spanX, int spanY) {
|
2009-10-30 16:36:56 -07:00
|
|
|
boolean allocatedAppWidgets = false;
|
|
|
|
|
final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext);
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
int appWidgetId = mAppWidgetHost.allocateAppWidgetId();
|
|
|
|
|
|
|
|
|
|
values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_APPWIDGET);
|
2009-12-09 15:38:25 +00:00
|
|
|
values.put(Favorites.SPANX, spanX);
|
|
|
|
|
values.put(Favorites.SPANY, spanY);
|
2009-10-30 16:36:56 -07:00
|
|
|
values.put(Favorites.APPWIDGET_ID, appWidgetId);
|
2011-04-28 14:59:33 -07:00
|
|
|
values.put(Favorites._ID, generateNewId());
|
|
|
|
|
dbInsertAndCheck(this, db, TABLE_FAVORITES, null, values);
|
2009-10-30 16:36:56 -07:00
|
|
|
|
|
|
|
|
allocatedAppWidgets = true;
|
|
|
|
|
|
|
|
|
|
appWidgetManager.bindAppWidgetId(appWidgetId, cn);
|
|
|
|
|
} catch (RuntimeException ex) {
|
2009-11-11 08:16:49 -08:00
|
|
|
Log.e(TAG, "Problem allocating appWidgetId", ex);
|
2009-10-30 16:36:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return allocatedAppWidgets;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private boolean addUriShortcut(SQLiteDatabase db, ContentValues values,
|
|
|
|
|
TypedArray a) {
|
|
|
|
|
Resources r = mContext.getResources();
|
|
|
|
|
|
|
|
|
|
final int iconResId = a.getResourceId(R.styleable.Favorite_icon, 0);
|
|
|
|
|
final int titleResId = a.getResourceId(R.styleable.Favorite_title, 0);
|
|
|
|
|
|
2009-12-02 20:10:07 -08:00
|
|
|
Intent intent;
|
2009-10-30 16:36:56 -07:00
|
|
|
String uri = null;
|
|
|
|
|
try {
|
|
|
|
|
uri = a.getString(R.styleable.Favorite_uri);
|
|
|
|
|
intent = Intent.parseUri(uri, 0);
|
|
|
|
|
} catch (URISyntaxException e) {
|
2009-11-11 08:16:49 -08:00
|
|
|
Log.w(TAG, "Shortcut has malformed uri: " + uri);
|
2009-10-30 16:36:56 -07:00
|
|
|
return false; // Oh well
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (iconResId == 0 || titleResId == 0) {
|
2009-11-11 08:16:49 -08:00
|
|
|
Log.w(TAG, "Shortcut is missing title or icon resource ID");
|
2009-10-30 16:36:56 -07:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
|
|
|
values.put(Favorites.INTENT, intent.toUri(0));
|
|
|
|
|
values.put(Favorites.TITLE, r.getString(titleResId));
|
|
|
|
|
values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_SHORTCUT);
|
|
|
|
|
values.put(Favorites.SPANX, 1);
|
|
|
|
|
values.put(Favorites.SPANY, 1);
|
|
|
|
|
values.put(Favorites.ICON_TYPE, Favorites.ICON_TYPE_RESOURCE);
|
|
|
|
|
values.put(Favorites.ICON_PACKAGE, mContext.getPackageName());
|
|
|
|
|
values.put(Favorites.ICON_RESOURCE, r.getResourceName(iconResId));
|
2011-04-28 14:59:33 -07:00
|
|
|
values.put(Favorites._ID, generateNewId());
|
|
|
|
|
dbInsertAndCheck(this, db, TABLE_FAVORITES, null, values);
|
2009-10-30 16:36:56 -07:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-03 19:32:27 -08:00
|
|
|
/**
|
|
|
|
|
* Build a query string that will match any row where the column matches
|
|
|
|
|
* anything in the values list.
|
|
|
|
|
*/
|
|
|
|
|
static String buildOrWhereString(String column, int[] values) {
|
|
|
|
|
StringBuilder selectWhere = new StringBuilder();
|
|
|
|
|
for (int i = values.length - 1; i >= 0; i--) {
|
|
|
|
|
selectWhere.append(column).append("=").append(values[i]);
|
|
|
|
|
if (i > 0) {
|
|
|
|
|
selectWhere.append(" OR ");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return selectWhere.toString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static class SqlArguments {
|
|
|
|
|
public final String table;
|
|
|
|
|
public final String where;
|
|
|
|
|
public final String[] args;
|
|
|
|
|
|
|
|
|
|
SqlArguments(Uri url, String where, String[] args) {
|
|
|
|
|
if (url.getPathSegments().size() == 1) {
|
|
|
|
|
this.table = url.getPathSegments().get(0);
|
|
|
|
|
this.where = where;
|
|
|
|
|
this.args = args;
|
|
|
|
|
} else if (url.getPathSegments().size() != 2) {
|
|
|
|
|
throw new IllegalArgumentException("Invalid URI: " + url);
|
|
|
|
|
} else if (!TextUtils.isEmpty(where)) {
|
|
|
|
|
throw new UnsupportedOperationException("WHERE clause not supported: " + url);
|
|
|
|
|
} else {
|
|
|
|
|
this.table = url.getPathSegments().get(0);
|
|
|
|
|
this.where = "_id=" + ContentUris.parseId(url);
|
|
|
|
|
this.args = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SqlArguments(Uri url) {
|
|
|
|
|
if (url.getPathSegments().size() == 1) {
|
|
|
|
|
table = url.getPathSegments().get(0);
|
|
|
|
|
where = null;
|
|
|
|
|
args = null;
|
|
|
|
|
} else {
|
|
|
|
|
throw new IllegalArgumentException("Invalid URI: " + url);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|