Search in sources :

Example 51 with DragLayer

use of com.android.launcher3.dragndrop.DragLayer in project android_packages_apps_Launcher3 by ArrowOS.

the class DragLayer method animateView.

/**
 * This method animates a view at the end of a drag and drop animation.
 * @param view The view to be animated. This view is drawn directly into DragLayer, and so
 *        doesn't need to be a child of DragLayer.
 * @param to The final location of the view. Only the left and top parameters are used. This
 *        location doesn't account for scaling, and so should be centered about the desired
 *        final location (including scaling).
 * @param finalAlpha The final alpha of the view, in case we want it to fade as it animates.
 * @param finalScaleX The final scale of the view. The view is scaled about its center.
 * @param finalScaleY The final scale of the view. The view is scaled about its center.
 * @param duration The duration of the animation.
 * @param motionInterpolator The interpolator to use for the location of the view.
 * @param onCompleteRunnable Optional runnable to run on animation completion.
 * @param animationEndStyle Whether or not to fade out the view once the animation completes.
 *        {@link #ANIMATION_END_DISAPPEAR} or {@link #ANIMATION_END_REMAIN_VISIBLE}.
 * @param anchorView If not null, this represents the view which the animated view stays
 */
public void animateView(final DragView view, final Rect to, final float finalAlpha, final float finalScaleX, final float finalScaleY, int duration, final Interpolator motionInterpolator, final Runnable onCompleteRunnable, final int animationEndStyle, View anchorView) {
    view.cancelAnimation();
    view.requestLayout();
    final int[] from = getViewLocationRelativeToSelf(view);
    // Calculate the duration of the animation based on the object's distance
    final float dist = (float) Math.hypot(to.left - from[0], to.top - from[1]);
    final Resources res = getResources();
    final float maxDist = (float) res.getInteger(R.integer.config_dropAnimMaxDist);
    // If duration < 0, this is a cue to compute the duration based on the distance
    if (duration < 0) {
        duration = res.getInteger(R.integer.config_dropAnimMaxDuration);
        if (dist < maxDist) {
            duration *= DEACCEL_1_5.getInterpolation(dist / maxDist);
        }
        duration = Math.max(duration, res.getInteger(R.integer.config_dropAnimMinDuration));
    }
    // Fall back to cubic ease out interpolator for the animation if none is specified
    TimeInterpolator interpolator = motionInterpolator == null ? DEACCEL_1_5 : motionInterpolator;
    // Animate the view
    PendingAnimation anim = new PendingAnimation(duration);
    anim.add(ofFloat(view, View.SCALE_X, finalScaleX), interpolator, SpringProperty.DEFAULT);
    anim.add(ofFloat(view, View.SCALE_Y, finalScaleY), interpolator, SpringProperty.DEFAULT);
    anim.setViewAlpha(view, finalAlpha, interpolator);
    anim.setFloat(view, VIEW_TRANSLATE_Y, to.top, interpolator);
    ObjectAnimator xMotion = ofFloat(view, VIEW_TRANSLATE_X, to.left);
    if (anchorView != null) {
        final int startScroll = anchorView.getScrollX();
        TypeEvaluator<Float> evaluator = (f, s, e) -> mapRange(f, s, e) + (anchorView.getScaleX() * (startScroll - anchorView.getScrollX()));
        xMotion.setEvaluator(evaluator);
    }
    anim.add(xMotion, interpolator, SpringProperty.DEFAULT);
    if (onCompleteRunnable != null) {
        anim.addListener(forEndCallback(onCompleteRunnable));
    }
    playDropAnimation(view, anim.buildAnim(), animationEndStyle);
}
Also used : Folder(com.android.launcher3.folder.Folder) DEACCEL_1_5(com.android.launcher3.anim.Interpolators.DEACCEL_1_5) Context(android.content.Context) Rect(android.graphics.Rect) TimeInterpolator(android.animation.TimeInterpolator) ViewGroupFocusHelper(com.android.launcher3.keyboard.ViewGroupFocusHelper) KeyEvent(android.view.KeyEvent) Animator(android.animation.Animator) Scrim(com.android.launcher3.graphics.Scrim) AnimatorListeners.forEndCallback(com.android.launcher3.anim.AnimatorListeners.forEndCallback) ArrayList(java.util.ArrayList) TypeEvaluator(android.animation.TypeEvaluator) BaseDragLayer(com.android.launcher3.views.BaseDragLayer) AccessibilityManager(android.view.accessibility.AccessibilityManager) AccessibilityManagerCompat.sendCustomAccessibilityEvent(com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent) AttributeSet(android.util.AttributeSet) MotionEvent(android.view.MotionEvent) View(android.view.View) Canvas(android.graphics.Canvas) AccessibilityEvent(android.view.accessibility.AccessibilityEvent) Launcher(com.android.launcher3.Launcher) Interpolator(android.view.animation.Interpolator) VIEW_TRANSLATE_Y(com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y) VIEW_TRANSLATE_X(com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X) ObjectAnimator(android.animation.ObjectAnimator) SpringProperty(com.android.launcher3.anim.SpringProperty) Utilities.mapRange(com.android.launcher3.Utilities.mapRange) CellLayout(com.android.launcher3.CellLayout) ObjectAnimator.ofFloat(android.animation.ObjectAnimator.ofFloat) DropTargetBar(com.android.launcher3.DropTargetBar) TouchController(com.android.launcher3.util.TouchController) R(com.android.launcher3.R) ShortcutAndWidgetContainer(com.android.launcher3.ShortcutAndWidgetContainer) Workspace(com.android.launcher3.Workspace) AbstractFloatingView(com.android.launcher3.AbstractFloatingView) PendingAnimation(com.android.launcher3.anim.PendingAnimation) Resources(android.content.res.Resources) PendingAnimation(com.android.launcher3.anim.PendingAnimation) ObjectAnimator.ofFloat(android.animation.ObjectAnimator.ofFloat) ObjectAnimator(android.animation.ObjectAnimator) Resources(android.content.res.Resources) TimeInterpolator(android.animation.TimeInterpolator)

Example 52 with DragLayer

use of com.android.launcher3.dragndrop.DragLayer in project android_packages_apps_Launcher3 by ArrowOS.

the class ArrowPopup method orientAboutObject.

/**
 * @see #orientAboutObject()
 *
 * @param allowAlignLeft Set to false if we already tried aligning left and didn't have room.
 * @param allowAlignRight Set to false if we already tried aligning right and didn't have room.
 * TODO: Can we test this with all permutations of widths/heights and icon locations + RTL?
 */
private void orientAboutObject(boolean allowAlignLeft, boolean allowAlignRight) {
    measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
    int extraVerticalSpace = mArrowHeight + mArrowOffsetVertical + getResources().getDimensionPixelSize(R.dimen.popup_vertical_padding);
    // The margins are added after we call this method, so we need to account for them here.
    int numVisibleChildren = 0;
    for (int i = getChildCount() - 1; i >= 0; --i) {
        if (getChildAt(i).getVisibility() == VISIBLE) {
            numVisibleChildren++;
        }
    }
    int childMargins = (numVisibleChildren - 1) * mMargin;
    int height = getMeasuredHeight() + extraVerticalSpace + childMargins;
    int width = getMeasuredWidth() + getPaddingLeft() + getPaddingRight();
    getTargetObjectLocation(mTempRect);
    InsettableFrameLayout dragLayer = getPopupContainer();
    Rect insets = dragLayer.getInsets();
    // Align left (right in RTL) if there is room.
    int leftAlignedX = mTempRect.left;
    int rightAlignedX = mTempRect.right - width;
    mIsLeftAligned = !mIsRtl ? allowAlignLeft : !allowAlignRight;
    int x = mIsLeftAligned ? leftAlignedX : rightAlignedX;
    // Offset x so that the arrow and shortcut icons are center-aligned with the original icon.
    int iconWidth = mTempRect.width();
    int xOffset = iconWidth / 2 - mArrowOffsetHorizontal - mArrowWidth / 2;
    x += mIsLeftAligned ? xOffset : -xOffset;
    // Check whether we can still align as we originally wanted, now that we've calculated x.
    if (!allowAlignLeft && !allowAlignRight) {
    // We've already tried both ways and couldn't make it fit. onLayout() will set the
    // gravity to CENTER_HORIZONTAL, but continue below to update y.
    } else {
        boolean canBeLeftAligned = x + width + insets.left < dragLayer.getWidth() - insets.right;
        boolean canBeRightAligned = x > insets.left;
        boolean alignmentStillValid = mIsLeftAligned && canBeLeftAligned || !mIsLeftAligned && canBeRightAligned;
        if (!alignmentStillValid) {
            // Try again, but don't allow this alignment we already know won't work.
            orientAboutObject(allowAlignLeft && !mIsLeftAligned, /* allowAlignLeft */
            allowAlignRight && mIsLeftAligned);
            return;
        }
    }
    // Open above icon if there is room.
    int iconHeight = mTempRect.height();
    int y = mTempRect.top - height;
    mIsAboveIcon = y > dragLayer.getTop() + insets.top;
    if (!mIsAboveIcon) {
        y = mTempRect.top + iconHeight + extraVerticalSpace;
    }
    // Insets are added later, so subtract them now.
    x -= insets.left;
    y -= insets.top;
    mGravity = 0;
    if (y + height > dragLayer.getBottom() - insets.bottom) {
        // The container is opening off the screen, so just center it in the drag layer instead.
        mGravity = Gravity.CENTER_VERTICAL;
        // Put the container next to the icon, preferring the right side in ltr (left in rtl).
        int rightSide = leftAlignedX + iconWidth - insets.left;
        int leftSide = rightAlignedX - iconWidth - insets.left;
        if (!mIsRtl) {
            if (rightSide + width < dragLayer.getRight()) {
                x = rightSide;
                mIsLeftAligned = true;
            } else {
                x = leftSide;
                mIsLeftAligned = false;
            }
        } else {
            if (leftSide > dragLayer.getLeft()) {
                x = leftSide;
                mIsLeftAligned = false;
            } else {
                x = rightSide;
                mIsLeftAligned = true;
            }
        }
        mIsAboveIcon = true;
    }
    setX(x);
    if (Gravity.isVertical(mGravity)) {
        return;
    }
    FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
    FrameLayout.LayoutParams arrowLp = (FrameLayout.LayoutParams) mArrow.getLayoutParams();
    if (mIsAboveIcon) {
        arrowLp.gravity = lp.gravity = Gravity.BOTTOM;
        lp.bottomMargin = getPopupContainer().getHeight() - y - getMeasuredHeight() - insets.top;
        arrowLp.bottomMargin = lp.bottomMargin - arrowLp.height - mArrowOffsetVertical - insets.bottom;
    } else {
        arrowLp.gravity = lp.gravity = Gravity.TOP;
        lp.topMargin = y + insets.top;
        arrowLp.topMargin = lp.topMargin - insets.top - arrowLp.height - mArrowOffsetVertical;
    }
}
Also used : Rect(android.graphics.Rect) FrameLayout(android.widget.FrameLayout) InsettableFrameLayout(com.android.launcher3.InsettableFrameLayout) InsettableFrameLayout(com.android.launcher3.InsettableFrameLayout)

