Merge "Change folder icon item overlay to white (issue 11030725)" into jb-ub-now-indigo-rose
diff --git a/res/layout-land/folder_cling.xml b/res/layout-land/folder_cling.xml
index 1f4a115..86286d7 100644
--- a/res/layout-land/folder_cling.xml
+++ b/res/layout-land/folder_cling.xml
@@ -27,22 +27,31 @@
         <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:paddingLeft="20dp"
-            android:paddingRight="20dp"
-            android:paddingTop="20dp"
-            android:paddingBottom="20dp"
-            android:orientation="vertical"
-            android:background="@drawable/cling">
-            <TextView
-                style="@style/ClingTitleText"
-                android:id="@+id/folder_cling_title"
-                android:text="@string/folder_cling_title" />
-            <TextView
-                style="@style/ClingText"
-                android:id="@+id/folder_cling_create_folder"
+            android:orientation="vertical">
+            <LinearLayout
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:text="@string/folder_cling_create_folder" />
+                android:paddingLeft="20dp"
+                android:paddingRight="20dp"
+                android:paddingTop="20dp"
+                android:paddingBottom="20dp"
+                android:orientation="vertical"
+                android:background="@drawable/cling">
+                <TextView
+                    style="@style/ClingTitleText"
+                    android:id="@+id/folder_cling_title"
+                    android:text="@string/folder_cling_title" />
+                <TextView
+                    style="@style/ClingText"
+                    android:id="@+id/folder_cling_create_folder"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:text="@string/folder_cling_create_folder" />
+            </LinearLayout>
+            <ImageView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:src="@drawable/cling_arrow_down" />
         </LinearLayout>
     </FrameLayout>
     <Button
diff --git a/res/layout-port/folder_cling.xml b/res/layout-port/folder_cling.xml
index 1f4a115..86286d7 100644
--- a/res/layout-port/folder_cling.xml
+++ b/res/layout-port/folder_cling.xml
@@ -27,22 +27,31 @@
         <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:paddingLeft="20dp"
-            android:paddingRight="20dp"
-            android:paddingTop="20dp"
-            android:paddingBottom="20dp"
-            android:orientation="vertical"
-            android:background="@drawable/cling">
-            <TextView
-                style="@style/ClingTitleText"
-                android:id="@+id/folder_cling_title"
-                android:text="@string/folder_cling_title" />
-            <TextView
-                style="@style/ClingText"
-                android:id="@+id/folder_cling_create_folder"
+            android:orientation="vertical">
+            <LinearLayout
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:text="@string/folder_cling_create_folder" />
+                android:paddingLeft="20dp"
+                android:paddingRight="20dp"
+                android:paddingTop="20dp"
+                android:paddingBottom="20dp"
+                android:orientation="vertical"
+                android:background="@drawable/cling">
+                <TextView
+                    style="@style/ClingTitleText"
+                    android:id="@+id/folder_cling_title"
+                    android:text="@string/folder_cling_title" />
+                <TextView
+                    style="@style/ClingText"
+                    android:id="@+id/folder_cling_create_folder"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:text="@string/folder_cling_create_folder" />
+            </LinearLayout>
+            <ImageView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:src="@drawable/cling_arrow_down" />
         </LinearLayout>
     </FrameLayout>
     <Button
diff --git a/res/layout/wallpaper_picker.xml b/res/layout/wallpaper_picker.xml
index 53c529c..3058a3c 100644
--- a/res/layout/wallpaper_picker.xml
+++ b/res/layout/wallpaper_picker.xml
@@ -18,7 +18,8 @@
 */
 -->
 
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.launcher3.WallpaperRootView
+    xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/wallpaper_root"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
@@ -41,8 +42,7 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_alignParentBottom="true"
-        android:orientation="vertical"
-        android:fitsSystemWindows="true" >
+        android:orientation="vertical" >
         <View
             android:layout_width="match_parent"
             android:layout_height="2dp"
