Support for dynamically adding/removing -1 screen

Change-Id: Ife68b64c04498e336192caf895edb9a090dcdc26
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 6e6cdf6..5aa200a 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -482,6 +482,33 @@
         return false;
     }
 
+    /**
+     * To be overridden by subclasses to create the custom content and call
+     * {@link #addToCustomContentPage}. This will only be invoked if
+     * {@link #hasCustomContentToLeft()} is {@code true}.
+     */
+    protected void addCustomContentToLeft() {
+    }
+
+    /**
+     * Invoked by subclasses to signal a change to the {@link #addCustomContentToLeft} value to
+     * ensure the custom content page is added or removed if necessary.
+     */
+    protected void invalidateHasCustomContentToLeft() {
+        if (mWorkspace.getScreenOrder().isEmpty()) {
+            // Not bound yet, wait for bindScreens to be called.
+            return;
+        }
+
+        if (!mWorkspace.hasCustomContent() && hasCustomContentToLeft()) {
+            // Create the custom content page and call the subclass to populate it.
+            mWorkspace.createCustomContentPage();
+            addCustomContentToLeft();
+        } else if (mWorkspace.hasCustomContent() && !hasCustomContentToLeft()) {
+            mWorkspace.removeCustomContentPage();
+        }
+    }
+
     private void updateGlobalIcons() {
         boolean searchVisible = false;
         boolean voiceVisible = false;
@@ -896,6 +923,9 @@
     }
 
     protected void onFinishBindingItems() {
+        if (hasCustomContentToLeft() && mWorkspace.hasCustomContent()) {
+            addCustomContentToLeft();
+        }
     }
 
     QSBScroller mQsbScroller = new QSBScroller() {
@@ -3606,7 +3636,8 @@
         }
 
         // Create the custom content page (this call updates mDefaultScreen which calls
-        // setCurrentPage() so ensure that all pages are added before calling this)
+        // setCurrentPage() so ensure that all pages are added before calling this).
+        // The actual content of the custom page will be added during onFinishBindingItems().
         if (!mWorkspace.hasCustomContent() && hasCustomContentToLeft()) {
             mWorkspace.createCustomContentPage();
         }
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 2758b87..be2eb1d 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -52,7 +52,6 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewParent;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
 import android.widget.TextView;
@@ -540,6 +539,24 @@
         setCurrentPage(getCurrentPage() + 1);
     }
 
+    public void removeCustomContentPage() {
+        Launcher.addDumpLog(TAG, "10249126 - removeCustomContentPage()", true);
+
+        CellLayout customScreen = getScreenWithId(CUSTOM_CONTENT_SCREEN_ID);
+        if (customScreen == null) {
+            throw new RuntimeException("Expected custom content screen to exist");
+        }
+
+        mWorkspaceScreens.remove(CUSTOM_CONTENT_SCREEN_ID);
+        mScreenOrder.remove(CUSTOM_CONTENT_SCREEN_ID);
+        removeView(customScreen);
+        mCustomContentCallbacks = null;
+
+        // Ensure that the current page and default page are maintained.
+        mDefaultPage = mOriginalDefaultPage - 1;
+        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");
@@ -1326,30 +1343,32 @@
     }
 
     private void updateStateForCustomContent(int screenCenter) {
+        float translationX = 0;
+        float progress = 0;
         if (hasCustomContent()) {
             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) /
+            translationX = Math.max(scrollDelta, 0);
+            progress = (1.0f * scrollDelta) /
                     (getScrollForPage(index + 1) - getScrollForPage(index));
             progress = Math.max(0, progress);
+        }
 
-            if (Float.compare(progress, mLastCustomContentScrollProgress) == 0) return;
-            mLastCustomContentScrollProgress = progress;
+        if (Float.compare(progress, mLastCustomContentScrollProgress) == 0) return;
+        mLastCustomContentScrollProgress = progress;
 
-            setBackgroundAlpha(progress * 0.8f);
+        setBackgroundAlpha(progress * 0.8f);
 
-            if (mLauncher.getHotseat() != null) {
-                mLauncher.getHotseat().setTranslationX(translationX);
-            }
+        if (mLauncher.getHotseat() != null) {
+            mLauncher.getHotseat().setTranslationX(translationX);
+        }
 
-            if (getPageIndicator() != null) {
-                getPageIndicator().setTranslationX(translationX);
-            }
+        if (getPageIndicator() != null) {
+            getPageIndicator().setTranslationX(translationX);
+        }
 
-            if (mCustomContentCallbacks != null) {
-                mCustomContentCallbacks.onScrollProgressChanged(progress);
-            }
+        if (mCustomContentCallbacks != null) {
+            mCustomContentCallbacks.onScrollProgressChanged(progress);
         }
     }
 
@@ -3793,7 +3812,7 @@
     @Override
     protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
         // We don't dispatch restoreInstanceState to our children using this code path.
-        // Some pages will be restored immediately as their items are bound immediately, and 
+        // Some pages will be restored immediately as their items are bound immediately, and
         // others we will need to wait until after their items are bound.
         mSavedStates = container;
     }