Example 53 with DragLayer

use of com.android.launcher3.dragndrop.DragLayer in project android_packages_apps_Launcher3 by ArrowOS.

the class ArrowPopup method initColorExtractionLocations.

private void initColorExtractionLocations(Launcher launcher) {
    if (mColorExtractors == null) {
        return;
    }
    Workspace workspace = launcher.getWorkspace();
    if (workspace == null) {
        return;
    }
    boolean firstVisibleChild = true;
    int screenId = workspace.getScreenIdForPageIndex(workspace.getCurrentPage());
    DragLayer dragLayer = launcher.getDragLayer();
    final View[] viewAlignedWithArrow = new View[1];
    // Order matters here, since we need the arrow to match the color of its adjacent view.
    for (final View view : getChildrenForColorExtraction()) {
        if (view != null && view.getVisibility() == VISIBLE) {
            Rect pos = new Rect();
            dragLayer.getDescendantRectRelativeToSelf(view, pos);
            if (!pos.isEmpty()) {
                LocalColorExtractor extractor = LocalColorExtractor.newInstance(launcher);
                extractor.setWorkspaceLocation(pos, dragLayer, screenId);
                extractor.setListener(extractedColors -> {
                    AnimatorSet colors = new AnimatorSet();
                    int newColor = getExtractedColor(extractedColors);
                    setChildColor(view, newColor, colors);
                    int numChildren = view instanceof ViewGroup ? ((ViewGroup) view).getChildCount() : 0;
                    for (int i = 0; i < numChildren; ++i) {
                        View childView = ((ViewGroup) view).getChildAt(i);
                        setChildColor(childView, newColor, colors);
                    }
                    if (viewAlignedWithArrow[0] == view) {
                        mArrowColor = newColor;
                        updateArrowColor();
                    }
                    colors.setDuration(150);
                    view.post(colors::start);
                });
                mColorExtractors.add(extractor);
                if (mIsAboveIcon || firstVisibleChild) {
                    viewAlignedWithArrow[0] = view;
                }
                firstVisibleChild = false;
            }
        }
    }
}
Also used : BaseDragLayer(com.android.launcher3.views.BaseDragLayer) DragLayer(com.android.launcher3.dragndrop.DragLayer) Rect(android.graphics.Rect) ViewGroup(android.view.ViewGroup) AnimatorSet(android.animation.AnimatorSet) LocalColorExtractor(com.android.launcher3.widget.LocalColorExtractor) View(android.view.View) DeepShortcutView(com.android.launcher3.shortcuts.DeepShortcutView) AbstractFloatingView(com.android.launcher3.AbstractFloatingView) Workspace(com.android.launcher3.Workspace)