@@ -73,4 +73,4 @@
             android:layout_height="2dp"
             android:background="@drawable/tile_shadow_bottom" />
     </LinearLayout>
-</RelativeLayout>
+</com.android.launcher3.WallpaperRootView>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index ac372fd..dfccd98 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -228,7 +228,7 @@
     <!-- The title text for the workspace cling [CHAR_LIMIT=none] -->
     <string name="first_run_cling_title">Welcome!</string>
     <!-- The description of how to use the workspace [CHAR_LIMIT=none] -->
-    <string name="first_run_cling_description">Make yourself at Home.</string>
+    <string name="first_run_cling_description">Make yourself at home.</string>
     <!-- The description of how to use the workspace [CHAR_LIMIT=none] -->
     <string name="first_run_cling_custom_content_hint"></string>
     <!-- The description of how to use the workspace [CHAR_LIMIT=none] -->
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index a114ec3..81f9af2 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -95,6 +95,7 @@
     private ArrayList<FolderRingAnimator> mFolderOuterRings = new ArrayList<FolderRingAnimator>();
     private int[] mFolderLeaveBehindCell = {-1, -1};
 
+    private float FOREGROUND_ALPHA_DAMPER = 0.65f;
     private int mForegroundAlpha = 0;
     private float mBackgroundAlpha;
     private float mBackgroundAlphaMultiplier = 1.0f;
@@ -349,6 +350,7 @@
             mOverScrollForegroundDrawable = mOverScrollRight;
         }
 
+        r *= FOREGROUND_ALPHA_DAMPER;
         mForegroundAlpha = (int) Math.round((r * 255));
         mOverScrollForegroundDrawable.setAlpha(mForegroundAlpha);
         invalidate();
diff --git a/src/com/android/launcher3/CropView.java b/src/com/android/launcher3/CropView.java
index c4d1475..f68f739 100644
--- a/src/com/android/launcher3/CropView.java
+++ b/src/com/android/launcher3/CropView.java
@@ -22,8 +22,8 @@
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.view.ScaleGestureDetector;
-import android.view.ViewConfiguration;
 import android.view.ScaleGestureDetector.OnScaleGestureListener;
+import android.view.ViewConfiguration;
 import android.view.ViewTreeObserver;
 import android.view.ViewTreeObserver.OnGlobalLayoutListener;
 
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 62e05e8..831637f 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -88,7 +88,6 @@
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.AccelerateDecelerateInterpolator;
-import android.view.animation.AccelerateInterpolator;
 import android.view.animation.DecelerateInterpolator;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.Advanceable;
@@ -103,12 +102,9 @@
 import java.io.DataOutputStream;
 import java.io.File;
 import java.io.FileDescriptor;
-import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
 import java.io.PrintWriter;
 import java.text.DateFormat;
 import java.util.ArrayList;
@@ -330,6 +326,8 @@
 
     private BubbleTextView mWaitingForResume;
 
+    protected TransparentBars mTransparentBars;
+
     private HideFromAccessibilityHelper mHideFromAccessibilityHelper
         = new HideFromAccessibilityHelper();
 
@@ -344,7 +342,7 @@
     private static ArrayList<PendingAddArguments> sPendingAddList
             = new ArrayList<PendingAddArguments>();
 
