From c763c4e4d28c256d1368be3fc1c4526c8b9bd232 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Fri, 19 Jul 2013 13:49:06 -0700 Subject: Verifying that new applications are added and fixing issue with new items getting wrong ids. - Fixing issue where the LauncherModel would be out of sync on first migration, and subsequent crashes Change-Id: I6f58b09b615b28958c7f941e58ff9ae0ee3ba939 --- src/com/android/launcher3/DragLayer.java | 73 +---------- src/com/android/launcher3/Launcher.java | 3 +- src/com/android/launcher3/LauncherModel.java | 126 +++++++++++-------- src/com/android/launcher3/LauncherProvider.java | 155 ++++++++++++++++++------ src/com/android/launcher3/PagedView.java | 4 +- src/com/android/launcher3/Utilities.java | 95 +++++++++++++++ src/com/android/launcher3/Workspace.java | 8 +- 7 files changed, 299 insertions(+), 165 deletions(-) (limited to 'src') diff --git a/src/com/android/launcher3/DragLayer.java b/src/com/android/launcher3/DragLayer.java index 3c064badb..514dca29f 100644 --- a/src/com/android/launcher3/DragLayer.java +++ b/src/com/android/launcher3/DragLayer.java @@ -327,84 +327,15 @@ public class DragLayer extends FrameLayout implements ViewGroup.OnHierarchyChang */ public float getDescendantCoordRelativeToSelf(View descendant, int[] coord, boolean includeRootScroll) { - return DragLayer.getDescendantCoordRelativeToParent(descendant, this, + return Utilities.getDescendantCoordRelativeToParent(descendant, this, coord, includeRootScroll); } - public static float getDescendantCoordRelativeToParent(View descendant, View root, - int[] coord, boolean includeRootScroll) { - ArrayList ancestorChain = new ArrayList(); - - float[] pt = {coord[0], coord[1]}; - - View v = descendant; - while(v != root && v != null) { - ancestorChain.add(v); - v = (View) v.getParent(); - } - ancestorChain.add(root); - - float scale = 1.0f; - int count = ancestorChain.size(); - for (int i = 0; i < count; i++) { - View v0 = ancestorChain.get(i); - View v1 = i < count -1 ? ancestorChain.get(i + 1) : null; - - // For TextViews, scroll has a meaning which relates to the text position - // which is very strange... ignore the scroll. - if (v0 != descendant || includeRootScroll) { - pt[0] -= v0.getScrollX(); - pt[1] -= v0.getScrollY(); - } - - v0.getMatrix().mapPoints(pt); - pt[0] += v0.getLeft(); - pt[1] += v0.getTop(); - scale *= v0.getScaleX(); - } - - coord[0] = (int) Math.round(pt[0]); - coord[1] = (int) Math.round(pt[1]); - return scale; - } - /** * Inverse of {@link #getDescendantCoordRelativeToSelf(View, int[])}. */ public float mapCoordInSelfToDescendent(View descendant, int[] coord) { - ArrayList ancestorChain = new ArrayList(); - - float[] pt = {coord[0], coord[1]}; - - View v = descendant; - while(v != this) { - ancestorChain.add(v); - v = (View) v.getParent(); - } - ancestorChain.add(this); - - float scale = 1.0f; - Matrix inverse = new Matrix(); - int count = ancestorChain.size(); - for (int i = count - 1; i >= 0; i--) { - View ancestor = ancestorChain.get(i); - View next = i > 0 ? ancestorChain.get(i-1) : null; - - pt[0] += ancestor.getScrollX(); - pt[1] += ancestor.getScrollY(); - - if (next != null) { - pt[0] -= next.getLeft(); - pt[1] -= next.getTop(); - next.getMatrix().invert(inverse); - inverse.mapPoints(pt); - scale *= next.getScaleX(); - } - } - - coord[0] = (int) Math.round(pt[0]); - coord[1] = (int) Math.round(pt[1]); - return scale; + return Utilities.mapCoordInSelfToDescendent(descendant, this, coord); } public void getViewRectRelativeToSelf(View v, Rect r) { diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 7d9ebc0b5..65845b41e 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -3585,6 +3585,8 @@ public class Launcher extends Activity workspace.addInScreenFromBind(newFolder, item.container, item.screenId, item.cellX, item.cellY, 1, 1); break; + default: + throw new RuntimeException("Invalid Item Type"); } } @@ -3724,7 +3726,6 @@ public class Launcher extends Activity mWorkspaceLoading = false; if (upgradePath) { - mWorkspace.saveWorkspaceToDb(); mWorkspace.stripDuplicateApps(); mIntentsOnWorkspaceFromUpgradePath = mWorkspace.stripDuplicateApps(); } diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index 28530e6ac..dd130d2f0 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -265,7 +265,6 @@ public class LauncherModel extends BroadcastReceiver { } } } - // XXX: Create a new page and add it to the first spot return null; } @@ -294,20 +293,27 @@ public class LauncherModel extends BroadcastReceiver { Pair coords = LauncherModel.findNextAvailableIconSpace(context, name, launchIntent, startSearchPageIndex); if (coords == null) { - // If we can't find a valid position, then just add a new screen. - // This takes time so we need to re-queue the add until the new - // page is added. LauncherAppState appState = LauncherAppState.getInstance(); LauncherProvider lp = appState.getLauncherProvider(); - long screenId = lp.generateNewScreenId(); - // Update the model - sBgWorkspaceScreens.add(screenId); - updateWorkspaceScreenOrder(context, sBgWorkspaceScreens); - // Save the screen id for binding in the workspace - addedWorkspaceScreensFinal.add(screenId); + + // If we can't find a valid position, then just add a new screen. + // This takes time so we need to re-queue the add until the new + // page is added. Create as many screens as necessary to satisfy + // the startSearchPageIndex. + int numPagesToAdd = Math.max(1, startSearchPageIndex + 1 - + sBgWorkspaceScreens.size()); + while (numPagesToAdd > 0) { + long screenId = lp.generateNewScreenId(); + // Update the model + sBgWorkspaceScreens.add(screenId); + updateWorkspaceScreenOrder(context, sBgWorkspaceScreens); + // Save the screen id for binding in the workspace + addedWorkspaceScreensFinal.add(screenId); + numPagesToAdd--; + } // Find the coordinate again coords = LauncherModel.findNextAvailableIconSpace(context, - a.title.toString(), a.intent, startSearchPageIndex); + name, launchIntent, startSearchPageIndex); } if (coords == null) { throw new RuntimeException("Coordinates should not be null"); @@ -1219,7 +1225,6 @@ public class LauncherModel extends BroadcastReceiver { private boolean mIsLoadingAndBindingWorkspace; private boolean mStopped; private boolean mLoadAndBindStepFinished; - private boolean mIsUpgradePath; private HashMap mLabelCache; @@ -1237,7 +1242,8 @@ public class LauncherModel extends BroadcastReceiver { return mIsLoadingAndBindingWorkspace; } - private void loadAndBindWorkspace() { + /** Returns whether this is an upgrade path */ + private boolean loadAndBindWorkspace() { mIsLoadingAndBindingWorkspace = true; // Load the workspace @@ -1245,18 +1251,20 @@ public class LauncherModel extends BroadcastReceiver { Log.d(TAG, "loadAndBindWorkspace mWorkspaceLoaded=" + mWorkspaceLoaded); } + boolean isUpgradePath = false; if (!mWorkspaceLoaded) { - loadWorkspace(); + isUpgradePath = loadWorkspace(); synchronized (LoaderTask.this) { if (mStopped) { - return; + return isUpgradePath; } mWorkspaceLoaded = true; } } // Bind the workspace - bindWorkspace(-1); + bindWorkspace(-1, isUpgradePath); + return isUpgradePath; } private void waitForIdle() { @@ -1325,13 +1333,15 @@ public class LauncherModel extends BroadcastReceiver { // Divide the set of loaded items into those that we are binding synchronously, and // everything else that is to be bound normally (asynchronously). - bindWorkspace(synchronousBindPage); + bindWorkspace(synchronousBindPage, false); // XXX: For now, continue posting the binding of AllApps as there are other issues that // arise from that. onlyBindAllApps(); } public void run() { + boolean isUpgrade = false; + synchronized (mLock) { mIsLoaderTaskRunning = true; } @@ -1349,7 +1359,7 @@ public class LauncherModel extends BroadcastReceiver { ? Process.THREAD_PRIORITY_DEFAULT : Process.THREAD_PRIORITY_BACKGROUND); } if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace"); - loadAndBindWorkspace(); + isUpgrade = loadAndBindWorkspace(); if (mStopped) { break keep_running; @@ -1384,6 +1394,12 @@ public class LauncherModel extends BroadcastReceiver { sBgDbIconCache.clear(); } + // Ensure that all the applications that are in the system are represented on the home + // screen. + if (!isUpgrade) { + verifyApplications(); + } + // Clear out this reference, otherwise we end up holding it until all of the // callback runnables are done. mContext = null; @@ -1434,6 +1450,29 @@ public class LauncherModel extends BroadcastReceiver { } } + private void verifyApplications() { + final Context context = mApp.getContext(); + + // Cross reference all the applications in our apps list with items in the workspace + ArrayList tmpInfos; + ArrayList added = new ArrayList(); + synchronized (sBgLock) { + for (ApplicationInfo app : mBgAllAppsList.data) { + tmpInfos = getItemInfoForComponentName(app.componentName); + if (tmpInfos.isEmpty()) { + // We are missing an application icon, so add this to the workspace + added.add(app); + // This is a rare event, so lets log it + Log.e(TAG, "Missing Application on load: " + app); + } + } + } + if (!added.isEmpty()) { + Callbacks cb = mCallbacks != null ? mCallbacks.get() : null; + addAndBindAddedApps(context, added, cb); + } + } + // check & update map of what's occupied; used to discard overlapping/invalid items private boolean checkItemPlacement(HashMap occupied, ItemInfo item) { long containerIndex = item.screenId; @@ -1487,7 +1526,8 @@ public class LauncherModel extends BroadcastReceiver { return true; } - private void loadWorkspace() { + /** Returns whether this is an upgradge path */ + private boolean loadWorkspace() { final long t = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0; final Context context = mContext; @@ -1497,11 +1537,10 @@ public class LauncherModel extends BroadcastReceiver { final boolean isSafeMode = manager.isSafeMode(); // Make sure the default workspace is loaded, if needed - boolean loadOldDb = mApp.getLauncherProvider().shouldLoadOldDb(); - Uri contentUri = loadOldDb ? LauncherSettings.Favorites.OLD_CONTENT_URI : - LauncherSettings.Favorites.CONTENT_URI; + mApp.getLauncherProvider().loadDefaultFavoritesIfNecessary(0); - mIsUpgradePath = loadOldDb; + // Check if we need to do any upgrade-path logic + boolean loadedOldDb = mApp.getLauncherProvider().justLoadedOldDb(); synchronized (sBgLock) { sBgWorkspaceItems.clear(); @@ -1512,7 +1551,7 @@ public class LauncherModel extends BroadcastReceiver { sBgWorkspaceScreens.clear(); final ArrayList itemsToRemove = new ArrayList(); - + final Uri contentUri = LauncherSettings.Favorites.CONTENT_URI; final Cursor c = contentResolver.query(contentUri, null, null, null, null); // +1 for the hotseat (it can be larger than the workspace) @@ -1620,10 +1659,6 @@ public class LauncherModel extends BroadcastReceiver { folderInfo.add(info); break; } - if (container != LauncherSettings.Favorites.CONTAINER_HOTSEAT && - loadOldDb) { - info.screenId = permuteScreens(info.screenId); - } sBgItemsIdMap.put(info.id, info); // now that we've loaded everthing re-save it with the @@ -1663,10 +1698,6 @@ public class LauncherModel extends BroadcastReceiver { sBgWorkspaceItems.add(folderInfo); break; } - if (container != LauncherSettings.Favorites.CONTAINER_HOTSEAT && - loadOldDb) { - folderInfo.screenId = permuteScreens(folderInfo.screenId); - } sBgItemsIdMap.put(folderInfo.id, folderInfo); sBgFolders.put(folderInfo.id, folderInfo); @@ -1707,11 +1738,6 @@ public class LauncherModel extends BroadcastReceiver { "CONTAINER_DESKTOP nor CONTAINER_HOTSEAT - ignoring!"); continue; } - if (container != LauncherSettings.Favorites.CONTAINER_HOTSEAT && - loadOldDb) { - appWidgetInfo.screenId = - permuteScreens(appWidgetInfo.screenId); - } appWidgetInfo.container = c.getInt(containerIndex); // check & update map of what's occupied @@ -1749,7 +1775,7 @@ public class LauncherModel extends BroadcastReceiver { } } - if (loadOldDb) { + if (loadedOldDb) { long maxScreenId = 0; // If we're importing we use the old screen order. for (ItemInfo item: sBgItemsIdMap.values()) { @@ -1765,6 +1791,15 @@ public class LauncherModel extends BroadcastReceiver { Collections.sort(sBgWorkspaceScreens); mApp.getLauncherProvider().updateMaxScreenId(maxScreenId); updateWorkspaceScreenOrder(context, sBgWorkspaceScreens); + + // Update the max item id after we load an old db + long maxItemId = 0; + // If we're importing we use the old screen order. + for (ItemInfo item: sBgItemsIdMap.values()) { + maxItemId = Math.max(maxItemId, item.id); + } + LauncherAppState app = LauncherAppState.getInstance(); + app.getLauncherProvider().updateMaxItemId(maxItemId); } else { Uri screensUri = LauncherSettings.WorkspaceScreens.CONTENT_URI; final Cursor sc = contentResolver.query(screensUri, null, null, null, null); @@ -1835,16 +1870,7 @@ public class LauncherModel extends BroadcastReceiver { } } } - } - - // We rearrange the screens from the old launcher - // 12345 -> 34512 - private long permuteScreens(long screen) { - if (screen >= 2) { - return screen - 2; - } else { - return screen + 3; - } + return loadedOldDb; } /** Filters the set of items who are directly or indirectly (via another container) on the @@ -2052,7 +2078,7 @@ public class LauncherModel extends BroadcastReceiver { /** * Binds all loaded data to actual views on the main thread. */ - private void bindWorkspace(int synchronizeBindPage) { + private void bindWorkspace(int synchronizeBindPage, final boolean isUpgradePath) { final long t = SystemClock.uptimeMillis(); Runnable r; @@ -2144,7 +2170,7 @@ public class LauncherModel extends BroadcastReceiver { public void run() { Callbacks callbacks = tryGetCallbacks(oldCallbacks); if (callbacks != null) { - callbacks.finishBindingItems(mIsUpgradePath); + callbacks.finishBindingItems(isUpgradePath); } // If we're profiling, ensure this is the last thing in the queue. diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java index ae227a998..7d090e1fd 100644 --- a/src/com/android/launcher3/LauncherProvider.java +++ b/src/com/android/launcher3/LauncherProvider.java @@ -73,8 +73,10 @@ public class LauncherProvider extends ContentProvider { static final String TABLE_FAVORITES = "favorites"; static final String TABLE_WORKSPACE_SCREENS = "workspaceScreens"; static final String PARAMETER_NOTIFY = "notify"; - static final String DB_CREATED_BUT_DEFAULT_WORKSPACE_NOT_LOADED = - "DB_CREATED_BUT_DEFAULT_WORKSPACE_NOT_LOADED"; + static final String UPGRADED_FROM_OLD_DATABASE = + "UPGRADED_FROM_OLD_DATABASE"; + static final String EMPTY_DATABASE_CREATED = + "EMPTY_DATABASE_CREATED"; static final String DEFAULT_WORKSPACE_RESOURCE_ID = "DEFAULT_WORKSPACE_RESOURCE_ID"; @@ -90,7 +92,7 @@ public class LauncherProvider extends ContentProvider { Uri.parse("content://" + AUTHORITY + "/appWidgetReset"); private DatabaseHelper mOpenHelper; - private static boolean sLoadOldDb; + private static boolean sJustLoadedFromOldDb; @Override public boolean onCreate() { @@ -208,6 +210,10 @@ public class LauncherProvider extends ContentProvider { return mOpenHelper.generateNewItemId(); } + public void updateMaxItemId(long id) { + mOpenHelper.updateMaxItemId(id); + } + public long generateNewScreenId() { return mOpenHelper.generateNewScreenId(); } @@ -221,21 +227,21 @@ public class LauncherProvider extends ContentProvider { /** * @param Should we load the old db for upgrade? first run only. */ - synchronized public boolean shouldLoadOldDb() { + synchronized public boolean justLoadedOldDb() { String spKey = LauncherAppState.getSharedPreferencesKey(); SharedPreferences sp = getContext().getSharedPreferences(spKey, Context.MODE_PRIVATE); - boolean loadOldDb = false || sLoadOldDb; + boolean loadedOldDb = false || sJustLoadedFromOldDb; - sLoadOldDb = false; - if (sp.getBoolean(DB_CREATED_BUT_DEFAULT_WORKSPACE_NOT_LOADED, false)) { + sJustLoadedFromOldDb = false; + if (sp.getBoolean(UPGRADED_FROM_OLD_DATABASE, false)) { SharedPreferences.Editor editor = sp.edit(); - editor.remove(DB_CREATED_BUT_DEFAULT_WORKSPACE_NOT_LOADED); + editor.remove(UPGRADED_FROM_OLD_DATABASE); editor.commit(); - loadOldDb = true; + loadedOldDb = true; } - return loadOldDb; + return loadedOldDb; } /** @@ -245,7 +251,7 @@ public class LauncherProvider extends ContentProvider { String spKey = LauncherAppState.getSharedPreferencesKey(); SharedPreferences sp = getContext().getSharedPreferences(spKey, Context.MODE_PRIVATE); - if (sp.getBoolean(DB_CREATED_BUT_DEFAULT_WORKSPACE_NOT_LOADED, false)) { + if (sp.getBoolean(EMPTY_DATABASE_CREATED, false)) { int workspaceResId = origWorkspaceResId; // Use default workspace resource if none provided @@ -255,16 +261,21 @@ public class LauncherProvider extends ContentProvider { // Populate favorites table with initial favorites SharedPreferences.Editor editor = sp.edit(); - editor.remove(DB_CREATED_BUT_DEFAULT_WORKSPACE_NOT_LOADED); + editor.remove(EMPTY_DATABASE_CREATED); if (origWorkspaceResId != 0) { editor.putInt(DEFAULT_WORKSPACE_RESOURCE_ID, origWorkspaceResId); } mOpenHelper.loadFavorites(mOpenHelper.getWritableDatabase(), workspaceResId); + mOpenHelper.setFlagJustLoadedOldDb(); editor.commit(); } } + private static interface ContentValuesCallback { + public void onRow(ContentValues values); + } + private static class DatabaseHelper extends SQLiteOpenHelper { private static final String TAG_FAVORITES = "favorites"; private static final String TAG_FAVORITE = "favorite"; @@ -341,10 +352,32 @@ public class LauncherProvider extends ContentProvider { sendAppWidgetResetNotify(); } - if (!convertDatabase(db)) { - // Set a shared pref so that we know we need to load the default workspace later - setFlagToLoadDefaultWorkspaceLater(); + // Try converting the old database + ContentValuesCallback permuteScreensCb = new ContentValuesCallback() { + public void onRow(ContentValues values) { + int container = values.getAsInteger(LauncherSettings.Favorites.CONTAINER); + if (container == Favorites.CONTAINER_DESKTOP) { + int screen = values.getAsInteger(LauncherSettings.Favorites.SCREEN); + screen = (int) upgradeLauncherDb_permuteScreens(screen); + values.put(LauncherSettings.Favorites.SCREEN, screen); + } + } + }; + Uri uri = Uri.parse("content://" + Settings.AUTHORITY + + "/old_favorites?notify=true"); + if (!convertDatabase(db, uri, permuteScreensCb, true)) { + // Try and upgrade from the Launcher2 db + uri = LauncherSettings.Favorites.OLD_CONTENT_URI; + if (!convertDatabase(db, uri, permuteScreensCb, false)) { + // If we fail, then set a flag to load the default workspace + setFlagEmptyDbCreated(); + return; + } } + // Right now, in non-default workspace cases, we want to run the final + // upgrade code (ie. to fix workspace screen indices -> ids, etc.), so + // set that flag too. + setFlagJustLoadedOldDb(); } private void addWorkspacesTable(SQLiteDatabase db) { @@ -354,20 +387,39 @@ public class LauncherProvider extends ContentProvider { ");"); } - private void setFlagToLoadDefaultWorkspaceLater() { + private void setFlagJustLoadedOldDb() { String spKey = LauncherAppState.getSharedPreferencesKey(); SharedPreferences sp = mContext.getSharedPreferences(spKey, Context.MODE_PRIVATE); SharedPreferences.Editor editor = sp.edit(); - editor.putBoolean(DB_CREATED_BUT_DEFAULT_WORKSPACE_NOT_LOADED, true); + editor.putBoolean(UPGRADED_FROM_OLD_DATABASE, true); + editor.putBoolean(EMPTY_DATABASE_CREATED, false); editor.commit(); } - private boolean convertDatabase(SQLiteDatabase db) { + private void setFlagEmptyDbCreated() { + String spKey = LauncherAppState.getSharedPreferencesKey(); + SharedPreferences sp = mContext.getSharedPreferences(spKey, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sp.edit(); + editor.putBoolean(EMPTY_DATABASE_CREATED, true); + editor.putBoolean(UPGRADED_FROM_OLD_DATABASE, false); + editor.commit(); + } + + // We rearrange the screens from the old launcher + // 12345 -> 34512 + private long upgradeLauncherDb_permuteScreens(long screen) { + if (screen >= 2) { + return screen - 2; + } else { + return screen + 3; + } + } + + private boolean convertDatabase(SQLiteDatabase db, Uri uri, + ContentValuesCallback cb, boolean deleteRows) { if (LOGD) Log.d(TAG, "converting database from an older format, but not onUpgrade"); boolean converted = false; - final Uri uri = Uri.parse("content://" + Settings.AUTHORITY + - "/old_favorites?notify=true"); final ContentResolver resolver = mContext.getContentResolver(); Cursor cursor = null; @@ -378,28 +430,33 @@ public class LauncherProvider extends ContentProvider { } // We already have a favorites database in the old provider - if (cursor != null && cursor.getCount() > 0) { + if (cursor != null) { try { - converted = copyFromCursor(db, cursor) > 0; + if (cursor.getCount() > 0) { + converted = copyFromCursor(db, cursor, cb) > 0; + if (converted && deleteRows) { + resolver.delete(uri, null, null); + } + } } finally { cursor.close(); } - - if (converted) { - resolver.delete(uri, null, null); - } } if (converted) { // Convert widgets from this import into widgets if (LOGD) Log.d(TAG, "converted and now triggering widget upgrade"); convertWidgets(db); + + // Update max item id + mMaxItemId = initializeMaxItemId(db); + if (LOGD) Log.d(TAG, "mMaxItemId: " + mMaxItemId); } return converted; } - private int copyFromCursor(SQLiteDatabase db, Cursor c) { + private int copyFromCursor(SQLiteDatabase db, Cursor c, ContentValuesCallback cb) { final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID); final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT); final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE); @@ -434,23 +491,28 @@ public class LauncherProvider extends ContentProvider { 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)); + if (cb != null) { + cb.onRow(values); + } rows[i++] = values; } - db.beginTransaction(); int total = 0; - try { - int numValues = rows.length; - for (i = 0; i < numValues; i++) { - if (dbInsertAndCheck(this, db, TABLE_FAVORITES, null, rows[i]) < 0) { - return 0; - } else { - total++; + if (i > 0) { + db.beginTransaction(); + try { + int numValues = rows.length; + for (i = 0; i < numValues; i++) { + if (dbInsertAndCheck(this, db, TABLE_FAVORITES, null, rows[i]) < 0) { + return 0; + } else { + total++; + } } + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); } - db.setTransactionSuccessful(); - } finally { - db.endTransaction(); } return total; @@ -458,7 +520,7 @@ public class LauncherProvider extends ContentProvider { @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - if (LOGD) Log.d(TAG, "onUpgrade triggered"); + if (LOGD) Log.d(TAG, "onUpgrade triggered: " + oldVersion); int version = oldVersion; if (version < 3) { @@ -558,7 +620,7 @@ public class LauncherProvider extends ContentProvider { // This will never happen in the wild, but when we switch to using workspace // screen ids, redo the import from old launcher. - sLoadOldDb = true; + sJustLoadedFromOldDb = true; addWorkspacesTable(db); version = 13; @@ -722,6 +784,10 @@ public class LauncherProvider extends ContentProvider { return mMaxItemId; } + public void updateMaxItemId(long id) { + mMaxItemId = id + 1; + } + private long initializeMaxItemId(SQLiteDatabase db) { Cursor c = db.rawQuery("SELECT MAX(_id) FROM favorites", null); @@ -861,6 +927,10 @@ public class LauncherProvider extends ContentProvider { c.close(); } } + + // Update max item id + mMaxItemId = initializeMaxItemId(db); + if (LOGD) Log.d(TAG, "mMaxItemId: " + mMaxItemId); } private static final void beginDocument(XmlPullParser parser, String firstElementName) @@ -1018,6 +1088,11 @@ public class LauncherProvider extends ContentProvider { Log.w(TAG, "Got exception parsing favorites.", e); } + // Update the max item id after we have loaded the database + if (mMaxItemId == -1) { + mMaxItemId = initializeMaxItemId(db); + } + return i; } diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java index aaff58886..d53fd751f 100644 --- a/src/com/android/launcher3/PagedView.java +++ b/src/com/android/launcher3/PagedView.java @@ -983,7 +983,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc // Check if the right edge of the page is in the viewport mTmpIntPoint[0] = currPage.getMeasuredWidth(); - DragLayer.getDescendantCoordRelativeToParent(currPage, this, mTmpIntPoint, false); + Utilities.getDescendantCoordRelativeToParent(currPage, this, mTmpIntPoint, false); if (mTmpIntPoint[0] < 0) { break; } @@ -993,7 +993,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc // Check if the left edge of the page is in the viewport mTmpIntPoint[0] = 0; - DragLayer.getDescendantCoordRelativeToParent(currPage, this, mTmpIntPoint, false); + Utilities.getDescendantCoordRelativeToParent(currPage, this, mTmpIntPoint, false); if (mTmpIntPoint[0] >= viewportWidth) { break; } diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java index 0cc29faa3..cc22bb5db 100644 --- a/src/com/android/launcher3/Utilities.java +++ b/src/com/android/launcher3/Utilities.java @@ -25,6 +25,7 @@ import android.graphics.BlurMaskFilter; import android.graphics.Canvas; import android.graphics.ColorMatrix; import android.graphics.ColorMatrixColorFilter; +import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.PaintFlagsDrawFilter; import android.graphics.PorterDuff; @@ -33,6 +34,10 @@ import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.PaintDrawable; import android.util.DisplayMetrics; +import android.view.View; +import android.view.ViewGroup; + +import java.util.ArrayList; import com.android.launcher3.R; @@ -232,6 +237,96 @@ final class Utilities { } } + /** + * Given a coordinate relative to the descendant, find the coordinate in a parent view's + * coordinates. + * + * @param descendant The descendant to which the passed coordinate is relative. + * @param root The root view to make the coordinates relative to. + * @param coord The coordinate that we want mapped. + * @param includeRootScroll Whether or not to account for the scroll of the descendant: + * sometimes this is relevant as in a child's coordinates within the descendant. + * @return The factor by which this descendant is scaled relative to this DragLayer. Caution + * this scale factor is assumed to be equal in X and Y, and so if at any point this + * assumption fails, we will need to return a pair of scale factors. + */ + public static float getDescendantCoordRelativeToParent(View descendant, View root, + int[] coord, boolean includeRootScroll) { + ArrayList ancestorChain = new ArrayList(); + + float[] pt = {coord[0], coord[1]}; + + View v = descendant; + while(v != root && v != null) { + ancestorChain.add(v); + v = (View) v.getParent(); + } + ancestorChain.add(root); + + float scale = 1.0f; + int count = ancestorChain.size(); + for (int i = 0; i < count; i++) { + View v0 = ancestorChain.get(i); + View v1 = i < count -1 ? ancestorChain.get(i + 1) : null; + + // For TextViews, scroll has a meaning which relates to the text position + // which is very strange... ignore the scroll. + if (v0 != descendant || includeRootScroll) { + pt[0] -= v0.getScrollX(); + pt[1] -= v0.getScrollY(); + } + + v0.getMatrix().mapPoints(pt); + pt[0] += v0.getLeft(); + pt[1] += v0.getTop(); + scale *= v0.getScaleX(); + } + + coord[0] = (int) Math.round(pt[0]); + coord[1] = (int) Math.round(pt[1]); + return scale; + } + + /** + * Inverse of {@link #getDescendantCoordRelativeToSelf(View, int[])}. + */ + public static float mapCoordInSelfToDescendent(View descendant, View root, + int[] coord) { + ArrayList ancestorChain = new ArrayList(); + + float[] pt = {coord[0], coord[1]}; + + View v = descendant; + while(v != root) { + ancestorChain.add(v); + v = (View) v.getParent(); + } + ancestorChain.add(root); + + float scale = 1.0f; + Matrix inverse = new Matrix(); + int count = ancestorChain.size(); + for (int i = count - 1; i >= 0; i--) { + View ancestor = ancestorChain.get(i); + View next = i > 0 ? ancestorChain.get(i-1) : null; + + pt[0] += ancestor.getScrollX(); + pt[1] += ancestor.getScrollY(); + + if (next != null) { + pt[0] -= next.getLeft(); + pt[1] -= next.getTop(); + next.getMatrix().invert(inverse); + inverse.mapPoints(pt); + scale *= next.getScaleX(); + } + } + + coord[0] = (int) Math.round(pt[0]); + coord[1] = (int) Math.round(pt[1]); + return scale; + } + private static void initStatics(Context context) { final Resources resources = context.getResources(); final DisplayMetrics metrics = resources.getDisplayMetrics(); diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index b8ef6b117..4f8f8d177 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -1330,7 +1330,13 @@ public class Workspace extends SmoothPagedView progress = Math.max(0, progress); setBackgroundAlpha(progress * 0.8f); - float transY = progress * (getViewportHeight() - getPageIndicator().getTop()); + float height = getViewportHeight(); + if (getPageIndicator() != null) { + height -= getPageIndicator().getTop(); + } else if (mLauncher.getHotseat() != null) { + height -= mLauncher.getHotseat().getTop(); + } + float transY = progress * height; if (mLauncher.getHotseat() != null) { mLauncher.getHotseat().setTranslationY(transY); -- cgit v1.2.3