diff options
Diffstat (limited to 'src/com/android')
-rw-r--r-- | src/com/android/launcher3/CellLayout.java | 16 | ||||
-rw-r--r-- | src/com/android/launcher3/DeviceProfile.java | 2 | ||||
-rw-r--r-- | src/com/android/launcher3/Folder.java | 472 | ||||
-rw-r--r-- | src/com/android/launcher3/FolderIcon.java | 134 | ||||
-rw-r--r-- | src/com/android/launcher3/HiddenFolderFragment.java | 8 | ||||
-rw-r--r-- | src/com/android/launcher3/Launcher.java | 40 | ||||
-rw-r--r-- | src/com/android/launcher3/SearchDropTargetBar.java | 21 | ||||
-rw-r--r-- | src/com/android/launcher3/Workspace.java | 6 |
8 files changed, 581 insertions, 118 deletions
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java index 2ecc639f7..b3cc89896 100644 --- a/src/com/android/launcher3/CellLayout.java +++ b/src/com/android/launcher3/CellLayout.java @@ -482,13 +482,15 @@ public class CellLayout extends ViewGroup { // Draw inner ring d = FolderRingAnimator.sSharedInnerRingDrawable; - width = (int) (fra.getInnerRingSize() * getChildrenScale()); - height = width; - canvas.save(); - canvas.translate(centerX - width / 2, centerY - width / 2); - d.setBounds(0, 0, width, height); - d.draw(canvas); - canvas.restore(); + if (d != null) { + width = (int) (fra.getInnerRingSize() * getChildrenScale()); + height = width; + canvas.save(); + canvas.translate(centerX - width / 2, centerY - width / 2); + d.setBounds(0, 0, width, height); + d.draw(canvas); + canvas.restore(); + } } } diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index d6c401d4f..47ed9b242 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -462,7 +462,7 @@ public class DeviceProfile { // Folder folderCellWidthPx = cellWidthPx + 3 * edgeMarginPx; folderCellHeightPx = cellHeightPx + edgeMarginPx; - folderBackgroundOffset = -edgeMarginPx; + folderBackgroundOffset = 0; folderIconSizePx = iconSizePx + 2 * -folderBackgroundOffset; // All Apps diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java index e66838fa3..7254a639f 100644 --- a/src/com/android/launcher3/Folder.java +++ b/src/com/android/launcher3/Folder.java @@ -25,14 +25,17 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.res.Resources; +import android.graphics.Bitmap; import android.graphics.PointF; import android.graphics.Rect; +import android.graphics.drawable.BitmapDrawable; import android.os.Bundle; import android.os.SystemClock; import android.support.v4.widget.AutoScrollHelper; import android.text.InputType; import android.text.Selection; import android.text.Spannable; +import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; import android.util.Pair; @@ -43,14 +46,16 @@ import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; +import android.view.ViewAnimationUtils; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.view.animation.AccelerateInterpolator; +import android.view.animation.DecelerateInterpolator; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; +import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; -import android.widget.RelativeLayout; import android.widget.ScrollView; import android.widget.TextView; @@ -115,6 +120,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList private Alarm mReorderAlarm = new Alarm(); private Alarm mOnExitAlarm = new Alarm(); private int mFolderNameHeight; + private int mFolderLockHeight; private Rect mTempRect = new Rect(); private boolean mDragInProgress = false; private boolean mDeleteFolderOnDropCompleted = false; @@ -122,11 +128,15 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList private boolean mItemAddedBackToSelfViaIcon = false; FolderEditText mFolderName; ImageView mFolderLock; - RelativeLayout mFolderTitleSection; private float mFolderIconPivotX; private float mFolderIconPivotY; private boolean mHideLabels; + // Instance variables to keep track of the left/top values calculated by centerAboutIcon() for + // use by the prepareOutline() method + private float mLeft; + private float mTop; + private boolean mIsEditingName = false; private InputMethodManager mInputMethodManager; @@ -239,10 +249,9 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList } mFolderLock = (ImageView) findViewById(R.id.folder_lock); - mFolderTitleSection = (RelativeLayout) findViewById(R.id.folder_title_section); mFolderLock.measure(measureSpec, measureSpec); mFolderLock.setOnClickListener(this); - mFolderTitleSection.measure(measureSpec, measureSpec); + mFolderLockHeight = mFolderLock.getMeasuredHeight(); } private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() { @@ -536,9 +545,60 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList setScaleY(1f); setAlpha(1f); mState = STATE_SMALL; + + View reveal = mLauncher.findViewById(R.id.reveal_fake_page_container); + reveal.setVisibility(View.VISIBLE); + View revealPage = mLauncher.findViewById(R.id.reveal_fake_page); + revealPage.setVisibility(View.VISIBLE); + View revealOutline = mLauncher.findViewById(R.id.reveal_fake_folder_outline); + revealOutline.setVisibility(View.INVISIBLE); + View revealFolderIcon = mLauncher.findViewById(R.id.reveal_fake_folder_icon); + revealFolderIcon.setVisibility(View.INVISIBLE); + } + + private void prepareOutline() { + View outline = mLauncher.findViewById(R.id.reveal_fake_folder_outline); + FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) outline.getLayoutParams(); + int width = getPaddingLeft() + getPaddingRight() + mContent.getDesiredWidth(); + int height = getFolderHeight(); + + lp.width = width; + lp.height = height; + outline.setLayoutParams(lp); + + outline.setX(mLeft); + outline.setY(mTop); + outline.setVisibility(View.INVISIBLE); } - public void animateOpen() { + private void prepareFakeFolderIcon() { + mFolderIcon.buildDrawingCache(true); + + Bitmap fakeFolderIcon = Bitmap.createBitmap(mFolderIcon.getDrawingCache()); + View fakeFolderIconView = mLauncher.findViewById(R.id.reveal_fake_folder_icon); + FrameLayout.LayoutParams flp = (FrameLayout.LayoutParams) + fakeFolderIconView.getLayoutParams(); + + // Get globalVisibleRect of the folderIcon. getWidth and getHeight are inaccurate for + // hotseat icons + Rect rect = new Rect(); + mFolderIcon.getGlobalVisibleRect(rect); + + flp.height = rect.height(); + flp.width = rect.width(); + + fakeFolderIconView.setLayoutParams(flp); + + int [] folderIconXY = new int[2]; + mFolderIcon.getLocationOnScreen(folderIconXY); + fakeFolderIconView.setX(folderIconXY[0]); + fakeFolderIconView.setY(folderIconXY[1]); + + fakeFolderIconView.setBackground(new BitmapDrawable(null, fakeFolderIcon)); + fakeFolderIconView.setVisibility(View.INVISIBLE); + } + + public void animateOpen(Workspace workspace) { if (!(getParent() instanceof DragLayer)) return; Animator openFolderAnim = null; @@ -563,49 +623,110 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList } }; } else { - prepareReveal(); centerAboutIcon(); - int width = getPaddingLeft() + getPaddingRight() + mContent.getDesiredWidth(); - int height = getFolderHeight(); - - float transX = - 0.075f * (width / 2 - getPivotX()); - float transY = - 0.075f * (height / 2 - getPivotY()); + float transX = 0; + float transY = getResources().getInteger(R.integer.folder_translate_y_dist); setTranslationX(transX); setTranslationY(transY); PropertyValuesHolder tx = PropertyValuesHolder.ofFloat("translationX", transX, 0); PropertyValuesHolder ty = PropertyValuesHolder.ofFloat("translationY", transY, 0); - int rx = (int) Math.max(Math.max(width - getPivotX(), 0), getPivotX()); - int ry = (int) Math.max(Math.max(height - getPivotY(), 0), getPivotY()); - float radius = (float) Math.sqrt(rx * rx + ry * ry); AnimatorSet anim = LauncherAnimUtils.createAnimatorSet(); - Animator reveal = LauncherAnimUtils.createCircularReveal(this, (int) getPivotX(), - (int) getPivotY(), 0, radius); - reveal.setDuration(mMaterialExpandDuration); - reveal.setInterpolator(new LogDecelerateInterpolator(100, 0)); + + mFolderLock.setAlpha(0f); + Animator lockAlpha = LauncherAnimUtils.ofFloat(mFolderLock, "alpha", 0f, 1f); + lockAlpha.setDuration(mMaterialExpandDuration); + lockAlpha.setStartDelay(mMaterialExpandStagger); + lockAlpha.setInterpolator(new LogDecelerateInterpolator(60, 0)); mContent.setAlpha(0f); Animator iconsAlpha = LauncherAnimUtils.ofFloat(mContent, "alpha", 0f, 1f); iconsAlpha.setDuration(mMaterialExpandDuration); iconsAlpha.setStartDelay(mMaterialExpandStagger); - iconsAlpha.setInterpolator(new AccelerateInterpolator(1.5f)); + iconsAlpha.setInterpolator(new LogDecelerateInterpolator(60, 0)); mFolderName.setAlpha(0f); Animator textAlpha = LauncherAnimUtils.ofFloat(mFolderName, "alpha", 0f, 1f); textAlpha.setDuration(mMaterialExpandDuration); textAlpha.setStartDelay(mMaterialExpandStagger); - textAlpha.setInterpolator(new AccelerateInterpolator(1.5f)); + textAlpha.setInterpolator(new LogDecelerateInterpolator(60, 0)); Animator drift = LauncherAnimUtils.ofPropertyValuesHolder(this, tx, ty); drift.setDuration(mMaterialExpandDuration); drift.setStartDelay(mMaterialExpandStagger); drift.setInterpolator(new LogDecelerateInterpolator(60, 0)); + final ArrayList<View> layerViews = new ArrayList<View>(); + + Animator workspaceAnim = workspace.getChangeStateAnimation( + Workspace.State.NORMAL_HIDDEN, true, layerViews); + if (workspaceAnim != null) { + workspaceAnim.setStartDelay(mMaterialExpandStagger); + } + + prepareFakeFolderIcon(); + float iconTransY = getResources().getInteger(R.integer.folder_icon_translate_y_dist); + + final View fakeFolderIconView = mLauncher.findViewById(R.id.reveal_fake_folder_icon); + float baseIconTranslationY = fakeFolderIconView.getTranslationY(); + PropertyValuesHolder iconty = PropertyValuesHolder.ofFloat("translationY", + baseIconTranslationY, baseIconTranslationY + iconTransY); + PropertyValuesHolder iconAlpha = PropertyValuesHolder.ofFloat("alpha", 1f, 0f); + + Animator fakeFolderIcon = LauncherAnimUtils.ofPropertyValuesHolder(fakeFolderIconView, + iconty, iconAlpha); + fakeFolderIcon.setDuration(mMaterialExpandDuration); + fakeFolderIcon.setInterpolator(new AccelerateInterpolator(1.5f)); + fakeFolderIcon.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + mFolderIcon.setPreviewBackground(-1); + mFolderIcon.setAlpha(0); + fakeFolderIconView.setVisibility(View.VISIBLE); + } + + @Override + public void onAnimationEnd(Animator animation) { + fakeFolderIconView.setVisibility(View.INVISIBLE); + } + }); + + Animator revealAnim = null; + prepareReveal(); + if (!mIsExternalDrag) { + revealAnim = getFolderIconRevealAnimator(false); + } else { + prepareOutline(); + View revealFakeView = mLauncher.findViewById(R.id.reveal_fake_page); + revealFakeView.setVisibility(View.INVISIBLE); + View outlineView = mLauncher.findViewById(R.id.reveal_fake_folder_outline); + outlineView.setAlpha(0f); + outlineView.setVisibility(View.VISIBLE); + + float baseOutlineTranslationY = outlineView.getTranslationY(); + PropertyValuesHolder outlineTransY = PropertyValuesHolder.ofFloat("translationY", + baseOutlineTranslationY + transY, baseOutlineTranslationY); + + PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 0f, 1f); + revealAnim = LauncherAnimUtils.ofPropertyValuesHolder(outlineView, alpha, + outlineTransY); + revealAnim.setDuration(mMaterialExpandDuration); + revealAnim.setStartDelay(mMaterialExpandStagger); + revealAnim.setInterpolator(new LogDecelerateInterpolator(60, 0)); + } + + if (revealAnim != null) { + anim.play(revealAnim); + } + anim.play(fakeFolderIcon); anim.play(drift); anim.play(iconsAlpha); + anim.play(lockAlpha); anim.play(textAlpha); - anim.play(reveal); + if (workspaceAnim != null) { + anim.play(workspaceAnim); + } openFolderAnim = anim; @@ -622,7 +743,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList public void onAnimationStart(Animator animation) { sendCustomAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED, String.format(getContext().getString(R.string.folder_opened), - mContent.getCountX(), mContent.getCountY())); + mContent.getCountX(), mContent.getCountY())); mState = STATE_ANIMATING; } @Override @@ -644,6 +765,44 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList } } + private Animator getFolderIconRevealAnimator(boolean reverse) { + DragLayer parent = (DragLayer) mLauncher.findViewById(R.id.drag_layer); + float scale = parent.getDescendantRectRelativeToSelf(mFolderIcon, mTempRect); + + int centerX = (int) (mTempRect.left + mTempRect.width() * scale / 2); + int centerY = (int) (mTempRect.top + mTempRect.height() * scale / 2); + + float targetRadius = 0; + return getRevealAnimator(reverse, centerX, centerY, targetRadius); + } + + private Animator getFolderRevealAnimator(boolean reverse) { + DragLayer parent = (DragLayer) mLauncher.findViewById(R.id.drag_layer); + float scale = parent.getDescendantRectRelativeToSelf(this, mTempRect); + + int centerX = (int) (mTempRect.left + mTempRect.width() * scale / 2); + int centerY = (int) (mTempRect.top + mTempRect.height() * scale / 2); + + float targetRadius = 0; + return getRevealAnimator(reverse, centerX, centerY, targetRadius); + } + + private Animator getRevealAnimator(boolean reverse, int centerX, int centerY, + float targetRadius) { + View reveal = mLauncher.findViewById(R.id.reveal_fake_page); + int height = reveal.getMeasuredHeight(); + + float startRadius = targetRadius; + float endRadius = height; + + if (reverse) { + endRadius = startRadius; + startRadius = height; + } + return ViewAnimationUtils.createCircularReveal(reveal, centerX, + centerY, startRadius, endRadius); + } + public void beginExternalDrag(ShortcutInfo item) { setupContentForNumItems(getItemCount() + 1); findAndSetEmptyCells(item); @@ -674,31 +833,142 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList } } - public void animateClosed() { + public int getState() { + return mState; + } + + public void animateClosed(final boolean animate) { if (!(getParent() instanceof DragLayer)) return; + AnimatorSet anim = LauncherAnimUtils.createAnimatorSet(); + PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 0); - PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 0.9f); - PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 0.9f); + float transY = getResources().getInteger(R.integer.folder_translate_y_dist); + PropertyValuesHolder translationY = PropertyValuesHolder.ofFloat("translationY", 0f, + transY); final ObjectAnimator oa = - LauncherAnimUtils.ofPropertyValuesHolder(this, alpha, scaleX, scaleY); + LauncherAnimUtils.ofPropertyValuesHolder(this, alpha, translationY); oa.addListener(new AnimatorListenerAdapter() { @Override - public void onAnimationEnd(Animator animation) { - onCloseComplete(); - setLayerType(LAYER_TYPE_NONE, null); - mState = STATE_SMALL; + public void onAnimationStart(Animator animation) { + if (animate && !mLauncher.getDragController().isDragging()) { + hideFolderOutline(false); + } + } + }); + oa.setDuration(mMaterialExpandDuration); + oa.setInterpolator(new LogDecelerateInterpolator(60, 0)); + setLayerType(LAYER_TYPE_HARDWARE, null); + + Animator workspaceAnim = mLauncher.getWorkspace().getChangeStateAnimation( + Workspace.State.NORMAL, animate, new ArrayList<View>()); + Animator reverseRevealAnim = null; + Animator fakeFolderIconAnim = null; + + if (animate) { + if (!mDragInProgress) { + reverseRevealAnim = getFolderIconRevealAnimator(true); + reverseRevealAnim.setInterpolator(new DecelerateInterpolator(2f)); + reverseRevealAnim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + View revealView = mLauncher.findViewById(R.id.reveal_fake_page_container); + revealView.setVisibility(View.INVISIBLE); + } + + @Override + public void onAnimationStart(Animator animation) { + View outline = mLauncher.findViewById(R.id.reveal_fake_folder_outline); + outline.setVisibility(View.INVISIBLE); + } + }); + } else { + prepareOutline(); + View revealFakeView = mLauncher.findViewById(R.id.reveal_fake_page); + revealFakeView.setVisibility(View.INVISIBLE); + View outlineView = mLauncher.findViewById(R.id.reveal_fake_folder_outline); + outlineView.setAlpha(1f); + outlineView.setVisibility(View.VISIBLE); + + float baseOutlineTranslationY = outlineView.getTranslationY(); + PropertyValuesHolder outlineTransY = PropertyValuesHolder.ofFloat("translationY", + baseOutlineTranslationY, baseOutlineTranslationY + transY); + + PropertyValuesHolder outlineAlpha = PropertyValuesHolder.ofFloat("alpha", 1f, 0f); + reverseRevealAnim = LauncherAnimUtils.ofPropertyValuesHolder(outlineView, + outlineAlpha, outlineTransY); + + reverseRevealAnim.setDuration(mMaterialExpandDuration); + reverseRevealAnim.setStartDelay(mMaterialExpandStagger); + reverseRevealAnim.setInterpolator(new DecelerateInterpolator(2f)); } + + prepareFakeFolderIcon(); + float iconTransY = getResources().getInteger(R.integer.folder_icon_translate_y_dist); + + final View fakeFolderIconView = mLauncher.findViewById(R.id.reveal_fake_folder_icon); + float baseIconTranslationY = fakeFolderIconView.getTranslationY(); + PropertyValuesHolder iconty = PropertyValuesHolder.ofFloat("translationY", + baseIconTranslationY + iconTransY, baseIconTranslationY); + PropertyValuesHolder iconAlpha = PropertyValuesHolder.ofFloat("alpha", 0f, 1f); + + fakeFolderIconAnim = LauncherAnimUtils.ofPropertyValuesHolder(fakeFolderIconView, + iconty, iconAlpha); + fakeFolderIconAnim.setDuration(mMaterialExpandDuration); + fakeFolderIconAnim.setInterpolator(new DecelerateInterpolator(2f)); + fakeFolderIconAnim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + mFolderIcon.setPreviewBackground(-1); + mFolderIcon.setAlpha(0); + fakeFolderIconView.setVisibility(View.VISIBLE); + } + + @Override + public void onAnimationEnd(Animator animation) { + fakeFolderIconView.setVisibility(View.INVISIBLE); + mFolderIcon.setAlpha(1); + mFolderIcon.setPreviewBackground(R.drawable.folder_bg); + + View revealView = mLauncher.findViewById(R.id.reveal_fake_page_container); + revealView.setVisibility(View.INVISIBLE); + } + }); + } else { + View revealView = mLauncher.findViewById(R.id.reveal_fake_page_container); + revealView.setVisibility(View.INVISIBLE); + mFolderIcon.setAlpha(1); + mFolderIcon.setPreviewBackground(R.drawable.folder_bg); + } + + anim.play(oa); + if (workspaceAnim != null) { + anim.play(workspaceAnim); + } + if (reverseRevealAnim != null) { + anim.play(reverseRevealAnim); + } + if (fakeFolderIconAnim != null) { + anim.play(fakeFolderIconAnim); + } + + anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { sendCustomAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED, getContext().getString(R.string.folder_closed)); mState = STATE_ANIMATING; } + + @Override + public void onAnimationEnd(Animator animation) { + onCloseComplete(); + setLayerType(LAYER_TYPE_NONE, null); + mState = STATE_SMALL; + } }); - oa.setDuration(mExpandDuration); - setLayerType(LAYER_TYPE_HARDWARE, null); - oa.start(); + + anim.start(); } public boolean acceptDrop(DragObject d) { @@ -756,6 +1026,10 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList mPreviousTargetCell[0] = -1; mPreviousTargetCell[1] = -1; mOnExitAlarm.cancelAlarm(); + + if (mState != STATE_ANIMATING && !mIsExternalDrag) { + showFolderOutline(true); + } } OnAlarmListener mReorderAlarmListener = new OnAlarmListener() { @@ -896,6 +1170,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList mSuppressOnAdd = false; mRearrangeOnClose = true; mIsExternalDrag = false; + mDragInProgress = false; } public void onDragExit(DragObject d) { @@ -908,6 +1183,10 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList mOnExitAlarm.setAlarm(ON_EXIT_CLOSE_DELAY); } mReorderAlarm.cancelAlarm(); + + if (!mLauncher.getDragController().isDragging()) { + hideFolderOutline(true); + } } public void onDropCompleted(final View target, final DragObject d, @@ -954,6 +1233,13 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList mCurrentDragView = null; mSuppressOnAdd = false; + if (mState == STATE_OPEN) { + hideFolderOutline(true); + mLauncher.hideSearch(); + } else if (mState == STATE_SMALL) { + mLauncher.showSearch(); + } + // Reordering may have occured, and we need to save the new item locations. We do this once // at the end to prevent unnecessary database operations. updateItemLocationsInDatabaseBatch(); @@ -1107,21 +1393,15 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList // We reset the workspaces scroll mLauncher.getWorkspace().resetFinalScrollForPageChange(currentPage); - // We need to bound the folder to the currently visible CellLayoutChildren - int left = Math.min(Math.max(bounds.left, centeredLeft), - bounds.left + bounds.width() - width); - int top = Math.min(Math.max(bounds.top, centeredTop), - bounds.top + bounds.height() - height); - if (grid.isPhone() && (grid.availableWidthPx - width) < grid.iconSizePx) { - // Center the folder if it is full (on phones only) - left = (grid.availableWidthPx - width) / 2; - } else if (width >= bounds.width()) { + // Center the folder + int left = (grid.availableWidthPx - width) / 2; + // Drop the top down a little so it isn't bounded by the page indicators + int top = (int) (bounds.top + (bounds.height() * 1.15) - height); + + if (width >= bounds.width()) { // If the folder doesn't fit within the bounds, center it about the desired bounds left = bounds.left + (bounds.width() - width) / 2; } - if (height >= bounds.height()) { - top = bounds.top + (bounds.height() - height) / 2; - } int folderPivotX = width / 2 + (centeredLeft - left); int folderPivotY = height / 2 + (centeredTop - top); @@ -1136,6 +1416,8 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList lp.height = height; lp.x = left; lp.y = top; + mLeft = left; + mTop = top; } float getPivotXForIconAnimation() { @@ -1166,16 +1448,13 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList } private int getFolderHeight() { - int height = getPaddingTop() + getPaddingBottom() + mFolderNameHeight + int height = getPaddingTop() + getPaddingBottom() + mFolderNameHeight + mFolderLockHeight + getContentAreaHeight(); return height; } protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int width = getPaddingLeft() - + getPaddingRight() - + Math.max(mContent.getDesiredWidth(), - mFolderTitleSection.getMeasuredWidth()); + int width = getPaddingLeft() + getPaddingRight() + mContent.getDesiredWidth(); int height = getFolderHeight(); int contentAreaWidthSpec = MeasureSpec.makeMeasureSpec(getContentAreaWidth(), MeasureSpec.EXACTLY); @@ -1190,12 +1469,10 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList } mScrollView.measure(contentAreaWidthSpec, contentAreaHeightSpec); - mFolderName.measure(contentAreaWidthSpec, MeasureSpec.makeMeasureSpec( - mFolderNameHeight, MeasureSpec.EXACTLY)); - mFolderLock.measure(contentAreaWidthSpec, MeasureSpec.makeMeasureSpec( - mFolderNameHeight, MeasureSpec.EXACTLY)); - mFolderTitleSection.measure(contentAreaWidthSpec, MeasureSpec - .makeMeasureSpec(mFolderNameHeight, MeasureSpec.EXACTLY)); + if (TextUtils.isEmpty(mInfo.title)) { + mFolderName.measure(contentAreaWidthSpec, MeasureSpec.makeMeasureSpec( + mFolderNameHeight, MeasureSpec.EXACTLY)); + } setMeasuredDimension(width, height); } @@ -1505,6 +1782,89 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList } } + // Instance variables to keep track of the hide/show outline animators + private Animator mRevealOutlinesAnimator = null; + private Animator mHideOutlinesAnimator = null; + // Sometimes the onAnimationEnd gets called despite getting cancelled, use this variable to + // handle the special cancel cases (when the user quickly picks up and drops an in the folder) + private boolean mCancelAnim = false; + + private void showFolderOutline(boolean animate) { + final View revealView = mLauncher.findViewById(R.id.reveal_fake_page); + final View outline = mLauncher.findViewById(R.id.reveal_fake_folder_outline); + + if (mHideOutlinesAnimator != null && mHideOutlinesAnimator.isRunning()) { + mHideOutlinesAnimator.cancel(); + } + prepareOutline(); + + if (!animate) { + revealView.setVisibility(View.INVISIBLE); + outline.setVisibility(View.VISIBLE); + return; + } + + mRevealOutlinesAnimator = getFolderRevealAnimator(true); + mRevealOutlinesAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (mCancelAnim) { + mCancelAnim = false; + } else { + revealView.setVisibility(View.INVISIBLE); + } + } + + @Override + public void onAnimationStart(Animator animation) { + outline.setAlpha(1f); + outline.setVisibility(View.VISIBLE); + } + }); + + mRevealOutlinesAnimator.start(); + } + + private void hideFolderOutline(boolean animate) { + final View revealView = mLauncher.findViewById(R.id.reveal_fake_page); + final View outline = mLauncher.findViewById(R.id.reveal_fake_folder_outline); + + if (revealView.getVisibility() == View.VISIBLE) { + // Nothing to do here + return; + } + + if (mRevealOutlinesAnimator != null && mRevealOutlinesAnimator.isRunning()) { + mCancelAnim = true; + mRevealOutlinesAnimator.cancel(); + } + + if (!animate) { + revealView.setVisibility(View.VISIBLE); + outline.setVisibility(View.INVISIBLE); + return; + } + + mHideOutlinesAnimator = getFolderRevealAnimator(false); + mHideOutlinesAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + revealView.setVisibility(View.VISIBLE); + } + + @Override + public void onAnimationEnd(Animator animation) { + if (mCancelAnim) { + mCancelAnim = false; + } else { + outline.setVisibility(View.INVISIBLE); + } + } + }); + + mHideOutlinesAnimator.start(); + } + @Override public void getHitRectRelativeToDragLayer(Rect outRect) { getHitRect(outRect); diff --git a/src/com/android/launcher3/FolderIcon.java b/src/com/android/launcher3/FolderIcon.java index 032d2a6f2..34603b90f 100644 --- a/src/com/android/launcher3/FolderIcon.java +++ b/src/com/android/launcher3/FolderIcon.java @@ -39,6 +39,7 @@ import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; import android.widget.FrameLayout; import android.widget.ImageView; +import android.widget.RelativeLayout; import android.widget.TextView; import com.android.launcher3.DropTarget.DragObject; @@ -58,17 +59,17 @@ public class FolderIcon extends FrameLayout implements FolderListener { private CheckLongPressHelper mLongPressHelper; // The number of icons to display in the - private static final int NUM_ITEMS_IN_PREVIEW = 3; + private static final int NUM_ITEMS_IN_PREVIEW = 4; private static final int CONSUMPTION_ANIMATION_DURATION = 100; private static final int DROP_IN_ANIMATION_DURATION = 400; private static final int INITIAL_ITEM_ANIMATION_DURATION = 350; private static final int FINAL_ITEM_ANIMATION_DURATION = 200; // The degree to which the inner ring grows when accepting drop - private static final float INNER_RING_GROWTH_FACTOR = 0.15f; + private static final float INNER_RING_GROWTH_FACTOR = 0.0f; // The degree to which the outer ring is scaled in its natural state - private static final float OUTER_RING_GROWTH_FACTOR = 0.3f; + private static final float OUTER_RING_GROWTH_FACTOR = 0.15f; // The amount of vertical spread between items in the stack [0...1] private static final float PERSPECTIVE_SHIFT_FACTOR = 0.18f; @@ -88,7 +89,7 @@ public class FolderIcon extends FrameLayout implements FolderListener { public static Drawable sSharedFolderLeaveBehind = null; - private ImageView mPreviewBackground; + private View mPreviewBackground; private BubbleTextView mFolderName; FolderRingAnimator mFolderRingAnimator = null; @@ -157,11 +158,11 @@ public class FolderIcon extends FrameLayout implements FolderListener { lp.topMargin = grid.iconSizePx + grid.iconDrawablePaddingPx; // Offset the preview background to center this view accordingly - icon.mPreviewBackground = (ImageView) icon.findViewById(R.id.preview_background); + icon.mPreviewBackground = icon.findViewById(R.id.preview_background); lp = (FrameLayout.LayoutParams) icon.mPreviewBackground.getLayoutParams(); - lp.topMargin = grid.folderBackgroundOffset; - lp.width = grid.folderIconSizePx; - lp.height = grid.folderIconSizePx; + lp.width = grid.iconSizePx; + lp.height = grid.iconSizePx; + icon.mPreviewBackground.setLayoutParams(lp); icon.setTag(folderInfo); icon.setOnClickListener(launcher); @@ -179,6 +180,7 @@ public class FolderIcon extends FrameLayout implements FolderListener { folderInfo.addListener(icon); icon.setOnFocusChangeListener(launcher.mFocusHandler); + icon.setDrawingCacheEnabled(true); return icon; } @@ -217,11 +219,11 @@ public class FolderIcon extends FrameLayout implements FolderListener { LauncherAppState app = LauncherAppState.getInstance(); DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); - sPreviewSize = grid.folderIconSizePx; + sPreviewSize = grid.iconSizePx; sPreviewPadding = res.getDimensionPixelSize(R.dimen.folder_preview_padding); - sSharedOuterRingDrawable = res.getDrawable(R.drawable.portal_ring_outer_holo); - sSharedInnerRingDrawable = res.getDrawable(R.drawable.portal_ring_inner_nolip_holo); - sSharedFolderLeaveBehind = res.getDrawable(R.drawable.portal_ring_rest); + sSharedOuterRingDrawable = res.getDrawable(R.drawable.folder_fill_highlight); + sSharedInnerRingDrawable = null; + sSharedFolderLeaveBehind = res.getDrawable(R.drawable.folder_bg); sStaticValuesDirty = false; } } @@ -236,7 +238,10 @@ public class FolderIcon extends FrameLayout implements FolderListener { final int previewSize = sPreviewSize; mAcceptAnimator.addUpdateListener(new AnimatorUpdateListener() { public void onAnimationUpdate(ValueAnimator animation) { - final float percent = (Float) animation.getAnimatedValue(); + float percent = (Float) animation.getAnimatedValue(); + if (mFolderIcon != null) { + percent = 1f; + } mOuterRingSize = (1 + percent * OUTER_RING_GROWTH_FACTOR) * previewSize; mInnerRingSize = (1 + percent * INNER_RING_GROWTH_FACTOR) * previewSize; if (mCellLayout != null) { @@ -248,7 +253,7 @@ public class FolderIcon extends FrameLayout implements FolderListener { @Override public void onAnimationStart(Animator animation) { if (mFolderIcon != null) { - mFolderIcon.mPreviewBackground.setVisibility(INVISIBLE); + mFolderIcon.mPreviewBackground.setBackground(null); } } }); @@ -265,7 +270,10 @@ public class FolderIcon extends FrameLayout implements FolderListener { final int previewSize = sPreviewSize; mNeutralAnimator.addUpdateListener(new AnimatorUpdateListener() { public void onAnimationUpdate(ValueAnimator animation) { - final float percent = (Float) animation.getAnimatedValue(); + float percent = (Float) animation.getAnimatedValue(); + if (mFolderIcon != null) { + percent = 0f; + } mOuterRingSize = (1 + (1 - percent) * OUTER_RING_GROWTH_FACTOR) * previewSize; mInnerRingSize = (1 + (1 - percent) * INNER_RING_GROWTH_FACTOR) * previewSize; if (mCellLayout != null) { @@ -280,7 +288,7 @@ public class FolderIcon extends FrameLayout implements FolderListener { mCellLayout.hideFolderAccept(FolderRingAnimator.this); } if (mFolderIcon != null) { - mFolderIcon.mPreviewBackground.setVisibility(VISIBLE); + mFolderIcon.mPreviewBackground.setBackgroundResource(R.drawable.folder_bg); } } }); @@ -353,6 +361,14 @@ public class FolderIcon extends FrameLayout implements FolderListener { mInfo.add(item); } + public void setPreviewBackground(int res) { + if (res < 0) { + mPreviewBackground.setBackground(null); + } else { + mPreviewBackground.setBackgroundResource(res); + } + } + public void onDragEnter(Object dragInfo) { if (mFolder.isDestroyed() || !willAcceptItem((ItemInfo) dragInfo)) return; CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams(); @@ -537,7 +553,7 @@ public class FolderIcon extends FrameLayout implements FolderListener { mMaxPerspectiveShift = mBaselineIconSize * PERSPECTIVE_SHIFT_FACTOR; mPreviewOffsetX = (mTotalWidth - mAvailableSpaceInPreview) / 2; - mPreviewOffsetY = previewPadding + grid.folderBackgroundOffset; + mPreviewOffsetY = grid.folderBackgroundOffset; } } @@ -649,26 +665,80 @@ public class FolderIcon extends FrameLayout implements FolderListener { int nItemsInPreview = Math.min(items.size(), NUM_ITEMS_IN_PREVIEW); // Hidden folder - don't display Preview + View folderLock = findViewById(R.id.folder_lock_image); + folderLock.setVisibility(mInfo.hidden ? VISIBLE : INVISIBLE); + View appView = findViewById(R.id.app_0); + appView.setVisibility(mInfo.hidden ? INVISIBLE : VISIBLE); + appView = findViewById(R.id.app_1); + appView.setVisibility(mInfo.hidden ? INVISIBLE : VISIBLE); + appView = findViewById(R.id.app_2); + appView.setVisibility(mInfo.hidden ? INVISIBLE : VISIBLE); + appView = findViewById(R.id.app_3); + appView.setVisibility(mInfo.hidden ? INVISIBLE : VISIBLE); + if (mInfo.hidden) { - mParams = computePreviewItemDrawingParams(NUM_ITEMS_IN_PREVIEW/2, mParams); - canvas.save(); - canvas.translate(mParams.transX + mPreviewOffsetX, mParams.transY + mPreviewOffsetY); - canvas.scale(mParams.scale, mParams.scale); - Drawable lock = getResources().getDrawable(R.drawable.folder_lock); - lock.setBounds(0, 0, mIntrinsicIconSize, mIntrinsicIconSize); - lock.draw(canvas); - canvas.restore(); return; } if (!mAnimating) { - for (int i = nItemsInPreview - 1; i >= 0; i--) { - v = (TextView) items.get(i); - if (!mHiddenItems.contains(v.getTag())) { - d = getTopDrawable(v); - mParams = computePreviewItemDrawingParams(i, mParams); - mParams.drawable = d; - drawPreviewItem(canvas, mParams); + LauncherAppState app = LauncherAppState.getInstance(); + DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + + // get dimen for the icon size + // ratio: iconsize = 3*padding + 2*small_icon_size + // padding*6.5 = small_icon_size + // so padding = folderIconSize / 16 + int padding = grid.iconSizePx / 16; + int smallIconSize = (int) (padding * 6.5); + + for (int i = NUM_ITEMS_IN_PREVIEW; i >= 0; i--) { + d = null; + if (i < items.size()) { + v = (TextView) items.get(i); + if (!mHiddenItems.contains(v.getTag())) { + d = getTopDrawable(v); + mParams = computePreviewItemDrawingParams(i, mParams); + mParams.drawable = d; + } + } + + ImageView appIcon = null; + int marginLeft = 0, marginRight = 0, marginTop = 0, marginBottom = 0; + switch(i) { + case 0: + appIcon = (ImageView) findViewById(R.id.app_0); + marginLeft = padding; + marginTop = padding; + break; + case 1: + appIcon = (ImageView) findViewById(R.id.app_1); + marginTop = padding; + marginRight = padding; + break; + case 2: + appIcon = (ImageView) findViewById(R.id.app_2); + marginBottom = padding; + marginLeft = padding; + break; + case 3: + appIcon = (ImageView) findViewById(R.id.app_3); + marginBottom = padding; + marginRight = padding; + break; + } + + if (appIcon != null) { + appIcon.setImageDrawable(d); + RelativeLayout.LayoutParams layoutParams + = (RelativeLayout.LayoutParams) appIcon.getLayoutParams(); + layoutParams.width = smallIconSize; + layoutParams.height = smallIconSize; + layoutParams.leftMargin = marginLeft; + layoutParams.rightMargin = marginRight; + layoutParams.topMargin = marginTop; + layoutParams.bottomMargin = marginBottom; + + appIcon.setLayoutParams(layoutParams); } } } else { diff --git a/src/com/android/launcher3/HiddenFolderFragment.java b/src/com/android/launcher3/HiddenFolderFragment.java index 279448cdb..1e902c5de 100644 --- a/src/com/android/launcher3/HiddenFolderFragment.java +++ b/src/com/android/launcher3/HiddenFolderFragment.java @@ -59,8 +59,8 @@ public class HiddenFolderFragment extends Fragment { mHidden = !mHidden; ImageView mLock = (ImageView) v; - Drawable mLockIcon = mHidden ? getResources().getDrawable(R.drawable.folder_lock_light) - : getResources().getDrawable(R.drawable.folder_unlock); + Drawable mLockIcon = mHidden ? getResources().getDrawable(R.drawable.folder_locked) + : getResources().getDrawable(R.drawable.folder_unlocked); mLock.setImageDrawable(mLockIcon); } }; @@ -103,8 +103,8 @@ public class HiddenFolderFragment extends Fragment { }); ImageView mLock = (ImageView) v.findViewById(R.id.folder_lock_icon); - Drawable mLockIcon = mHidden ? getResources().getDrawable(R.drawable.folder_lock_light) - : getResources().getDrawable(R.drawable.folder_unlock); + Drawable mLockIcon = mHidden ? getResources().getDrawable(R.drawable.folder_locked) + : getResources().getDrawable(R.drawable.folder_unlocked); mLock.setImageDrawable(mLockIcon); mLock.setOnClickListener(mClicklistener); diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 74551e662..12a1f9f90 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -2263,10 +2263,12 @@ public class Launcher extends Activity // If we are already on home, then just animate back to the workspace, // otherwise, just wait until onResume to set the state back to Workspace - if (alreadyOnHome) { - showWorkspace(true); - } else { - mOnResumeState = State.WORKSPACE; + if (mWorkspace.getOpenFolder() == null) { + if (alreadyOnHome) { + showWorkspace(true); + } else { + mOnResumeState = State.WORKSPACE; + } } final View v = getWindow().peekDecorView(); @@ -2318,7 +2320,7 @@ public class Launcher extends Activity outState.putInt(RUNTIME_STATE, mState.ordinal()); // We close any open folder since it will not be re-opened, and we need to make sure // this state is reflected. - closeFolder(); + closeFolder(false); if (mPendingAddInfo.container != ItemInfo.NO_ID && mPendingAddInfo.screenId > -1 && mWaitingForResult) { @@ -3437,6 +3439,10 @@ public class Launcher extends Activity Folder folder = folderIcon.getFolder(); FolderInfo info = folder.mInfo; + if (folder.getState() == Folder.STATE_ANIMATING) { + return; + } + if (info.hidden) { folder.startHiddenFolderManager(); return; @@ -3453,8 +3459,7 @@ public class Launcher extends Activity Log.w(TAG, "Opening folder (" + folder + ") which already has a parent (" + folder.getParent() + ")."); } - folder.animateOpen(); - growAndFadeOutFolderIcon(folderIcon); + folder.animateOpen(getWorkspace()); // Notify the accessibility manager that this folder "window" has appeared and occluded // the workspace items @@ -3463,24 +3468,31 @@ public class Launcher extends Activity } public void closeFolder() { + closeFolder(true); + } + + public void closeFolder(boolean animate) { Folder folder = mWorkspace != null ? mWorkspace.getOpenFolder() : null; if (folder != null) { if (folder.isEditingName()) { folder.dismissEditingName(); } - closeFolder(folder); + closeFolder(folder, animate); } } void closeFolder(Folder folder) { - folder.getInfo().opened = false; + closeFolder(folder, true); + } - ViewGroup parent = (ViewGroup) folder.getParent().getParent(); - if (parent != null) { - FolderIcon fi = (FolderIcon) mWorkspace.getViewForTag(folder.mInfo); - shrinkAndFadeInFolderIcon(fi); + void closeFolder(Folder folder, boolean animate) { + if (folder.getState() == Folder.STATE_ANIMATING) { + return; } - folder.animateClosed(); + + folder.getInfo().opened = false; + + folder.animateClosed(animate); // Notify the accessibility manager that this folder "window" has disappeard and no // longer occludeds the workspace items diff --git a/src/com/android/launcher3/SearchDropTargetBar.java b/src/com/android/launcher3/SearchDropTargetBar.java index d38c61209..e2f4b386c 100644 --- a/src/com/android/launcher3/SearchDropTargetBar.java +++ b/src/com/android/launcher3/SearchDropTargetBar.java @@ -52,6 +52,8 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D private Drawable mPreviousBackground; private boolean mEnableDropDownDropTargets; + private Launcher mLauncher; + public SearchDropTargetBar(Context context, AttributeSet attrs) { this(context, attrs, 0); } @@ -74,6 +76,7 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D } public void setupQSB(Launcher launcher) { + mLauncher = launcher; mQSBSearchBar = launcher.getQsbBar(); if (mEnableDropDownDropTargets) { mQSBSearchBarAnim = LauncherAnimUtils.ofFloat(mQSBSearchBar, "translationY", 0, @@ -95,6 +98,13 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D anim.setDuration(sTransitionInDuration); anim.addListener(new AnimatorListenerAdapter() { @Override + public void onAnimationStart(Animator animation) { + if (v.getVisibility() != View.VISIBLE) { + v.setVisibility(View.VISIBLE); + } + } + + @Override public void onAnimationEnd(Animator animation) { v.setLayerType(View.LAYER_TYPE_NONE, null); } @@ -193,7 +203,7 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D // Animate out the QSB search bar, and animate in the drop target bar prepareStartAnimation(mDropTargetBar); mDropTargetBarAnim.start(); - if (!mIsSearchBarHidden || mQSBSearchBar.getAlpha() > 0f) { + if (!isAnyFolderOpen() && (!mIsSearchBarHidden || mQSBSearchBar.getAlpha() > 0f)) { prepareStartAnimation(mQSBSearchBar); mQSBSearchBarAnim.start(); } @@ -203,13 +213,20 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D mDeferOnDragEnd = true; } + private boolean isAnyFolderOpen() { + if (mLauncher != null) { + return mLauncher.getWorkspace().getOpenFolder() != null; + } + return false; + } + @Override public void onDragEnd() { if (!mDeferOnDragEnd) { // Restore the QSB search bar, and animate out the drop target bar prepareStartAnimation(mDropTargetBar); mDropTargetBarAnim.reverse(); - if (!mIsSearchBarHidden || mQSBSearchBar.getAlpha() < 1f) { + if (!isAnyFolderOpen() && (!mIsSearchBarHidden || mQSBSearchBar.getAlpha() < 1f)) { prepareStartAnimation(mQSBSearchBar); mQSBSearchBarAnim.reverse(); } diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index a0b99e51e..298589650 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -2545,7 +2545,9 @@ public class Workspace extends SmoothPagedView // Animation animation = AnimationUtils.loadAnimation(mLauncher, R.anim.drop_down); // overviewPanel.startAnimation(animation); anim.play(hotseatAlpha); - if (mShowSearchBar) anim.play(searchBarAlpha); + if (mShowSearchBar && !mLauncher.getDragController().isDragging()) { + anim.play(searchBarAlpha); + } anim.play(pageIndicatorAlpha); anim.setStartDelay(delay); } else { @@ -2558,7 +2560,7 @@ public class Workspace extends SmoothPagedView AlphaUpdateListener.updateVisibility(pageIndicator); } - if (mShowSearchBar) { + if (mShowSearchBar && !mLauncher.getDragController().isDragging()) { searchBar.setAlpha(finalSearchBarAlpha); AlphaUpdateListener.updateVisibility(searchBar); } |