-    private static boolean sForceEnableRotation = isPropertyEnabled(FORCE_ENABLE_ROTATION_PROPERTY);
+    public static boolean sForceEnableRotation = isPropertyEnabled(FORCE_ENABLE_ROTATION_PROPERTY);
 
     private static class PendingAddArguments {
         int requestCode;
@@ -425,6 +423,10 @@
 
         checkForLocaleChange();
         setContentView(R.layout.launcher);
+
+        mTransparentBars = new TransparentBars(findViewById(R.id.launcher));
+        mTransparentBars.requestTransparentBars(true);
+
         setupViews();
         grid.layout(this);
 
@@ -495,7 +497,7 @@
      * ensure the custom content page is added or removed if necessary.
      */
     protected void invalidateHasCustomContentToLeft() {
-        if (mWorkspace.getScreenOrder().isEmpty()) {
+        if (mWorkspace == null || mWorkspace.getScreenOrder().isEmpty()) {
             // Not bound yet, wait for bindScreens to be called.
             return;
         }
@@ -900,6 +902,9 @@
         // Process any items that were added while Launcher was away.
         InstallShortcutReceiver.disableAndFlushInstallQueue(this);
 
+        // Update the voice search button proxy
+        updateVoiceButtonProxyVisible(false);
+
         // Again, as with the above scenario, it's possible that one or more of the global icons
         // were updated in the wrong orientation.
         updateGlobalIcons();
@@ -2848,8 +2853,6 @@
             mStateAnimation.play(alphaAnim).after(startDelay);
 
             mStateAnimation.addListener(new AnimatorListenerAdapter() {
-                boolean animationCancelled = false;
-
                 @Override
                 public void onAnimationStart(Animator animation) {
                     // Prepare the position
@@ -2868,11 +2871,6 @@
                         mSearchDropTargetBar.hideSearchBar(false);
                     }
                 }
-
-                @Override
-                public void onAnimationCancel(Animator animation) {
-                    animationCancelled = true;
-                }
             });
 
             if (workspaceAnim != null) {
@@ -3338,7 +3336,7 @@
             if (voiceButtonContainer != null) voiceButtonContainer.setVisibility(View.GONE);
             if (searchButton != null) searchButton.setVisibility(View.GONE);
             if (voiceButton != null) voiceButton.setVisibility(View.GONE);
-            setVoiceButtonProxyVisible(false);
+            updateVoiceButtonProxyVisible(false);
             return false;
         }
     }
@@ -3385,13 +3383,13 @@
             }
             if (voiceButtonContainer != null) voiceButtonContainer.setVisibility(View.VISIBLE);
             voiceButton.setVisibility(View.VISIBLE);
-            setVoiceButtonProxyVisible(true);
+            updateVoiceButtonProxyVisible(false);
             invalidatePressedFocusedStates(voiceButtonContainer, voiceButton);
             return true;
         } else {
             if (voiceButtonContainer != null) voiceButtonContainer.setVisibility(View.GONE);
             if (voiceButton != null) voiceButton.setVisibility(View.GONE);
-            setVoiceButtonProxyVisible(false);
+            updateVoiceButtonProxyVisible(false);
             return false;
         }
     }
@@ -3403,12 +3401,23 @@
         invalidatePressedFocusedStates(voiceButtonContainer, voiceButton);
     }
 
-    public void setVoiceButtonProxyVisible(boolean visible) {
+    public void updateVoiceButtonProxyVisible(boolean forceDisableVoiceButtonProxy) {
         final View voiceButtonProxy = findViewById(R.id.voice_button_proxy);
         if (voiceButtonProxy != null) {
+            boolean visible = !forceDisableVoiceButtonProxy &&
+                    mWorkspace.shouldVoiceButtonProxyBeVisible();
             voiceButtonProxy.setVisibility(visible ? View.VISIBLE : View.GONE);
+            voiceButtonProxy.bringToFront();
         }
     }
+
+    /**
+     * This is an overrid eot disable the voice button proxy.  If disabled is true, then the voice button proxy
+     * will be hidden regardless of what shouldVoiceButtonProxyBeVisible() returns.
+     */
+    public void disableVoiceButtonProxy(boolean disabled) {
+        updateVoiceButtonProxyVisible(disabled);
+    }
     /**
      * Sets the app market icon
      */
@@ -3611,22 +3620,6 @@
         return show;
     }
 
-    private boolean emailSent() {
-        String spKey = LauncherAppState.getSharedPreferencesKey();
-        SharedPreferences sp = getSharedPreferences(spKey, Context.MODE_PRIVATE);
-        boolean show = sp.getBoolean(CORRUPTION_EMAIL_SENT_KEY, false);
-        return show;
-    }
-
-    private void setEmailSent(boolean sent) {
-        String spKey = LauncherAppState.getSharedPreferencesKey();
-        SharedPreferences sp = getSharedPreferences(spKey, Context.MODE_PRIVATE);
-
-        SharedPreferences.Editor editor = sp.edit();
-        editor.putBoolean(CORRUPTION_EMAIL_SENT_KEY, sent);
-        editor.commit();
-    }
-
     private void toggleShowWeightWatcher() {
         String spKey = LauncherAppState.getSharedPreferencesKey();
         SharedPreferences sp = getSharedPreferences(spKey, Context.MODE_PRIVATE);
diff --git a/src/com/android/launcher3/LauncherViewPropertyAnimator.java b/src/com/android/launcher3/LauncherViewPropertyAnimator.java
index 8a9c35d..4cafbbf 100644
--- a/src/com/android/launcher3/LauncherViewPropertyAnimator.java
+++ b/src/com/android/launcher3/LauncherViewPropertyAnimator.java
@@ -35,7 +35,8 @@
             ALPHA,
             START_DELAY,
             DURATION,
-            INTERPOLATOR
+            INTERPOLATOR,
+            WITH_LAYER
     }
     EnumSet<Properties> mPropertiesToSet = EnumSet.noneOf(Properties.class);
     ViewPropertyAnimator mViewPropertyAnimator;
@@ -223,6 +224,9 @@
         if (mPropertiesToSet.contains(Properties.INTERPOLATOR)) {
             mViewPropertyAnimator.setInterpolator(mInterpolator);
         }
+        if (mPropertiesToSet.contains(Properties.WITH_LAYER)) {
+            mViewPropertyAnimator.withLayer();
+        }
         mViewPropertyAnimator.setListener(this);
         mViewPropertyAnimator.start();
         LauncherAnimUtils.cancelOnDestroyActivity(this);
@@ -263,4 +267,9 @@
         mAlpha = value;
         return this;
     }
+
+    public LauncherViewPropertyAnimator withLayer() {
+        mPropertiesToSet.add(Properties.WITH_LAYER);
+        return this;
+    }
 }
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 41687d3..0a15ecd 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -518,6 +518,9 @@
     void setCurrentPage(int currentPage) {
         if (!mScroller.isFinished()) {
             mScroller.abortAnimation();
+            // We need to clean up the next page here to avoid computeScrollHelper from
+            // updating current page on the pass.
+            mNextPage = INVALID_PAGE;
         }
         // don't introduce any checks like mCurrentPage == currentPage here-- if we change the
         // the default
diff --git a/src/com/android/launcher3/ThirdPartyWallpaperPickerListAdapter.java b/src/com/android/launcher3/ThirdPartyWallpaperPickerListAdapter.java
index 7ed1c1b..70ef7c3 100644
--- a/src/com/android/launcher3/ThirdPartyWallpaperPickerListAdapter.java
+++ b/src/com/android/launcher3/ThirdPartyWallpaperPickerListAdapter.java
@@ -39,7 +39,8 @@
     private final LayoutInflater mInflater;
     private final PackageManager mPackageManager;
 
-    private List<ResolveInfo> mThirdPartyWallpaperPickers = new ArrayList<ResolveInfo>();
+    private List<ThirdPartyWallpaperTile> mThirdPartyWallpaperPickers =
+            new ArrayList<ThirdPartyWallpaperTile>();
 
     public static class ThirdPartyWallpaperTile extends WallpaperPickerActivity.WallpaperTileInfo {
         private ResolveInfo mResolveInfo;
@@ -96,7 +97,7 @@
                     continue outerLoop;
                 }
             }
-            mThirdPartyWallpaperPickers.add(info);
+            mThirdPartyWallpaperPickers.add(new ThirdPartyWallpaperTile(info));
         }
     }
 
@@ -104,7 +105,7 @@
         return mThirdPartyWallpaperPickers.size();
     }
 
