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; 264ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek 278f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinekimport com.android.systemui.Interpolators; 28646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinekimport com.android.systemui.R; 294ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinekimport com.android.systemui.statusbar.notification.TransformState; 308f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinekimport com.android.systemui.statusbar.stack.StackStateAnimator; 314ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek 32646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinekimport java.util.Stack; 33646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek 344ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek/** 354ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek * A view that can be transformed to and from. 364ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek */ 374ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinekpublic class ViewTransformationHelper implements TransformableView { 38646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek 39646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek private static final int TAG_CONTAINS_TRANSFORMED_VIEW = R.id.contains_transformed_view; 40646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek 414ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek private ArrayMap<Integer, View> mTransformedViews = new ArrayMap<>(); 42fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek private ArrayMap<Integer, CustomTransformation> mCustomTransformations = new ArrayMap<>(); 438f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek private ValueAnimator mViewTransformationAnimation; 444ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek 454ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek public void addTransformedView(int key, View transformedView) { 464ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek mTransformedViews.put(key, transformedView); 474ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek } 484ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek 494ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek public void reset() { 504ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek mTransformedViews.clear(); 514ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek } 524ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek 53fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek public void setCustomTransformation(CustomTransformation transformation, int viewType) { 54fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek mCustomTransformations.put(viewType, transformation); 55fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek } 56fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek 574ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek @Override 584ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek public TransformState getCurrentState(int fadingView) { 594ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek View view = mTransformedViews.get(fadingView); 604ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek if (view != null && view.getVisibility() != View.GONE) { 614ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek return TransformState.createFrom(view); 624ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek } 634ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek return null; 644ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek } 654ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek 664ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek @Override 678f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek public void transformTo(final TransformableView notification, final Runnable endRunnable) { 688f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek if (mViewTransformationAnimation != null) { 698f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek mViewTransformationAnimation.cancel(); 708f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek } 718f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek mViewTransformationAnimation = ValueAnimator.ofFloat(0.0f, 1.0f); 728f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek mViewTransformationAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 738f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek @Override 748f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek public void onAnimationUpdate(ValueAnimator animation) { 758f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek transformTo(notification, animation.getAnimatedFraction()); 768f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek } 778f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek }); 788f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek mViewTransformationAnimation.setInterpolator(Interpolators.LINEAR); 798f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek mViewTransformationAnimation.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD); 8051d94917c7dc53845701702bfd63f102a3a2dbc8Selim Cinek mViewTransformationAnimation.addListener(new AnimatorListenerAdapter() { 8151d94917c7dc53845701702bfd63f102a3a2dbc8Selim Cinek public boolean mCancelled; 828f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek 8351d94917c7dc53845701702bfd63f102a3a2dbc8Selim Cinek @Override 8451d94917c7dc53845701702bfd63f102a3a2dbc8Selim Cinek public void onAnimationEnd(Animator animation) { 8551d94917c7dc53845701702bfd63f102a3a2dbc8Selim Cinek if (!mCancelled) { 8651d94917c7dc53845701702bfd63f102a3a2dbc8Selim Cinek if (endRunnable != null) { 8751d94917c7dc53845701702bfd63f102a3a2dbc8Selim Cinek endRunnable.run(); 888f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek } 8951d94917c7dc53845701702bfd63f102a3a2dbc8Selim Cinek setVisible(false); 9051d94917c7dc53845701702bfd63f102a3a2dbc8Selim Cinek } else { 9151d94917c7dc53845701702bfd63f102a3a2dbc8Selim Cinek abortTransformations(); 928f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek } 9351d94917c7dc53845701702bfd63f102a3a2dbc8Selim Cinek } 948f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek 9551d94917c7dc53845701702bfd63f102a3a2dbc8Selim Cinek @Override 9651d94917c7dc53845701702bfd63f102a3a2dbc8Selim Cinek public void onAnimationCancel(Animator animation) { 9751d94917c7dc53845701702bfd63f102a3a2dbc8Selim Cinek mCancelled = true; 9851d94917c7dc53845701702bfd63f102a3a2dbc8Selim Cinek } 9951d94917c7dc53845701702bfd63f102a3a2dbc8Selim Cinek }); 1008f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek mViewTransformationAnimation.start(); 1018f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek } 1028f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek 1038f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek @Override 1048f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek public void transformTo(TransformableView notification, float transformationAmount) { 1054ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek for (Integer viewType : mTransformedViews.keySet()) { 1064ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek TransformState ownState = getCurrentState(viewType); 1074ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek if (ownState != null) { 108fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek CustomTransformation customTransformation = mCustomTransformations.get(viewType); 109fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek if (customTransformation != null && customTransformation.transformTo( 1108f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek ownState, notification, transformationAmount)) { 111fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek ownState.recycle(); 112fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek continue; 113fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek } 1144ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek TransformState otherState = notification.getCurrentState(viewType); 1154ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek if (otherState != null) { 1168f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek ownState.transformViewTo(otherState, transformationAmount); 1174ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek otherState.recycle(); 1184ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek } else { 1194ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek // there's no other view available 1208f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek CrossFadeHelper.fadeOut(mTransformedViews.get(viewType), transformationAmount); 1214ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek } 1224ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek ownState.recycle(); 1234ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek } 1244ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek } 1258f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek } 1268f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek 1278f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek @Override 1288f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek public void transformFrom(final TransformableView notification) { 1298f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek if (mViewTransformationAnimation != null) { 1308f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek mViewTransformationAnimation.cancel(); 1314ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek } 1328f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek mViewTransformationAnimation = ValueAnimator.ofFloat(0.0f, 1.0f); 1338f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek mViewTransformationAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 1348f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek @Override 1358f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek public void onAnimationUpdate(ValueAnimator animation) { 1368f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek transformFrom(notification, animation.getAnimatedFraction()); 1378f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek } 1388f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek }); 1398f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek mViewTransformationAnimation.addListener(new AnimatorListenerAdapter() { 1408f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek public boolean mCancelled; 1418f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek 1428f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek @Override 1438f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek public void onAnimationEnd(Animator animation) { 1448f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek if (!mCancelled) { 1458f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek setVisible(true); 1468f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek } else { 1478f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek abortTransformations(); 1488f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek } 1498f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek } 1508f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek 1518f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek @Override 1528f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek public void onAnimationCancel(Animator animation) { 1538f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek mCancelled = true; 1548f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek } 1558f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek }); 1568f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek mViewTransformationAnimation.setInterpolator(Interpolators.LINEAR); 1578f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek mViewTransformationAnimation.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD); 1588f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek mViewTransformationAnimation.start(); 1594ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek } 1604ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek 1614ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek @Override 1628f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek public void transformFrom(TransformableView notification, float transformationAmount) { 1634ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek for (Integer viewType : mTransformedViews.keySet()) { 1644ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek TransformState ownState = getCurrentState(viewType); 1654ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek if (ownState != null) { 166fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek CustomTransformation customTransformation = mCustomTransformations.get(viewType); 167fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek if (customTransformation != null && customTransformation.transformFrom( 1688f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek ownState, notification, transformationAmount)) { 169fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek ownState.recycle(); 170fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek continue; 171fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek } 1724ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek TransformState otherState = notification.getCurrentState(viewType); 1734ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek if (otherState != null) { 1748f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek ownState.transformViewFrom(otherState, transformationAmount); 1754ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek otherState.recycle(); 1764ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek } else { 1774ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek // There's no other view, lets fade us in 1784ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek // Certain views need to prepare the fade in and make sure its children are 1794ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek // completely visible. An example is the notification header. 1808f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek if (transformationAmount == 0.0f) { 1818f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek ownState.prepareFadeIn(); 1828f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek } 1838f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek CrossFadeHelper.fadeIn(mTransformedViews.get(viewType), transformationAmount); 1844ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek } 1854ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek ownState.recycle(); 1864ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek } 1874ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek } 1884ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek } 1894ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek 1904ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek @Override 1914ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek public void setVisible(boolean visible) { 192d607daf30e8ce3d42cc6896271ab1e7679c7a5faSelim Cinek if (mViewTransformationAnimation != null) { 193d607daf30e8ce3d42cc6896271ab1e7679c7a5faSelim Cinek mViewTransformationAnimation.cancel(); 194d607daf30e8ce3d42cc6896271ab1e7679c7a5faSelim Cinek } 1954ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek for (Integer viewType : mTransformedViews.keySet()) { 1964ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek TransformState ownState = getCurrentState(viewType); 1974ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek if (ownState != null) { 19875524417ac507597b19abb2a91389044bec682adAdrian Roos ownState.setVisible(visible, false /* force */); 1994ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek ownState.recycle(); 2004ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek } 2014ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek } 2024ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek } 203646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek 2048f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek private void abortTransformations() { 2058f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek for (Integer viewType : mTransformedViews.keySet()) { 2068f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek TransformState ownState = getCurrentState(viewType); 2078f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek if (ownState != null) { 2088f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek ownState.abortTransformation(); 2098f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek ownState.recycle(); 2108f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek } 2118f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek } 2128f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek } 2138f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek 214646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek /** 215646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek * Add the remaining transformation views such that all views are being transformed correctly 216646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek * @param viewRoot the root below which all elements need to be transformed 217646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek */ 218646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek public void addRemainingTransformTypes(View viewRoot) { 219646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek // lets now tag the right views 220646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek int numValues = mTransformedViews.size(); 221646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek for (int i = 0; i < numValues; i++) { 222646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek View view = mTransformedViews.valueAt(i); 223646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek while (view != viewRoot.getParent()) { 224646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek view.setTag(TAG_CONTAINS_TRANSFORMED_VIEW, true); 225646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek view = (View) view.getParent(); 226646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek } 227646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek } 228646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek Stack<View> stack = new Stack<>(); 229646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek // Add the right views now 230646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek stack.push(viewRoot); 231646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek while (!stack.isEmpty()) { 232646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek View child = stack.pop(); 233646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek if (child.getVisibility() == View.GONE) { 234646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek continue; 235646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek } 236646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek Boolean containsView = (Boolean) child.getTag(TAG_CONTAINS_TRANSFORMED_VIEW); 237646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek if (containsView == null) { 238646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek // This one is unhandled, let's add it to our list. 239646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek int id = child.getId(); 240646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek if (id != View.NO_ID) { 241646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek // We only fade views with an id 242646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek addTransformedView(id, child); 243646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek continue; 244646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek } 245646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek } 246646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek child.setTag(TAG_CONTAINS_TRANSFORMED_VIEW, null); 247646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek if (child instanceof ViewGroup && !mTransformedViews.containsValue(child)){ 248646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek ViewGroup group = (ViewGroup) child; 249646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek for (int i = 0; i < group.getChildCount(); i++) { 250646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek stack.push(group.getChildAt(i)); 251646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek } 252646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek } 253646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek } 254646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek } 255fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek 25675524417ac507597b19abb2a91389044bec682adAdrian Roos public void resetTransformedView(View view) { 25775524417ac507597b19abb2a91389044bec682adAdrian Roos TransformState state = TransformState.createFrom(view); 25875524417ac507597b19abb2a91389044bec682adAdrian Roos state.setVisible(true /* visible */, true /* force */); 25975524417ac507597b19abb2a91389044bec682adAdrian Roos state.recycle(); 26075524417ac507597b19abb2a91389044bec682adAdrian Roos } 26175524417ac507597b19abb2a91389044bec682adAdrian Roos 26275524417ac507597b19abb2a91389044bec682adAdrian Roos /** 26375524417ac507597b19abb2a91389044bec682adAdrian Roos * @return a set of all views are being transformed. 26475524417ac507597b19abb2a91389044bec682adAdrian Roos */ 26575524417ac507597b19abb2a91389044bec682adAdrian Roos public ArraySet<View> getAllTransformingViews() { 26675524417ac507597b19abb2a91389044bec682adAdrian Roos return new ArraySet<>(mTransformedViews.values()); 26775524417ac507597b19abb2a91389044bec682adAdrian Roos } 26875524417ac507597b19abb2a91389044bec682adAdrian Roos 2698f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek public static abstract class CustomTransformation { 270fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek /** 271fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek * Transform a state to the given view 272fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek * @param ownState the state to transform 273fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek * @param notification the view to transform to 2748f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek * @param transformationAmount how much transformation should be done 275fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek * @return whether a custom transformation is performed 276fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek */ 2778f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek public abstract boolean transformTo(TransformState ownState, 2788f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek TransformableView notification, 2798f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek float transformationAmount); 280fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek 281fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek /** 282fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek * Transform to this state from the given view 283fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek * @param ownState the state to transform to 284fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek * @param notification the view to transform from 2858f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek * @param transformationAmount how much transformation should be done 286fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek * @return whether a custom transformation is performed 287fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek */ 2888f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek public abstract boolean transformFrom(TransformState ownState, 2898f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek TransformableView notification, 2908f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek float transformationAmount); 2918f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek 2928f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek /** 2938f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek * Perform a custom initialisation before transforming. 2948f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek * 2958f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek * @param ownState our own state 2968f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek * @param otherState the other state 2978f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek * @return whether a custom initialization is done 2988f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek */ 2998f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek public boolean initTransformation(TransformState ownState, 3008f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek TransformState otherState) { 3018f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek return false; 3028f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek } 3038f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek 3048f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek public boolean customTransformTarget(TransformState ownState, 3058f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek TransformState otherState) { 3068f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek return false; 3078f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek } 308fd3e2624b55a0988fc129c2fe0e2db4885eb87f9Selim Cinek } 3094ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek} 310