14ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek/*
24ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek * Copyright (C) 2016 The Android Open Source Project
34ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek *
44ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek * Licensed under the Apache License, Version 2.0 (the "License");
54ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek * you may not use this file except in compliance with the License.
64ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek * You may obtain a copy of the License at
74ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek *
84ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek *      http://www.apache.org/licenses/LICENSE-2.0
94ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek *
104ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek * Unless required by applicable law or agreed to in writing, software
114ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek * distributed under the License is distributed on an "AS IS" BASIS,
124ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek * See the License for the specific language governing permissions and
144ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek * limitations under the License
154ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek */
164ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek
174ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinekpackage com.android.systemui.statusbar;
184ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek
198f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinekimport android.animation.Animator;
208f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinekimport android.animation.AnimatorListenerAdapter;
218f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinekimport android.animation.ValueAnimator;
224ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinekimport android.util.ArrayMap;
2375524417ac507597b19abb2a91389044bec682adAdrian Roosimport android.util.ArraySet;
244ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinekimport android.view.View;
25646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinekimport android.view.ViewGroup;
265be6f33996ed50f382f46a392a5a5f74d4c020ebSelim Cinekimport android.view.animation.Interpolator;
274ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek
288f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinekimport com.android.systemui.Interpolators;
29646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinekimport com.android.systemui.R;
304ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinekimport com.android.systemui.statusbar.notification.TransformState;
318f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinekimport com.android.systemui.statusbar.stack.StackStateAnimator;
324ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek
33646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinekimport java.util.Stack;
34646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek
354ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek/**
364ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek * A view that can be transformed to and from.
374ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek */
381d6b50eccf3b608a34a2a92f46c7ee8b8641e0e4Selim Cinekpublic class ViewTransformationHelper implements TransformableView,
391d6b50eccf3b608a34a2a92f46c7ee8b8641e0e4Selim Cinek        TransformState.TransformInfo {
40646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek
41646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek    private static final int TAG_CONTAINS_TRANSFORMED_VIEW = R.id.contains_transformed_view;
42646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek
434ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek    private ArrayMap<Integer, View> mTransformedViews = new ArrayMap<>();
44fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek    private ArrayMap<Integer, CustomTransformation> mCustomTransformations = new ArrayMap<>();
458f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek    private ValueAnimator mViewTransformationAnimation;
464ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek
474ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek    public void addTransformedView(int key, View transformedView) {
484ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek        mTransformedViews.put(key, transformedView);
494ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek    }
504ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek
514ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek    public void reset() {
524ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek        mTransformedViews.clear();
534ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek    }
544ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek
55fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek    public void setCustomTransformation(CustomTransformation transformation, int viewType) {
56fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek        mCustomTransformations.put(viewType, transformation);
57fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek    }
58fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek
594ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek    @Override
604ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek    public TransformState getCurrentState(int fadingView) {
614ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek        View view = mTransformedViews.get(fadingView);
624ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek        if (view != null && view.getVisibility() != View.GONE) {
631d6b50eccf3b608a34a2a92f46c7ee8b8641e0e4Selim Cinek            return TransformState.createFrom(view, this);
644ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek        }
654ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek        return null;
664ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek    }
674ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek
684ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek    @Override
698f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek    public void transformTo(final TransformableView notification, final Runnable endRunnable) {
708f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek        if (mViewTransformationAnimation != null) {
718f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek            mViewTransformationAnimation.cancel();
728f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek        }
738f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek        mViewTransformationAnimation = ValueAnimator.ofFloat(0.0f, 1.0f);
748f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek        mViewTransformationAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
758f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek            @Override
768f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek            public void onAnimationUpdate(ValueAnimator animation) {
778f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek                transformTo(notification, animation.getAnimatedFraction());
788f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek            }
798f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek        });
808f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek        mViewTransformationAnimation.setInterpolator(Interpolators.LINEAR);
818f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek        mViewTransformationAnimation.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
8251d94917c7dc53845701702bfd63f102a3a2dbc8Selim Cinek        mViewTransformationAnimation.addListener(new AnimatorListenerAdapter() {
8351d94917c7dc53845701702bfd63f102a3a2dbc8Selim Cinek            public boolean mCancelled;
848f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek
8551d94917c7dc53845701702bfd63f102a3a2dbc8Selim Cinek            @Override
8651d94917c7dc53845701702bfd63f102a3a2dbc8Selim Cinek            public void onAnimationEnd(Animator animation) {
8751d94917c7dc53845701702bfd63f102a3a2dbc8Selim Cinek                if (!mCancelled) {
8851d94917c7dc53845701702bfd63f102a3a2dbc8Selim Cinek                    if (endRunnable != null) {
8951d94917c7dc53845701702bfd63f102a3a2dbc8Selim Cinek                        endRunnable.run();
908f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek                    }
9151d94917c7dc53845701702bfd63f102a3a2dbc8Selim Cinek                    setVisible(false);
921d6b50eccf3b608a34a2a92f46c7ee8b8641e0e4Selim Cinek                    mViewTransformationAnimation = null;
9351d94917c7dc53845701702bfd63f102a3a2dbc8Selim Cinek                } else {
9451d94917c7dc53845701702bfd63f102a3a2dbc8Selim Cinek                    abortTransformations();
958f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek                }
9651d94917c7dc53845701702bfd63f102a3a2dbc8Selim Cinek            }
978f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek
9851d94917c7dc53845701702bfd63f102a3a2dbc8Selim Cinek            @Override
9951d94917c7dc53845701702bfd63f102a3a2dbc8Selim Cinek            public void onAnimationCancel(Animator animation) {
10051d94917c7dc53845701702bfd63f102a3a2dbc8Selim Cinek                mCancelled = true;
10151d94917c7dc53845701702bfd63f102a3a2dbc8Selim Cinek            }
10251d94917c7dc53845701702bfd63f102a3a2dbc8Selim Cinek        });
1038f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek        mViewTransformationAnimation.start();
1048f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek    }
1058f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek
1068f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek    @Override
1078f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek    public void transformTo(TransformableView notification, float transformationAmount) {
1084ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek        for (Integer viewType : mTransformedViews.keySet()) {
1094ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek            TransformState ownState = getCurrentState(viewType);
1104ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek            if (ownState != null) {
111fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek                CustomTransformation customTransformation = mCustomTransformations.get(viewType);
112fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek                if (customTransformation != null && customTransformation.transformTo(
1138f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek                        ownState, notification, transformationAmount)) {
114fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek                    ownState.recycle();
115fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek                    continue;
116fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek                }
1174ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek                TransformState otherState = notification.getCurrentState(viewType);
1184ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek                if (otherState != null) {
1198f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek                    ownState.transformViewTo(otherState, transformationAmount);
1204ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek                    otherState.recycle();
1214ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek                } else {
1228a71ad032f208d5ba1f8553612b355c7633ee3e2Selim Cinek                    ownState.disappear(transformationAmount, notification);
1234ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek                }
1244ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek                ownState.recycle();
1254ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek            }
1264ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek        }
1278f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek    }
1288f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek
1298f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek    @Override
1308f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek    public void transformFrom(final TransformableView notification) {
1318f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek        if (mViewTransformationAnimation != null) {
1328f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek            mViewTransformationAnimation.cancel();
1334ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek        }
1348f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek        mViewTransformationAnimation = ValueAnimator.ofFloat(0.0f, 1.0f);
1358f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek        mViewTransformationAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
1368f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek            @Override
1378f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek            public void onAnimationUpdate(ValueAnimator animation) {
1388f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek                transformFrom(notification, animation.getAnimatedFraction());
1398f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek            }
1408f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek        });
1418f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek        mViewTransformationAnimation.addListener(new AnimatorListenerAdapter() {
1428f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek            public boolean mCancelled;
1438f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek
1448f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek            @Override
1458f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek            public void onAnimationEnd(Animator animation) {
1468f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek                if (!mCancelled) {
1478f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek                    setVisible(true);
1488f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek                } else {
1498f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek                    abortTransformations();
1508f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek                }
1518f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek            }
1528f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek
1538f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek            @Override
1548f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek            public void onAnimationCancel(Animator animation) {
1558f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek                mCancelled = true;
1568f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek            }
1578f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek        });
1588f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek        mViewTransformationAnimation.setInterpolator(Interpolators.LINEAR);
1598f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek        mViewTransformationAnimation.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
1608f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek        mViewTransformationAnimation.start();
1614ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek    }
1624ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek
1634ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek    @Override
1648f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek    public void transformFrom(TransformableView notification, float transformationAmount) {
1654ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek        for (Integer viewType : mTransformedViews.keySet()) {
1664ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek            TransformState ownState = getCurrentState(viewType);
1674ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek            if (ownState != null) {
168fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek                CustomTransformation customTransformation = mCustomTransformations.get(viewType);
169fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek                if (customTransformation != null && customTransformation.transformFrom(
1708f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek                        ownState, notification, transformationAmount)) {
171fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek                    ownState.recycle();
172fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek                    continue;
173fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek                }
1744ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek                TransformState otherState = notification.getCurrentState(viewType);
1754ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek                if (otherState != null) {
1768f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek                    ownState.transformViewFrom(otherState, transformationAmount);
1774ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek                    otherState.recycle();
1784ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek                } else {
1798a71ad032f208d5ba1f8553612b355c7633ee3e2Selim Cinek                    ownState.appear(transformationAmount, notification);
1804ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek                }
1814ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek                ownState.recycle();
1824ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek            }
1834ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek        }
1844ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek    }
1854ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek
1864ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek    @Override
1874ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek    public void setVisible(boolean visible) {
188d607daf30e8ce3d42cc6896271ab1e7679c7a5faSelim Cinek        if (mViewTransformationAnimation != null) {
189d607daf30e8ce3d42cc6896271ab1e7679c7a5faSelim Cinek            mViewTransformationAnimation.cancel();
190d607daf30e8ce3d42cc6896271ab1e7679c7a5faSelim Cinek        }
1914ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek        for (Integer viewType : mTransformedViews.keySet()) {
1924ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek            TransformState ownState = getCurrentState(viewType);
1934ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek            if (ownState != null) {
19475524417ac507597b19abb2a91389044bec682adAdrian Roos                ownState.setVisible(visible, false /* force */);
1954ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek                ownState.recycle();
1964ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek            }
1974ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek        }
1984ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek    }
199646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek
2008f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek    private void abortTransformations() {
2018f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek        for (Integer viewType : mTransformedViews.keySet()) {
2028f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek            TransformState ownState = getCurrentState(viewType);
2038f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek            if (ownState != null) {
2048f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek                ownState.abortTransformation();
2058f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek                ownState.recycle();
2068f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek            }
2078f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek        }
2088f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek    }
2098f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek
210646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek    /**
211646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek     * Add the remaining transformation views such that all views are being transformed correctly
212646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek     * @param viewRoot the root below which all elements need to be transformed
213646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek     */
214646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek    public void addRemainingTransformTypes(View viewRoot) {
215646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek        // lets now tag the right views
216646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek        int numValues = mTransformedViews.size();
217646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek        for (int i = 0; i < numValues; i++) {
218646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek            View view = mTransformedViews.valueAt(i);
219646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek            while (view != viewRoot.getParent()) {
220646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek                view.setTag(TAG_CONTAINS_TRANSFORMED_VIEW, true);
221646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek                view = (View) view.getParent();
222646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek            }
223646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek        }
224646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek        Stack<View> stack = new Stack<>();
225646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek        // Add the right views now
226646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek        stack.push(viewRoot);
227646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek        while (!stack.isEmpty()) {
228646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek            View child = stack.pop();
229646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek            Boolean containsView = (Boolean) child.getTag(TAG_CONTAINS_TRANSFORMED_VIEW);
230646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek            if (containsView == null) {
231646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek                // This one is unhandled, let's add it to our list.
232646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek                int id = child.getId();
233646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek                if (id != View.NO_ID) {
234646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek                    // We only fade views with an id
235646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek                    addTransformedView(id, child);
236646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek                    continue;
237646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek                }
238646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek            }
239646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek            child.setTag(TAG_CONTAINS_TRANSFORMED_VIEW, null);
240646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek            if (child instanceof ViewGroup && !mTransformedViews.containsValue(child)){
241646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek                ViewGroup group = (ViewGroup) child;
242646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek                for (int i = 0; i < group.getChildCount(); i++) {
243646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek                    stack.push(group.getChildAt(i));
244646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek                }
245646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek            }
246646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek        }
247646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek    }
248fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek
24975524417ac507597b19abb2a91389044bec682adAdrian Roos    public void resetTransformedView(View view) {
2501d6b50eccf3b608a34a2a92f46c7ee8b8641e0e4Selim Cinek        TransformState state = TransformState.createFrom(view, this);
25175524417ac507597b19abb2a91389044bec682adAdrian Roos        state.setVisible(true /* visible */, true /* force */);
25275524417ac507597b19abb2a91389044bec682adAdrian Roos        state.recycle();
25375524417ac507597b19abb2a91389044bec682adAdrian Roos    }
25475524417ac507597b19abb2a91389044bec682adAdrian Roos
25575524417ac507597b19abb2a91389044bec682adAdrian Roos    /**
25675524417ac507597b19abb2a91389044bec682adAdrian Roos     * @return a set of all views are being transformed.
25775524417ac507597b19abb2a91389044bec682adAdrian Roos     */
25875524417ac507597b19abb2a91389044bec682adAdrian Roos    public ArraySet<View> getAllTransformingViews() {
25975524417ac507597b19abb2a91389044bec682adAdrian Roos        return new ArraySet<>(mTransformedViews.values());
26075524417ac507597b19abb2a91389044bec682adAdrian Roos    }
26175524417ac507597b19abb2a91389044bec682adAdrian Roos
2621d6b50eccf3b608a34a2a92f46c7ee8b8641e0e4Selim Cinek    @Override
2631d6b50eccf3b608a34a2a92f46c7ee8b8641e0e4Selim Cinek    public boolean isAnimating() {
2641d6b50eccf3b608a34a2a92f46c7ee8b8641e0e4Selim Cinek        return mViewTransformationAnimation != null && mViewTransformationAnimation.isRunning();
2651d6b50eccf3b608a34a2a92f46c7ee8b8641e0e4Selim Cinek    }
2661d6b50eccf3b608a34a2a92f46c7ee8b8641e0e4Selim Cinek
2678f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek    public static abstract class CustomTransformation {
268fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek        /**
269fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek         * Transform a state to the given view
270fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek         * @param ownState the state to transform
271fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek         * @param notification the view to transform to
2728f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek         * @param transformationAmount how much transformation should be done
273fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek         * @return whether a custom transformation is performed
274fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek         */
2758f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek        public abstract boolean transformTo(TransformState ownState,
2768f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek                TransformableView notification,
2778f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek                float transformationAmount);
278fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek
279fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek        /**
280fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek         * Transform to this state from the given view
281fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek         * @param ownState the state to transform to
282fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek         * @param notification the view to transform from
2838f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek         * @param transformationAmount how much transformation should be done
284fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek         * @return whether a custom transformation is performed
285fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek         */
2868f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek        public abstract boolean transformFrom(TransformState ownState,
2878f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek                TransformableView notification,
2888f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek                float transformationAmount);
2898f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek
2908f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek        /**
2918f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek         * Perform a custom initialisation before transforming.
2928f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek         *
2938f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek         * @param ownState our own state
2948f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek         * @param otherState the other state
2958f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek         * @return whether a custom initialization is done
2968f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek         */
2978f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek        public boolean initTransformation(TransformState ownState,
2988f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek                TransformState otherState) {
2998f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek            return false;
3008f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek        }
3018f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek
3028f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek        public boolean customTransformTarget(TransformState ownState,
3038f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek                TransformState otherState) {
3048f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek            return false;
3058f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek        }
3065be6f33996ed50f382f46a392a5a5f74d4c020ebSelim Cinek
3075be6f33996ed50f382f46a392a5a5f74d4c020ebSelim Cinek        /**
3085be6f33996ed50f382f46a392a5a5f74d4c020ebSelim Cinek         * Get a custom interpolator for this animation
3095be6f33996ed50f382f46a392a5a5f74d4c020ebSelim Cinek         * @param interpolationType the type of the interpolation, i.e TranslationX / TranslationY
3105be6f33996ed50f382f46a392a5a5f74d4c020ebSelim Cinek         * @param isFrom true if this transformation from the other view
3115be6f33996ed50f382f46a392a5a5f74d4c020ebSelim Cinek         */
3125be6f33996ed50f382f46a392a5a5f74d4c020ebSelim Cinek        public Interpolator getCustomInterpolator(int interpolationType, boolean isFrom) {
3135be6f33996ed50f382f46a392a5a5f74d4c020ebSelim Cinek            return null;
3145be6f33996ed50f382f46a392a5a5f74d4c020ebSelim Cinek        }
315fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek    }
3164ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek}
317