diff options
18 files changed, 472 insertions, 214 deletions
diff --git a/res/drawable-hdpi/now_page.png b/res/drawable-hdpi/now_page.png Binary files differnew file mode 100644 index 000000000..9eef50c92 --- /dev/null +++ b/res/drawable-hdpi/now_page.png diff --git a/res/drawable-mdpi/now_page.png b/res/drawable-mdpi/now_page.png Binary files differnew file mode 100644 index 000000000..cc4005ded --- /dev/null +++ b/res/drawable-mdpi/now_page.png diff --git a/res/drawable-xhdpi/now_page.png b/res/drawable-xhdpi/now_page.png Binary files differnew file mode 100644 index 000000000..e1da91c61 --- /dev/null +++ b/res/drawable-xhdpi/now_page.png diff --git a/res/layout/now_page_indicator_marker.xml b/res/layout/now_page_indicator_marker.xml new file mode 100644 index 000000000..7d0562743 --- /dev/null +++ b/res/layout/now_page_indicator_marker.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2013 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. +--> +<com.android.launcher3.PageIndicatorMarker + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" + android:layout_width="wrap_content" + android:layout_height="wrap_content"> + <ImageView + android:id="@+id/inactive" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/now_page" + /> + <ImageView + android:id="@+id/active" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/now_page" + android:alpha="0" + /> +</com.android.launcher3.PageIndicatorMarker> diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java index ac41a2bd7..86bc1b047 100644 --- a/src/com/android/launcher3/CellLayout.java +++ b/src/com/android/launcher3/CellLayout.java @@ -3231,6 +3231,11 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) { public boolean isLockedToGrid = true; /** + * Indicates that this item should use the full extents of its parent. + */ + public boolean isFullscreen = false; + + /** * Indicates whether this item can be reordered. Always true except in the case of the * the AllApps button. */ diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java index 763ec3faa..c98f761f2 100644 --- a/src/com/android/launcher3/DeleteDropTarget.java +++ b/src/com/android/launcher3/DeleteDropTarget.java @@ -55,6 +55,8 @@ public class DeleteDropTarget extends ButtonDropTarget { private TransitionDrawable mRemoveDrawable; private TransitionDrawable mCurrentDrawable; + private boolean mWaitingForUninstall = false; + public DeleteDropTarget(Context context, AttributeSet attrs) { this(context, attrs, 0); } @@ -251,7 +253,6 @@ public class DeleteDropTarget extends ButtonDropTarget { return AppsCustomizePagedView.DISABLE_ALL_APPS && isWorkspaceOrFolderApplication(d); } - private boolean mWaitingForUninstall = false; private void completeDrop(final DragObject d) { ItemInfo item = (ItemInfo) d.dragInfo; boolean wasWaitingForUninstall = mWaitingForUninstall; 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<View> ancestorChain = new ArrayList<View>(); - - 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<View> ancestorChain = new ArrayList<View>(); - - 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/FocusHelper.java b/src/com/android/launcher3/FocusHelper.java index a591433f2..1acaf3e3b 100644 --- a/src/com/android/launcher3/FocusHelper.java +++ b/src/com/android/launcher3/FocusHelper.java @@ -21,6 +21,7 @@ import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; +import android.widget.ScrollView; import android.widget.TabHost; import android.widget.TabWidget; @@ -817,7 +818,8 @@ public class FocusHelper { static boolean handleFolderKeyEvent(View v, int keyCode, KeyEvent e) { ShortcutAndWidgetContainer parent = (ShortcutAndWidgetContainer) v.getParent(); final CellLayout layout = (CellLayout) parent.getParent(); - final Folder folder = (Folder) layout.getParent(); + final ScrollView scrollView = (ScrollView) layout.getParent(); + final Folder folder = (Folder) scrollView.getParent(); View title = folder.mFolderName; final int action = e.getAction(); diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java index bb3993efc..c70cbe0a5 100644 --- a/src/com/android/launcher3/Folder.java +++ b/src/com/android/launcher3/Folder.java @@ -775,7 +775,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList if (target != this) { if (mOnExitAlarm.alarmPending()) { mOnExitAlarm.cancelAlarm(); - if (successfulDrop) { + if (!successfulDrop) { mSuppressFolderDeletion = true; } completeDragExit(); diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index c32de33f6..f990d2595 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -442,6 +442,11 @@ public class Launcher extends Activity sPausedFromUserAction = true; } + /** To be overriden by subclasses to hint to Launcher that we have custom content */ + protected boolean hasCustomContentToLeft() { + return false; + } + private void updateGlobalIcons() { boolean searchVisible = false; boolean voiceVisible = false; @@ -795,6 +800,12 @@ public class Launcher extends Activity (System.currentTimeMillis() - startTimeCallbacks)); } } + if (mOnResumeCallbacks.size() > 0) { + for (int i = 0; i < mOnResumeCallbacks.size(); i++) { + mOnResumeCallbacks.get(i).run(); + } + mOnResumeCallbacks.clear(); + } // Reset the pressed state of icons that were locked in the press state while activities // were launching @@ -869,13 +880,13 @@ public class Launcher extends Activity } // Add a fullscreen unpadded view to the workspace to the left all other screens. - public QSBScroller addCustomContentToLeft(View customContent) { - return addCustomContentToLeft(customContent, null); + public QSBScroller addToCustomContentPage(View customContent) { + return addToCustomContentPage(customContent, null); } - public QSBScroller addCustomContentToLeft(View customContent, + public QSBScroller addToCustomContentPage(View customContent, CustomContentCallbacks callbacks) { - mWorkspace.addCustomContentToLeft(customContent, callbacks); + mWorkspace.addToCustomContentPage(customContent, callbacks); return mQsbScroller; } @@ -991,7 +1002,7 @@ public class Launcher extends Activity int currentScreen = savedState.getInt(RUNTIME_STATE_CURRENT_SCREEN, -1); if (currentScreen > -1) { - mWorkspace.setCurrentPage(currentScreen); + mWorkspace.setRestorePage(currentScreen); } final long pendingAddContainer = savedState.getLong(RUNTIME_STATE_PENDING_ADD_CONTAINER, -1); @@ -3434,11 +3445,11 @@ public class Launcher extends Activity } public void addOnResumeCallback(Runnable run) { - mBindOnResumeCallbacks.add(run); + mOnResumeCallbacks.add(run); } public void removeOnResumeCallback(Runnable run) { - mBindOnResumeCallbacks.remove(run); + mOnResumeCallbacks.remove(run); } /** @@ -3603,6 +3614,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"); } } @@ -3710,6 +3723,11 @@ public class Launcher extends Activity mSavedState = null; } + // Create the custom content page here before onLayout to prevent flashing + if (!mWorkspace.hasCustomContent() && hasCustomContentToLeft()) { + mWorkspace.createCustomContentPage(); + } + mWorkspace.restoreInstanceStateForRemainingPages(); // If we received the result of any pending adds while the loader was running (e.g. the @@ -3725,7 +3743,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 f79e08166..63089870a 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -300,17 +300,24 @@ public class LauncherModel extends BroadcastReceiver { Pair<Long, int[]> 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, name, launchIntent, startSearchPageIndex); @@ -1254,7 +1261,6 @@ public class LauncherModel extends BroadcastReceiver { private boolean mIsLoadingAndBindingWorkspace; private boolean mStopped; private boolean mLoadAndBindStepFinished; - private boolean mIsUpgradePath; private HashMap<Object, CharSequence> mLabelCache; @@ -1272,7 +1278,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 @@ -1280,18 +1287,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() { @@ -1360,13 +1369,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; } @@ -1384,7 +1395,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; @@ -1419,6 +1430,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; @@ -1469,6 +1486,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<ItemInfo> tmpInfos; + ArrayList<ApplicationInfo> added = new ArrayList<ApplicationInfo>(); + 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<Long, ItemInfo[][]> occupied, ItemInfo item) { long containerIndex = item.screenId; @@ -1522,7 +1562,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; @@ -1532,11 +1573,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(); @@ -1547,7 +1587,7 @@ public class LauncherModel extends BroadcastReceiver { sBgWorkspaceScreens.clear(); final ArrayList<Long> itemsToRemove = new ArrayList<Long>(); - + 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) @@ -1655,10 +1695,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 @@ -1698,10 +1734,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); @@ -1742,11 +1774,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 @@ -1763,7 +1790,9 @@ public class LauncherModel extends BroadcastReceiver { } } } finally { - c.close(); + if (c != null) { + c.close(); + } } if (itemsToRemove.size() > 0) { @@ -1784,7 +1813,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()) { @@ -1800,6 +1829,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); @@ -1870,16 +1908,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 @@ -2087,7 +2116,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; @@ -2179,7 +2208,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/PageIndicator.java b/src/com/android/launcher3/PageIndicator.java index d7778fb1a..ce9814505 100644 --- a/src/com/android/launcher3/PageIndicator.java +++ b/src/com/android/launcher3/PageIndicator.java @@ -161,18 +161,17 @@ public class PageIndicator extends LinearLayout { mWindowRange[1] = windowEnd; } - void addMarker(int index) { + void addMarker(int index, int layoutId) { index = Math.max(0, Math.min(index, mMarkers.size())); - int mLayoutId = R.layout.page_indicator_marker; PageIndicatorMarker marker = - (PageIndicatorMarker) mLayoutInflater.inflate(mLayoutId, this, false); + (PageIndicatorMarker) mLayoutInflater.inflate(layoutId, this, false); mMarkers.add(index, marker); offsetWindowCenterTo(mActiveMarkerIndex, true); } - void addMarkers(int count) { - for (int i = 0; i < count; ++i) { - addMarker(Integer.MAX_VALUE); + void addMarkers(ArrayList<Integer> layoutIds) { + for (int i = 0; i < layoutIds.size(); ++i) { + addMarker(Integer.MAX_VALUE, layoutIds.get(i)); } } diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java index aaff58886..bb596a79e 100644 --- a/src/com/android/launcher3/PagedView.java +++ b/src/com/android/launcher3/PagedView.java @@ -104,6 +104,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc protected boolean mFirstLayout = true; protected int mCurrentPage; + protected int mRestorePage = -1; protected int mChildCountOnLastLayout; protected int mNextPage = INVALID_PAGE; @@ -326,7 +327,12 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc if (mPageIndicator == null && mPageIndicatorViewId > -1) { mPageIndicator = (PageIndicator) parent.findViewById(mPageIndicatorViewId); mPageIndicator.removeAllMarkers(); - mPageIndicator.addMarkers(getChildCount()); + + ArrayList<Integer> markers = new ArrayList<Integer>(); + for (int i = 0; i < getChildCount(); ++i) { + markers.add(getPageIndicatorMarker(i)); + } + mPageIndicator.addMarkers(markers); } } @@ -403,6 +409,9 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc PageIndicator getPageIndicator() { return mPageIndicator; } + protected int getPageIndicatorMarker(int pageIndex) { + return R.layout.page_indicator_marker; + } public void setPageSwitchListener(PageSwitchListener pageSwitchListener) { mPageSwitchListener = pageSwitchListener; @@ -506,6 +515,14 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc invalidate(); } + /** + * The restore page will be set in place of the current page at the next (likely first) + * layout. + */ + void setRestorePage(int restorePage) { + mRestorePage = restorePage; + } + protected void notifyPageSwitchListener() { if (mPageSwitchListener != null) { mPageSwitchListener.onPageSwitch(getPageAt(mCurrentPage), mCurrentPage); @@ -824,6 +841,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc } for (int i = startIndex; i != endIndex; i += delta) { + final View child = getPageAt(i); LayoutParams lp = (LayoutParams) child.getLayoutParams(); int childTop; @@ -847,10 +865,13 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc // We assume the left and right padding are equal, and hence center the pages // horizontally - int scrollOffset = false ? 0 : (getViewportWidth() - childWidth) / 2; + int scrollOffset = (getViewportWidth() - childWidth) / 2; mPageScrolls[i] = childLeft - scrollOffset - offsetX; - childLeft += childWidth + mPageSpacing; + if (i != endIndex - delta) { + int nextScrollOffset = (getViewportWidth() - getChildWidth(i + delta)) / 2; + childLeft += childWidth + nextScrollOffset; + } } } @@ -870,7 +891,12 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc if (mScroller.isFinished() && mChildCountOnLastLayout != getChildCount() && !mDeferringForDelete) { - setCurrentPage(getNextPage()); + if (mRestorePage > -1) { + setCurrentPage(mRestorePage); + mRestorePage = -1; + } else { + setCurrentPage(getNextPage()); + } } mChildCountOnLastLayout = getChildCount(); } @@ -896,7 +922,8 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc // Update the page indicator, we don't update the page indicator as we // add/remove pages if (mPageIndicator != null && !isReordering(false)) { - mPageIndicator.addMarker(indexOfChild(child)); + int pageIndex = indexOfChild(child); + mPageIndicator.addMarker(pageIndex, getPageIndicatorMarker(pageIndex)); } // This ensures that when children are added, they get the correct transforms / alphas @@ -983,7 +1010,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 +1020,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/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java index 18b9399d1..64a87ef07 100644 --- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java +++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java @@ -92,13 +92,15 @@ public class ShortcutAndWidgetContainer extends ViewGroup { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int count = getChildCount(); + + int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); + int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); + setMeasuredDimension(widthSpecSize, heightSpecSize); + for (int i = 0; i < count; i++) { View child = getChildAt(i); measureChild(child); } - int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); - int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); - setMeasuredDimension(widthSpecSize, heightSpecSize); } public void setupLp(CellLayout.LayoutParams lp) { @@ -115,8 +117,15 @@ public class ShortcutAndWidgetContainer extends ViewGroup { final int cellWidth = mCellWidth; final int cellHeight = mCellHeight; CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams(); - - lp.setup(cellWidth, cellHeight, mWidthGap, mHeightGap, invertLayoutHorizontally(), mCountX); + if (!lp.isFullscreen) { + lp.setup(cellWidth, cellHeight, mWidthGap, mHeightGap, invertLayoutHorizontally(), + mCountX); + } else { + lp.x = 0; + lp.y = 0; + lp.width = getMeasuredWidth(); + lp.height = getMeasuredHeight(); + } int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY); int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY); diff --git a/src/com/android/launcher3/ShortcutInfo.java b/src/com/android/launcher3/ShortcutInfo.java index fac96d2a2..b4e564283 100644 --- a/src/com/android/launcher3/ShortcutInfo.java +++ b/src/com/android/launcher3/ShortcutInfo.java @@ -83,7 +83,8 @@ class ShortcutInfo extends ItemInfo { } mIcon = info.mIcon; // TODO: should make a copy here. maybe we don't need this ctor at all customIcon = info.customIcon; - initFlagsAndFirstInstallTime(getPackageInfo(context, intent.getComponent().getPackageName())); + initFlagsAndFirstInstallTime( + getPackageInfo(context, intent.getComponent().getPackageName())); } /** TODO: Remove this. It's only called by ApplicationInfo.makeShortcut. */ @@ -141,7 +142,8 @@ class ShortcutInfo extends ItemInfo { intent.setComponent(className); intent.setFlags(launchFlags); itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_APPLICATION; - initFlagsAndFirstInstallTime(getPackageInfo(context, intent.getComponent().getPackageName())); + initFlagsAndFirstInstallTime( + getPackageInfo(context, intent.getComponent().getPackageName())); } @Override 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<View> ancestorChain = new ArrayList<View>(); + + 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<View> ancestorChain = new ArrayList<View>(); + + 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 90b54c679..6989c9aa6 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -528,18 +528,10 @@ public class Workspace extends SmoothPagedView return screenId; } - public void addCustomContentToLeft(View customContent, CustomContentCallbacks callbacks) { + public void createCustomContentPage() { CellLayout customScreen = (CellLayout) mLauncher.getLayoutInflater().inflate(R.layout.workspace_screen, null); - int spanX = customScreen.getCountX(); - int spanY = customScreen.getCountY(); - - CellLayout.LayoutParams lp = new CellLayout.LayoutParams(0, 0, spanX, spanY); - lp.canReorder = false; - - customScreen.addViewToCellLayout(customContent, 0, 0, lp, true); - Rect p = new Rect(); AppWidgetHostView.getDefaultPaddingForWidget(mLauncher, mLauncher.getComponentName(), p); @@ -548,13 +540,28 @@ public class Workspace extends SmoothPagedView addFullScreenPage(customScreen); - mCustomContentCallbacks = callbacks; - // Ensure that the current page and default page are maintained. mDefaultPage++; setCurrentPage(getCurrentPage() + 1); } + public void addToCustomContentPage(View customContent, CustomContentCallbacks callbacks) { + if (getPageIndexForScreenId(CUSTOM_CONTENT_SCREEN_ID) < 0) { + throw new RuntimeException("Expected custom content screen to exist"); + } + + // Add the custom content to the full screen custom page + CellLayout customScreen = getScreenWithId(CUSTOM_CONTENT_SCREEN_ID); + int spanX = customScreen.getCountX(); + int spanY = customScreen.getCountY(); + CellLayout.LayoutParams lp = new CellLayout.LayoutParams(0, 0, spanX, spanY); + lp.canReorder = false; + lp.isFullscreen = true; + customScreen.addViewToCellLayout(customContent, 0, 0, lp, true); + + mCustomContentCallbacks = callbacks; + } + public long commitExtraEmptyScreen() { CellLayout cl = mWorkspaceScreens.get(EXTRA_EMPTY_SCREEN_ID); mWorkspaceScreens.remove(EXTRA_EMPTY_SCREEN_ID); @@ -769,6 +776,13 @@ public class Workspace extends SmoothPagedView protected void onWindowVisibilityChanged (int visibility) { mLauncher.onWindowVisibilityChanged(visibility); + if (mCustomContentShowing && mCustomContentCallbacks != null) { + if (visibility == View.VISIBLE) { + mCustomContentCallbacks.onShow(); + } else if (visibility == View.GONE) { + mCustomContentCallbacks.onHide(); + } + } } @Override @@ -929,25 +943,25 @@ public class Workspace extends SmoothPagedView stripEmptyScreens(); mStripScreensOnPageStopMoving = false; } - } - - @Override - protected void notifyPageSwitchListener() { - super.notifyPageSwitchListener(); - Launcher.setScreen(mCurrentPage); - if (hasCustomContent() && mCurrentPage == 0) { + if (hasCustomContent() && getNextPage() == 0 && !mCustomContentShowing) { mCustomContentShowing = true; if (mCustomContentCallbacks != null) { mCustomContentCallbacks.onShow(); } - } else if (hasCustomContent() && mCustomContentShowing) { + } else if (hasCustomContent() && getNextPage() != 0 && mCustomContentShowing) { mCustomContentShowing = false; if (mCustomContentCallbacks != null) { mCustomContentCallbacks.onHide(); mLauncher.resetQSBScroll(); } } + } + + @Override + protected void notifyPageSwitchListener() { + super.notifyPageSwitchListener(); + Launcher.setScreen(mCurrentPage); }; // As a ratio of screen height, the total distance we want the parallax effect to span @@ -1292,7 +1306,7 @@ public class Workspace extends SmoothPagedView } } - private boolean hasCustomContent() { + public boolean hasCustomContent() { return (mScreenOrder.size() > 0 && mScreenOrder.get(0) == CUSTOM_CONTENT_SCREEN_ID); } @@ -1302,21 +1316,26 @@ public class Workspace extends SmoothPagedView private void updateStateForCustomContent(int screenCenter) { if (hasCustomContent()) { - CellLayout customContent = getScreenWithId(CUSTOM_CONTENT_SCREEN_ID); int index = mScreenOrder.indexOf(CUSTOM_CONTENT_SCREEN_ID); int scrollDelta = getScrollForPage(index + 1) - getScrollX(); - float translationX = Math.max(scrollDelta, 0); float progress = (1.0f * scrollDelta) / (getScrollForPage(index + 1) - getScrollForPage(index)); 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); + mLauncher.getHotseat().setAlpha(1 - progress); } if (getPageIndicator() != null) { getPageIndicator().setAlpha(1 - progress); @@ -3702,6 +3721,11 @@ public class Workspace extends SmoothPagedView setCurrentDropLayout(null); if (0 <= page && page < getChildCount()) { + // Ensure that we are not dragging over to the custom content screen + if (getScreenIdForPageIndex(page) == CUSTOM_CONTENT_SCREEN_ID) { + return false; + } + CellLayout layout = (CellLayout) getChildAt(page); setCurrentDragOverlappingLayout(layout); @@ -3990,6 +4014,14 @@ public class Workspace extends SmoothPagedView } @Override + protected int getPageIndicatorMarker(int pageIndex) { + if (getScreenIdForPageIndex(pageIndex) == CUSTOM_CONTENT_SCREEN_ID) { + return R.layout.now_page_indicator_marker; + } + return super.getPageIndicatorMarker(pageIndex); + } + + @Override public void syncPages() { } |