-    public ResolveInfo getItem(int position) {
+    public ThirdPartyWallpaperTile getItem(int position) {
         return mThirdPartyWallpaperPickers.get(position);
     }
 
@@ -123,7 +124,7 @@
 
         WallpaperPickerActivity.setWallpaperItemPaddingToZero((FrameLayout) view);
 
-        ResolveInfo info = mThirdPartyWallpaperPickers.get(position);
+        ResolveInfo info = mThirdPartyWallpaperPickers.get(position).mResolveInfo;
         TextView label = (TextView) view.findViewById(R.id.wallpaper_item_label);
         label.setText(info.loadLabel(mPackageManager));
         label.setCompoundDrawablesWithIntrinsicBounds(
diff --git a/src/com/android/launcher3/TransparentBars.java b/src/com/android/launcher3/TransparentBars.java
new file mode 100644
index 0000000..a12da9e
--- /dev/null
+++ b/src/com/android/launcher3/TransparentBars.java
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+package com.android.launcher3;
+
+import android.view.View;
+
+public class TransparentBars {
+    private static final int SYSTEM_UI_FLAG_TRANSPARENT_STATUS = 0x00001000;
+    private static final int SYSTEM_UI_FLAG_TRANSPARENT_NAVIGATION = 0x00002000;
+
+    // Behave properly on early K builds.  Replace with api check once sdk is baked.
+    public static final boolean SUPPORTED = !hasSystemUiFlag("ALLOW_TRANSIENT")
+            && hasSystemUiFlag("TRANSPARENT_STATUS")
+            && hasSystemUiFlag("TRANSPARENT_NAVIGATION");
+
+    private final View mTarget;
+
+    public TransparentBars(View target) {
+        mTarget = target;
+    }
+
+    public void requestTransparentBars(boolean transparent) {
+        if (!SUPPORTED) return;
+        int flags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+                  | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                  | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
+        if (transparent) {
+            flags |= SYSTEM_UI_FLAG_TRANSPARENT_STATUS | SYSTEM_UI_FLAG_TRANSPARENT_NAVIGATION;
+        }
+        mTarget.setSystemUiVisibility(flags);
+    }
+
+    private static boolean hasSystemUiFlag(String name) {
+        try {
+            return View.class.getField("SYSTEM_UI_FLAG_" + name) != null;
+        } catch (NoSuchFieldException e) {
+            return false;
+        }
+    }
+}
diff --git a/src/com/android/launcher3/WallpaperCropActivity.java b/src/com/android/launcher3/WallpaperCropActivity.java
index bc8df6c..343d0ff 100644
--- a/src/com/android/launcher3/WallpaperCropActivity.java
+++ b/src/com/android/launcher3/WallpaperCropActivity.java
@@ -75,6 +75,9 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         init();
+        if (!enableRotation()) {
+            setRequestedOrientation(Configuration.ORIENTATION_PORTRAIT);
+        }
     }
 
     protected void init() {
@@ -99,6 +102,12 @@
                         cropImageAndSetWallpaper(imageUri, null, finishActivityWhenDone);
                     }
                 });
+        TransparentBars transparentBars = new TransparentBars(findViewById(R.id.wallpaper_root));
+        transparentBars.requestTransparentBars(true);
+    }
+
+    public boolean enableRotation() {
+        return getResources().getBoolean(R.bool.allow_rotation);
     }
 
     public static String getSharedPreferencesKey() {
@@ -506,7 +515,9 @@
                             (int) returnRect.height(), Bitmap.Config.ARGB_8888);
                     if (tmp != null) {
                         Canvas c = new Canvas(tmp);
-                        c.drawBitmap(crop, m, new Paint());
+                        Paint p = new Paint();
+                        p.setFilterBitmap(true);
+                        c.drawBitmap(crop, m, p);
                         crop = tmp;
                     }
                 } else if (mRotation > 0) {
diff --git a/src/com/android/launcher3/WallpaperPickerActivity.java b/src/com/android/launcher3/WallpaperPickerActivity.java
index ef94fe8..7f49c86 100644
--- a/src/com/android/launcher3/WallpaperPickerActivity.java
+++ b/src/com/android/launcher3/WallpaperPickerActivity.java
@@ -77,6 +77,7 @@
     private OnClickListener mThumbnailOnClickListener;
 
     private LinearLayout mWallpapersView;
+    private View mWallpaperStrip;
 
     private ActionMode.Callback mActionModeCallback;
     private ActionMode mActionMode;
@@ -169,12 +170,19 @@
         }
     }
 
