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
|
|
|
|
2009-03-11 12:11:58 -07:00
|
|
|
import android.appwidget.AppWidgetHost;
|
2009-10-30 16:36:56 -07:00
|
|
|
import android.appwidget.AppWidgetManager;
|
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;
|
|
|
|
|
import android.database.sqlite.SQLiteOpenHelper;
|
|
|
|
|
import android.database.sqlite.SQLiteDatabase;
|
|
|
|
|
import android.database.sqlite.SQLiteQueryBuilder;
|
|
|
|
|
import android.database.Cursor;
|
|
|
|
|
import android.database.SQLException;
|
|
|
|
|
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.os.*;
|
|
|
|
|
import android.provider.Settings;
|
|
|
|
|
|
|
|
|
|
import java.io.IOException;
|
2009-10-30 16:36:56 -07:00
|
|
|
import java.net.URISyntaxException;
|
2009-03-03 19:32:27 -08:00
|
|
|
import java.util.ArrayList;
|
|
|
|
|
|
|
|
|
|
import org.xmlpull.v1.XmlPullParserException;
|
2009-03-18 17:39:48 -07:00
|
|
|
import org.xmlpull.v1.XmlPullParser;
|
2009-03-03 19:32:27 -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
|
|
|
|
|
|
|
|
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";
|
|
|
|
|
|
2009-11-05 17:17:42 -08:00
|
|
|
private static final int DATABASE_VERSION = 5;
|
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
|
|
|
|
2009-07-30 13:37:37 -07:00
|
|
|
static final String EXTRA_BIND_SOURCES = "com.android.launcher2.settings.bindsources";
|
|
|
|
|
static final String EXTRA_BIND_TARGETS = "com.android.launcher2.settings.bindtargets";
|
2009-03-03 19:32:27 -08:00
|
|
|
|
|
|
|
|
static final String TABLE_FAVORITES = "favorites";
|
2009-06-09 12:57:21 -07:00
|
|
|
static final String TABLE_GESTURES = "gestures";
|
2009-03-03 19:32:27 -08:00
|
|
|
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");
|
|
|
|
|
|
2009-03-03 19:32:27 -08:00
|
|
|
private SQLiteOpenHelper mOpenHelper;
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean onCreate() {
|
|
|
|
|
mOpenHelper = new DatabaseHelper(getContext());
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Uri insert(Uri uri, ContentValues initialValues) {
|
|
|
|
|
SqlArguments args = new SqlArguments(uri);
|
|
|
|
|
|
|
|
|
|
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
|
|
|
|
|
final long rowId = db.insert(args.table, null, initialValues);
|
|
|
|
|
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++) {
|
|
|
|
|
if (db.insert(args.table, null, values[i]) < 0) return 0;
|
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
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);
|
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");
|
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-06-09 12:57:21 -07:00
|
|
|
db.execSQL("CREATE TABLE gestures (" +
|
|
|
|
|
"_id INTEGER PRIMARY KEY," +
|
|
|
|
|
"title TEXT," +
|
|
|
|
|
"intent TEXT," +
|
|
|
|
|
"itemType INTEGER," +
|
|
|
|
|
"iconType INTEGER," +
|
|
|
|
|
"iconPackage TEXT," +
|
|
|
|
|
"iconResource TEXT," +
|
|
|
|
|
"icon BLOB" +
|
|
|
|
|
");");
|
|
|
|
|
|
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) {
|
|
|
|
|
// Ignore
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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++) {
|
|
|
|
|
if (db.insert(TABLE_FAVORITES, null, rows[i]) < 0) {
|
|
|
|
|
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) {
|
|
|
|
|
db.beginTransaction();
|
|
|
|
|
try {
|
|
|
|
|
db.execSQL("CREATE TABLE gestures (" +
|
|
|
|
|
"_id INTEGER PRIMARY KEY," +
|
|
|
|
|
"title TEXT," +
|
|
|
|
|
"intent TEXT," +
|
|
|
|
|
"itemType INTEGER," +
|
|
|
|
|
"iconType INTEGER," +
|
|
|
|
|
"iconPackage TEXT," +
|
|
|
|
|
"iconResource TEXT," +
|
|
|
|
|
"icon BLOB" +
|
|
|
|
|
");");
|
|
|
|
|
db.setTransactionSuccessful();
|
|
|
|
|
version = 4;
|
|
|
|
|
} 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-06-09 12:57:21 -07:00
|
|
|
} finally {
|
|
|
|
|
db.endTransaction();
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-03-03 19:32:27 -08:00
|
|
|
|
2009-11-05 17:17:42 -08:00
|
|
|
if (version < 5) {
|
|
|
|
|
// 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();
|
|
|
|
|
version = 5;
|
|
|
|
|
} 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();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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);
|
2009-06-19 14:28:51 -07:00
|
|
|
db.execSQL("DROP TABLE IF EXISTS " + TABLE_GESTURES);
|
2009-03-03 19:32:27 -08:00
|
|
|
onCreate(db);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2009-03-11 12:11:58 -07:00
|
|
|
* Upgrade existing clock and photo frame widgets into their new widget
|
|
|
|
|
* equivalents. This method allocates appWidgetIds, and then hands off to
|
|
|
|
|
* LauncherAppWidgetBinder to finish the actual binding.
|
2009-03-03 19:32:27 -08:00
|
|
|
*/
|
|
|
|
|
private void convertWidgets(SQLiteDatabase db) {
|
|
|
|
|
final int[] bindSources = new int[] {
|
|
|
|
|
Favorites.ITEM_TYPE_WIDGET_CLOCK,
|
|
|
|
|
Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
final ArrayList<ComponentName> bindTargets = new ArrayList<ComponentName>();
|
|
|
|
|
bindTargets.add(new ComponentName("com.android.alarmclock",
|
2009-03-11 12:11:58 -07:00
|
|
|
"com.android.alarmclock.AnalogAppWidgetProvider"));
|
2009-03-03 19:32:27 -08:00
|
|
|
bindTargets.add(new ComponentName("com.android.camera",
|
2009-03-11 12:11:58 -07:00
|
|
|
"com.android.camera.PhotoAppWidgetProvider"));
|
2009-03-03 19:32:27 -08:00
|
|
|
|
|
|
|
|
final String selectWhere = buildOrWhereString(Favorites.ITEM_TYPE, bindSources);
|
|
|
|
|
|
|
|
|
|
Cursor c = null;
|
2009-03-11 12:11:58 -07:00
|
|
|
boolean allocatedAppWidgets = false;
|
2009-03-03 19:32:27 -08:00
|
|
|
|
|
|
|
|
db.beginTransaction();
|
|
|
|
|
try {
|
|
|
|
|
// Select and iterate through each matching widget
|
|
|
|
|
c = db.query(TABLE_FAVORITES, new String[] { Favorites._ID },
|
|
|
|
|
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-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-03-11 12:11:58 -07:00
|
|
|
values.put(LauncherSettings.Favorites.APPWIDGET_ID, appWidgetId);
|
2009-03-03 19:32:27 -08:00
|
|
|
|
|
|
|
|
// Original widgets might not have valid spans when upgrading
|
|
|
|
|
values.put(LauncherSettings.Favorites.SPANX, 2);
|
|
|
|
|
values.put(LauncherSettings.Favorites.SPANY, 2);
|
|
|
|
|
|
|
|
|
|
String updateWhere = Favorites._ID + "=" + favoriteId;
|
|
|
|
|
db.update(TABLE_FAVORITES, values, updateWhere, null);
|
|
|
|
|
|
2009-03-11 12:11:58 -07:00
|
|
|
allocatedAppWidgets = true;
|
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();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-11 12:11:58 -07:00
|
|
|
// If any appWidgetIds allocated, then launch over to binder
|
|
|
|
|
if (allocatedAppWidgets) {
|
|
|
|
|
launchAppWidgetBinder(bindSources, bindTargets);
|
2009-03-03 19:32:27 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2009-03-11 12:11:58 -07:00
|
|
|
* Launch the widget binder that walks through the Launcher database,
|
2009-03-03 19:32:27 -08:00
|
|
|
* binding any matching widgets to the corresponding targets. We can't
|
|
|
|
|
* bind ourselves because our parent process can't obtain the
|
2009-03-11 12:11:58 -07:00
|
|
|
* BIND_APPWIDGET permission.
|
2009-03-03 19:32:27 -08:00
|
|
|
*/
|
2009-03-11 12:11:58 -07:00
|
|
|
private void launchAppWidgetBinder(int[] bindSources, ArrayList<ComponentName> bindTargets) {
|
2009-03-03 19:32:27 -08:00
|
|
|
final Intent intent = new Intent();
|
|
|
|
|
intent.setComponent(new ComponentName("com.android.settings",
|
2009-03-11 12:11:58 -07:00
|
|
|
"com.android.settings.LauncherAppWidgetBinder"));
|
2009-03-03 19:32:27 -08:00
|
|
|
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
|
|
|
|
|
|
|
|
final Bundle extras = new Bundle();
|
|
|
|
|
extras.putIntArray(EXTRA_BIND_SOURCES, bindSources);
|
|
|
|
|
extras.putParcelableArrayList(EXTRA_BIND_TARGETS, bindTargets);
|
|
|
|
|
intent.putExtras(extras);
|
|
|
|
|
|
|
|
|
|
mContext.startActivity(intent);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 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)) {
|
|
|
|
|
added = addAppWidget(db, values, a);
|
|
|
|
|
} 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 {
|
|
|
|
|
ComponentName cn = new ComponentName(packageName, className);
|
|
|
|
|
info = packageManager.getActivityInfo(cn, 0);
|
|
|
|
|
intent.setComponent(cn);
|
2009-03-24 21:00:33 -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);
|
|
|
|
|
db.insert(TABLE_FAVORITES, null, values);
|
|
|
|
|
} 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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private boolean addSearchWidget(SQLiteDatabase db, ContentValues values) {
|
2009-03-03 19:32:27 -08:00
|
|
|
// Add a search box
|
2009-03-18 17:39:48 -07:00
|
|
|
values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_WIDGET_SEARCH);
|
|
|
|
|
values.put(Favorites.SPANX, 4);
|
|
|
|
|
values.put(Favorites.SPANY, 1);
|
2009-03-03 19:32:27 -08:00
|
|
|
db.insert(TABLE_FAVORITES, null, values);
|
2009-03-18 17:39:48 -07:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private boolean addClockWidget(SQLiteDatabase db, ContentValues values) {
|
2009-03-03 19:32:27 -08:00
|
|
|
final int[] bindSources = new int[] {
|
|
|
|
|
Favorites.ITEM_TYPE_WIDGET_CLOCK,
|
|
|
|
|
};
|
2009-03-18 17:39:48 -07:00
|
|
|
|
2009-03-03 19:32:27 -08:00
|
|
|
final ArrayList<ComponentName> bindTargets = new ArrayList<ComponentName>();
|
|
|
|
|
bindTargets.add(new ComponentName("com.android.alarmclock",
|
2009-03-11 12:11:58 -07:00
|
|
|
"com.android.alarmclock.AnalogAppWidgetProvider"));
|
2009-03-18 17:39:48 -07:00
|
|
|
|
2009-03-11 12:11:58 -07:00
|
|
|
boolean allocatedAppWidgets = false;
|
2009-10-30 16:36:56 -07:00
|
|
|
|
2009-03-11 12:11:58 -07:00
|
|
|
// Try binding to an analog clock widget
|
2009-03-03 19:32:27 -08:00
|
|
|
try {
|
2009-03-11 12:11:58 -07:00
|
|
|
int appWidgetId = mAppWidgetHost.allocateAppWidgetId();
|
2009-03-18 17:39:48 -07:00
|
|
|
|
|
|
|
|
values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_WIDGET_CLOCK);
|
|
|
|
|
values.put(Favorites.SPANX, 2);
|
|
|
|
|
values.put(Favorites.SPANY, 2);
|
|
|
|
|
values.put(Favorites.APPWIDGET_ID, appWidgetId);
|
2009-03-03 19:32:27 -08:00
|
|
|
db.insert(TABLE_FAVORITES, null, values);
|
2009-03-18 17:39:48 -07:00
|
|
|
|
2009-03-11 12:11:58 -07:00
|
|
|
allocatedAppWidgets = true;
|
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
|
|
|
}
|
|
|
|
|
|
2009-03-11 12:11:58 -07:00
|
|
|
// If any appWidgetIds allocated, then launch over to binder
|
|
|
|
|
if (allocatedAppWidgets) {
|
|
|
|
|
launchAppWidgetBinder(bindSources, bindTargets);
|
2009-03-03 19:32:27 -08:00
|
|
|
}
|
2009-03-18 17:39:48 -07:00
|
|
|
|
|
|
|
|
return allocatedAppWidgets;
|
2009-03-03 19:32:27 -08:00
|
|
|
}
|
2009-10-30 16:36:56 -07:00
|
|
|
|
|
|
|
|
private boolean addAppWidget(SQLiteDatabase db, ContentValues values, TypedArray a) {
|
|
|
|
|
final int[] bindSources = new int[] {
|
|
|
|
|
Favorites.ITEM_TYPE_APPWIDGET,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
String packageName = a.getString(R.styleable.Favorite_packageName);
|
|
|
|
|
String className = a.getString(R.styleable.Favorite_className);
|
|
|
|
|
|
|
|
|
|
if (packageName == null || className == null) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ComponentName cn = new ComponentName(packageName, className);
|
|
|
|
|
|
|
|
|
|
final ArrayList<ComponentName> bindTargets = new ArrayList<ComponentName>();
|
|
|
|
|
bindTargets.add(cn);
|
2009-03-03 19:32:27 -08:00
|
|
|
|
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);
|
|
|
|
|
values.put(Favorites.SPANX, a.getString(R.styleable.Favorite_spanX));
|
|
|
|
|
values.put(Favorites.SPANY, a.getString(R.styleable.Favorite_spanY));
|
|
|
|
|
values.put(Favorites.APPWIDGET_ID, appWidgetId);
|
|
|
|
|
db.insert(TABLE_FAVORITES, null, values);
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
Intent intent = null;
|
|
|
|
|
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));
|
|
|
|
|
|
|
|
|
|
db.insert(TABLE_FAVORITES, null, values);
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|