diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/com/android/launcher2/BubbleTextView.java | 3 | ||||
-rw-r--r-- | src/com/android/launcher2/CacheableTextView.java | 172 | ||||
-rw-r--r-- | src/com/android/launcher2/CellLayout.java | 8 | ||||
-rw-r--r-- | src/com/android/launcher2/HolographicOutlineHelper.java | 2 | ||||
-rw-r--r-- | src/com/android/launcher2/IconCache.java | 2 | ||||
-rw-r--r-- | src/com/android/launcher2/Launcher.java | 88 | ||||
-rw-r--r-- | src/com/android/launcher2/LauncherAppWidgetHost.java | 6 | ||||
-rw-r--r-- | src/com/android/launcher2/LauncherModel.java | 3 | ||||
-rw-r--r-- | src/com/android/launcher2/PagedView.java | 8 | ||||
-rw-r--r-- | src/com/android/launcher2/PagedViewIcon.java | 4 | ||||
-rw-r--r-- | src/com/android/launcher2/PagedViewWithDraggableItems.java | 6 | ||||
-rw-r--r-- | src/com/android/launcher2/Workspace.java | 213 |
12 files changed, 280 insertions, 235 deletions
diff --git a/src/com/android/launcher2/BubbleTextView.java b/src/com/android/launcher2/BubbleTextView.java index 4d1dbf8..f3aa342 100644 --- a/src/com/android/launcher2/BubbleTextView.java +++ b/src/com/android/launcher2/BubbleTextView.java @@ -37,7 +37,7 @@ import android.view.View; * because we want to make the bubble taller than the text and TextView's clip is * too aggressive. */ -public class BubbleTextView extends CacheableTextView implements VisibilityChangedBroadcaster { +public class BubbleTextView extends CachedTextView implements VisibilityChangedBroadcaster { static final float CORNER_RADIUS = 4.0f; static final float SHADOW_LARGE_RADIUS = 4.0f; static final float SHADOW_SMALL_RADIUS = 1.75f; @@ -118,7 +118,6 @@ public class BubbleTextView extends CacheableTextView implements VisibilityChang new FastBitmapDrawable(b), null, null); setText(info.title); - buildAndEnableCache(); setTag(info); } diff --git a/src/com/android/launcher2/CacheableTextView.java b/src/com/android/launcher2/CacheableTextView.java deleted file mode 100644 index da2f302..0000000 --- a/src/com/android/launcher2/CacheableTextView.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (C) 2010 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.launcher2; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Bitmap.Config; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.text.Layout; -import android.util.AttributeSet; -import android.widget.TextView; - -/* - * This class is a bit of a hack, designed to speed up long text labels in Launcher. It caches the - * text in a TextView to a bitmap and then just draws that Bitmap instead afterward, speeding up - * rendering. Marquee scrolling is not currently supported. - * - */ -public class CacheableTextView extends TextView { - private Bitmap mCache; - private final Paint mCachePaint = new Paint(); - private final Canvas mCacheCanvas = new Canvas(); - - private int mPrevAlpha = -1; - private boolean mIsBuildingCache; - boolean mWaitingToGenerateCache; - float mTextCacheLeft; - float mTextCacheTop; - float mTextCacheScrollX; - float mRectLeft, mRectTop; - private float mPaddingH = 0; - private float mPaddingV = 0; - private CharSequence mText; - - public CacheableTextView(Context context) { - super(context); - } - - public CacheableTextView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public CacheableTextView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - - protected int getCacheTopPadding() { - return 0; - } - protected int getCacheLeftPadding() { - return 0; - } - protected int getCacheRightPadding() { - return 0; - } - protected int getCacheBottomPadding() { - return 0; - } - - public void buildAndEnableCache() { - // Defers building the cache until the next draw to allow measuring - // and laying out. - buildAndEnableCache(false); - } - - public void buildAndEnableCache(boolean isImmediate) { - if (getLayout() == null || !isImmediate) { - mWaitingToGenerateCache = true; - return; - } - - final Layout layout = getLayout(); - final int left = getCompoundPaddingLeft(); - final int top = getExtendedPaddingTop(); - final float prevAlpha = getAlpha(); - - mTextCacheLeft = layout.getLineLeft(0) - getCacheLeftPadding(); - mTextCacheTop = top + layout.getLineTop(0) - mPaddingV - getCacheTopPadding(); - - mRectLeft = mScrollX + getLeft(); - mRectTop = 0; - mTextCacheScrollX = mScrollX; - - final float textCacheRight = - Math.min(left + layout.getLineRight(0) + mPaddingH, mScrollX + mRight - mLeft) + - getCacheRightPadding(); - final float textCacheBottom = top + layout.getLineBottom(0) + mPaddingV + - getCacheBottomPadding(); - final float xCharWidth = getPaint().measureText("x"); - - int width = (int) (textCacheRight - mTextCacheLeft + (2 * xCharWidth)); - int height = (int) (textCacheBottom - mTextCacheTop); - - if (width != 0 && height != 0) { - if (mCache != null) { - if (mCache.getWidth() != width || mCache.getHeight() != height) { - mCache.recycle(); - mCache = null; - } - } - if (mCache == null) { - mCache = Bitmap.createBitmap(width, height, Config.ARGB_8888); - mCacheCanvas.setBitmap(mCache); - } else { - mCacheCanvas.drawColor(0x00000000); - } - - mCacheCanvas.save(); - mCacheCanvas.translate(-mTextCacheLeft, -mTextCacheTop); - - mIsBuildingCache = true; - setAlpha(1.0f); - draw(mCacheCanvas); - setAlpha(prevAlpha); - mIsBuildingCache = false; - mCacheCanvas.restore(); - - // A hack-- we set the text to be one space (we don't make it empty just to avoid any - // potential issues with text measurement, like line height, etc.) so that the text view - // doesn't draw it anymore, since it's been cached. We have to manually rebuild - // the cache whenever the text is changed (which is never in Launcher) - mText = getText(); - setText(" "); - } - } - - public CharSequence getText() { - return (mText == null) ? super.getText() : mText; - } - - public void draw(Canvas canvas) { - if (mWaitingToGenerateCache && !mIsBuildingCache) { - buildAndEnableCache(true); - mWaitingToGenerateCache = false; - } - if (mCache != null && !mIsBuildingCache) { - canvas.drawBitmap(mCache, mTextCacheLeft - mTextCacheScrollX + mScrollX, - mTextCacheTop, mCachePaint); - } - super.draw(canvas); - } - - protected boolean isBuildingCache() { - return mIsBuildingCache; - } - - @Override - protected boolean onSetAlpha(int alpha) { - if (mPrevAlpha != alpha) { - mPrevAlpha = alpha; - mCachePaint.setAlpha(alpha); - super.onSetAlpha(alpha); - } - return true; - } -} diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java index fd389ca..45de630 100644 --- a/src/com/android/launcher2/CellLayout.java +++ b/src/com/android/launcher2/CellLayout.java @@ -417,7 +417,7 @@ public class CellLayout extends ViewGroup implements Dimmable, VisibilityChanged } public void updateCache() { - mCacheCanvas.drawColor(0x00000000, Mode.CLEAR); + mCacheCanvas.drawColor(0, Mode.CLEAR); float alpha = getAlpha(); setAlpha(1.0f); @@ -625,6 +625,7 @@ public class CellLayout extends ViewGroup implements Dimmable, VisibilityChanged child.setId(childId); addView(child, index, lp); + child.setAlpha(getAlpha()); if (child instanceof VisibilityChangedBroadcaster) { VisibilityChangedBroadcaster v = (VisibilityChangedBroadcaster) child; v.setVisibilityChangedListener(this); @@ -972,6 +973,7 @@ public class CellLayout extends ViewGroup implements Dimmable, VisibilityChanged } } prepareCacheBitmap(); + invalidateCache(); } @Override @@ -1388,7 +1390,9 @@ public class CellLayout extends ViewGroup implements Dimmable, VisibilityChanged lp.isDragging = false; lp.dropped = true; lp.animateDrop = animate; - child.setVisibility(View.INVISIBLE); + if (animate) { + child.setVisibility(View.INVISIBLE); + } child.requestLayout(); } } diff --git a/src/com/android/launcher2/HolographicOutlineHelper.java b/src/com/android/launcher2/HolographicOutlineHelper.java index 6d0899d..1efc123 100644 --- a/src/com/android/launcher2/HolographicOutlineHelper.java +++ b/src/com/android/launcher2/HolographicOutlineHelper.java @@ -184,7 +184,7 @@ public class HolographicOutlineHelper { // draw the inner and outer blur srcDstCanvas.setBitmap(srcDst); - srcDstCanvas.drawColor(0x00000000, PorterDuff.Mode.CLEAR); + srcDstCanvas.drawColor(0, PorterDuff.Mode.CLEAR); mHolographicPaint.setColor(color); srcDstCanvas.drawBitmap(thickInnerBlur, thickInnerBlurOffset[0], thickInnerBlurOffset[1], mHolographicPaint); diff --git a/src/com/android/launcher2/IconCache.java b/src/com/android/launcher2/IconCache.java index ae8c98a..468645b 100644 --- a/src/com/android/launcher2/IconCache.java +++ b/src/com/android/launcher2/IconCache.java @@ -67,7 +67,7 @@ public class IconCache { public Drawable getFullResDefaultActivityIcon() { return getFullResIcon(Resources.getSystem(), - com.android.internal.R.drawable.sym_def_app_icon); + com.android.internal.R.mipmap.sym_def_app_icon); } public Drawable getFullResIcon(Resources resources, int iconId) { diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java index 7faa520..2281c84 100644 --- a/src/com/android/launcher2/Launcher.java +++ b/src/com/android/launcher2/Launcher.java @@ -27,13 +27,13 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; +import android.animation.TimeInterpolator; import android.animation.ValueAnimator; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.app.SearchManager; import android.app.StatusBarManager; -import android.app.WallpaperManager; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProviderInfo; import android.content.ActivityNotFoundException; @@ -77,7 +77,6 @@ import android.text.SpannableStringBuilder; import android.text.TextUtils; import android.text.method.TextKeyListener; import android.util.Log; -import android.view.Display; import android.view.HapticFeedbackConstants; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -89,6 +88,7 @@ import android.view.ViewGroup; import android.view.WindowManager; import android.view.View.OnLongClickListener; import android.view.accessibility.AccessibilityEvent; +import android.view.animation.DecelerateInterpolator; import android.view.inputmethod.InputMethodManager; import android.widget.Advanceable; import android.widget.EditText; @@ -106,6 +106,7 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.FileNotFoundException; import java.io.IOException; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -308,7 +309,6 @@ public final class Launcher extends Activity loadHotseats(); checkForLocaleChange(); - setWallpaperDimension(); setContentView(R.layout.launcher); mHomeCustomizationDrawer = (TabHost) findViewById(R.id.customization_drawer); if (mHomeCustomizationDrawer != null) { @@ -546,18 +546,6 @@ public final class Launcher extends Activity } } - private void setWallpaperDimension() { - WallpaperManager wpm = (WallpaperManager)getSystemService(WALLPAPER_SERVICE); - - Display display = getWindowManager().getDefaultDisplay(); - // TODO: Put back when we decide about scrolling the wallpaper - // boolean isPortrait = display.getWidth() < display.getHeight(); - // final int width = isPortrait ? display.getWidth() : display.getHeight(); - // final int height = isPortrait ? display.getHeight() : display.getWidth(); - wpm.suggestDesiredDimensions(Math.max(display.getWidth(), display.getHeight()), - Math.max(display.getWidth(), display.getHeight())); - } - // Note: This doesn't do all the client-id magic that BrowserProvider does // in Browser. (http://b/2425179) private Uri getDefaultBrowserUri() { @@ -1001,6 +989,7 @@ public final class Launcher extends Activity workspace.setOnLongClickListener(this); workspace.setDragController(dragController); workspace.setLauncher(this); + workspace.setWallpaperDimension(); deleteZone.setLauncher(this); deleteZone.setDragController(dragController); @@ -1325,6 +1314,7 @@ public final class Launcher extends Activity (System.currentTimeMillis() - mAutoAdvanceSentTime)); } mHandler.removeMessages(ADVANCE_MSG); + mHandler.removeMessages(0); // Remove messages sent using postDelayed() } } } @@ -1425,8 +1415,10 @@ public final class Launcher extends Activity } if (!mWorkspace.isDefaultPageShowing()) { // on the phone, we don't animate the change to the workspace if all apps is visible - mWorkspace.moveToDefaultScreen(alreadyOnHome && - (LauncherApplication.isScreenXLarge() || mState != State.ALL_APPS)); + boolean animate = alreadyOnHome && + (LauncherApplication.isScreenXLarge() || mState != State.ALL_APPS); + mWorkspace.moveToDefaultScreen(animate); + if (!animate) mWorkspace.updateWallpaperOffsetImmediately(); } showWorkspace(alreadyOnHome); @@ -1503,6 +1495,9 @@ public final class Launcher extends Activity } catch (NullPointerException ex) { Log.w(TAG, "problem while stopping AppWidgetHost during Launcher destruction", ex); } + mAppWidgetHost = null; + + mWidgetsToAdvance.clear(); TextKeyListener.getInstance().release(); @@ -1521,6 +1516,11 @@ public final class Launcher extends Activity } unregisterReceiver(mCloseSystemDialogsReceiver); + + ((ViewGroup) mWorkspace.getParent()).removeAllViews(); + mWorkspace.removeAllViews(); + mWorkspace = null; + mDragController = null; } @Override @@ -1987,6 +1987,7 @@ public final class Launcher extends Activity for (ItemInfo item: mDesktopItems) { item.unbind(); } + mDesktopItems.clear(); } /** @@ -2647,10 +2648,11 @@ public final class Launcher extends Activity // Set pivotY so that at the starting zoom factor, the view is partially // visible. Modifying initialHeightFactor changes how much of the view is // initially showing, and hence the perceived angle from which the view enters. - final float initialHeightFactor = 0.2f; if (state == State.ALL_APPS) { - view.setPivotY((1 + initialHeightFactor) * height); + final float initialHeightFactor = 0.165f; + view.setPivotY((1 - initialHeightFactor) * height); } else { + final float initialHeightFactor = 0.2f; view.setPivotY(-initialHeightFactor * height); } } @@ -2663,15 +2665,23 @@ public final class Launcher extends Activity */ private void cameraZoomOut(State toState, boolean animated) { final Resources res = getResources(); - final int duration = res.getInteger(R.integer.config_allAppsZoomInTime); - final float scale = (float) res.getInteger(R.integer.config_allAppsZoomScaleFactor); final boolean toAllApps = (toState == State.ALL_APPS); + + final int duration = toAllApps ? + res.getInteger(R.integer.config_allAppsZoomInTime) : + res.getInteger(R.integer.config_customizeZoomInTime); + + final float scale = toAllApps ? + (float) res.getInteger(R.integer.config_allAppsZoomScaleFactor) : + (float) res.getInteger(R.integer.config_customizeZoomScaleFactor); + final View toView = toAllApps ? (View) mAllAppsGrid : mHomeCustomizationDrawer; setPivotsForZoom(toView, toState, scale); if (toAllApps) { mWorkspace.shrink(ShrinkState.BOTTOM_HIDDEN, animated); + toView.setAlpha(0f); } else { mWorkspace.shrink(ShrinkState.TOP, animated); } @@ -2680,8 +2690,17 @@ public final class Launcher extends Activity ValueAnimator scaleAnim = ObjectAnimator.ofPropertyValuesHolder(toView, PropertyValuesHolder.ofFloat("scaleX", scale, 1.0f), PropertyValuesHolder.ofFloat("scaleY", scale, 1.0f)); + scaleAnim.setDuration(duration); + if (toAllApps) { + ObjectAnimator alphaAnim = ObjectAnimator.ofPropertyValuesHolder(toView, + PropertyValuesHolder.ofFloat("alpha", 1.0f)); + alphaAnim.setInterpolator(new DecelerateInterpolator(1.5f)); + alphaAnim.setDuration(duration); + alphaAnim.start(); + } + scaleAnim.setInterpolator(new Workspace.ZoomOutInterpolator()); scaleAnim.addListener(new AnimatorListenerAdapter() { @Override @@ -2690,7 +2709,9 @@ public final class Launcher extends Activity toView.setTranslationX(0.0f); toView.setTranslationY(0.0f); toView.setVisibility(View.VISIBLE); - toView.setAlpha(1.0f); + if (!toAllApps) { + toView.setAlpha(1.0f); + } } @Override public void onAnimationEnd(Animator animation) { @@ -2707,7 +2728,7 @@ public final class Launcher extends Activity hideAndShowToolbarButtons(toState, toolbarShowAnim, toolbarHideAnim); // toView should appear right at the end of the workspace shrink animation - final int startDelay = res.getInteger(R.integer.config_workspaceShrinkTime) - duration; + final int startDelay = 0; if (mStateAnimation != null) mStateAnimation.cancel(); mStateAnimation = new AnimatorSet(); @@ -2726,6 +2747,8 @@ public final class Launcher extends Activity toView.setVisibility(View.VISIBLE); hideAndShowToolbarButtons(toState, null, null); } + mWorkspace.setVerticalWallpaperOffset(toAllApps ? + Workspace.WallpaperVerticalOffset.TOP : Workspace.WallpaperVerticalOffset.BOTTOM); } /** @@ -2740,10 +2763,17 @@ public final class Launcher extends Activity private void cameraZoomIn(State fromState, boolean animated, boolean springLoaded) { Resources res = getResources(); - int duration = res.getInteger(R.integer.config_allAppsZoomOutTime); - float scaleFactor = (float) res.getInteger(R.integer.config_allAppsZoomScaleFactor); - final View fromView = - (fromState == State.ALL_APPS) ? (View) mAllAppsGrid : mHomeCustomizationDrawer; + final boolean fromAllApps = (fromState == State.ALL_APPS); + + int duration = fromAllApps ? + res.getInteger(R.integer.config_allAppsZoomOutTime) : + res.getInteger(R.integer.config_customizeZoomOutTime); + + float scaleFactor = fromAllApps ? + (float) res.getInteger(R.integer.config_allAppsZoomScaleFactor) : + (float) res.getInteger(R.integer.config_customizeZoomScaleFactor); + + final View fromView = fromAllApps ? (View) mAllAppsGrid : mHomeCustomizationDrawer; mCustomizePagedView.endChoiceMode(); mAllAppsPagedView.endChoiceMode(); @@ -2766,6 +2796,7 @@ public final class Launcher extends Activity ValueAnimator alphaAnim = ObjectAnimator.ofPropertyValuesHolder(fromView, PropertyValuesHolder.ofFloat("alpha", 1.0f, 0.0f)); alphaAnim.setDuration(res.getInteger(R.integer.config_allAppsFadeOutTime)); + alphaAnim.setInterpolator(new DecelerateInterpolator(1.5f)); alphaAnim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { @@ -2792,6 +2823,7 @@ public final class Launcher extends Activity hideAndShowToolbarButtons(State.WORKSPACE, null, null); } } + mWorkspace.setVerticalWallpaperOffset(Workspace.WallpaperVerticalOffset.MIDDLE); } /** @@ -2869,6 +2901,8 @@ public final class Launcher extends Activity toView.setVisibility(View.VISIBLE); hideAndShowToolbarButtons(toState, null, null); } + mWorkspace.setVerticalWallpaperOffset((toState == State.ALL_APPS) ? + Workspace.WallpaperVerticalOffset.TOP : Workspace.WallpaperVerticalOffset.BOTTOM); } void showAllApps(boolean animated) { diff --git a/src/com/android/launcher2/LauncherAppWidgetHost.java b/src/com/android/launcher2/LauncherAppWidgetHost.java index 46e66e7..68d4903 100644 --- a/src/com/android/launcher2/LauncherAppWidgetHost.java +++ b/src/com/android/launcher2/LauncherAppWidgetHost.java @@ -36,4 +36,10 @@ public class LauncherAppWidgetHost extends AppWidgetHost { AppWidgetProviderInfo appWidget) { return new LauncherAppWidgetHostView(context); } + + @Override + public void stopListening() { + super.stopListening(); + clearViews(); + } } diff --git a/src/com/android/launcher2/LauncherModel.java b/src/com/android/launcher2/LauncherModel.java index 713268a..7e72610 100644 --- a/src/com/android/launcher2/LauncherModel.java +++ b/src/com/android/launcher2/LauncherModel.java @@ -492,6 +492,9 @@ public class LauncherModel extends BroadcastReceiver { mLoaderTask.stopLocked(); } } + mItems.clear(); + mAppWidgets.clear(); + mFolders.clear(); } /** diff --git a/src/com/android/launcher2/PagedView.java b/src/com/android/launcher2/PagedView.java index 6c9aac1..bb59678 100644 --- a/src/com/android/launcher2/PagedView.java +++ b/src/com/android/launcher2/PagedView.java @@ -888,6 +888,14 @@ public abstract class PagedView extends ViewGroup { invalidate(); } + protected float maxOverScroll() { + // Using the formula in overScroll, assuming that f = 1.0 (which it should generally not + // exceed). Used to find out how much extra wallpaper we need for the overscroll effect + float f = 1.0f; + f = f / (Math.abs(f)) * (overScrollInfluenceCurve(Math.abs(f))); + return OVERSCROLL_DAMP_FACTOR * f; + } + @Override public boolean onTouchEvent(MotionEvent ev) { // Skip touch handling if there are no pages to swipe diff --git a/src/com/android/launcher2/PagedViewIcon.java b/src/com/android/launcher2/PagedViewIcon.java index 6ce308b..0af7b8a 100644 --- a/src/com/android/launcher2/PagedViewIcon.java +++ b/src/com/android/launcher2/PagedViewIcon.java @@ -39,7 +39,7 @@ import com.android.launcher.R; * An icon on a PagedView, specifically for items in the launcher's paged view (with compound * drawables on the top). */ -public class PagedViewIcon extends CacheableTextView implements Checkable { +public class PagedViewIcon extends CachedTextView implements Checkable { private static final String TAG = "PagedViewIcon"; // holographic outline @@ -143,7 +143,6 @@ public class PagedViewIcon extends CacheableTextView implements Checkable { mIcon = info.iconBitmap; setCompoundDrawablesWithIntrinsicBounds(null, new FastBitmapDrawable(mIcon), null, null); setText(info.title); - buildAndEnableCache(); setTag(info); if (createHolographicOutlines) { @@ -160,7 +159,6 @@ public class PagedViewIcon extends CacheableTextView implements Checkable { modelIconCache.getFullResIcon(info, packageManager), mContext); setCompoundDrawablesWithIntrinsicBounds(null, new FastBitmapDrawable(mIcon), null, null); setText(info.loadLabel(packageManager)); - buildAndEnableCache(); setTag(info); if (createHolographicOutlines) { diff --git a/src/com/android/launcher2/PagedViewWithDraggableItems.java b/src/com/android/launcher2/PagedViewWithDraggableItems.java index f24d7e0..3f72292 100644 --- a/src/com/android/launcher2/PagedViewWithDraggableItems.java +++ b/src/com/android/launcher2/PagedViewWithDraggableItems.java @@ -150,4 +150,10 @@ public abstract class PagedViewWithDraggableItems extends PagedView public void setDragSlopeThreshold(float dragSlopeThreshold) { mDragSlopeThreshold = dragSlopeThreshold; } + + @Override + protected void onDetachedFromWindow() { + mLastTouchedItem = null; + super.onDetachedFromWindow(); + } } diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java index 9fcd1b4..8e0308c 100644 --- a/src/com/android/launcher2/Workspace.java +++ b/src/com/android/launcher2/Workspace.java @@ -203,6 +203,17 @@ public class Workspace extends SmoothPagedView private final Camera mCamera = new Camera(); private final float mTempFloat2[] = new float[2]; + enum WallpaperVerticalOffset { TOP, MIDDLE, BOTTOM }; + int mWallpaperWidth; + int mWallpaperHeight; + float mTargetHorizontalWallpaperOffset = 0.0f; + float mTargetVerticalWallpaperOffset = 0.5f; + float mHorizontalWallpaperOffset = 0.0f; + float mVerticalWallpaperOffset = 0.5f; + long mLastWallpaperOffsetUpdateTime; + boolean mWallpaperOffsetDirty; + boolean mUpdateWallpaperOffsetImmediately = false; + /** * Used to inflate the Workspace from XML. * @@ -387,17 +398,6 @@ public class Workspace extends SmoothPagedView } /** - * Sets the current screen. - * - * @param currentPage - */ - @Override - void setCurrentPage(int currentPage) { - super.setCurrentPage(currentPage); - updateWallpaperOffset(mScrollX); - } - - /** * Adds the specified child in the specified screen. The position and dimension of * the child are defined by x, y, spanX and spanY. * @@ -558,17 +558,157 @@ public class Workspace extends SmoothPagedView Launcher.setScreen(mCurrentPage); }; - private void updateWallpaperOffset(int scrollRange) { - final boolean isStaticWallpaper = (mWallpaperManager != null) && - (mWallpaperManager.getWallpaperInfo() == null); - if (LauncherApplication.isScreenXLarge() && !isStaticWallpaper) { - IBinder token = getWindowToken(); - if (token != null) { - mWallpaperManager.setWallpaperOffsetSteps(1.0f / (getChildCount() - 1), 0 ); - mWallpaperManager.setWallpaperOffsets(getWindowToken(), - Math.max(0.f, Math.min(mScrollX/(float)scrollRange, 1.f)), 0); - } + // As a ratio of screen height, the total distance we want the parallax effect to span + // vertically + private float wallpaperTravelToScreenHeightRatio(int width, int height) { + return 1.1f; + } + + // As a ratio of screen height, the total distance we want the parallax effect to span + // horizontally + private float wallpaperTravelToScreenWidthRatio(int width, int height) { + float aspectRatio = width / (float) height; + + // At an aspect ratio of 16/10, the wallpaper parallax effect should span 1.5 * screen width + // At an aspect ratio of 10/16, the wallpaper parallax effect should span 1.2 * screen width + // We will use these two data points to extrapolate how much the wallpaper parallax effect + // to span (ie travel) at any aspect ratio: + + final float ASPECT_RATIO_LANDSCAPE = 16/10f; + final float ASPECT_RATIO_PORTRAIT = 10/16f; + final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE = 1.5f; + final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT = 1.2f; + + // To find out the desired width at different aspect ratios, we use the following two + // formulas, where the coefficient on x is the aspect ratio (width/height): + // (16/10)x + y = 1.5 + // (10/16)x + y = 1.2 + // We solve for x and y and end up with a final formula: + final float x = + (WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE - WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT) / + (ASPECT_RATIO_LANDSCAPE - ASPECT_RATIO_PORTRAIT); + final float y = WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT - x * ASPECT_RATIO_PORTRAIT; + return x * aspectRatio + y; + } + + // The range of scroll values for Workspace + private int getScrollRange() { + return getChildOffset(getChildCount() - 1) - getChildOffset(0); + } + + protected void setWallpaperDimension() { + WallpaperManager wpm = + (WallpaperManager) mLauncher.getSystemService(Context.WALLPAPER_SERVICE); + + Display display = mLauncher.getWindowManager().getDefaultDisplay(); + final int maxDim = Math.max(display.getWidth(), display.getHeight()); + final int minDim = Math.min(display.getWidth(), display.getHeight()); + + // We need to ensure that there is enough extra space in the wallpaper for the intended + // parallax effects + mWallpaperWidth = (int) (maxDim * wallpaperTravelToScreenWidthRatio(maxDim, minDim)); + mWallpaperHeight = (int)(maxDim * wallpaperTravelToScreenHeightRatio(maxDim, minDim)); + wpm.suggestDesiredDimensions(mWallpaperWidth, mWallpaperHeight); + } + + public void setVerticalWallpaperOffset(WallpaperVerticalOffset offsetPosition) { + float offset = 0.5f; + Display display = mLauncher.getWindowManager().getDefaultDisplay(); + int wallpaperTravelHeight = (int) (display.getHeight() * + wallpaperTravelToScreenHeightRatio(display.getWidth(), display.getHeight())); + float offsetFromCenter = (wallpaperTravelHeight / (float) mWallpaperHeight) / 2f; + switch (offsetPosition) { + case TOP: + offset = 0.5f - offsetFromCenter; + break; + case MIDDLE: + offset = 0.5f; + break; + case BOTTOM: + offset = 0.5f + offsetFromCenter; + break; + } + mTargetVerticalWallpaperOffset = offset; + mWallpaperOffsetDirty = true; + } + + private void updateHorizontalWallpaperOffset() { + if (LauncherApplication.isScreenXLarge()) { + Display display = mLauncher.getWindowManager().getDefaultDisplay(); + // The wallpaper travel width is how far, from left to right, the wallpaper will move + // at this orientation (for example, in portrait mode we don't move all the way to the + // edges of the wallpaper, or otherwise the parallax effect would be too strong) + int wallpaperTravelWidth = (int) (display.getWidth() * + wallpaperTravelToScreenWidthRatio(display.getWidth(), display.getHeight())); + + // Account for overscroll: you only see the absolute edge of the wallpaper if + // you overscroll as far as you can in landscape mode + int overscrollOffset = (int) (maxOverScroll() * display.getWidth()); + float overscrollRatio = overscrollOffset / (float) getScrollRange(); + int scrollRangeWithOverscroll = getScrollRange() + 2 * overscrollOffset; + + // Set wallpaper offset steps (1 / (number of screens - 1)) + // We have 3 vertical offset states (centered, and then top/bottom aligned + // for all apps/customize) + mWallpaperManager.setWallpaperOffsetSteps(1.0f / (getChildCount() - 1), 1.0f / (3 - 1)); + + float scrollProgress = + mScrollX / (float) scrollRangeWithOverscroll + overscrollRatio; + float offsetInDips = wallpaperTravelWidth * scrollProgress + + (mWallpaperWidth - wallpaperTravelWidth) / 2; + float offset = offsetInDips / (float) mWallpaperWidth; + + mTargetHorizontalWallpaperOffset = Math.max(0f, Math.min(offset, 1.0f)); + mWallpaperOffsetDirty = true; + } + } + + public void updateWallpaperOffsetImmediately() { + mUpdateWallpaperOffsetImmediately = true; + } + + private void updateWallpaperOffsets(boolean immediate) { + long currentTime = System.currentTimeMillis(); + long millisecondsSinceLastUpdate = currentTime - mLastWallpaperOffsetUpdateTime; + millisecondsSinceLastUpdate = Math.min((long) (1000/30f), millisecondsSinceLastUpdate); + millisecondsSinceLastUpdate = Math.min(1L, millisecondsSinceLastUpdate); + final float PERCENT_TO_CATCH_UP_IN_100_MS_HORIZONTAL = 25f; + final float PERCENT_TO_CATCH_UP_IN_100_MS_VERTICAL = 25f; + final float UPDATE_THRESHOLD = 0.0001f; + float hOffsetDelta = mTargetHorizontalWallpaperOffset - mHorizontalWallpaperOffset; + float vOffsetDelta = mTargetVerticalWallpaperOffset - mVerticalWallpaperOffset; + boolean stopUpdating = + Math.abs(hOffsetDelta / mTargetHorizontalWallpaperOffset) < UPDATE_THRESHOLD && + Math.abs(vOffsetDelta / mTargetVerticalWallpaperOffset) < UPDATE_THRESHOLD; + + if (stopUpdating || immediate) { + mHorizontalWallpaperOffset = mTargetHorizontalWallpaperOffset; + mVerticalWallpaperOffset = mTargetVerticalWallpaperOffset; + } else { + float percentToCatchUpVertical = + millisecondsSinceLastUpdate / 100f * PERCENT_TO_CATCH_UP_IN_100_MS_VERTICAL; + float percentToCatchUpHorizontal = + millisecondsSinceLastUpdate / 100f * PERCENT_TO_CATCH_UP_IN_100_MS_HORIZONTAL; + mHorizontalWallpaperOffset += percentToCatchUpHorizontal * hOffsetDelta; + mVerticalWallpaperOffset += + percentToCatchUpVertical * (mTargetVerticalWallpaperOffset - mVerticalWallpaperOffset); + } + IBinder token = getWindowToken(); + if (token != null) { + mWallpaperManager.setWallpaperOffsets(getWindowToken(), + mHorizontalWallpaperOffset, mVerticalWallpaperOffset); } + if (!stopUpdating && !immediate) { + invalidate(); + mWallpaperOffsetDirty = true; + } + mLastWallpaperOffsetUpdateTime = System.currentTimeMillis(); + } + + @Override + public void computeScroll() { + super.computeScroll(); + updateHorizontalWallpaperOffset(); } public void showOutlines() { @@ -737,6 +877,9 @@ public class Workspace extends SmoothPagedView @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + if (mFirstLayout && mCurrentPage >= 0 && mCurrentPage < getChildCount()) { + mUpdateWallpaperOffsetImmediately = true; + } super.onLayout(changed, left, top, right, bottom); // if shrinkToBottom() is called on initialization, it has to be deferred @@ -777,12 +920,15 @@ public class Workspace extends SmoothPagedView @Override protected void onDraw(Canvas canvas) { + if (mWallpaperOffsetDirty) { + updateWallpaperOffsets(mUpdateWallpaperOffsetImmediately); + mWallpaperOffsetDirty = false; + mUpdateWallpaperOffsetImmediately = false; + } + // Draw the background gradient if necessary if (mBackground != null && mBackgroundAlpha > 0.0f) { int alpha = (int) (mBackgroundAlpha * 255); - mBackground.setAlpha(alpha); - mBackground.setBounds(mScrollX, 0, mScrollX + getMeasuredWidth(), getMeasuredHeight()); - mBackground.draw(canvas); if (mDrawCustomizeTrayBackground) { // Find out where to offset the gradient for the customization tray content mCustomizationDrawer.getLocationOnScreen(mCustomizationDrawerPos); @@ -800,9 +946,15 @@ public class Workspace extends SmoothPagedView // Draw the bg gradient final int offset = (int) (mCustomizationDrawerPos[1] + mCustomizationDrawerTransformedPos[1]); + mBackground.setAlpha(alpha); mBackground.setBounds(mScrollX, offset, mScrollX + getMeasuredWidth(), offset + getMeasuredHeight()); mBackground.draw(canvas); + } else { + mBackground.setAlpha(alpha); + mBackground.setBounds(mScrollX, 0, mScrollX + getMeasuredWidth(), + getMeasuredHeight()); + mBackground.draw(canvas); } } super.onDraw(canvas); @@ -1031,6 +1183,7 @@ public class Workspace extends SmoothPagedView getResources().getDimension(R.dimen.allAppsSmallScreenVerticalMarginLandscape)); float finalAlpha = 1.0f; float extraShrinkFactor = 1.0f; + if (shrinkState == ShrinkState.BOTTOM_VISIBLE) { newY = screenHeight - newY - scaledPageHeight; } else if (shrinkState == ShrinkState.BOTTOM_HIDDEN) { @@ -1048,6 +1201,13 @@ public class Workspace extends SmoothPagedView getResources().getDimension(R.dimen.customizeSmallScreenVerticalMarginLandscape)); } + int duration; + if (shrinkState == ShrinkState.BOTTOM_HIDDEN || shrinkState == ShrinkState.BOTTOM_VISIBLE) { + duration = res.getInteger(R.integer.config_allAppsWorkspaceShrinkTime); + } else { + duration = res.getInteger(R.integer.config_customizeWorkspaceShrinkTime); + } + // We animate all the screens to the centered position in workspace // At the same time, the screens become greyed/dimmed @@ -1062,17 +1222,16 @@ public class Workspace extends SmoothPagedView if (mAnimator != null) { mAnimator.cancel(); } + mAnimator = new AnimatorSet(); for (int i = 0; i < screenCount; i++) { - CellLayout cl = (CellLayout) getChildAt(i); + final CellLayout cl = (CellLayout) getChildAt(i); float rotation = (-i + 2) * WORKSPACE_ROTATION; float rotationScaleX = (float) (1.0f / Math.cos(Math.PI * rotation / 180.0f)); float rotationScaleY = getYScaleForScreen(i); if (animated) { - final int duration = res.getInteger(R.integer.config_workspaceShrinkTime); - ObjectAnimator animWithInterpolator = ObjectAnimator.ofPropertyValuesHolder(cl, PropertyValuesHolder.ofFloat("x", newX), PropertyValuesHolder.ofFloat("y", newY), |