+    public void setWallpaperStripYOffset(float offset) {
+        mWallpaperStrip.setPadding(0, 0, 0, (int) offset);
+    }
+
     // called by onCreate; this is subclassed to overwrite WallpaperCropActivity
     protected void init() {
         setContentView(R.layout.wallpaper_picker);
+        final WallpaperRootView root = (WallpaperRootView) findViewById(R.id.wallpaper_root);
+        TransparentBars transparentBars = new TransparentBars(root);
+        transparentBars.requestTransparentBars(true);
 
         mCropView = (CropView) findViewById(R.id.cropView);
-        final View wallpaperStrip = findViewById(R.id.wallpaper_strip);
+        mWallpaperStrip = findViewById(R.id.wallpaper_strip);
         mCropView.setTouchCallback(new CropView.TouchCallback() {
             LauncherViewPropertyAnimator mAnim;
             @Override
@@ -182,11 +190,11 @@
                 if (mAnim != null) {
                     mAnim.cancel();
                 }
-                if (wallpaperStrip.getTranslationY() == 0) {
+                if (mWallpaperStrip.getTranslationY() == 0) {
                     mIgnoreNextTap = true;
                 }
-                mAnim = new LauncherViewPropertyAnimator(wallpaperStrip);
-                mAnim.translationY(wallpaperStrip.getHeight()).alpha(0f)
+                mAnim = new LauncherViewPropertyAnimator(mWallpaperStrip);
+                mAnim.translationY(mWallpaperStrip.getHeight()).alpha(0f)
                         .setInterpolator(new DecelerateInterpolator(0.75f));
                 mAnim.start();
             }
@@ -202,8 +210,8 @@
                     if (mAnim != null) {
                         mAnim.cancel();
                     }
-                    mAnim = new LauncherViewPropertyAnimator(wallpaperStrip);
-                    mAnim.translationY(0).alpha(1f)
+                    mAnim = new LauncherViewPropertyAnimator(mWallpaperStrip);
+                    mAnim.translationY(0f).alpha(1f)
                             .setInterpolator(new DecelerateInterpolator(0.75f));
                     mAnim.start();
                 }
@@ -401,6 +409,10 @@
         };
     }
 
+    public boolean enableRotation() {
+        return super.enableRotation() || Launcher.sForceEnableRotation;
+    }
+
     protected Bitmap getThumbnailOfLastPhoto() {
         Cursor cursor = MediaStore.Images.Media.query(getContentResolver(),
                 MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
@@ -419,10 +431,10 @@
 
     protected void onStop() {
         super.onStop();
-        final View wallpaperStrip = findViewById(R.id.wallpaper_strip);
-        if (wallpaperStrip.getTranslationY() > 0) {
-            wallpaperStrip.setTranslationY(0);
-            wallpaperStrip.setAlpha(1f);
+        mWallpaperStrip = findViewById(R.id.wallpaper_strip);
+        if (mWallpaperStrip.getTranslationY() > 0f) {
+            mWallpaperStrip.setTranslationY(0f);
+            mWallpaperStrip.setAlpha(1f);
         }
     }
 
diff --git a/src/com/android/launcher3/WallpaperRootView.java b/src/com/android/launcher3/WallpaperRootView.java
new file mode 100644
index 0000000..ceaa043
--- /dev/null
+++ b/src/com/android/launcher3/WallpaperRootView.java
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+package com.android.launcher3;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.widget.RelativeLayout;
+
+public class WallpaperRootView extends RelativeLayout {
+    private final WallpaperPickerActivity a;
+    public WallpaperRootView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        a = (WallpaperPickerActivity) context;
+    }
+    public WallpaperRootView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        a = (WallpaperPickerActivity) context;
+    }
+
+    protected boolean fitSystemWindows(Rect insets) {
+        a.setWallpaperStripYOffset(insets.bottom);
+        return true;
+    }
+}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 132f42d..ea348ef 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -1036,14 +1036,14 @@
             if (mCustomContentCallbacks != null) {
                 mCustomContentCallbacks.onShow();
                 mCustomContentShowTime = System.currentTimeMillis();
-                mLauncher.setVoiceButtonProxyVisible(false);
+                mLauncher.updateVoiceButtonProxyVisible(false);
             }
         } else if (hasCustomContent() && getNextPage() != 0 && mCustomContentShowing) {
             mCustomContentShowing = false;
             if (mCustomContentCallbacks != null) {
                 mCustomContentCallbacks.onHide();
                 mLauncher.resetQSBScroll();
-                mLauncher.setVoiceButtonProxyVisible(true);
+                mLauncher.updateVoiceButtonProxyVisible(false);
             }
         }
     };
