// Path: flow/src/main/java/flow/KeyChanger.java
// public interface KeyChanger {
//   void changeKey(@Nullable State outgoingState, @NonNull State incomingState,
//       @NonNull Direction direction, @NonNull Map<Object, Context> incomingContexts,
//       @NonNull TraversalCallback callback);
// }
// 
// Path: flow/src/main/java/flow/State.java
// public class State {
//   /** Creates a State instance that has no state and is effectively immutable. */
//   @NonNull public static State empty(@NonNull final Object key) {
//     return new EmptyState(key);
//   }
// 
//   @NonNull static State fromBundle(@NonNull Bundle savedState, @NonNull KeyParceler parceler) {
//     Object key = parceler.toKey(savedState.getParcelable("KEY"));
//     State state = new State(key);
//     state.viewState = savedState.getSparseParcelableArray("VIEW_STATE");
//     state.bundle = savedState.getBundle("BUNDLE");
//     return state;
//   }
// 
//   private final Object key;
//   @Nullable private Bundle bundle;
//   @Nullable SparseArray<Parcelable> viewState;
// 
//   State(Object key) {
//     // No external instances.
//     this.key = key;
//   }
// 
//   @NonNull public final <T> T getKey() {
//     @SuppressWarnings("unchecked") final T state = (T) key;
//     return state;
//   }
// 
//   public void save(@NonNull View view) {
//     SparseArray<Parcelable> state = new SparseArray<>();
//     view.saveHierarchyState(state);
//     viewState = state;
//   }
// 
//   public void restore(@NonNull View view) {
//     if (viewState != null) {
//       view.restoreHierarchyState(viewState);
//     }
//   }
// 
//   public void setBundle(@Nullable Bundle bundle) {
//     this.bundle = bundle;
//   }
// 
//   @Nullable public Bundle getBundle() {
//     return bundle;
//   }
// 
//   Bundle toBundle(KeyParceler parceler) {
//     Bundle outState = new Bundle();
//     outState.putParcelable("KEY", parceler.toParcelable(getKey()));
//     if (viewState != null && viewState.size() > 0) {
//       outState.putSparseParcelableArray("VIEW_STATE", viewState);
//     }
//     if (bundle != null && !bundle.isEmpty()) {
//       outState.putBundle("BUNDLE", bundle);
//     }
//     return outState;
//   }
// 
//   @Override public boolean equals(Object o) {
//     if (this == o) return true;
//     if (o == null || getClass() != o.getClass()) return false;
//     State state = (State) o;
//     return (getKey().equals(state.getKey()));
//   }
// 
//   @Override public int hashCode() {
//     return getKey().hashCode();
//   }
// 
//   @Override public String toString() {
//     return getKey().toString();
//   }
// 
//   private static final class EmptyState extends State {
//     public EmptyState(Object flowState) {
//       super(flowState);
//     }
// 
//     @Override public void save(@NonNull View view) {
//     }
// 
//     @Override public void restore(@NonNull View view) {
//     }
// 
//     @Override public void setBundle(Bundle bundle) {
//     }
// 
//     @Nullable @Override public Bundle getBundle() {
//       return null;
//     }
//   }
// }
// 
// Path: app/src/main/java/leonardo2204/com/br/flowtests/flow/FlowUtils.java
// public final class FlowUtils {
// 
//     public interface OnMeasuredCallback {
//         void onMeasured(View view, int width, int height);
//     }
// 
//     public static void waitForMeasure(final View view, final OnMeasuredCallback callback) {
//         int width = view.getWidth();
//         int height = view.getHeight();
// 
//         if (width > 0 && height > 0) {
//             callback.onMeasured(view, width, height);
//             return;
//         }
// 
//         view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
//             @Override
//             public boolean onPreDraw() {
//                 final ViewTreeObserver observer = view.getViewTreeObserver();
//                 if (observer.isAlive()) {
//                     observer.removeOnPreDrawListener(this);
//                 }
// 
//                 callback.onMeasured(view, view.getWidth(), view.getHeight());
// 
//                 return true;
//             }
//         });
//     }
// 
//     private FlowUtils() {
//     }
// }