Example 54 with DragLayer

use of com.android.launcher3.dragndrop.DragLayer in project android_packages_apps_Launcher3 by ArrowOS.

the class Folder method animateOpen.

/**
 * Opens the user folder described by the specified tag. The opening of the folder
 * is animated relative to the specified View. If the View is null, no animation
 * is played.
 */
private void animateOpen(List<WorkspaceItemInfo> items, int pageNo) {
    Folder openFolder = getOpen(mActivityContext);
    if (openFolder != null && openFolder != this) {
        // Close any open folder before opening a folder.
        openFolder.close(true);
    }
    mContent.bindItems(items);
    centerAboutIcon();
    mItemsInvalidated = true;
    updateTextViewFocus();
    mIsOpen = true;
    BaseDragLayer dragLayer = mActivityContext.getDragLayer();
    // There was a one-off crash where the folder had a parent already.
    if (getParent() == null) {
        dragLayer.addView(this);
        mDragController.addDropTarget(this);
    } else {
        if (FeatureFlags.IS_STUDIO_BUILD) {
            Log.e(TAG, "Opening folder (" + this + ") which already has a parent:" + getParent());
        }
    }
    mContent.completePendingPageChanges();
    mContent.setCurrentPage(pageNo);
    // This is set to true in close(), but isn't reset to false until onDropCompleted(). This
    // leads to an inconsistent state if you drag out of the folder and drag back in without
    // dropping. One resulting issue is that replaceFolderWithFinalItem() can be called twice.
    mDeleteFolderOnDropCompleted = false;
    cancelRunningAnimations();
    FolderAnimationManager fam = new FolderAnimationManager(this, true);
    AnimatorSet anim = fam.getAnimator();
    anim.addListener(new AnimatorListenerAdapter() {

        @Override
        public void onAnimationStart(Animator animation) {
            mFolderIcon.setIconVisible(false);
            mFolderIcon.drawLeaveBehindIfExists();
        }

        @Override
        public void onAnimationEnd(Animator animation) {
            mState = STATE_OPEN;
            announceAccessibilityChanges();
            AccessibilityManagerCompat.sendFolderOpenedEventToTest(getContext());
            mContent.setFocusOnFirstChild();
        }
    });
    // Footer animation
    if (mContent.getPageCount() > 1 && !mInfo.hasOption(FolderInfo.FLAG_MULTI_PAGE_ANIMATION)) {
        int footerWidth = mContent.getDesiredWidth() - mFooter.getPaddingLeft() - mFooter.getPaddingRight();
        float textWidth = mFolderName.getPaint().measureText(mFolderName.getText().toString());
        float translation = (footerWidth - textWidth) / 2;
        mFolderName.setTranslationX(mContent.mIsRtl ? -translation : translation);
        mPageIndicator.prepareEntryAnimation();
        // Do not update the flag if we are in drag mode. The flag will be updated, when we
        // actually drop the icon.
        final boolean updateAnimationFlag = !mDragInProgress;
        anim.addListener(new AnimatorListenerAdapter() {

            @SuppressLint("InlinedApi")
            @Override
            public void onAnimationEnd(Animator animation) {
                mFolderName.animate().setDuration(FOLDER_NAME_ANIMATION_DURATION).translationX(0).setInterpolator(AnimationUtils.loadInterpolator(getContext(), android.R.interpolator.fast_out_slow_in));
                mPageIndicator.playEntryAnimation();
                if (updateAnimationFlag) {
                    mInfo.setOption(FolderInfo.FLAG_MULTI_PAGE_ANIMATION, true, mLauncherDelegate.getModelWriter());
                }
            }
        });
    } else {
        mFolderName.setTranslationX(0);
    }
    mPageIndicator.stopAllAnimations();
    startAnimation(anim);
    // Because t=0 has the folder match the folder icon, we can skip the
    // first frame and have the same movement one frame earlier.
    anim.setCurrentPlayTime(Math.min(getSingleFrameMs(getContext()), anim.getTotalDuration()));
    // Make sure the folder picks up the last drag move even if the finger doesn't move.
    if (mDragController.isDragging()) {
        mDragController.forceTouchMove();
    }
    mContent.verifyVisibleHighResIcons(mContent.getNextPage());
}
Also used : BaseDragLayer(com.android.launcher3.views.BaseDragLayer) Animator(android.animation.Animator) AnimatorListenerAdapter(android.animation.AnimatorListenerAdapter) SuppressLint(android.annotation.SuppressLint) AnimatorSet(android.animation.AnimatorSet) SuppressLint(android.annotation.SuppressLint)