@@ -1070,7 +1070,6 @@
     class WallpaperOffsetInterpolator implements Choreographer.FrameCallback {
         float mFinalOffset = 0.0f;
         float mCurrentOffset = 0.5f; // to force an initial update
-        //long mLastWallpaperOffsetUpdateTime;
         boolean mWaitingForUpdate;
         Choreographer mChoreographer;
         Interpolator mInterpolator;
@@ -1135,10 +1134,12 @@
             }
 
             // Exclude the leftmost page
-            final int firstIndex = isLayoutRtl() ? getChildCount() - 2 : 1;
+            final int startPage = hasCustomContent() ? 1 : 0;
+            final int firstIndex = isLayoutRtl() ? getChildCount() - 1 - startPage : startPage;
             // Exclude the last extra empty screen (if we have > MIN_PARALLAX_PAGE_SPAN pages)
-            int extra = numExtraScreensToIgnore();
-            final int lastIndex = isLayoutRtl() ? 0 + extra : getChildCount() - 1 - extra;
+            int emptyExtraPages = numExtraScreensToIgnore();
+            final int lastIndex =
+                    isLayoutRtl() ? 0 + emptyExtraPages : getChildCount() - 1 - emptyExtraPages;
 
             int firstPageScrollX = getScrollForPage(firstIndex);
             int scrollRange = getScrollForPage(lastIndex) - firstPageScrollX;
@@ -1166,7 +1167,8 @@
         }
 
         private int getNumScreensExcludingExtraEmptyScreenAndLeftmost() {
-            int numScrollingPages = getChildCount() - 1 - numExtraScreensToIgnore();
+            int numScrollingPages = getChildCount() - numExtraScreensToIgnore();
+            if (hasCustomContent()) numScrollingPages -= 1;
             return numScrollingPages;
         }
 
@@ -1823,6 +1825,16 @@
         return offsetDelta;
     }
 
+    boolean shouldVoiceButtonProxyBeVisible() {
+        if (isOnOrMovingToCustomContent()) {
+            return false;
+        }
+        if (mState != State.NORMAL) {
+            return false;
+        }
+        return true;
+    }
+
     Animator getChangeStateAnimation(final State state, boolean animated, int delay, int snapPage) {
         if (mState == state) {
             return null;
@@ -1975,11 +1987,7 @@
             setScaleY(mNewScale);
             setTranslationY(finalWorkspaceTranslationY);
         }
-        if (finalSearchBarAlpha == 0) {
-            mLauncher.setVoiceButtonProxyVisible(false);
-        } else {
-            mLauncher.setVoiceButtonProxyVisible(true);
-        }
+        mLauncher.updateVoiceButtonProxyVisible(false);
 
         if (stateIsSpringLoaded) {
             // Right now we're covered by Apps Customize