12f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu/*
22f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu * Copyright (C) 2014 The Android Open Source Project
32f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu *
42f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu * Licensed under the Apache License, Version 2.0 (the "License");
52f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu * you may not use this file except in compliance with the License.
62f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu * You may obtain a copy of the License at
72f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu *
82f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu *      http://www.apache.org/licenses/LICENSE-2.0
92f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu *
102f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu * Unless required by applicable law or agreed to in writing, software
112f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu * distributed under the License is distributed on an "AS IS" BASIS,
122f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu * See the License for the specific language governing permissions and
142f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu * limitations under the License.
152f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu */
1695400e6d31a1ac09e48cb8944a79b7250484aa4cDake Gupackage android.support.v17.leanback.transition;
172f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu
182f97594742886d045ca1ce409ebc6e6e780452f6Dake Guimport android.animation.Animator;
192f97594742886d045ca1ce409ebc6e6e780452f6Dake Guimport android.animation.AnimatorListenerAdapter;
202f97594742886d045ca1ce409ebc6e6e780452f6Dake Guimport android.animation.ObjectAnimator;
212f97594742886d045ca1ce409ebc6e6e780452f6Dake Guimport android.animation.TimeInterpolator;
224735bfcd924fec2d694523f34fac5f8151257dc7Dake Guimport android.content.Context;
234735bfcd924fec2d694523f34fac5f8151257dc7Dake Guimport android.content.res.TypedArray;
248f886fe8c7e23fe6ccb8734167c960c2ed3429c3Alan Viveretteimport android.support.annotation.RequiresApi;
258f886fe8c7e23fe6ccb8734167c960c2ed3429c3Alan Viveretteimport android.support.v17.leanback.R;
268f886fe8c7e23fe6ccb8734167c960c2ed3429c3Alan Viveretteimport android.transition.TransitionValues;
278f886fe8c7e23fe6ccb8734167c960c2ed3429c3Alan Viveretteimport android.transition.Visibility;
284735bfcd924fec2d694523f34fac5f8151257dc7Dake Guimport android.util.AttributeSet;
292f97594742886d045ca1ce409ebc6e6e780452f6Dake Guimport android.util.Property;
304735bfcd924fec2d694523f34fac5f8151257dc7Dake Guimport android.view.Gravity;
312f97594742886d045ca1ce409ebc6e6e780452f6Dake Guimport android.view.View;
322f97594742886d045ca1ce409ebc6e6e780452f6Dake Guimport android.view.ViewGroup;
332f97594742886d045ca1ce409ebc6e6e780452f6Dake Guimport android.view.animation.AccelerateInterpolator;
344735bfcd924fec2d694523f34fac5f8151257dc7Dake Guimport android.view.animation.AnimationUtils;
352f97594742886d045ca1ce409ebc6e6e780452f6Dake Guimport android.view.animation.DecelerateInterpolator;
362f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu
372f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu/**
384735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu * Slide distance toward/from a edge.
394735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu * This is a limited Slide implementation for KitKat without propagation support.
402f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu */
418f886fe8c7e23fe6ccb8734167c960c2ed3429c3Alan Viverette@RequiresApi(19)
424735bfcd924fec2d694523f34fac5f8151257dc7Dake Guclass SlideKitkat extends Visibility {
434735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu    private static final String TAG = "SlideKitkat";
442f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu
452f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    private static final TimeInterpolator sDecelerate = new DecelerateInterpolator();
462f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    private static final TimeInterpolator sAccelerate = new AccelerateInterpolator();
472f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu
484735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu    private int mSlideEdge;
494735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu    private CalculateSlide mSlideCalculator;
502f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu
512f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    private interface CalculateSlide {
522f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        /** Returns the translation value for view when it out of the scene */
534735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu        float getGone(View view);
542f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu
552f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        /** Returns the translation value for view when it is in the scene */
562f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        float getHere(View view);
572f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu
582f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        /** Returns the property to animate translation */
592f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        Property<View, Float> getProperty();
602f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    }
612f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu
622f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    private static abstract class CalculateSlideHorizontal implements CalculateSlide {
6399ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas        CalculateSlideHorizontal() {
6499ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas        }
6599ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas
662f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        @Override
672f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        public float getHere(View view) {
682f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu            return view.getTranslationX();
692f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        }
702f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu
712f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        @Override
722f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        public Property<View, Float> getProperty() {
732f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu            return View.TRANSLATION_X;
742f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        }
752f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    }
762f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu
772f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    private static abstract class CalculateSlideVertical implements CalculateSlide {
7899ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas        CalculateSlideVertical() {
7999ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas        }
8099ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas
812f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        @Override
822f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        public float getHere(View view) {
832f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu            return view.getTranslationY();
842f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        }
852f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu
862f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        @Override
872f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        public Property<View, Float> getProperty() {
882f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu            return View.TRANSLATION_Y;
892f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        }
902f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    }
912f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu
922f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    private static final CalculateSlide sCalculateLeft = new CalculateSlideHorizontal() {
932f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        @Override
944735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu        public float getGone(View view) {
954735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu            return view.getTranslationX() - view.getWidth();
962f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        }
972f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    };
982f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu
992f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    private static final CalculateSlide sCalculateTop = new CalculateSlideVertical() {
1002f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        @Override
1014735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu        public float getGone(View view) {
1024735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu            return view.getTranslationY() - view.getHeight();
1032f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        }
1042f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    };
1052f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu
1062f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    private static final CalculateSlide sCalculateRight = new CalculateSlideHorizontal() {
1072f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        @Override
1084735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu        public float getGone(View view) {
1094735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu            return view.getTranslationX() + view.getWidth();
1102f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        }
1112f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    };
1122f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu
1132f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    private static final CalculateSlide sCalculateBottom = new CalculateSlideVertical() {
1142f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        @Override
1154735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu        public float getGone(View view) {
1164735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu            return view.getTranslationY() + view.getHeight();
1174735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu        }
1184735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu    };
1194735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu
1204735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu    private static final CalculateSlide sCalculateStart = new CalculateSlideHorizontal() {
1214735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu        @Override
1224735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu        public float getGone(View view) {
1234735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu            if (view.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
1244735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu                return view.getTranslationX() + view.getWidth();
1254735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu            } else {
1264735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu                return view.getTranslationX() - view.getWidth();
1274735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu            }
1282f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        }
1292f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    };
1302f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu
1314735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu    private static final CalculateSlide sCalculateEnd = new CalculateSlideHorizontal() {
1324735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu        @Override
1334735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu        public float getGone(View view) {
1344735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu            if (view.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
1354735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu                return view.getTranslationX() - view.getWidth();
1364735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu            } else {
1374735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu                return view.getTranslationX() + view.getWidth();
1384735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu            }
1394735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu        }
1404735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu    };
1414735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu
1424735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu    public SlideKitkat() {
1434735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu        setSlideEdge(Gravity.BOTTOM);
1442f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    }
1452f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu
1464735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu    public SlideKitkat(Context context, AttributeSet attrs) {
1474735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.lbSlide);
1484735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu        int edge = a.getInt(R.styleable.lbSlide_lb_slideEdge, Gravity.BOTTOM);
1494735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu        setSlideEdge(edge);
1504735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu        long duration = a.getInt(R.styleable.lbSlide_android_duration, -1);
1514735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu        if (duration >= 0) {
1524735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu            setDuration(duration);
1534735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu        }
1544735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu        long startDelay = a.getInt(R.styleable.lbSlide_android_startDelay, -1);
1554735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu        if (startDelay > 0) {
1564735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu            setStartDelay(startDelay);
1574735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu        }
1584735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu        final int resID = a.getResourceId(R.styleable.lbSlide_android_interpolator, 0);
1594735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu        if (resID > 0) {
1604735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu            setInterpolator(AnimationUtils.loadInterpolator(context, resID));
1614735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu        }
1624735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu        a.recycle();
1632f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    }
1642f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu
1654735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu    /**
1664735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu     * Change the edge that Views appear and disappear from.
1674735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu     *
1684735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu     * @param slideEdge The edge of the scene to use for Views appearing and disappearing. One of
1694735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu     *                  {@link android.view.Gravity#LEFT}, {@link android.view.Gravity#TOP},
1704735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu     *                  {@link android.view.Gravity#RIGHT}, {@link android.view.Gravity#BOTTOM},
1714735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu     *                  {@link android.view.Gravity#START}, {@link android.view.Gravity#END}.
1724735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu     */
1734735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu    public void setSlideEdge(int slideEdge) {
1742f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        switch (slideEdge) {
1754735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu            case Gravity.LEFT:
1764735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu                mSlideCalculator = sCalculateLeft;
1774735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu                break;
1784735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu            case Gravity.TOP:
1794735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu                mSlideCalculator = sCalculateTop;
1804735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu                break;
1814735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu            case Gravity.RIGHT:
1824735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu                mSlideCalculator = sCalculateRight;
1834735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu                break;
1844735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu            case Gravity.BOTTOM:
1854735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu                mSlideCalculator = sCalculateBottom;
1864735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu                break;
1874735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu            case Gravity.START:
1884735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu                mSlideCalculator = sCalculateStart;
1894735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu                break;
1904735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu            case Gravity.END:
1914735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu                mSlideCalculator = sCalculateEnd;
1924735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu                break;
1932f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu            default:
1942f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu                throw new IllegalArgumentException("Invalid slide direction");
1952f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        }
1964735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu        mSlideEdge = slideEdge;
1974735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu    }
1984735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu
1994735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu    /**
2004735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu     * Returns the edge that Views appear and disappear from.
2014735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu     * @return the edge of the scene to use for Views appearing and disappearing. One of
2024735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu     *         {@link android.view.Gravity#LEFT}, {@link android.view.Gravity#TOP},
2034735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu     *         {@link android.view.Gravity#RIGHT}, {@link android.view.Gravity#BOTTOM},
2044735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu     *         {@link android.view.Gravity#START}, {@link android.view.Gravity#END}.
2054735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu     */
2064735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu    public int getSlideEdge() {
2074735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu        return mSlideEdge;
2082f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    }
2092f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu
2102f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    private Animator createAnimation(final View view, Property<View, Float> property,
21133f66eb67b6457ea75434dfd9f79703ad9e03560Dake Gu            float start, float end, float terminalValue, TimeInterpolator interpolator,
21233f66eb67b6457ea75434dfd9f79703ad9e03560Dake Gu            int finalVisibility) {
21333f66eb67b6457ea75434dfd9f79703ad9e03560Dake Gu        float[] startPosition = (float[]) view.getTag(R.id.lb_slide_transition_value);
21433f66eb67b6457ea75434dfd9f79703ad9e03560Dake Gu        if (startPosition != null) {
21533f66eb67b6457ea75434dfd9f79703ad9e03560Dake Gu            start = View.TRANSLATION_Y == property ? startPosition[1] : startPosition[0];
21633f66eb67b6457ea75434dfd9f79703ad9e03560Dake Gu            view.setTag(R.id.lb_slide_transition_value, null);
2172f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        }
2182f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        final ObjectAnimator anim = ObjectAnimator.ofFloat(view, property, start, end);
2192f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu
22033f66eb67b6457ea75434dfd9f79703ad9e03560Dake Gu        SlideAnimatorListener listener = new SlideAnimatorListener(view, property, terminalValue, end,
22133f66eb67b6457ea75434dfd9f79703ad9e03560Dake Gu                finalVisibility);
2222f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        anim.addListener(listener);
2232f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        anim.addPauseListener(listener);
2242f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        anim.setInterpolator(interpolator);
2252f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        return anim;
2262f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    }
2272f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu
2282f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    @Override
2292f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    public Animator onAppear(ViewGroup sceneRoot,
2302f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu            TransitionValues startValues, int startVisibility,
2312f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu            TransitionValues endValues, int endVisibility) {
2322f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        View view = (endValues != null) ? endValues.view : null;
2332f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        if (view == null) {
2342f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu            return null;
2352f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        }
2364735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu        float end = mSlideCalculator.getHere(view);
2374735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu        float start = mSlideCalculator.getGone(view);
2384735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu        return createAnimation(view, mSlideCalculator.getProperty(), start, end, end, sDecelerate,
23933f66eb67b6457ea75434dfd9f79703ad9e03560Dake Gu                View.VISIBLE);
2402f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    }
2412f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu
2422f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    @Override
2432f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    public Animator onDisappear(ViewGroup sceneRoot,
2442f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu            TransitionValues startValues, int startVisibility,
2452f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu            TransitionValues endValues, int endVisibility) {
2462f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        View view = (startValues != null) ? startValues.view : null;
2472f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        if (view == null) {
2482f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu            return null;
2492f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        }
2504735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu        float start = mSlideCalculator.getHere(view);
2514735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu        float end = mSlideCalculator.getGone(view);
2522f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu
2534735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu        return createAnimation(view, mSlideCalculator.getProperty(), start, end, start,
25433f66eb67b6457ea75434dfd9f79703ad9e03560Dake Gu                sAccelerate, View.INVISIBLE);
2552f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    }
2562f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu
2572f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    private static class SlideAnimatorListener extends AnimatorListenerAdapter {
2582f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        private boolean mCanceled = false;
25933f66eb67b6457ea75434dfd9f79703ad9e03560Dake Gu        private float mPausedValue;
2602f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        private final View mView;
26133f66eb67b6457ea75434dfd9f79703ad9e03560Dake Gu        private final float mEndValue;
26233f66eb67b6457ea75434dfd9f79703ad9e03560Dake Gu        private final float mTerminalValue;
26333f66eb67b6457ea75434dfd9f79703ad9e03560Dake Gu        private final int mFinalVisibility;
26433f66eb67b6457ea75434dfd9f79703ad9e03560Dake Gu        private final Property<View, Float> mProp;
26533f66eb67b6457ea75434dfd9f79703ad9e03560Dake Gu
26633f66eb67b6457ea75434dfd9f79703ad9e03560Dake Gu        public SlideAnimatorListener(View view, Property<View, Float> prop,
26733f66eb67b6457ea75434dfd9f79703ad9e03560Dake Gu                float terminalValue, float endValue, int finalVisibility) {
26833f66eb67b6457ea75434dfd9f79703ad9e03560Dake Gu            mProp = prop;
2692f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu            mView = view;
27033f66eb67b6457ea75434dfd9f79703ad9e03560Dake Gu            mTerminalValue = terminalValue;
27133f66eb67b6457ea75434dfd9f79703ad9e03560Dake Gu            mEndValue = endValue;
27233f66eb67b6457ea75434dfd9f79703ad9e03560Dake Gu            mFinalVisibility = finalVisibility;
27333f66eb67b6457ea75434dfd9f79703ad9e03560Dake Gu            view.setVisibility(View.VISIBLE);
2742f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        }
2752f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu
2762f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        @Override
2772f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        public void onAnimationCancel(Animator animator) {
27833f66eb67b6457ea75434dfd9f79703ad9e03560Dake Gu            float[] transitionPosition = new float[2];
27933f66eb67b6457ea75434dfd9f79703ad9e03560Dake Gu            transitionPosition[0] = mView.getTranslationX();
28033f66eb67b6457ea75434dfd9f79703ad9e03560Dake Gu            transitionPosition[1] = mView.getTranslationY();
28133f66eb67b6457ea75434dfd9f79703ad9e03560Dake Gu            mView.setTag(R.id.lb_slide_transition_value, transitionPosition);
28233f66eb67b6457ea75434dfd9f79703ad9e03560Dake Gu            mProp.set(mView, mTerminalValue);
2832f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu            mCanceled = true;
2842f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        }
2852f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu
2862f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        @Override
2872f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        public void onAnimationEnd(Animator animator) {
2882f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu            if (!mCanceled) {
28933f66eb67b6457ea75434dfd9f79703ad9e03560Dake Gu                mProp.set(mView, mTerminalValue);
2902f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu            }
29133f66eb67b6457ea75434dfd9f79703ad9e03560Dake Gu            mView.setVisibility(mFinalVisibility);
2922f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        }
2932f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu
2942f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        @Override
2952f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        public void onAnimationPause(Animator animator) {
29633f66eb67b6457ea75434dfd9f79703ad9e03560Dake Gu            mPausedValue = mProp.get(mView);
29733f66eb67b6457ea75434dfd9f79703ad9e03560Dake Gu            mProp.set(mView, mEndValue);
29833f66eb67b6457ea75434dfd9f79703ad9e03560Dake Gu            mView.setVisibility(mFinalVisibility);
2992f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        }
3002f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu
3012f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        @Override
3022f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        public void onAnimationResume(Animator animator) {
30333f66eb67b6457ea75434dfd9f79703ad9e03560Dake Gu            mProp.set(mView, mPausedValue);
30433f66eb67b6457ea75434dfd9f79703ad9e03560Dake Gu            mView.setVisibility(View.VISIBLE);
3052f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        }
3062f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    }
3072f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu}