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