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 } 2283a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren if (heightMode == MeasureSpec.UNSPECIFIED) { 2293a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren return tallestView; 2303a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren } 2313a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren if (heightSize > tallestViewSize) { 2323a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren return tallestView; 2333a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren } 2343a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren return smallestView; 2353a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren } 2363a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren 2373a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren @Override 2383a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 2393a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren if (DEBUG) Log.d(TAG, this + " onlayout height: " + (bottom - top)); 2403a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren mLastActive = mActiveChild; 2413a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren int measureSpec = View.MeasureSpec.makeMeasureSpec(bottom - top, 2423a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren View.MeasureSpec.EXACTLY); 2433a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren mActiveChild = selectActiveChild(measureSpec); 2443a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren mActiveChild.setVisibility(View.VISIBLE); 2453a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren 2463a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren if (mLastActive != mActiveChild && mLastActive != null) { 2473a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren if (DEBUG) Log.d(TAG, this + " changed children from: " + mLastActive + 2483a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren " to: " + mActiveChild); 2493a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren 2503a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren mEnteringView = mActiveChild; 2513a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren mLeavingView = mLastActive; 2523a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren 2533a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren mEnteringView.setAlpha(1f); 2543a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren 2553a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren mModestyPanel.setAlpha(1f); 2563a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren mModestyPanel.bringToFront(); 2573a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren mModestyPanelTop = mLeavingView.getHeight(); 2583a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren mModestyPanel.setVisibility(View.VISIBLE); 2593a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren // TODO: mModestyPanel background should be compatible with mLeavingView 2603a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren 2613a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren mLeavingView.bringToFront(); 2623a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren 2633a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren if (mTransitionAnimation.isRunning()) { 2643a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren mTransitionAnimation.cancel(); 2653a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren } 2663a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren mFadeView.setTarget(mLeavingView); 2673a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren mFadeView.setFloatValues(0f); 2683a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren mFadePanel.setFloatValues(0f); 2693a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren mTransitionAnimation.setupStartValues(); 2703a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren mTransitionAnimation.start(); 2713a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren } 2723a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren final int childWidth = mActiveChild.getMeasuredWidth(); 2733a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren final int childHeight = mActiveChild.getMeasuredHeight(); 2743a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren // TODO investigate setting LAYER_TYPE_HARDWARE on mLastActive 2753a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren mActiveChild.layout(0, 0, 0 + childWidth, 0 + childHeight); 2763a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren 2773a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren if (DEBUG) Log.d(TAG, "got modesty offset of " + mModestyPanelTop); 2783a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren mModestyPanel.layout(0, mModestyPanelTop, 0 + childWidth, mModestyPanelTop + childHeight); 2793a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren } 2803a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren 2813a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren @Override 2823a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren public LayoutParams generateLayoutParams(AttributeSet attrs) { 2833a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren if (DEBUG) Log.d(TAG, "generate layout from attrs"); 2843a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren return new SizeAdaptiveLayout.LayoutParams(getContext(), attrs); 2853a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren } 2863a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren 2873a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren @Override 2883a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 2893a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren if (DEBUG) Log.d(TAG, "generate default layout from viewgroup"); 2903a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren return new SizeAdaptiveLayout.LayoutParams(p); 2913a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren } 2923a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren 2933a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren @Override 2943a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren protected LayoutParams generateDefaultLayoutParams() { 2953a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren if (DEBUG) Log.d(TAG, "generate default layout from null"); 2963a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren return new SizeAdaptiveLayout.LayoutParams(); 2973a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren } 2983a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren 2993a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren @Override 3003a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 3013a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren return p instanceof SizeAdaptiveLayout.LayoutParams; 3023a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren } 3033a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren 3043a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren /** 3053a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren * Per-child layout information associated with ViewSizeAdaptiveLayout. 3063a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren * 3073a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren * TODO extend to width and height 3083a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren * 3093a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren * @attr ref android.R.styleable#SizeAdaptiveLayout_Layout_layout_minHeight 3103a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren * @attr ref android.R.styleable#SizeAdaptiveLayout_Layout_layout_maxHeight 3113a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren */ 3123a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren public static class LayoutParams extends ViewGroup.LayoutParams { 3133a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren 3143a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren /** 3153a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren * Indicates the minimum valid height for the child. 3163a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren */ 3173a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren @ViewDebug.ExportedProperty(category = "layout") 3183a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren public int minHeight; 3193a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren 3203a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren /** 3213a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren * Indicates the maximum valid height for the child. 3223a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren */ 3233a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren @ViewDebug.ExportedProperty(category = "layout") 3243a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren public int maxHeight; 3253a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren 3263a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren /** 3273a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren * Constant value for maxHeight that indicates there is not maximum height. 3283a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren */ 3293a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren public static final int UNBOUNDED = -1; 3303a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren 3313a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren /** 3323a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren * {@inheritDoc} 3333a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren */ 3343a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren public LayoutParams(Context c, AttributeSet attrs) { 3353a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren super(c, attrs); 3363a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren if (DEBUG) { 3373a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren Log.d(TAG, "construct layout from attrs"); 3383a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren for (int i = 0; i < attrs.getAttributeCount(); i++) { 3393a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren Log.d(TAG, " " + attrs.getAttributeName(i) + " = " + 3403a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren attrs.getAttributeValue(i)); 3413a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren } 3423a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren } 3433a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren TypedArray a = 3443a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren c.obtainStyledAttributes(attrs, 3453a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren R.styleable.SizeAdaptiveLayout_Layout); 3463a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren 3473a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren minHeight = a.getDimensionPixelSize(MIN_VALID_HEIGHT, 0); 3483a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren if (DEBUG) Log.d(TAG, "got minHeight of: " + minHeight); 3493a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren 3503a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren try { 3513a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren maxHeight = a.getLayoutDimension(MAX_VALID_HEIGHT, UNBOUNDED); 3523a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren if (DEBUG) Log.d(TAG, "got maxHeight of: " + maxHeight); 3533a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren } catch (Exception e) { 3543a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren if (DEBUG) Log.d(TAG, "caught exception looking for maxValidHeight " + e); 3553a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren } 3563a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren 3573a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren a.recycle(); 3583a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren } 3593a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren 3603a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren /** 3613a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren * Creates a new set of layout parameters with the specified width, height 3623a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren * and valid height bounds. 3633a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren * 3643a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren * @param width the width, either {@link #MATCH_PARENT}, 3653a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren * {@link #WRAP_CONTENT} or a fixed size in pixels 3663a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren * @param height the height, either {@link #MATCH_PARENT}, 3673a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren * {@link #WRAP_CONTENT} or a fixed size in pixels 3683a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren * @param minHeight the minimum height of this child 3693a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren * @param maxHeight the maximum height of this child 3703a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren * or {@link #UNBOUNDED} if the child can grow forever 3713a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren */ 3723a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren public LayoutParams(int width, int height, int minHeight, int maxHeight) { 3733a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren super(width, height); 3743a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren this.minHeight = minHeight; 3753a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren this.maxHeight = maxHeight; 3763a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren } 3773a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren 3783a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren /** 3793a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren * {@inheritDoc} 3803a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren */ 3813a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren public LayoutParams(int width, int height) { 3823a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren this(width, height, UNBOUNDED, UNBOUNDED); 3833a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren } 3843a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren 3853a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren /** 3863a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren * Constructs a new LayoutParams with default values as defined in {@link LayoutParams}. 3873a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren */ 3883a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren public LayoutParams() { 3893a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren this(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); 3903a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren } 3913a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren 3923a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren /** 3933a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren * {@inheritDoc} 3943a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren */ 3953a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren public LayoutParams(ViewGroup.LayoutParams p) { 3963a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren super(p); 3973a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren minHeight = UNBOUNDED; 3983a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren maxHeight = UNBOUNDED; 3993a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren } 4003a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren 4013a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren public String debug(String output) { 4023a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren return output + "SizeAdaptiveLayout.LayoutParams={" + 4033a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren ", max=" + maxHeight + 4043a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren ", max=" + minHeight + "}"; 4053a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren } 4063a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren } 4073a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren 4083a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren class BringToFrontOnEnd implements AnimatorListener { 4093a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren @Override 4103a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren public void onAnimationEnd(Animator animation) { 4113a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren if (mCanceledAnimationCount == 0) { 4123a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren mLeavingView.setVisibility(View.GONE); 4133a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren mModestyPanel.setVisibility(View.GONE); 4143a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren mEnteringView.bringToFront(); 4153a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren mEnteringView = null; 4163a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren mLeavingView = null; 4173a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren } else { 4183a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren mCanceledAnimationCount--; 4193a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren } 4203a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren } 4213a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren 4223a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren @Override 4233a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren public void onAnimationCancel(Animator animation) { 4243a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren mCanceledAnimationCount++; 4253a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren } 4263a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren 4273a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren @Override 4283a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren public void onAnimationRepeat(Animator animation) { 4293a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren if (DEBUG) Log.d(TAG, "fade animation repeated: should never happen."); 4303a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren assert(false); 4313a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren } 4323a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren 4333a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren @Override 4343a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren public void onAnimationStart(Animator animation) { 4353a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren } 4363a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren } 4373a59d6e26dbec61ede7d6f87d966698e27c91d78Chris Wren} 438