import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.app.Activity;
import android.content.Context;
import android.support.annotation.LayoutRes;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
import flow.Direction;
import flow.KeyChanger;
import flow.State;
import flow.TraversalCallback;
import leonardo2204.com.br.flowtests.Layout;
import leonardo2204.com.br.flowtests.R;
import leonardo2204.com.br.flowtests.flow.FlowUtils;
                          final TraversalCallback callback) {

        final ViewGroup frame = (ViewGroup) activity.findViewById(R.id.content);

        View fromView = null;
        if(incomingState != null){

            if(frame.getChildCount() > 0){
                fromView = frame.getChildAt(0);
                incomingState.save(frame.getChildAt(0));
            }
        }

        Context context = incomingContexts.get(incomingState.getKey());
        @LayoutRes final int layout = getLayout(incomingState.getKey());

        //MortarScope scope = MortarScope.getScope(context.getApplicationContext());
        //Context newContext =  scope.findChild(incomingState.getKey().getClass().getName()).createContext(context);

        final View incomingView = LayoutInflater.from(context).inflate(layout,frame,false);
        if(outgoingState != null)
            outgoingState.restore(incomingView);

        if(fromView == null || direction == Direction.REPLACE) {
            frame.removeAllViews();
            frame.addView(incomingView);
            callback.onTraversalCompleted();
        } else {
            frame.addView(incomingView);
            final View fromViewFinal = fromView;
// Path: flow/src/main/java/flow/KeyChanger.java
// public interface KeyChanger {
//   void changeKey(@Nullable State outgoingState, @NonNull State incomingState,
//       @NonNull Direction direction, @NonNull Map<Object, Context> incomingContexts,
//       @NonNull TraversalCallback callback);
// }
// 
// Path: flow/src/main/java/flow/State.java
// public class State {
//   /** Creates a State instance that has no state and is effectively immutable. */
//   @NonNull public static State empty(@NonNull final Object key) {
//     return new EmptyState(key);
//   }
// 
//   @NonNull static State fromBundle(@NonNull Bundle savedState, @NonNull KeyParceler parceler) {
//     Object key = parceler.toKey(savedState.getParcelable("KEY"));
//     State state = new State(key);
//     state.viewState = savedState.getSparseParcelableArray("VIEW_STATE");
//     state.bundle = savedState.getBundle("BUNDLE");
//     return state;
//   }
// 
//   private final Object key;
//   @Nullable private Bundle bundle;
//   @Nullable SparseArray<Parcelable> viewState;
// 
//   State(Object key) {
//     // No external instances.
//     this.key = key;
//   }
// 
//   @NonNull public final <T> T getKey() {
//     @SuppressWarnings("unchecked") final T state = (T) key;
//     return state;
//   }
// 
//   public void save(@NonNull View view) {
//     SparseArray<Parcelable> state = new SparseArray<>();
//     view.saveHierarchyState(state);
//     viewState = state;
//   }
// 
//   public void restore(@NonNull View view) {
//     if (viewState != null) {
//       view.restoreHierarchyState(viewState);
//     }
//   }
// 
//   public void setBundle(@Nullable Bundle bundle) {
//     this.bundle = bundle;
//   }
// 
//   @Nullable public Bundle getBundle() {
//     return bundle;
//   }
// 
//   Bundle toBundle(KeyParceler parceler) {
//     Bundle outState = new Bundle();
//     outState.putParcelable("KEY", parceler.toParcelable(getKey()));
//     if (viewState != null && viewState.size() > 0) {
//       outState.putSparseParcelableArray("VIEW_STATE", viewState);
//     }
//     if (bundle != null && !bundle.isEmpty()) {
//       outState.putBundle("BUNDLE", bundle);
//     }
//     return outState;
//   }
// 
//   @Override public boolean equals(Object o) {
//     if (this == o) return true;
//     if (o == null || getClass() != o.getClass()) return false;
//     State state = (State) o;
//     return (getKey().equals(state.getKey()));
//   }
// 
//   @Override public int hashCode() {
//     return getKey().hashCode();
//   }
// 
//   @Override public String toString() {
//     return getKey().toString();
//   }
// 
//   private static final class EmptyState extends State {
//     public EmptyState(Object flowState) {
//       super(flowState);
//     }
// 
//     @Override public void save(@NonNull View view) {
//     }
// 
//     @Override public void restore(@NonNull View view) {
//     }
// 
//     @Override public void setBundle(Bundle bundle) {
//     }
// 
//     @Nullable @Override public Bundle getBundle() {
//       return null;
//     }
//   }
// }
// 
// Path: app/src/main/java/leonardo2204/com/br/flowtests/flow/FlowUtils.java
// public final class FlowUtils {
// 
//     public interface OnMeasuredCallback {
//         void onMeasured(View view, int width, int height);
//     }
// 
//     public static void waitForMeasure(final View view, final OnMeasuredCallback callback) {
//         int width = view.getWidth();
//         int height = view.getHeight();
// 
//         if (width > 0 && height > 0) {
//             callback.onMeasured(view, width, height);
//             return;
//         }
// 
//         view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
//             @Override
//             public boolean onPreDraw() {
//                 final ViewTreeObserver observer = view.getViewTreeObserver();
//                 if (observer.isAlive()) {
//                     observer.removeOnPreDrawListener(this);
//                 }
// 
//                 callback.onMeasured(view, view.getWidth(), view.getHeight());
// 
//                 return true;
//             }
//         });
//     }
// 
//     private FlowUtils() {
//     }
// }


// Path: app/src/main/java/leonardo2204/com/br/flowtests/flow/dispatcher/Changer.java
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.app.Activity;
import android.content.Context;
import android.support.annotation.LayoutRes;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
import flow.Direction;
import flow.KeyChanger;
import flow.State;
import flow.TraversalCallback;
import leonardo2204.com.br.flowtests.Layout;
import leonardo2204.com.br.flowtests.R;
import leonardo2204.com.br.flowtests.flow.FlowUtils;

                          final TraversalCallback callback) {

        final ViewGroup frame = (ViewGroup) activity.findViewById(R.id.content);

        View fromView = null;
        if(incomingState != null){

            if(frame.getChildCount() > 0){
                fromView = frame.getChildAt(0);
                incomingState.save(frame.getChildAt(0));
            }
        }

        Context context = incomingContexts.get(incomingState.getKey());
        @LayoutRes final int layout = getLayout(incomingState.getKey());

        //MortarScope scope = MortarScope.getScope(context.getApplicationContext());
        //Context newContext =  scope.findChild(incomingState.getKey().getClass().getName()).createContext(context);

        final View incomingView = LayoutInflater.from(context).inflate(layout,frame,false);
        if(outgoingState != null)
            outgoingState.restore(incomingView);

        if(fromView == null || direction == Direction.REPLACE) {
            frame.removeAllViews();
            frame.addView(incomingView);
            callback.onTraversalCompleted();
        } else {
            frame.addView(incomingView);
            final View fromViewFinal = fromView;
            FlowUtils.waitForMeasure(incomingView, new FlowUtils.OnMeasuredCallback() {