Example 55 with DragLayer

use of com.android.launcher3.dragndrop.DragLayer in project android_packages_apps_Launcher3 by ArrowOS.

the class FolderIcon method onDrop.

private void onDrop(final WorkspaceItemInfo item, DragObject d, Rect finalRect, float scaleRelativeToDragLayer, int index, boolean itemReturnedOnFailedDrop) {
    item.cellX = -1;
    item.cellY = -1;
    DragView animateView = d.dragView;
    // will not have a view to animate
    if (animateView != null && mActivity instanceof Launcher) {
        final Launcher launcher = (Launcher) mActivity;
        DragLayer dragLayer = launcher.getDragLayer();
        Rect to = finalRect;
        if (to == null) {
            to = new Rect();
            Workspace workspace = launcher.getWorkspace();
            // Set cellLayout and this to it's final state to compute final animation locations
            workspace.setFinalTransitionTransform();
            float scaleX = getScaleX();
            float scaleY = getScaleY();
            setScaleX(1.0f);
            setScaleY(1.0f);
            scaleRelativeToDragLayer = dragLayer.getDescendantRectRelativeToSelf(this, to);
            // Finished computing final animation locations, restore current state
            setScaleX(scaleX);
            setScaleY(scaleY);
            workspace.resetTransitionTransform();
        }
        int numItemsInPreview = Math.min(MAX_NUM_ITEMS_IN_PREVIEW, index + 1);
        boolean itemAdded = false;
        if (itemReturnedOnFailedDrop || index >= MAX_NUM_ITEMS_IN_PREVIEW) {
            List<WorkspaceItemInfo> oldPreviewItems = new ArrayList<>(mCurrentPreviewItems);
            mInfo.add(item, index, false);
            mCurrentPreviewItems.clear();
            mCurrentPreviewItems.addAll(getPreviewItemsOnPage(0));
            if (!oldPreviewItems.equals(mCurrentPreviewItems)) {
                int newIndex = mCurrentPreviewItems.indexOf(item);
                if (newIndex >= 0) {
                    // If the item dropped is going to be in the preview, we update the
                    // index here to reflect its position in the preview.
                    index = newIndex;
                }
                mPreviewItemManager.hidePreviewItem(index, true);
                mPreviewItemManager.onDrop(oldPreviewItems, mCurrentPreviewItems, item);
                itemAdded = true;
            } else {
                removeItem(item, false);
            }
        }
        if (!itemAdded) {
            mInfo.add(item, index, true);
        }
        int[] center = new int[2];
        float scale = getLocalCenterForIndex(index, numItemsInPreview, center);
        center[0] = Math.round(scaleRelativeToDragLayer * center[0]);
        center[1] = Math.round(scaleRelativeToDragLayer * center[1]);
        to.offset(center[0] - animateView.getMeasuredWidth() / 2, center[1] - animateView.getMeasuredHeight() / 2);
        float finalAlpha = index < MAX_NUM_ITEMS_IN_PREVIEW ? 1f : 0f;
        float finalScale = scale * scaleRelativeToDragLayer;
        // Account for potentially different icon sizes with non-default grid settings
        if (d.dragSource instanceof AllAppsContainerView) {
            DeviceProfile grid = mActivity.getDeviceProfile();
            float containerScale = (1f * grid.iconSizePx / grid.allAppsIconSizePx);
            finalScale *= containerScale;
        }
        final int finalIndex = index;
        dragLayer.animateView(animateView, to, finalAlpha, finalScale, finalScale, DROP_IN_ANIMATION_DURATION, Interpolators.DEACCEL_2, () -> {
            mPreviewItemManager.hidePreviewItem(finalIndex, false);
            mFolder.showItem(item);
        }, DragLayer.ANIMATION_END_DISAPPEAR, null);
        mFolder.hideItem(item);
        if (!itemAdded)
            mPreviewItemManager.hidePreviewItem(index, true);
        FolderNameInfos nameInfos = new FolderNameInfos();
        if (FeatureFlags.FOLDER_NAME_SUGGEST.get()) {
            Executors.MODEL_EXECUTOR.post(() -> {
                d.folderNameProvider.getSuggestedFolderName(getContext(), mInfo.contents, nameInfos);
                showFinalView(finalIndex, item, nameInfos, d.logInstanceId);
            });
        } else {
            showFinalView(finalIndex, item, nameInfos, d.logInstanceId);
        }
    } else {
        addItem(item);
    }
}
Also used : AllAppsContainerView(com.android.launcher3.allapps.AllAppsContainerView) Rect(android.graphics.Rect) ArrayList(java.util.ArrayList) DragView(com.android.launcher3.dragndrop.DragView) DeviceProfile(com.android.launcher3.DeviceProfile) DragLayer(com.android.launcher3.dragndrop.DragLayer) Launcher(com.android.launcher3.Launcher) Workspace(com.android.launcher3.Workspace) WorkspaceItemInfo(com.android.launcher3.model.data.WorkspaceItemInfo)

Aggregations

DragLayer (com.android.launcher3.dragndrop.DragLayer)100 Rect (android.graphics.Rect)67 BaseDragLayer (com.android.launcher3.views.BaseDragLayer)33 ViewGroup (android.view.ViewGroup)23 Resources (android.content.res.Resources)22 AnimatorSet (android.animation.AnimatorSet)20 View (android.view.View)18 SuppressLint (android.annotation.SuppressLint)16 AbstractFloatingView (com.android.launcher3.AbstractFloatingView)15 DeviceProfile (com.android.launcher3.DeviceProfile)15 Workspace (com.android.launcher3.Workspace)15 Animator (android.animation.Animator)14 ObjectAnimator (android.animation.ObjectAnimator)14 Point (android.graphics.Point)12 ItemInfo (com.android.launcher3.model.data.ItemInfo)12 CellLayout (com.android.launcher3.CellLayout)11 DragView (com.android.launcher3.dragndrop.DragView)11 ArrayList (java.util.ArrayList)11 AnimatorListenerAdapter (android.animation.AnimatorListenerAdapter)10 Drawable (android.graphics.drawable.Drawable)10