11bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham/*
21bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham * Copyright (C) 2016 The Android Open Source Project
31bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham *
41bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham * Licensed under the Apache License, Version 2.0 (the "License");
51bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham * you may not use this file except in compliance with the License.
61bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham * You may obtain a copy of the License at
71bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham *
81bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham *      http://www.apache.org/licenses/LICENSE-2.0
91bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham *
101bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham * Unless required by applicable law or agreed to in writing, software
111bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham * distributed under the License is distributed on an "AS IS" BASIS,
121bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham * See the License for the specific language governing permissions and
141bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham * limitations under the License.
151bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham */
161bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham
171bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickhampackage com.android.launcher3.shortcuts;
181bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham
198f58e61d02fcb0ca90a2803e76a8792ec2c1f99aTony Wickhamimport android.animation.Animator;
200ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickhamimport android.animation.ValueAnimator;
211bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickhamimport android.content.Context;
22a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyalimport android.graphics.Point;
238f58e61d02fcb0ca90a2803e76a8792ec2c1f99aTony Wickhamimport android.graphics.Rect;
245836bf728e85c1c4fae67862deb4e973ac55e944Sunny Goyalimport android.text.TextUtils;
251bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickhamimport android.util.AttributeSet;
26a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyalimport android.view.View;
278f58e61d02fcb0ca90a2803e76a8792ec2c1f99aTony Wickhamimport android.widget.FrameLayout;
281bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham
29a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyalimport com.android.launcher3.IconCache;
305836bf728e85c1c4fae67862deb4e973ac55e944Sunny Goyalimport com.android.launcher3.Launcher;
31a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyalimport com.android.launcher3.LauncherAppState;
320ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickhamimport com.android.launcher3.LogAccelerateInterpolator;
331bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickhamimport com.android.launcher3.R;
34a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyalimport com.android.launcher3.ShortcutInfo;
35a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyalimport com.android.launcher3.Utilities;
365836bf728e85c1c4fae67862deb4e973ac55e944Sunny Goyalimport com.android.launcher3.shortcuts.DeepShortcutsContainer.UnbadgedShortcutInfo;
378f58e61d02fcb0ca90a2803e76a8792ec2c1f99aTony Wickhamimport com.android.launcher3.util.PillRevealOutlineProvider;
38a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyalimport com.android.launcher3.util.PillWidthRevealOutlineProvider;
391bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham
401bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham/**
418f58e61d02fcb0ca90a2803e76a8792ec2c1f99aTony Wickham * A {@link android.widget.FrameLayout} that contains a {@link DeepShortcutView}.
428f58e61d02fcb0ca90a2803e76a8792ec2c1f99aTony Wickham * This lets us animate the DeepShortcutView (icon and text) separately from the background.
431bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham */
440ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickhampublic class DeepShortcutView extends FrameLayout implements ValueAnimator.AnimatorUpdateListener {
458f58e61d02fcb0ca90a2803e76a8792ec2c1f99aTony Wickham
46a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal    private static final Point sTempPoint = new Point();
478f58e61d02fcb0ca90a2803e76a8792ec2c1f99aTony Wickham
48a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal    private final Rect mPillRect;
49a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal
50a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal    private DeepShortcutTextView mBubbleText;
51a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal    private View mIconView;
520ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham    private float mOpenAnimationProgress;
531bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham
545836bf728e85c1c4fae67862deb4e973ac55e944Sunny Goyal    private UnbadgedShortcutInfo mInfo;
555836bf728e85c1c4fae67862deb4e973ac55e944Sunny Goyal
561bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham    public DeepShortcutView(Context context) {
571bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham        this(context, null, 0);
581bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham    }
591bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham
601bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham    public DeepShortcutView(Context context, AttributeSet attrs) {
611bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham        this(context, attrs, 0);
621bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham    }
631bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham
641bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham    public DeepShortcutView(Context context, AttributeSet attrs, int defStyle) {
651bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham        super(context, attrs, defStyle);
661bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham
678f58e61d02fcb0ca90a2803e76a8792ec2c1f99aTony Wickham        mPillRect = new Rect();
688f58e61d02fcb0ca90a2803e76a8792ec2c1f99aTony Wickham    }
698f58e61d02fcb0ca90a2803e76a8792ec2c1f99aTony Wickham
708f58e61d02fcb0ca90a2803e76a8792ec2c1f99aTony Wickham    @Override
718f58e61d02fcb0ca90a2803e76a8792ec2c1f99aTony Wickham    protected void onFinishInflate() {
728f58e61d02fcb0ca90a2803e76a8792ec2c1f99aTony Wickham        super.onFinishInflate();
73a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        mIconView = findViewById(R.id.deep_shortcut_icon);
74a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        mBubbleText = (DeepShortcutTextView) findViewById(R.id.deep_shortcut);
751bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham    }
761bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham
77a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal    public DeepShortcutTextView getBubbleText() {
788f58e61d02fcb0ca90a2803e76a8792ec2c1f99aTony Wickham        return mBubbleText;
798f58e61d02fcb0ca90a2803e76a8792ec2c1f99aTony Wickham    }
808f58e61d02fcb0ca90a2803e76a8792ec2c1f99aTony Wickham
81a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal    public void setWillDrawIcon(boolean willDraw) {
82a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        mIconView.setVisibility(willDraw ? View.VISIBLE : View.INVISIBLE);
83a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal    }
84a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal
85a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal    public boolean willDrawIcon() {
86a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        return mIconView.getVisibility() == View.VISIBLE;
87a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal    }
88a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal
898f58e61d02fcb0ca90a2803e76a8792ec2c1f99aTony Wickham    @Override
908f58e61d02fcb0ca90a2803e76a8792ec2c1f99aTony Wickham    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
918f58e61d02fcb0ca90a2803e76a8792ec2c1f99aTony Wickham        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
928f58e61d02fcb0ca90a2803e76a8792ec2c1f99aTony Wickham        mPillRect.set(0, 0, getMeasuredWidth(), getMeasuredHeight());
938f58e61d02fcb0ca90a2803e76a8792ec2c1f99aTony Wickham    }
948f58e61d02fcb0ca90a2803e76a8792ec2c1f99aTony Wickham
955836bf728e85c1c4fae67862deb4e973ac55e944Sunny Goyal    /** package private **/
965836bf728e85c1c4fae67862deb4e973ac55e944Sunny Goyal    void applyShortcutInfo(UnbadgedShortcutInfo info, DeepShortcutsContainer container) {
975836bf728e85c1c4fae67862deb4e973ac55e944Sunny Goyal        mInfo = info;
98a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        IconCache cache = LauncherAppState.getInstance().getIconCache();
99a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        mBubbleText.applyFromShortcutInfo(info, cache);
100a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        mIconView.setBackground(mBubbleText.getIcon());
1015836bf728e85c1c4fae67862deb4e973ac55e944Sunny Goyal
1025836bf728e85c1c4fae67862deb4e973ac55e944Sunny Goyal        // Use the long label as long as it exists and fits.
1035836bf728e85c1c4fae67862deb4e973ac55e944Sunny Goyal        CharSequence longLabel = info.mDetail.getLongLabel();
1045836bf728e85c1c4fae67862deb4e973ac55e944Sunny Goyal        int availableWidth = mBubbleText.getWidth() - mBubbleText.getTotalPaddingLeft()
1055836bf728e85c1c4fae67862deb4e973ac55e944Sunny Goyal                - mBubbleText.getTotalPaddingRight();
1065836bf728e85c1c4fae67862deb4e973ac55e944Sunny Goyal        boolean usingLongLabel = !TextUtils.isEmpty(longLabel)
1075836bf728e85c1c4fae67862deb4e973ac55e944Sunny Goyal                && mBubbleText.getPaint().measureText(longLabel.toString()) <= availableWidth;
1085836bf728e85c1c4fae67862deb4e973ac55e944Sunny Goyal        mBubbleText.setText(usingLongLabel ? longLabel : info.mDetail.getShortLabel());
1095836bf728e85c1c4fae67862deb4e973ac55e944Sunny Goyal
1105836bf728e85c1c4fae67862deb4e973ac55e944Sunny Goyal        // TODO: Add the click handler to this view directly and not the child view.
1115836bf728e85c1c4fae67862deb4e973ac55e944Sunny Goyal        mBubbleText.setOnClickListener(Launcher.getLauncher(getContext()));
1125836bf728e85c1c4fae67862deb4e973ac55e944Sunny Goyal        mBubbleText.setOnLongClickListener(container);
1135836bf728e85c1c4fae67862deb4e973ac55e944Sunny Goyal        mBubbleText.setOnTouchListener(container);
1145836bf728e85c1c4fae67862deb4e973ac55e944Sunny Goyal    }
1155836bf728e85c1c4fae67862deb4e973ac55e944Sunny Goyal
1165836bf728e85c1c4fae67862deb4e973ac55e944Sunny Goyal    /**
1175836bf728e85c1c4fae67862deb4e973ac55e944Sunny Goyal     * Returns the shortcut info that is suitable to be added on the homescreen
1185836bf728e85c1c4fae67862deb4e973ac55e944Sunny Goyal     */
1195836bf728e85c1c4fae67862deb4e973ac55e944Sunny Goyal    public ShortcutInfo getFinalInfo() {
1205836bf728e85c1c4fae67862deb4e973ac55e944Sunny Goyal        ShortcutInfo badged = new ShortcutInfo(mInfo);
1215836bf728e85c1c4fae67862deb4e973ac55e944Sunny Goyal        // Queue an update task on the worker thread. This ensures that the badged
1225836bf728e85c1c4fae67862deb4e973ac55e944Sunny Goyal        // shortcut eventually gets its icon updated.
1235836bf728e85c1c4fae67862deb4e973ac55e944Sunny Goyal        Launcher.getLauncher(getContext()).getModel().updateShortcutInfo(mInfo.mDetail, badged);
1245836bf728e85c1c4fae67862deb4e973ac55e944Sunny Goyal        return badged;
1258f58e61d02fcb0ca90a2803e76a8792ec2c1f99aTony Wickham    }
1268f58e61d02fcb0ca90a2803e76a8792ec2c1f99aTony Wickham
127a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal    public View getIconView() {
128a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        return mIconView;
129a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal    }
130a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal
131a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal    /**
1320ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham     * Creates an animator to play when the shortcut container is being opened.
133a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal     */
1340ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham    public Animator createOpenAnimation(boolean isContainerAboveIcon, boolean pivotLeft) {
135a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        Point center = getIconCenter();
1360ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham        ValueAnimator openAnimator =  new ZoomRevealOutlineProvider(center.x, center.y,
1370ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham                mPillRect, this, mIconView, isContainerAboveIcon, pivotLeft)
1380ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham                        .createRevealAnimator(this, false);
1390ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham        mOpenAnimationProgress = 0f;
1400ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham        openAnimator.addUpdateListener(this);
1410ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham        return openAnimator;
1420ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham    }
1430ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham
1440ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham    @Override
1450ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham    public void onAnimationUpdate(ValueAnimator valueAnimator) {
1460ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham        mOpenAnimationProgress = valueAnimator.getAnimatedFraction();
1470ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham    }
1480ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham
1490ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham    public boolean isOpenOrOpening() {
1500ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham        return mOpenAnimationProgress > 0;
1510ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham    }
1520ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham
1530ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham    /**
1540ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham     * Creates an animator to play when the shortcut container is being closed.
1550ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham     */
1560ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham    public Animator createCloseAnimation(boolean isContainerAboveIcon, boolean pivotLeft,
1570ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham            long duration) {
1580ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham        Point center = getIconCenter();
1590ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham        ValueAnimator closeAnimator =  new ZoomRevealOutlineProvider(center.x, center.y,
1600ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham                mPillRect, this, mIconView, isContainerAboveIcon, pivotLeft)
1610ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham                        .createRevealAnimator(this, true);
1620ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham        // Scale down the duration and interpolator according to the progress
1630ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham        // that the open animation was at when the close started.
1640ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham        closeAnimator.setDuration((long) (duration * mOpenAnimationProgress));
1650ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham        closeAnimator.setInterpolator(new CloseInterpolator(mOpenAnimationProgress));
1660ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham        return closeAnimator;
167a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal    }
168a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal
169a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal    /**
170a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal     * Creates an animator which clips the container to form a circle around the icon.
171a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal     */
172a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal    public Animator collapseToIcon() {
173a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        int halfHeight = getMeasuredHeight() / 2;
174a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        int iconCenterX = getIconCenter().x;
175a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        return new PillWidthRevealOutlineProvider(mPillRect,
176a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal                iconCenterX - halfHeight, iconCenterX + halfHeight)
1770ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham                        .createRevealAnimator(this, true);
1788f58e61d02fcb0ca90a2803e76a8792ec2c1f99aTony Wickham    }
1798f58e61d02fcb0ca90a2803e76a8792ec2c1f99aTony Wickham
1808f58e61d02fcb0ca90a2803e76a8792ec2c1f99aTony Wickham    /**
181a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal     * Returns the position of the center of the icon relative to the container.
1828f58e61d02fcb0ca90a2803e76a8792ec2c1f99aTony Wickham     */
183a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal    public Point getIconCenter() {
184a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        sTempPoint.y = sTempPoint.x = getMeasuredHeight() / 2;
185a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        if (Utilities.isRtl(getResources())) {
186a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal            sTempPoint.x = getMeasuredWidth() - sTempPoint.x;
187a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        }
188a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        return sTempPoint;
189a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal    }
190a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal
191a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal    /**
192a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal     * Extension of {@link PillRevealOutlineProvider} which scales the icon based on the height.
193a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal     */
194a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal    private static class ZoomRevealOutlineProvider extends PillRevealOutlineProvider {
195a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal
196a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        private final View mTranslateView;
197a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        private final View mZoomView;
198a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal
199a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        private final float mFullHeight;
200a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        private final float mTranslateYMultiplier;
201a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal
202a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        private final boolean mPivotLeft;
203a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        private final float mTranslateX;
204a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal
205a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        public ZoomRevealOutlineProvider(int x, int y, Rect pillRect,
206a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal                View translateView, View zoomView, boolean isContainerAboveIcon, boolean pivotLeft) {
207a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal            super(x, y, pillRect);
208a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal            mTranslateView = translateView;
209a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal            mZoomView = zoomView;
210a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal            mFullHeight = pillRect.height();
211a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal
212a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal            mTranslateYMultiplier = isContainerAboveIcon ? 0.5f : -0.5f;
213a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal
214a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal            mPivotLeft = pivotLeft;
215a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal            mTranslateX = pivotLeft ? pillRect.height() / 2 : pillRect.right - pillRect.height() / 2;
216a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        }
217a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal
218a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        @Override
219a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        public void setProgress(float progress) {
220a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal            super.setProgress(progress);
221a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal
222a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal            mZoomView.setScaleX(progress);
223a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal            mZoomView.setScaleY(progress);
224a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal
225a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal            float height = mOutline.height();
226a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal            mTranslateView.setTranslationY(mTranslateYMultiplier * (mFullHeight - height));
227a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal
228a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal            float pivotX = mPivotLeft ? (mOutline.left + height / 2) : (mOutline.right - height / 2);
229a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal            mTranslateView.setTranslationX(mTranslateX - pivotX);
230a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        }
2311bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham    }
2320ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham
2330ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham    /**
2340ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham     * An interpolator that reverses the current open animation progress.
2350ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham     */
2360ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham    private static class CloseInterpolator extends LogAccelerateInterpolator {
2370ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham        private float mStartProgress;
2380ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham        private float mRemainingProgress;
2390ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham
2400ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham        /**
2410ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham         * @param openAnimationProgress The progress that the open interpolator ended at.
2420ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham         */
2430ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham        public CloseInterpolator(float openAnimationProgress) {
2440ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham            super(100, 0);
2450ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham            mStartProgress = 1f - openAnimationProgress;
2460ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham            mRemainingProgress = openAnimationProgress;
2470ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham        }
2480ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham
2490ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham        @Override
2500ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham        public float getInterpolation(float v) {
2510ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham            return mStartProgress + super.getInterpolation(v) * mRemainingProgress;
2520ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham        }
2530ba81607e30c008a7aa24ca76d74f9c4aaafd053Tony Wickham    }
2541bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham}
255