am 8b5b05b7: Merge "New launcher2 icon migration algorithm." into jb-ub-now-kermit
* commit '8b5b05b7f3c8c5d705116c425bd5dbff2b75d56a': New launcher2 icon migration algorithm.
This commit is contained in:
@@ -20,6 +20,7 @@
|
||||
<manifest
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.launcher3">
|
||||
<uses-sdk android:targetSdkVersion="19" android:minSdkVersion="16"/>
|
||||
|
||||
<permission
|
||||
android:name="com.android.launcher3.permission.PRELOAD_WORKSPACE"
|
||||
|
||||
@@ -130,6 +130,8 @@ public class Launcher extends Activity
|
||||
static final boolean DEBUG_RESUME_TIME = false;
|
||||
static final boolean DEBUG_DUMP_LOG = false;
|
||||
|
||||
static final boolean ENABLE_DEBUG_INTENTS = false; // allow DebugIntents to run
|
||||
|
||||
private static final int REQUEST_CREATE_SHORTCUT = 1;
|
||||
private static final int REQUEST_CREATE_APPWIDGET = 5;
|
||||
private static final int REQUEST_PICK_APPLICATION = 6;
|
||||
@@ -1571,6 +1573,15 @@ public class Launcher extends Activity
|
||||
} else if (Intent.ACTION_USER_PRESENT.equals(action)) {
|
||||
mUserPresent = true;
|
||||
updateRunning();
|
||||
} else if (ENABLE_DEBUG_INTENTS && DebugIntents.DELETE_DATABASE.equals(action)) {
|
||||
mModel.resetLoadedState(false, true);
|
||||
mModel.startLoader(false, PagedView.INVALID_RESTORE_PAGE,
|
||||
LauncherModel.LOADER_FLAG_CLEAR_WORKSPACE);
|
||||
} else if (ENABLE_DEBUG_INTENTS && DebugIntents.MIGRATE_DATABASE.equals(action)) {
|
||||
mModel.resetLoadedState(false, true);
|
||||
mModel.startLoader(false, PagedView.INVALID_RESTORE_PAGE,
|
||||
LauncherModel.LOADER_FLAG_CLEAR_WORKSPACE
|
||||
| LauncherModel.LOADER_FLAG_MIGRATE_SHORTCUTS);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1583,6 +1594,10 @@ public class Launcher extends Activity
|
||||
final IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(Intent.ACTION_SCREEN_OFF);
|
||||
filter.addAction(Intent.ACTION_USER_PRESENT);
|
||||
if (ENABLE_DEBUG_INTENTS) {
|
||||
filter.addAction(DebugIntents.DELETE_DATABASE);
|
||||
filter.addAction(DebugIntents.MIGRATE_DATABASE);
|
||||
}
|
||||
registerReceiver(mReceiver, filter);
|
||||
FirstFrameAnimatorHelper.initializeDrawListener(getWindow().getDecorView());
|
||||
mAttached = true;
|
||||
@@ -4704,3 +4719,8 @@ interface LauncherTransitionable {
|
||||
void onLauncherTransitionStep(Launcher l, float t);
|
||||
void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace);
|
||||
}
|
||||
|
||||
interface DebugIntents {
|
||||
static final String DELETE_DATABASE = "com.android.launcher3.action.DELETE_DATABASE";
|
||||
static final String MIGRATE_DATABASE = "com.android.launcher3.action.MIGRATE_DATABASE";
|
||||
}
|
||||
|
||||
@@ -75,6 +75,10 @@ public class LauncherModel extends BroadcastReceiver {
|
||||
// false = strew non-workspace apps across the workspace on upgrade
|
||||
public static final boolean UPGRADE_USE_MORE_APPS_FOLDER = false;
|
||||
|
||||
public static final int LOADER_FLAG_NONE = 0;
|
||||
public static final int LOADER_FLAG_CLEAR_WORKSPACE = 1 << 0;
|
||||
public static final int LOADER_FLAG_MIGRATE_SHORTCUTS = 1 << 1;
|
||||
|
||||
private static final int ITEMS_CHUNK = 6; // batch size for the workspace icons
|
||||
private static final long INVALID_SCREEN_ID = -1L;
|
||||
private final boolean mAppsCanBeOnRemoveableStorage;
|
||||
@@ -1193,6 +1197,10 @@ public class LauncherModel extends BroadcastReceiver {
|
||||
}
|
||||
|
||||
public void startLoader(boolean isLaunching, int synchronousBindPage) {
|
||||
startLoader(isLaunching, synchronousBindPage, LOADER_FLAG_NONE);
|
||||
}
|
||||
|
||||
public void startLoader(boolean isLaunching, int synchronousBindPage, int loadFlags) {
|
||||
synchronized (mLock) {
|
||||
if (DEBUG_LOADERS) {
|
||||
Log.d(TAG, "startLoader isLaunching=" + isLaunching);
|
||||
@@ -1207,7 +1215,7 @@ public class LauncherModel extends BroadcastReceiver {
|
||||
// If there is already one running, tell it to stop.
|
||||
// also, don't downgrade isLaunching if we're already running
|
||||
isLaunching = isLaunching || stopLoaderLocked();
|
||||
mLoaderTask = new LoaderTask(mApp.getContext(), isLaunching);
|
||||
mLoaderTask = new LoaderTask(mApp.getContext(), isLaunching, loadFlags);
|
||||
if (synchronousBindPage != PagedView.INVALID_RESTORE_PAGE
|
||||
&& mAllAppsLoaded && mWorkspaceLoaded) {
|
||||
mLoaderTask.runBindSynchronousPage(synchronousBindPage);
|
||||
@@ -1298,13 +1306,15 @@ public class LauncherModel extends BroadcastReceiver {
|
||||
private boolean mIsLoadingAndBindingWorkspace;
|
||||
private boolean mStopped;
|
||||
private boolean mLoadAndBindStepFinished;
|
||||
private int mFlags;
|
||||
|
||||
private HashMap<Object, CharSequence> mLabelCache;
|
||||
|
||||
LoaderTask(Context context, boolean isLaunching) {
|
||||
LoaderTask(Context context, boolean isLaunching, int flags) {
|
||||
mContext = context;
|
||||
mIsLaunching = isLaunching;
|
||||
mLabelCache = new HashMap<Object, CharSequence>();
|
||||
mFlags = flags;
|
||||
}
|
||||
|
||||
boolean isLaunching() {
|
||||
@@ -1651,7 +1661,7 @@ public class LauncherModel extends BroadcastReceiver {
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns whether this is an upgradge path */
|
||||
/** Returns whether this is an upgrade path */
|
||||
private boolean loadWorkspace() {
|
||||
// Log to disk
|
||||
Launcher.addDumpLog(TAG, "11683562 - loadWorkspace()", true);
|
||||
@@ -1669,8 +1679,20 @@ public class LauncherModel extends BroadcastReceiver {
|
||||
int countX = (int) grid.numColumns;
|
||||
int countY = (int) grid.numRows;
|
||||
|
||||
// Make sure the default workspace is loaded, if needed
|
||||
LauncherAppState.getLauncherProvider().loadDefaultFavoritesIfNecessary(0);
|
||||
if ((mFlags & LOADER_FLAG_CLEAR_WORKSPACE) != 0) {
|
||||
Launcher.addDumpLog(TAG, "loadWorkspace: resetting launcher database", true);
|
||||
LauncherAppState.getLauncherProvider().deleteDatabase();
|
||||
}
|
||||
|
||||
if ((mFlags & LOADER_FLAG_MIGRATE_SHORTCUTS) != 0) {
|
||||
// append the user's Launcher2 shortcuts
|
||||
Launcher.addDumpLog(TAG, "loadWorkspace: migrating from launcher2", true);
|
||||
LauncherAppState.getLauncherProvider().migrateLauncher2Shortcuts();
|
||||
} else {
|
||||
// Make sure the default workspace is loaded
|
||||
Launcher.addDumpLog(TAG, "loadWorkspace: loading default favorites", false);
|
||||
LauncherAppState.getLauncherProvider().loadDefaultFavoritesIfNecessary(0);
|
||||
}
|
||||
|
||||
// Check if we need to do any upgrade-path logic
|
||||
// (Includes having just imported default favorites)
|
||||
|
||||
@@ -55,9 +55,11 @@ import com.android.launcher3.config.ProviderConfig;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
public class LauncherProvider extends ContentProvider {
|
||||
@@ -72,7 +74,7 @@ public class LauncherProvider extends ContentProvider {
|
||||
static final String AUTHORITY = ProviderConfig.AUTHORITY;
|
||||
|
||||
// Should we attempt to load anything from the com.android.launcher2 provider?
|
||||
static final boolean IMPORT_LAUNCHER2_DATABASE = true;
|
||||
static final boolean IMPORT_LAUNCHER2_DATABASE = false;
|
||||
|
||||
static final String TABLE_FAVORITES = "favorites";
|
||||
static final String TABLE_WORKSPACE_SCREENS = "workspaceScreens";
|
||||
@@ -133,6 +135,9 @@ public class LauncherProvider extends ContentProvider {
|
||||
|
||||
private static long dbInsertAndCheck(DatabaseHelper helper,
|
||||
SQLiteDatabase db, String table, String nullColumnHack, ContentValues values) {
|
||||
if (values == null) {
|
||||
throw new RuntimeException("Error: attempting to insert null values");
|
||||
}
|
||||
if (!values.containsKey(LauncherSettings.Favorites._ID)) {
|
||||
throw new RuntimeException("Error: attempting to add item without specifying an id");
|
||||
}
|
||||
@@ -287,6 +292,11 @@ public class LauncherProvider extends ContentProvider {
|
||||
}
|
||||
}
|
||||
|
||||
public void migrateLauncher2Shortcuts() {
|
||||
mOpenHelper.migrateLauncher2Shortcuts(mOpenHelper.getWritableDatabase(),
|
||||
LauncherSettings.Favorites.OLD_CONTENT_URI);
|
||||
}
|
||||
|
||||
private static int getDefaultWorkspaceResourceId() {
|
||||
if (LauncherAppState.isDisableAllApps()) {
|
||||
return R.xml.default_workspace_no_all_apps;
|
||||
@@ -306,6 +316,15 @@ public class LauncherProvider extends ContentProvider {
|
||||
return !isTablet && IMPORT_LAUNCHER2_DATABASE;
|
||||
}
|
||||
|
||||
public void deleteDatabase() {
|
||||
// Are you sure? (y/n)
|
||||
final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
|
||||
final String dbFile = db.getPath();
|
||||
mOpenHelper.close();
|
||||
SQLiteDatabase.deleteDatabase(new File(dbFile));
|
||||
mOpenHelper = new DatabaseHelper(getContext());
|
||||
}
|
||||
|
||||
private static class DatabaseHelper extends SQLiteOpenHelper {
|
||||
private static final String TAG_FAVORITES = "favorites";
|
||||
private static final String TAG_FAVORITE = "favorite";
|
||||
@@ -1431,6 +1450,209 @@ public class LauncherProvider extends ContentProvider {
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
public void migrateLauncher2Shortcuts(SQLiteDatabase db, Uri uri) {
|
||||
final ContentResolver resolver = mContext.getContentResolver();
|
||||
Cursor c = null;
|
||||
int count = 0;
|
||||
int curScreen = 0;
|
||||
|
||||
try {
|
||||
c = resolver.query(uri, null, null, null, "title ASC");
|
||||
} catch (Exception e) {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
|
||||
// We already have a favorites database in the old provider
|
||||
if (c != null) {
|
||||
try {
|
||||
if (c.getCount() > 0) {
|
||||
final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
|
||||
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);
|
||||
|
||||
int i = 0;
|
||||
int curX = 0;
|
||||
int curY = 0;
|
||||
|
||||
final LauncherAppState app = LauncherAppState.getInstance();
|
||||
final DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
|
||||
final int width = (int) grid.numColumns;
|
||||
final int height = (int) grid.numRows;
|
||||
final int hotseatWidth = (int) grid.numHotseatIcons;
|
||||
|
||||
final HashSet<String> seenIntents = new HashSet<String>(c.getCount());
|
||||
|
||||
final ContentValues[] rows = new ContentValues[c.getCount()];
|
||||
|
||||
while (c.moveToNext()) {
|
||||
final int itemType = c.getInt(itemTypeIndex);
|
||||
if (itemType != Favorites.ITEM_TYPE_APPLICATION
|
||||
&& itemType != Favorites.ITEM_TYPE_SHORTCUT
|
||||
&& itemType != Favorites.ITEM_TYPE_FOLDER) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final int cellX = c.getInt(cellXIndex);
|
||||
final int cellY = c.getInt(cellYIndex);
|
||||
final int screen = c.getInt(screenIndex);
|
||||
int container = c.getInt(containerIndex);
|
||||
final String intentStr = c.getString(intentIndex);
|
||||
Launcher.addDumpLog(TAG, "migrating \""
|
||||
+ c.getString(titleIndex) + "\": " + intentStr, true);
|
||||
|
||||
if (itemType != Favorites.ITEM_TYPE_FOLDER) {
|
||||
if (TextUtils.isEmpty(intentStr)) {
|
||||
// no intent? no icon
|
||||
Launcher.addDumpLog(TAG, "skipping empty intent", true);
|
||||
continue;
|
||||
} else {
|
||||
try {
|
||||
// Canonicalize
|
||||
final Intent intent = Intent.parseUri(intentStr, 0);
|
||||
// the Play Store sets the package parameter, but Launcher
|
||||
// does not, so we clear that out to keep them the same
|
||||
intent.setPackage(null);
|
||||
final String key = intent.toUri(0);
|
||||
if (seenIntents.contains(key)) {
|
||||
Launcher.addDumpLog(TAG, "skipping duplicate", true);
|
||||
continue;
|
||||
} else {
|
||||
seenIntents.add(key);
|
||||
}
|
||||
} catch (URISyntaxException e) {
|
||||
// bogus intent?
|
||||
Launcher.addDumpLog(TAG,
|
||||
"skipping invalid intent uri", true);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ContentValues values = new ContentValues(c.getColumnCount());
|
||||
values.put(LauncherSettings.Favorites._ID, c.getInt(idIndex));
|
||||
values.put(LauncherSettings.Favorites.INTENT, intentStr);
|
||||
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.ITEM_TYPE, itemType);
|
||||
values.put(LauncherSettings.Favorites.APPWIDGET_ID, -1);
|
||||
values.put(LauncherSettings.Favorites.URI, c.getString(uriIndex));
|
||||
values.put(LauncherSettings.Favorites.DISPLAY_MODE,
|
||||
c.getInt(displayModeIndex));
|
||||
|
||||
if (container == LauncherSettings.Favorites.CONTAINER_HOTSEAT
|
||||
&& screen >= hotseatWidth) {
|
||||
// no room for you in the hotseat? it's off to the desktop with you
|
||||
container = Favorites.CONTAINER_DESKTOP;
|
||||
}
|
||||
|
||||
if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {
|
||||
// In a folder or in the hotseat, preserve position
|
||||
values.put(LauncherSettings.Favorites.SCREEN, screen);
|
||||
values.put(LauncherSettings.Favorites.CELLX, cellX);
|
||||
values.put(LauncherSettings.Favorites.CELLY, cellY);
|
||||
} else {
|
||||
values.put(LauncherSettings.Favorites.SCREEN, curScreen);
|
||||
values.put(LauncherSettings.Favorites.CELLX, curX);
|
||||
values.put(LauncherSettings.Favorites.CELLY, curY);
|
||||
curX = (curX + 1) % width;
|
||||
if (curX == 0) {
|
||||
curY = (curY + 1);
|
||||
}
|
||||
// Leave the last row of icons blank on screen 0
|
||||
if (curScreen == 0 && curY == height - 1 || curY == height) {
|
||||
curScreen = (int) generateNewScreenId();
|
||||
curY = 0;
|
||||
}
|
||||
}
|
||||
|
||||
values.put(LauncherSettings.Favorites.CONTAINER, container);
|
||||
|
||||
rows[i++] = values;
|
||||
}
|
||||
|
||||
if (i > 0) {
|
||||
db.beginTransaction();
|
||||
try {
|
||||
final int N = rows.length;
|
||||
for (i = 0; i < N; i++) {
|
||||
if (rows[i] == null) continue;
|
||||
if (dbInsertAndCheck(this, db, TABLE_FAVORITES, null, rows[i])
|
||||
< 0) {
|
||||
return;
|
||||
} else {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
db.beginTransaction();
|
||||
try {
|
||||
for (i=0; i<=curScreen; i++) {
|
||||
final ContentValues values = new ContentValues();
|
||||
values.put(LauncherSettings.WorkspaceScreens._ID, i);
|
||||
values.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i);
|
||||
if (dbInsertAndCheck(this, db, TABLE_WORKSPACE_SCREENS, null, values)
|
||||
< 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
|
||||
Launcher.addDumpLog(TAG, "migrated " + count + " icons from Launcher2 into "
|
||||
+ (curScreen+1) + " screens", true);
|
||||
|
||||
// ensure that new screens are created to hold these icons
|
||||
setFlagJustLoadedOldDb();
|
||||
|
||||
// Update max IDs; very important since we just grabbed IDs from another database
|
||||
mMaxItemId = initializeMaxItemId(db);
|
||||
mMaxScreenId = initializeMaxScreenId(db);
|
||||
if (LOGD) Log.d(TAG, "mMaxItemId: " + mMaxItemId + " mMaxScreenId: " + mMaxScreenId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user