13a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren/*
23a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren * Copyright (C) 2012 The Android Open Source Project
33a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren *
43a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren * Licensed under the Apache License, Version 2.0 (the "License");
53a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren * you may not use this file except in compliance with the License.
63a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren * You may obtain a copy of the License at
73a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren *
83a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren *      http://www.apache.org/licenses/LICENSE-2.0
93a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren *
103a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren * Unless required by applicable law or agreed to in writing, software
113a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren * distributed under the License is distributed on an "AS IS" BASIS,
123a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren * See the License for the specific language governing permissions and
143a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren * limitations under the License.
153a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren */
163a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
173a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wrenpackage com.android.internal.widget;
183a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
1954dfa5d90e49037eba05f5278076b45428b2bd11Chris Wrenimport java.lang.Math;
2054dfa5d90e49037eba05f5278076b45428b2bd11Chris Wren
213a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wrenimport com.android.internal.R;
223a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
233a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wrenimport android.animation.Animator;
243a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wrenimport android.animation.Animator.AnimatorListener;
253a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wrenimport android.animation.AnimatorSet;
263a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wrenimport android.animation.ObjectAnimator;
273a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wrenimport android.content.Context;
283a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wrenimport android.content.res.TypedArray;
293a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wrenimport android.graphics.Color;
303a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wrenimport android.graphics.drawable.ColorDrawable;
31d84e5937468f6ebf2313ccd5ae54d5405f5e9cdeChris Wrenimport android.graphics.drawable.Drawable;
32d84e5937468f6ebf2313ccd5ae54d5405f5e9cdeChris Wrenimport android.graphics.drawable.StateListDrawable;
333a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wrenimport android.util.AttributeSet;
343a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wrenimport android.util.Log;
35d84e5937468f6ebf2313ccd5ae54d5405f5e9cdeChris Wrenimport android.util.StateSet;
363a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wrenimport android.view.View;
373a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wrenimport android.view.ViewDebug;
383a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wrenimport android.view.ViewGroup;
393a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wrenimport android.widget.RemoteViews.RemoteView;
403a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
413a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren/**
423a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren * A layout that switches between its children based on the requested layout height.
433a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren * Each child specifies its minimum and maximum valid height.  Results are undefined
443a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren * if children specify overlapping ranges.  A child may specify the maximum height
453a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren * as 'unbounded' to indicate that it is willing to be displayed arbitrarily tall.
463a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren *
473a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren * <p>
483a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren * See {@link SizeAdaptiveLayout.LayoutParams} for a full description of the
493a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren * layout parameters used by SizeAdaptiveLayout.
503a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren */
513a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren@RemoteView
523a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wrenpublic class SizeAdaptiveLayout extends ViewGroup {
533a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
543a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    private static final String TAG = "SizeAdaptiveLayout";
553a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    private static final boolean DEBUG = false;
56ed5cc0e1f7648962f5c93e1277d282be75bcd537Chris Wren    private static final boolean REPORT_BAD_BOUNDS = true;
573a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    private static final long CROSSFADE_TIME = 250;
583a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
593a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    // TypedArray indices
603a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    private static final int MIN_VALID_HEIGHT =
613a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            R.styleable.SizeAdaptiveLayout_Layout_layout_minHeight;
623a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    private static final int MAX_VALID_HEIGHT =
633a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            R.styleable.SizeAdaptiveLayout_Layout_layout_maxHeight;
643a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
653a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    // view state
663a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    private View mActiveChild;
673a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    private View mLastActive;
683a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
693a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    // animation state
703a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    private AnimatorSet mTransitionAnimation;
713a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    private AnimatorListener mAnimatorListener;
723a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    private ObjectAnimator mFadePanel;
733a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    private ObjectAnimator mFadeView;
743a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    private int mCanceledAnimationCount;
753a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    private View mEnteringView;
763a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    private View mLeavingView;
773a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    // View used to hide larger views under smaller ones to create a uniform crossfade
783a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    private View mModestyPanel;
793a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    private int mModestyPanelTop;
803a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
813a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    public SizeAdaptiveLayout(Context context) {
823a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        super(context);
833a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        initialize();
843a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    }
853a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
863a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    public SizeAdaptiveLayout(Context context, AttributeSet attrs) {
873a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        super(context, attrs);
883a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        initialize();
893a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    }
903a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
913a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    public SizeAdaptiveLayout(Context context, AttributeSet attrs, int defStyle) {
923a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        super(context, attrs, defStyle);
933a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        initialize();
943a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    }
953a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
963a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    private void initialize() {
973a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        mModestyPanel = new View(getContext());
983a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        // If the SizeAdaptiveLayout has a solid background, use it as a transition hint.
99d84e5937468f6ebf2313ccd5ae54d5405f5e9cdeChris Wren        Drawable background = getBackground();
100d84e5937468f6ebf2313ccd5ae54d5405f5e9cdeChris Wren        if (background instanceof StateListDrawable) {
101d84e5937468f6ebf2313ccd5ae54d5405f5e9cdeChris Wren            StateListDrawable sld = (StateListDrawable) background;
102d84e5937468f6ebf2313ccd5ae54d5405f5e9cdeChris Wren            sld.setState(StateSet.WILD_CARD);
103d84e5937468f6ebf2313ccd5ae54d5405f5e9cdeChris Wren            background = sld.getCurrent();
104d84e5937468f6ebf2313ccd5ae54d5405f5e9cdeChris Wren        }
105d84e5937468f6ebf2313ccd5ae54d5405f5e9cdeChris Wren        if (background instanceof ColorDrawable) {
106d84e5937468f6ebf2313ccd5ae54d5405f5e9cdeChris Wren            mModestyPanel.setBackgroundDrawable(background);
1073a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        } else {
1083a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            mModestyPanel.setBackgroundColor(Color.BLACK);
1093a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        }
1103a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        SizeAdaptiveLayout.LayoutParams layout =
1113a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                new SizeAdaptiveLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
1123a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                                                    ViewGroup.LayoutParams.MATCH_PARENT);
1133a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        mModestyPanel.setLayoutParams(layout);
1143a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        addView(mModestyPanel);
1153a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        mFadePanel = ObjectAnimator.ofFloat(mModestyPanel, "alpha", 0f);
1163a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        mFadeView = ObjectAnimator.ofFloat(null, "alpha", 0f);
1173a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        mAnimatorListener = new BringToFrontOnEnd();
1183a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        mTransitionAnimation = new AnimatorSet();
1193a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        mTransitionAnimation.play(mFadeView).with(mFadePanel);
1203a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        mTransitionAnimation.setDuration(CROSSFADE_TIME);
1213a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        mTransitionAnimation.addListener(mAnimatorListener);
1223a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    }
1233a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
1243a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    /**
1253a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren     * Visible for testing
1263a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren     * @hide
1273a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren     */
1283a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    public Animator getTransitionAnimation() {
1293a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        return mTransitionAnimation;
1303a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    }
1313a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
1323a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    /**
1333a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren     * Visible for testing
1343a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren     * @hide
1353a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren     */
1363a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    public View getModestyPanel() {
1373a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        return mModestyPanel;
1383a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    }
1393a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
1403a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    @Override
1413a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    public void onAttachedToWindow() {
1423a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        mLastActive = null;
1433a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        // make sure all views start off invisible.
1443a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        for (int i = 0; i < getChildCount(); i++) {
1453a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            getChildAt(i).setVisibility(View.GONE);
1463a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        }
1473a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    }
1483a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
1493a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    @Override
1503a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
1513a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        if (DEBUG) Log.d(TAG, this + " measure spec: " +
1523a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                         MeasureSpec.toString(heightMeasureSpec));
1533a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        View model = selectActiveChild(heightMeasureSpec);
1543a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        SizeAdaptiveLayout.LayoutParams lp =
1553a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren          (SizeAdaptiveLayout.LayoutParams) model.getLayoutParams();
1563a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        if (DEBUG) Log.d(TAG, "active min: " + lp.minHeight + " max: " + lp.maxHeight);
1573a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        measureChild(model, widthMeasureSpec, heightMeasureSpec);
1583a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        int childHeight = model.getMeasuredHeight();
1593a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        int childWidth = model.getMeasuredHeight();
1603a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        int childState = combineMeasuredStates(0, model.getMeasuredState());
1613a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        if (DEBUG) Log.d(TAG, "measured child at: " + childHeight);
1623a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        int resolvedWidth = resolveSizeAndState(childWidth, widthMeasureSpec, childState);
16354dfa5d90e49037eba05f5278076b45428b2bd11Chris Wren        int resolvedHeight = resolveSizeAndState(childHeight, heightMeasureSpec, childState);
16454dfa5d90e49037eba05f5278076b45428b2bd11Chris Wren        if (DEBUG) Log.d(TAG, "resolved to: " + resolvedHeight);
16554dfa5d90e49037eba05f5278076b45428b2bd11Chris Wren        int boundedHeight = clampSizeToBounds(resolvedHeight, model);
16654dfa5d90e49037eba05f5278076b45428b2bd11Chris Wren        if (DEBUG) Log.d(TAG, "bounded to: " + boundedHeight);
16754dfa5d90e49037eba05f5278076b45428b2bd11Chris Wren        setMeasuredDimension(resolvedWidth, boundedHeight);
16854dfa5d90e49037eba05f5278076b45428b2bd11Chris Wren    }
16954dfa5d90e49037eba05f5278076b45428b2bd11Chris Wren
17054dfa5d90e49037eba05f5278076b45428b2bd11Chris Wren    private int clampSizeToBounds(int measuredHeight, View child) {
17154dfa5d90e49037eba05f5278076b45428b2bd11Chris Wren        SizeAdaptiveLayout.LayoutParams lp =
17254dfa5d90e49037eba05f5278076b45428b2bd11Chris Wren                (SizeAdaptiveLayout.LayoutParams) child.getLayoutParams();
17354dfa5d90e49037eba05f5278076b45428b2bd11Chris Wren        int heightIn = View.MEASURED_SIZE_MASK & measuredHeight;
17454dfa5d90e49037eba05f5278076b45428b2bd11Chris Wren        int height = Math.max(heightIn, lp.minHeight);
17554dfa5d90e49037eba05f5278076b45428b2bd11Chris Wren        if (lp.maxHeight != SizeAdaptiveLayout.LayoutParams.UNBOUNDED) {
17654dfa5d90e49037eba05f5278076b45428b2bd11Chris Wren            height = Math.min(height, lp.maxHeight);
17754dfa5d90e49037eba05f5278076b45428b2bd11Chris Wren        }
17854dfa5d90e49037eba05f5278076b45428b2bd11Chris Wren
179ed5cc0e1f7648962f5c93e1277d282be75bcd537Chris Wren        if (REPORT_BAD_BOUNDS && heightIn != height) {
18054dfa5d90e49037eba05f5278076b45428b2bd11Chris Wren            Log.d(TAG, this + "child view " + child + " " +
18154dfa5d90e49037eba05f5278076b45428b2bd11Chris Wren                  "measured out of bounds at " + heightIn +"px " +
18254dfa5d90e49037eba05f5278076b45428b2bd11Chris Wren                  "clamped to " + height + "px");
18354dfa5d90e49037eba05f5278076b45428b2bd11Chris Wren        }
18454dfa5d90e49037eba05f5278076b45428b2bd11Chris Wren
18554dfa5d90e49037eba05f5278076b45428b2bd11Chris Wren        return height;
1863a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    }
1873a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
1883a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    //TODO extend to width and height
1893a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    private View selectActiveChild(int heightMeasureSpec) {
1903a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
1913a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
1923a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
1933a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        View unboundedView = null;
1943a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        View tallestView = null;
1953a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        int tallestViewSize = 0;
1963a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        View smallestView = null;
1973a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        int smallestViewSize = Integer.MAX_VALUE;
1983a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        for (int i = 0; i < getChildCount(); i++) {
1993a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            View child = getChildAt(i);
2003a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            if (child != mModestyPanel) {
2013a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                SizeAdaptiveLayout.LayoutParams lp =
2023a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                    (SizeAdaptiveLayout.LayoutParams) child.getLayoutParams();
2033a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                if (DEBUG) Log.d(TAG, "looking at " + i +
2043a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                                 " with min: " + lp.minHeight +
2053a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                                 " max: " +  lp.maxHeight);
2063a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                if (lp.maxHeight == SizeAdaptiveLayout.LayoutParams.UNBOUNDED &&
2073a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                    unboundedView == null) {
2083a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                    unboundedView = child;
2093a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                }
2103a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                if (lp.maxHeight > tallestViewSize) {
2113a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                    tallestViewSize = lp.maxHeight;
2123a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                    tallestView = child;
2133a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                }
2143a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                if (lp.minHeight < smallestViewSize) {
2153a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                    smallestViewSize = lp.minHeight;
2163a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                    smallestView = child;
2173a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                }
2183a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                if (heightMode != MeasureSpec.UNSPECIFIED &&
2193a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                    heightSize >= lp.minHeight && heightSize <= lp.maxHeight) {
2203a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                    if (DEBUG) Log.d(TAG, "  found exact match, finishing early");
2213a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                    return child;
2223a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                }
2233a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            }
2243a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        }
2253a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        if (unboundedView != null) {
2263a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            tallestView = unboundedView;
2273a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        }
2288afcd149970c79054a3a16377834aa0aec35eee0Fabrice Di Meglio        if (heightMode == MeasureSpec.UNSPECIFIED || heightSize > tallestViewSize) {
2293a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            return tallestView;
2308afcd149970c79054a3a16377834aa0aec35eee0Fabrice Di Meglio        } else {
2318afcd149970c79054a3a16377834aa0aec35eee0Fabrice Di Meglio            return smallestView;
2323a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        }
2333a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    }
2343a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
2353a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    @Override
2363a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
2373a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        if (DEBUG) Log.d(TAG, this + " onlayout height: " + (bottom - top));
2383a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        mLastActive = mActiveChild;
2393a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        int measureSpec = View.MeasureSpec.makeMeasureSpec(bottom - top,
2403a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                                                           View.MeasureSpec.EXACTLY);
2413a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        mActiveChild = selectActiveChild(measureSpec);
2423a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        mActiveChild.setVisibility(View.VISIBLE);
2433a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
2443a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        if (mLastActive != mActiveChild && mLastActive != null) {
2453a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            if (DEBUG) Log.d(TAG, this + " changed children from: " + mLastActive +
2463a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                    " to: " + mActiveChild);
2473a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
2483a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            mEnteringView = mActiveChild;
2493a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            mLeavingView = mLastActive;
2503a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
2513a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            mEnteringView.setAlpha(1f);
2523a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
2533a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            mModestyPanel.setAlpha(1f);
2543a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            mModestyPanel.bringToFront();
2553a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            mModestyPanelTop = mLeavingView.getHeight();
2563a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            mModestyPanel.setVisibility(View.VISIBLE);
2573a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            // TODO: mModestyPanel background should be compatible with mLeavingView
2583a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
2593a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            mLeavingView.bringToFront();
2603a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
2613a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            if (mTransitionAnimation.isRunning()) {
2623a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                mTransitionAnimation.cancel();
2633a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            }
2643a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            mFadeView.setTarget(mLeavingView);
2653a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            mFadeView.setFloatValues(0f);
2663a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            mFadePanel.setFloatValues(0f);
2673a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            mTransitionAnimation.setupStartValues();
2683a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            mTransitionAnimation.start();
2693a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        }
2703a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        final int childWidth = mActiveChild.getMeasuredWidth();
2713a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        final int childHeight = mActiveChild.getMeasuredHeight();
2723a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        // TODO investigate setting LAYER_TYPE_HARDWARE on mLastActive
2738afcd149970c79054a3a16377834aa0aec35eee0Fabrice Di Meglio        mActiveChild.layout(0, 0, childWidth, childHeight);
2743a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
2753a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        if (DEBUG) Log.d(TAG, "got modesty offset of " + mModestyPanelTop);
2768afcd149970c79054a3a16377834aa0aec35eee0Fabrice Di Meglio        mModestyPanel.layout(0, mModestyPanelTop, childWidth, mModestyPanelTop + childHeight);
2773a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    }
2783a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
2793a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    @Override
2803a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    public LayoutParams generateLayoutParams(AttributeSet attrs) {
2813a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        if (DEBUG) Log.d(TAG, "generate layout from attrs");
2823a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        return new SizeAdaptiveLayout.LayoutParams(getContext(), attrs);
2833a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    }
2843a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
2853a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    @Override
2863a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
2873a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        if (DEBUG) Log.d(TAG, "generate default layout from viewgroup");
2883a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        return new SizeAdaptiveLayout.LayoutParams(p);
2893a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    }
2903a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
2913a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    @Override
2923a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    protected LayoutParams generateDefaultLayoutParams() {
2933a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        if (DEBUG) Log.d(TAG, "generate default layout from null");
2943a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        return new SizeAdaptiveLayout.LayoutParams();
2953a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    }
2963a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
2973a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    @Override
2983a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
2993a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        return p instanceof SizeAdaptiveLayout.LayoutParams;
3003a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    }
3013a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
3023a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    /**
3033a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren     * Per-child layout information associated with ViewSizeAdaptiveLayout.
3043a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren     *
3053a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren     * TODO extend to width and height
3063a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren     *
3073a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren     * @attr ref android.R.styleable#SizeAdaptiveLayout_Layout_layout_minHeight
3083a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren     * @attr ref android.R.styleable#SizeAdaptiveLayout_Layout_layout_maxHeight
3093a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren     */
3103a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    public static class LayoutParams extends ViewGroup.LayoutParams {
3113a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
3123a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        /**
3133a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren         * Indicates the minimum valid height for the child.
3143a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren         */
3153a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        @ViewDebug.ExportedProperty(category = "layout")
3163a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        public int minHeight;
3173a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
3183a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        /**
3193a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren         * Indicates the maximum valid height for the child.
3203a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren         */
3213a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        @ViewDebug.ExportedProperty(category = "layout")
3223a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        public int maxHeight;
3233a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
3243a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        /**
3253a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren         * Constant value for maxHeight that indicates there is not maximum height.
3263a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren         */
3273a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        public static final int UNBOUNDED = -1;
3283a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
3293a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        /**
3303a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren         * {@inheritDoc}
3313a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren         */
3323a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        public LayoutParams(Context c, AttributeSet attrs) {
3333a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            super(c, attrs);
3343a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            if (DEBUG) {
3353a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                Log.d(TAG, "construct layout from attrs");
3363a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                for (int i = 0; i < attrs.getAttributeCount(); i++) {
3373a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                    Log.d(TAG, " " + attrs.getAttributeName(i) + " = " +
3383a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                          attrs.getAttributeValue(i));
3393a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                }
3403a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            }
3413a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            TypedArray a =
3423a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                    c.obtainStyledAttributes(attrs,
3433a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                            R.styleable.SizeAdaptiveLayout_Layout);
3443a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
3453a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            minHeight = a.getDimensionPixelSize(MIN_VALID_HEIGHT, 0);
3463a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            if (DEBUG) Log.d(TAG, "got minHeight of: " + minHeight);
3473a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
3483a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            try {
3493a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                maxHeight = a.getLayoutDimension(MAX_VALID_HEIGHT, UNBOUNDED);
3503a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                if (DEBUG) Log.d(TAG, "got maxHeight of: " + maxHeight);
3513a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            } catch (Exception e) {
3523a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                if (DEBUG) Log.d(TAG, "caught exception looking for maxValidHeight " + e);
3533a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            }
3543a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
3553a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            a.recycle();
3563a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        }
3573a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
3583a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        /**
3593a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren         * Creates a new set of layout parameters with the specified width, height
3603a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren         * and valid height bounds.
3613a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren         *
3623a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren         * @param width the width, either {@link #MATCH_PARENT},
3633a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren         *        {@link #WRAP_CONTENT} or a fixed size in pixels
3643a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren         * @param height the height, either {@link #MATCH_PARENT},
3653a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren         *        {@link #WRAP_CONTENT} or a fixed size in pixels
3663a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren         * @param minHeight the minimum height of this child
3673a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren         * @param maxHeight the maximum height of this child
3683a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren         *        or {@link #UNBOUNDED} if the child can grow forever
3693a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren         */
3703a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        public LayoutParams(int width, int height, int minHeight, int maxHeight) {
3713a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            super(width, height);
3723a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            this.minHeight = minHeight;
3733a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            this.maxHeight = maxHeight;
3743a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        }
3753a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
3763a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        /**
3773a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren         * {@inheritDoc}
3783a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren         */
3793a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        public LayoutParams(int width, int height) {
3803a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            this(width, height, UNBOUNDED, UNBOUNDED);
3813a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        }
3823a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
3833a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        /**
3843a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren         * Constructs a new LayoutParams with default values as defined in {@link LayoutParams}.
3853a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren         */
3863a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        public LayoutParams() {
3873a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            this(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
3883a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        }
3893a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
3903a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        /**
3913a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren         * {@inheritDoc}
3923a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren         */
3933a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        public LayoutParams(ViewGroup.LayoutParams p) {
3943a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            super(p);
3953a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            minHeight = UNBOUNDED;
3963a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            maxHeight = UNBOUNDED;
3973a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        }
3983a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
3993a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        public String debug(String output) {
4003a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            return output + "SizeAdaptiveLayout.LayoutParams={" +
4013a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                    ", max=" + maxHeight +
4023a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                    ", max=" + minHeight + "}";
4033a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        }
4043a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    }
4053a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
4063a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    class BringToFrontOnEnd implements AnimatorListener {
4073a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        @Override
4083a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            public void onAnimationEnd(Animator animation) {
4093a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            if (mCanceledAnimationCount == 0) {
4103a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                mLeavingView.setVisibility(View.GONE);
4113a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                mModestyPanel.setVisibility(View.GONE);
4123a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                mEnteringView.bringToFront();
4133a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                mEnteringView = null;
4143a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                mLeavingView = null;
4153a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            } else {
4163a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren                mCanceledAnimationCount--;
4173a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            }
4183a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        }
4193a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
4203a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        @Override
4213a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            public void onAnimationCancel(Animator animation) {
4223a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            mCanceledAnimationCount++;
4233a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        }
4243a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
4253a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        @Override
4263a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            public void onAnimationRepeat(Animator animation) {
4273a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            if (DEBUG) Log.d(TAG, "fade animation repeated: should never happen.");
4283a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            assert(false);
4293a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        }
4303a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren
4313a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        @Override
4323a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren            public void onAnimationStart(Animator animation) {
4333a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren        }
4343a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren    }
4353a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren}
436